我必须管理对服务的大量API调用,并且所有响应消息都有一个公共结构,除了"data“字段,该字段根据调用的端点和调用是否成功而变化。为了找到一种聪明地管理整个情况的方法,我用泛型和Mapster提供了一个令人满意的解决方案。这是一个典型的响应消息:
{
"type": "send",
"datetime": "2022-02-21",
"correlation_id": "dc659b16-0781-4e32-ae0d-fbe737ff3215",
"data": {
"id": 22,
"description": "blue t-shirt with stripes",
"category": "t-shirt",
"size": "XL"
}
}数据字段是完全可变的,有时是一级结构,有时是多级结构,有时是数组,有时是简单字符串,有时是空值。显然,响应消息是已知的,并且取决于被调用的端点,所以我知道当我进行调用时会期望什么,但是在这种情况下,结构仍然可以改变。如果调用失败且出现错误,则仍将从端点返回200,但响应如下:
{
"type": "error",
"datetime": "2022-02-21",
"correlation_id": "dc659b16-0781-4e32-ae0d-fbe737ff3215",
"data": {
"id": 1522,
"description": "product code not found",
}
}为了寻找一个优雅而简洁的解决方案,用一个方法来管理所有的案例,我找到了一个解决方案:这些是我的模型:
public class Response<T> where T : class
{
public string type { get; set; }
public T data { get; set; } = null;
public Error Error { get; set; } = null;
public bool IsError => Error != null;
public string ErrorMessage => IsError ? $"An error occurred. Error code {Error.id} - {Error.description}" : "";
}
public class Customer
{
public int customerId { get; set; }
public string name { get; set; }
}
public class Supplier
{
public int supplierId { get; set; }
public string company { get; set; }
}
public class Error
{
public int id { get; set; }
public string description { get; set; }
}这是我管理所有反序列化的功能:
private static Response<T> GetData<T>(string json) where T : class
{
//Deserialize the json using dynamic as T so can receive any kind of data structure
var resp = JsonConvert.DeserializeObject<Response<dynamic>>(json);
var ret = resp.Adapt<Response<T>>();
if (resp.type == "error")
{
//Adapt the dynamic to Error property
ret.Error = ((object)resp.data).Adapt<Error>();
ret.data = null;
}
return ret;
}所以我用这种方式调用我的函数:
var customerData = GetData<Customer>("{\"type\":\"send\", \"data\": {\"id\":1, \"name\": \"John Ross\"}}");
if (customerData.IsError)
Console.WriteLine($"ERROR! {customerData.ErrorMessage}");
else
Console.WriteLine($"The response is OK. Customer name is {customerData.data.name}");正如您所看到的,所采用的解决方案是优雅的,而且效果很好。我还没有找到解决方案的唯一问题是,如果我尝试将错误的json插入T类型,Mapster.Adapt就不会失败,因此,如果我在供应商类中反序列化客户的json,我就不会注意到这个问题。
在Mapster中是否有一种方法可以知道我试图适应的对象是否与目标类型不兼容?所以我可以提出一个例外,我的程序将是完美的。
下面是一个带有工作示例https://github.com/mmassari/MapDynamicWIthMapster的回购
谢谢
发布于 2022-02-13 11:18:19
您正在尝试的解决方案可能看起来很优雅,但实际上您可能会引入一个code smell,它可能会在将来很难捕获bug。
您可能需要重新考虑使用有关端点的知识将响应反序列化为其正确的响应类型。这是一个很好的实践,对您自己和未来的开发人员来说都很容易理解和维护。
对于有问题的“未找到的产品代码”响应,您可以添加一个验证步骤,将JSON响应反序列化到JObject类型的对象,您可以安全地查询该对象,以检查是否存在已知的错误消息。
下面是一个简单的例子:
private static void ValidateResponse(string json)
{
var knownErrors = new List<string>()
{
"Product code not found",
"Customer does not exist",
"Other known errors here"
};
var jobj = JsonConvert.DeserializeObject<JObject>(json);
var error = jobj.SelectToken("data.description");
if (error != null)
{
var errorMessage = error.Value<string>();
if (knownErrors.Contains(errorMessage))
{
throw new ApplicationException(errorMessage);
}
}
}您可能需要考虑修整和正常化套管,以避免被错误消息中的小变化抛出。
https://stackoverflow.com/questions/71078222
复制相似问题