我正在调用一个返回响应的 API,如下所示
{
"data": {
"name": "John",
"score": 51
},
"ret": 0
}
发生错误时,响应将更改为
{
"data": "error message",
"ret": 1
}
请注意,"data"属性因对象而异。
现在我能够使用 JsonConverter 在不同类型上返回不同的类,问题是保存此响应的模型。
即如果我使用public class MyResponse
{
[JsonConverter(typeof(MyResponseType))]
[JsonProperty(PropertyName = "data")]
public MyResponseType Data { get; set; }
[JsonProperty(PropertyName = "ret")]
public int ReturnCode { get; set; }
}
MyResponseType当然可以保存对象,但不能强制转换为字符串。
我尝试使用泛型类型来保存数据
public class MyReponse<T>
{
[JsonProperty(PropertyName = "data")]
public T Data { get; set; }
[JsonProperty(PropertyName = "ret")]
public int ReturnCode { get; set; }
}
但这里出现了另一个问题,这个MyReponse类由.Net Core中的服务使用,其中服务在ConfigureServices步骤中通过依赖注入初始化,这不允许传入泛型。这就是此模型在服务中的使用方式以及服务的初始化方式
服务:
public class MyService<T> : IMyService {
public bool someMethod() {
...
var resp = JsonConvert.DeserializeObject<MyReponse<T>>(myResponse);
...
}
}
启动时.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IMyService, MyService>(); // Generics can't be passed in here
...
}
关于如何创建可以处理这种情况的适当数据模型的任何建议?
因此,假设出现错误时"ret"值为 1,我能想到的最简单的解决方案是在强制转换之前检查该属性。
所以你可以有两个模型
public class MyResponse
{
[JsonConverter(typeof(MyResponseType))]
[JsonProperty(PropertyName = "data")]
public MyResponseType Data { get; set; }
[JsonProperty(PropertyName = "ret")]
public int ReturnCode { get; set; }
}
和
public class MyErrorResponse
{
[JsonProperty(PropertyName = "data")]
public string Data { get; set; }
[JsonProperty(PropertyName = "ret")]
public int ReturnCode { get; set; }
}
然后决定应该投射到哪种类型。
我会在 api 客户端级别管理它。
public class MyApiClientException: Exception
{
public int ErrorCode { get; private set; }
public MyApiClientException(string message, int errorCode): base(message)
{
this.ErrorCode = errorCode;
}
}
public class MyApiClient
{
private readonly HttpClient httpClient;
public MyApiClient(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task<T> GetAsync<T>(string uri)
{
using (var response = await httpClient.GetAsync(uri))
{
var stringContent = await response.Content.ReadAsStringAsync();
var jtoken = JToken.Parse(stringContent);
int errorCode = (int)jtoken["ret"];
var jdata = jtoken["data"];
if (errorCode > 0)
{
throw new MyApiClientException((string)jdata, errorCode);
}
return jdata.ToObject<T>();
}
}
}
然后像这样打电话:
var data = await client.GetAsync<MyResponseType>("api/whatever");
请注意,您不再需要JsonConverter
。MyApiClient.GetAsync
返回MyResponseType
或其他什么,它不再返回整个响应MyResponse
,因为一旦你知道ret = 0
这意味着没有错误,你就不再需要它,只需要数据。
关于依赖注入,与其使服务类泛型MyService<T>
,不如使它成为非泛型,并且它们的方法泛型。
另一种选择是提供这样的工厂:
public class MyServiceFactory
{
public MyService<T> CreateService<T>()
{
throw NotImplementedException();
}
}