【问题标题】:How to deserialise or format WebAPI result into specific json structure如何将 Web API 结果反序列化或格式化为特定的 json 结构
【发布时间】:2020-12-07 14:29:36
【问题描述】:

我正在使用 .net core 3.1 Web API。这是从外部 API 获取数据。以下是我的代码控制器部分

[HttpGet("transinfo/{id}")]        
public Object GettransactionData(int id)
{
  var result=_transaction.GettransactionDetails(id).Result;
  List<PipeLineResponse> P = JsonConvert.DeserializeObject<List<PipeLineResponse>>(result.ToString());
  PipeLineResponseObject P1 = new PipeLineResponseObject();
  P1.data = P;
  return P1;
}

而我的服务代码如下

public async Task<Object> GettransactionDetails(int id)
{
  string request=//fetched from db 
  var stringContent = new StringContent(request);            
  Client = utilities.GetHttpClient();
  string apiEndpoint=//External API URL
  HttpResponseMessage httpResponseMessage = await Client.PostAsync(apiEndpoint, stringContent);
  if (httpResponseMessage.IsSuccessStatusCode)
  {
      return await httpResponseMessage.Content.ReadAsAsync<Object>();     
  }
}

但我得到以下格式的结果(邮递员的回复)

{
  "data": [
    {
      "Tranid": "34540d40-7db8-44c1-9a2a-5072c2d01756",
      "fields": {
        "Fields.10": "1001",
        "Fields.11": "Test1",
        "Fields.12": "Fixed1"
      }
    },
    {
      "Tranid": "145800f9-c4a5-4625-84d7-29af5e674a14",
      "fields": {
        "Fields.10": "1002",
        "Fields.11": "Test2",
        "Fields.12": "Fixed2"
      }
    }
  ]
}

但我需要以下格式的数据

{
  "data": [
    {
      "TransactionID": "34540d40-7db8-44c1-9a2a-5072c2d01756",
      "fieldsList": [
        {
          "fieldId": "10",
          "fieldValue": "1001"
        },
        {
          "fieldId": "11",
          "fieldValue": "Test1"
        },
        {
          "fieldId": "12",
          "fieldValue": "Fixed1"
        }
      ]
    },
    {
      "TransactionID": "145800f9-c4a5-4625-84d7-29af5e674a14",
      "fieldsList": [
        {
          "fieldId": "10",
          "fieldValue": "1002"
        },
        {
          "fieldId": "11",
          "fieldValue": "Test2"
        },
        {
          "fieldId": "12",
          "fieldValue": "Fixed2"
        }
      ]
    }
  ]
}

我怎样才能做到这一点?可以使用 JObject 或 JArray 反序列化吗?请帮忙。 我试图创建以下模型类并尝试反序列化但没有得到预期的结果。

public class PipeLineResponse
{
   public string TransactionID { get; set; }
   public List<Dictionary<string, string>> fields { get; set; }
}    

public class PipeLineResponseObject
{
 public List<PipeLineResponse> data { get; set; }
}

如何以任何 DTO 或 Automapper 都可以使用的格式创建该 json?请帮我提供样品。

【问题讨论】:

  • 您可以使用自定义解析 json 字符串来实现。但是,更简洁的方法可以创建所需结构的 ViewModel(对于您的情况,您可以拥有一个属性为 data 类型为 IEnumerable&lt;T&gt; 的类,而 T 是内部对象的类型),map服务对您的视图模型的响应,并让默认序列化从那里接管。
  • @SaiGummaluri :我在创建类模型后尝试过,但对如何创建它感到困惑
  • 试试这个json2csharp.com,只需粘贴你的json,它就会给你类结构
  • @AcAnanth - 您正在调用的服务的响应实际上将fields 作为一个对象返回,其中所有字段都捆绑在一起。但是,您所需的结构具有一组单独的字段。由于这种差异,您会遇到错误。一个出路可以是将您的响应捕获到中间DTO(这可以是您使用json2csharp 获得的结构)。手动或使用 AutoMapper 之类的方法将此 DTO 映射到 ViewModel。您正在查看的要求是完全可行的。
  • @AcAnanth - 或者,如果您不想采用 DTO 路线,您可以利用 Newtonsoft.Json 并使用 LINQ To JSON:解析来自服务的响应并将其手动映射到 ViewModel。 newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm

