从 Web API 中的通用列表返回 Json

Posted

技术标签:

【中文标题】从 Web API 中的通用列表返回 Json【英文标题】:Return Json from Generic List in Web API 【发布时间】:2014-01-04 10:24:45 【问题描述】:

我这样建立我的清单:

public static List<SearchFormula> SearchData(string searchString)

    var searchResults = new List<SearchFormula>();

    SqlDataReader drResults = FormulaUtility.SearchFormulas(searchString);

    if ((drResults != null) && (drResults.HasRows))
                    
        while (drResults.Read())
        
            searchResults.Add(new SearchFormula() 
              
                // id  use the GetValue function
                Title = drResults.GetString(1),
                Description = drResults.GetString(2), 
                Url = drResults.GetString(3)
                // total use the GetValue Function
                );
            
        
    return searchResults;

使用这个对象:

public class SearchFormula

    public string Title  get; set; 

    public string Description  get; set; 

    public string Url  get; set; 

我开始使用 IHttpActionResult,返回 OK(results);功能。我相信这就是让我走上混乱道路的原因。我已经成功发送了一个 ArrayList,但这并没有像我想象的那样序列化。

我尝试将其更改为 ActionResult 并尝试返回 Json(result) Result 作为实际列表。

我想继续使用 IhttpActionResult 并使用 OK() 方法发送序列化数据。我似乎也有内置 json 序列化器和 NewtonSoft json 序列化器之间的冲突。

我应该使用什么。仅序列化通用列表并将结果传递给 IHttpActionResult OK() 方法的最简单方法是什么?

我尝试了 javascriptSerializer,但它返回 XML 而不是 Json...

public class SearchController : ApiController

    public IHttpActionResult Get(string searchTerm)
                
        var jsonSerialiser = new JavaScriptSerializer();
        var jsonResult = jsonSerialiser.Serialize(SearchUtility.SearchData(searchTerm));

        if (jsonResult != null)
        
            return Ok(jsonResult);
        
        return NotFound();

    

这是 Json.Net 示例:

public class SearchController : ApiController

    public IHttpActionResult Get(string searchTerm)
       
        var jsonResult = JsonConvert.SerializeObject(SearchUtility.SearchData(searchTerm));

        if (jsonResult != null)
        
            return Ok(jsonResult);
        
        return NotFound();        
    

我已经尝试过 MemoryStream...等等等等...似乎没有什么是一种干净、直接的方法,并且没有针对此特定解决方案的主题。

让我从这个开始......

如何将通用列表序列化为 Json?

如何通过 IHttpActionResult 发送该结果?

*更新*

这就是我从 Json.Net 获得的序列化结果。但是格式有问题......即使是 Fiddler 也无法确定它是 Json。我的 Header 看起来像这样(在 Fiddler 中):

接受:application/json、text/javascript、/; q=0.01

"[\"title\":\"Lacidofil®\",\"description\":\"Lacidofil® 含有 Institut Rosell 的瑞士乳杆菌和鼠李糖乳杆菌。这两种菌株都已在人体临床试验中得到广泛研究,具有...\",\"url\":\"/products/product-detail.aspx?pid=103\",\"title\ ":\"MedCaps GI™\",\"description\":\"MedCaps GI™ 的成分旨在营养支持胃肠道内壁的完整性和最佳功能。强化营养成分,例如 l-谷氨酰胺...\",\"url\":\"/products/product-detail.aspx?pid=114\",\"title\":\"OrganiX™ PhytoFood ™\",\"description\":\"OrganiX PhytoFood 是一种方便的粉状配方,提供关键营养素以支持健康的生活方式。这个综合配方融合了有机...\",\"url\":\"/products/product-detail.aspx?pid=271\",\"title\":\"Probio Defense ™\",\"description\":\"Probio Defense™ 是支持免疫系统的益生菌的最佳组合。\r\n此产品包含:\r\n\r\n瑞士乳杆菌 Rosell-52(30 亿)\r\n乳酸杆菌...\",\"url\":\"/products/product-detail.aspx?pid=102\",\"title\":\"ProbioMax Daily DF™\" ,\"description\":\"ProbioMax Daily DF™ 是一种素食、不含乳制品和麸质的四菌株益生菌,每粒胶囊总计 300 亿个 CFU†。每个素食胶囊都密封在氮气净化铝中...\",\"url\":\"/products/product-detail.aspx?pid=181\",\"title\":\"ProbioMax DF™\",\"description\":\"ProbioMax DF™ 是一种素食、不含乳制品和麸质的四菌株益生菌,每粒胶囊总计 1000 亿个 CFU†。每个素食胶囊都密封在氮气吹扫的铝中...\",\"url\":\"/products/product-detail.aspx?pid=184\",\"title\":\"ProbioMax Plus DF™\",\"description\":\"通过个体补充益生菌菌株、非致病性酵母菌、布拉氏酵母菌、免疫球蛋白等多种健康益处...\",\"url \":\"/products/product-detail.aspx?pid=185\",\"title\":\"Saccharomycin DF™\",\"description\":\"Saccharomycin DF™ 是一种乳糖- 不含、抗胃酸、稳定、正在申请欧洲专利的配方,含有经 DNA 验证的布拉氏酵母。这个益生菌酵母支持...\",\"url\":\"/products/product-detail.aspx?pid=197\"]"

