在MVC中反序列化JSON

时间:2017-08-27 21:55:11

标签: c# json asp.net-mvc azure

我是.NET和MVC的新手。努力将一些JSON反序列化为ViewBag中的对象。 JSON来自Azure搜索。我已经验证了WebHttpRequest返回JSON,如下所示:

{
    "@odata.context": "https://url.toazuresearch/indexes('index01')/$metadata#docs",
    "value": [
        {
            "@search.score": 0.31507686,
            "Id": "34",
            "Date": "2017-08-24T09:14:56.193Z",
            "Domain": "domain.com",
            "RuleName": "Legacy Reports",
            "Log": "Log text",
            "ChangeId": "changeId",
            "ParentId": "0",
            "Comments": "Comments"
        },
        {
            "@search.score": 0.2553736,
            "Id": "35",
            "Date": "2017-08-24T09:14:56.193Z",
            "Domain": "domain.com",
            "RuleName": "Legacy Reports",
            "Log": "Log text",
            "ChangeId": "changeId",
            "ParentId": "0",
            "Comments": "Comments"
        }
    ]
}

我的班级看起来像这样:

[DataContract]
public class SearchResult
{
    [DataMember]
    public float SearchScore { get; set; }
    [DataMember]
    public string Id { get; set; }
    [DataMember]
    public DateTime Date { get; set; }
    [DataMember]
    public string Domain { get; set; }
    [DataMember]
    public string RuleName { get; set; }
    [DataMember]
    public string Log { get; set; }
    [DataMember]
    public string ChangeId { get; set; }
    [DataMember]
    public string ParentId { get; set; }
    [DataMember]
    public string Comments { get; set; }
}

我在控制器中的代码来处理响应:

try
{
    WebResponse response = request.GetResponse();
    using (Stream responseStream = response.GetResponseStream())
    {
        StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);

        DataContractJsonSerializer serializer = 
            new DataContractJsonSerializer(typeof(IEnumerable<SearchResult>));
        var results = 
            (IEnumerable<SearchResult>)serializer.ReadObject(responseStream);

        ViewBag.SearchResults = results;
    }
}
catch (WebException ex)
{
    WebResponse errorResponse = ex.Response;
    using (Stream responseStream = errorResponse.GetResponseStream())
    {
        StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
        ViewBag.SearchError = reader.ReadToEnd();
        ViewBag.SearchResults = "0 Results";

    }
    throw;
}

最后,我试图在我看来循环结果:

@foreach (var searchResult in ViewBag.SearchResults)
{
    @searchResult.Id <br />
}

我只是得到一个空白页面。我在VS中测试没有例外。

2 个答案:

答案 0 :(得分:6)

使用Json.Net代替 DataContractJsonSerializer 更容易。

首先你的模特:

public class Value
{
    [JsonProperty("@search.score")]
    public double SearchScore { get; set; }
    public string Id { get; set; }
    public string Date { get; set; }
    public string Domain { get; set; }
    public string RuleName { get; set; }
    public string Log { get; set; }
    public string ChangeId { get; set; }
    public string ParentId { get; set; }
    public string Comments { get; set; }
}

public class RootObject
{
    [JsonProperty("@odata.context")]
    public string Contextcontext { get; set; }
    public List<Value> value { get; set; }
}

序列化代码:

var result = JsonConvert.DeserializeObject<RootObject>(reader.ReadToEnd());

修改

如果您真的想使用 DataContractJsonSerializer 方式,那么您的模型将是

[DataContract]
public class SearchResult
{
    [DataMember(Name = "@search.score")]
    public float SearchScore { get; set; }
    [DataMember]
    public string Id { get; set; }
    [DataMember]
    public DateTime Date { get; set; }
    [DataMember]
    public string Domain { get; set; }
    [DataMember]
    public string RuleName { get; set; }
    [DataMember]
    public string Log { get; set; }
    [DataMember]
    public string ChangeId { get; set; }
    [DataMember]
    public string ParentId { get; set; }
    [DataMember]
    public string Comments { get; set; }
}

[DataContract]
public class RootObject
{
    [DataMember(Name = "@odata.context")]
    public string Context { get; set; }
    [DataMember]
    public List<SearchResult> value { get; set; }
}

您的序列化代码(请参阅DateTime处理代码)

var settings = new DataContractJsonSerializerSettings()
{
    DateTimeFormat = new DateTimeFormat(@"yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)
};
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(RootObject),settings);

var results =  (RootObject)serializer.ReadObject(responseStream);

答案 1 :(得分:3)

您遇到的反序列化问题是由于Azure搜索响应将搜索结果包装在值数组中。读取结果的一种方法是创建自己的包装器对象,以反映Azure有效负载。

例如:

public class AzureSearchResponse
{
    [JsonProperty("@odata.context")]
    public string ODataContext { get; set; }
    public List<SearchResult> value { get; set; }
}

您可能会发现使用Newtonsoft.Json库很有帮助,可以使用Nuget命令安装该库:

Install-Package Newtonsoft.Json

然后可以使用以下命令反序列化:

var searchResult = JsonConvert.DeserializeObject<AzureSearchResponse>(reader.ReadToEnd());

对于与您的CLR属性名称不匹配的属性名称,使用属性

进行装饰
[JsonProperty(PropertyName = "@search.score")]

不需要[DataContract]和[DataMember]属性

关于将数据放入您的视图,我建议您使用View Model而不是ViewBag。您可以创建一个基本上是反序列化搜索结果的ViewModel,并在剃刀中迭代它。

在视图顶部使用模型关键字进行装饰,例如:

@model Namespace.Path.To.Your.Model

您的模型类可以包含List,然后在循环中使用它,例如

<ul>
@foreach(var result in Models.Results) {
    <li>@result.RuleName</li>
}
</ul>

希望这会有所帮助,让我知道你是如何继续的。

此致 菲尔