标签: c# .net json asp.net-web-api asp.net-core-webapi


【解决方案1】:

我在这里提出的解决方案采用DTO 方法。来自服务的响应被反序列化到 DTO,进一步被手动映射到我们发送给客户端的最终 ViewModel无论如何,这个实现已经准备好生产并且还有改进的余地,为此我在 cmets 中添加了。但这让我们详细了解了我们如何处理这些场景。 我们正在使用Newtonsoft.Json,可以通过NuGet 包管理器将其拉入您的项目中。

DTO 的结构

// RootDTO.cs
// This structure is directly based on the response obtained from remote service.

public class Fields
{
    [JsonProperty(PropertyName ="Fields.10")]
    public string Fields10 { get; set; }
    [JsonProperty(PropertyName = "Fields.11")]
    public string Fields11 { get; set; }
    [JsonProperty(PropertyName = "Fields.12")]
    public string Fields12 { get; set; } 
}

public class Datum
{
    public string Tranid { get; set; }
    public Fields fields { get; set; }
}

public class RootDTO
{
    [JsonProperty(PropertyName ="data")]
    public List<Datum> data { get; set; }
}

ViewModel的结构

// PipelineResponse.cs
public class FieldsList
{
    public string fieldId { get; set; }
    public string fieldValue { get; set; }
}

public class ResponseDatum
{
    [JsonProperty(PropertyName = "TransactionID")]
    public string TransactionID { get; set; }
    public List<FieldsList> fieldsList { get; set; }
}
   
public class PipelineResponse
{        
    public List<ResponseDatum> data { get; set; }
}

反序列化对DTO的响应

// ...other code
var responseString = await httpResponseMessage.Content.ReadAsAsync<Object>();
// This is where the DTO object is created. This should be mapped to view model type.
var responseDTO = JsonConvert.DeserializeObject<RootDTO>(responseString);

DTO 映射到ViewModel

从 DTO 类型到 ViewModel 类型的映射需要在向客户端发送响应之前完成。它是发送给客户端的视图模型类型。根据您所遵循的做法,此逻辑可以放置在单独的帮助程序中(理想情况下,用于分离关注点)或任何其他位置。

public PipelineResponse ConvertResponseDTOToResponse(RootDTO responseDTO)
{
    // FieldId is being hardcoded here. Instead, you can use Reflection to 
    // fetch the property name, split on '.' and take the item at index 1.
    // Notice that DTO properties have "JsonProperty" attributes for this.
    try
    {        
        List<ResponseDatum> responseList = new List<ResponseDatum>();
        if (responseDTO != null)
        {
            // Reflection can be used to avoid hardcoding on 'fieldId'
            foreach (var item in responseDTO.data)
            {
                var responseDataObj = new ResponseDatum
                {
                    TransactionID = item.Tranid,
                    fieldsList = new List<FieldsList>
                    {
                        new FieldsList
                        {
                            fieldValue = item.fields.Fields10,
                            fieldId = "10"
                        },
                        new FieldsList
                        {
                            fieldValue = item.fields.Fields11,
                            fieldId = "11"
                        },
                        new FieldsList
                        {
                            fieldValue = item.fields.Fields12,
                            fieldId = "12"
                        }
                    }
                };
                responseList.Add(responseDataObj);
            }
        }

        // This object is what you return from your controller endpoint finally.
        // The serialized response of this object is of the json structure you need 
        return new PipelineResponse { data = responseList };
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

【讨论】:

  • 感谢您的回答。 public class Fields 这个是硬编码的 10,11 和 12 对吧?在我的情况下,我的变化,没有字段可能会改变。有动态的方法来处理吗?
  • @AcAnanth - 如果你想处理不同的 json 结构,你可以通过创建一个自定义的JsonConverter 来实现(我们在上面的实现中使用了默认的 JsonConverter)。映射将使用reflection,就像我在答案中的 cmets 中提到的那样。看看这个,如果您需要进一步的帮助,请告诉我! jerriepelser.com/blog/…
  • 非常感谢兄弟。真的很有帮助
猜你喜欢
  • 2019-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
相关资源
最近更新 更多