【问题讨论】:

你研究过 Json.Net 吗? 这是问题的一部分,我在默认值和 newtonsoft 之间遇到了冲突。 我认为 Web API 默认已经使用 JSON.NET。在我所写的内容中,我总是返回我的对象​​,除非我特别想返回 HTTP 错误代码。这样,如果您的客户想要使用 XML 而不是 JSON,您就无需再做任何工作了。 根据您的更新,提琴手没有将其视为 JSON 的原因是因为它是 JSON 字符串,而不是 JSON。注意开头和结尾的双引号,以及所有转义的引号。 @damienc88,谢谢。这和我看到的一样,也是我困惑的原因。为什么要序列化成一个字符串?我如何更改为 Json? (由于整个字符串,我的 Ajax 调用无法通过 id “解析”数据。) 【参考方案1】:

我采用这种方法,它看起来更简单,并且不涉及为您拥有的数据更改 json 序列化程序。

如果您将对象作为列表返回,则默认媒体类型格式化程序将根据客户端指定的内容类型(假设它是 json 或 xml)处理序列化。

出于演示目的,添加以下返回硬编码对象的方法。

    // GET api/search
    public List<SearchFormula> Get(string searchTerm)
    
        var searchItems = SearchData(searchTerm);
        return searchItems;
    

    public static List<SearchFormula> SearchData(string searchString)
    
        var searchResults = new List<SearchFormula>();

        searchResults.Add(new SearchFormula  Description = "desc1", Title = "title1", Url = "http://url.com" );
        searchResults.Add(new SearchFormula  Description = "desc2", Title = "title2", Url = "http://url.com" );

        return searchResults;

    

然后在 fiddler 中指定客户端接受application/json,如下图所示,内容返回为json

有关序列化的更多信息,请参见此处:

http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

【讨论】:

标题正确。对象填充正确。更新我的问题中的结果。 我已经在上面的提琴手屏幕抓取中突出显示了它从我的演示应用程序返回的 json 结果,黄色框。那不是你要的json吗? 如果您将其更改为只返回对象而不序列化它们,它应该可以正常工作。正如我上面的例子,唯一的区别是我不是从数据库中读取它们。 你使用了哪种序列化方法?我想做和你一样的事情。 (感谢您的帮助和澄清。) 它下面使用模型绑定器,根据指定的客户端内容类型将您的对象序列化为 xml 或 json。请投票并接受答案。我会使用 jQuery getJson 来接听您的电话。祝你好运。 :)【参考方案2】:

我通常使用这种扩展方法序列化为 JSON:

    public static class Extensions

    public static string SerializeToJson<T>(this T obj, DateTimeSerializationFormat format = DateTimeSerializationFormat.DotNet) where T : class
    
        string result;
        var serializer = new DataContractJsonSerializer(typeof(T));
        using (var stream = new MemoryStream())
        
            serializer.WriteObject(stream, obj);
            result = Encoding.UTF8.GetString(stream.ToArray());
        

        if (formaat != DateTimeSerializationFormat.DotNet)
        
            const string dotNetDateTimePattern = @"""\\/Date\((-?\d+)([\+-]\d4)?\)\\/""";

            if (format ==DateTimeSerializationFormat.Iso8601 || format ==DateTimeSerializationFormat.Ruby))
            
                var matchEvaluator = new MatchEvaluator(ConvertJsonDateToIso8601DateString);
                var regex = new Regex(dotNetDateTimePattern);
                resultaat = regex.Replace(resultaat, matchEvaluator);
                if (format == DateTimeSerializationFormat.Ruby && resultaat.Length > 10) // Ruby time
                
                    result = Regex.Replace(result, @"([\+-]\d1,2\:\d2)", " $0"); // Add an space before the timeZone, for example bv "+01:00" becomes " +01:00"
                
            

        
        return result;
    

    public enum DateTimeSerializationFormat
    
        /// <summary>
        /// Example: "\/Date(1198908717056)\/" (aantal miliseconden na 1-1-1970)
        /// </summary>
        DotNet,
        /// <summary>
        /// Example: "1997-07-16T19:20:30.45+01:00"
        /// </summary>
        Iso8601,
        /// <summary>
        /// Example: "1997-07-16T19:20:30.45 +01:00"
        /// </summary>
        Ruby,
        ///// <summary>
        ///// Example: new Date(1198908717056) or other formats like new (date (1997,7,16)
        ///// </summary>
        //JavascriptDateObject
    

不要忘记添加使用和引用:

System.Runtime.Serialization.Json;

【讨论】:

你不需要这个,除非你需要自定义 JSON 格式。 Web API Http 管道中的 MediaTypeFormatter 实例处理序列化为 JSON/XML 和反序列化回 CLR 类型。

以上是关于从 Web API 中的通用列表返回 Json的主要内容,如果未能解决你的问题,请参考以下文章

从 ASP.NET Web API 中的控制器返回二进制文件

require.js POST 请求以发现返回“解析 json 错误”的 web api

如何从动态列表中为 Vue 中的 API 响应创建列表渲染 JSON?

SwiftUI 中的动态列表从 JSON 和 Textfield 更新

如何在不知道匹配返回的 json 数据中的所有值的情况下从 .Net 核心中的 Web api 调用创建模型?

下载文件请求返回 JSON 而不是服务器上 ASP.NET Web API 中的文件