如何创建不同类型的JSON数据模型



我正在调用一个返回响应的 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");

请注意,您不再需要JsonConverterMyApiClient.GetAsync返回MyResponseType或其他什么,它不再返回整个响应MyResponse,因为一旦你知道ret = 0这意味着没有错误,你就不再需要它,只需要数据。

关于依赖注入,与其使服务类泛型MyService<T>,不如使它成为非泛型,并且它们的方法泛型。

另一种选择是提供这样的工厂:

public class MyServiceFactory 
{
public MyService<T> CreateService<T>() 
{
throw NotImplementedException();
}
}

最新更新