我必须管理对服务的大量 API 调用,并且所有响应消息都有一个共同的结构,除了“数据”字段,它根据调用的端点以及调用是否成功而有所不同。寻找一种巧妙地管理整个情况的方法,我使用泛型和 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
谢谢