Return Json from Generic List in Web API
Asked Answered
C

2

14

I build my list like this:

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;
}

Using this Object:

public class SearchFormula
{
    public string Title { get; set; }

    public string Description { get; set; }

    public string Url { get; set; }
}

I began using the IHttpActionResult, returning the OK(results); function. I believe this is what started me down the confusing road. I had successfully sent an ArrayList but this did not serialize the way I thought it would.

I tried changing it to ActionResult and attempted to return Json(result) Result being the actual list.

I would like to continue to use the IhttpActionResult and send the serialized data with the OK() method. I also seem to be having a conflict between the built-in json serializer and NewtonSoft json serializer.

What should I use. What is the simplest way of just serializing a generic list and passing the result into the IHttpActionResult OK() method?

I tried the JavaScriptSerializer but it returns XML not 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();

    }
}

Here is the Json.Net Example:

public class SearchController : ApiController
{
    public IHttpActionResult Get(string searchTerm)
    {   
        var jsonResult = JsonConvert.SerializeObject(SearchUtility.SearchData(searchTerm));

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

I have tried the MemoryStream... blah blah blah... nothing seems like a clean, straightforward approach and there is no subject matter for this specific solution.

Let me start with this...

How can I serialize a Generic list to Json?

How can I send that result through the IHttpActionResult?

*Update*

This is what I am getting for the serialization from Json.Net. BUT something is wrong with the format... Even Fiddler can not determine that it is Json. My Header looks like this (in Fiddler):

Accept: application/json, text/javascript, /; q=0.01

"[{\"title\":\"Lacidofil®\",\"description\":\"Lacidofil® features Institut Rosell’s Lactobacillus helveticus and Lactobacillus rhamnosus. Both of these strains have been extensively studied in human clinical trials, possess an...\",\"url\":\"/products/product-detail.aspx?pid=103\"},{\"title\":\"MedCaps GI™\",\"description\":\"MedCaps GI™ features ingredients that are designed to nutritionally support the integrity and optimal function of the gastrointestinal lining. Fortified with nutrients such as l-glutam...\",\"url\":\"/products/product-detail.aspx?pid=114\"},{\"title\":\"OrganiX™ PhytoFood™\",\"description\":\"OrganiX PhytoFood is a convenient powdered formulation providing key nutrients to support a healthy lifestyle. This comprehensive formula incorporates an innovative blend of organi...\",\"url\":\"/products/product-detail.aspx?pid=271\"},{\"title\":\"Probio Defense™\",\"description\":\"Probio Defense™ is an optimal combination of probiotic bacteria that supports the immune system.\r\nThis product contains:\r\n\r\nLactobacillus helveticus Rosell-52 (3 billion)\r\nLactobacillu...\",\"url\":\"/products/product-detail.aspx?pid=102\"},{\"title\":\"ProbioMax Daily DF™\",\"description\":\"ProbioMax Daily DF™ is a vegetarian, dairy- and gluten-free, four-strain probiotic totaling 30 billion CFU† per capsule. Each vegetarian capsule is sealed in nitrogen-purged alu...\",\"url\":\"/products/product-detail.aspx?pid=181\"},{\"title\":\"ProbioMax DF™\",\"description\":\"ProbioMax DF™ is a vegetarian, dairy- and gluten-free, four-strain probiotic totaling 100 billion CFU† per capsule. Each vegetarian capsule is sealed in nitrogen-purged aluminum...\",\"url\":\"/products/product-detail.aspx?pid=184\"},{\"title\":\"ProbioMax Plus DF™\",\"description\":\"The multitude of healthful benefits attained by the individual supplementation of probiotic strains of bacteria, the non-pathogenic yeast, Saccharomyces boulardii, immunoglobulins,...\",\"url\":\"/products/product-detail.aspx?pid=185\"},{\"title\":\"Saccharomycin DF™\",\"description\":\"Saccharomycin DF™ is a lactose-free, stomach acid–resistant, stable, European patent-pending formula containing DNA-verified Saccharomyces boulardii. This probiotic yeast support...\",\"url\":\"/products/product-detail.aspx?pid=197\"}]"

Clapperclaw answered 16/12, 2013 at 21:6 Comment(6)
Have you looked into Json.Net?Ridiculous
That's part of the problem, I'm getting a conflict between the default and the newtonsoft.Clapperclaw
I thought Web API already used JSON.NET by default. In what I have written I return my object always, unless I specifically want to return HTTP Error code. That way if your client wants to use XML instead of JSON, you don't have anymore work to do.Eisler
As per your update, the reason fiddler isn't seeing that as JSON is because it's a JSON String, not JSON. Note the leading and trailing double-quote, and all the escaped quotes throughout.Glacis
@damienc88, thank you. That is the same thing I saw and why I am confused. Why is it serializing into one string? How do I change into just Json? (My Ajax call can't "parse" the data by id because of the whole string.)Clapperclaw
Update See Comments in AnswerClapperclaw
S
11

I take this approach which seems a lot simpler and does not involve changing the json serializer for the data that you have.

If you return the objects as a list the default media type formatter will handle the serialization based on the content type specified from the client (providing it is json or xml).

For demo purposes add the below methods which return hard coded objects.

    // 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;

    }

Then in fiddler specify the client accepts application/json as pictured below and the content is returned as json.

enter image description here

For further info on serialization see here:

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

Stark answered 16/12, 2013 at 21:34 Comment(11)
The header is correct. The objects are populated correct. Updating what the result looks like in my question.Clapperclaw
I have highlighted the json result that it returns from my demo app in the above fiddler screen grab, the yellow box. Is that not the json you are after?Stark
If you change it to just return the objects as they are without serialising them it should work ok. As in my example above, the only difference is that I am not reading them from a db.Stark
Which serialization method did you use? I want do the exact same thing that you did. (Thank you for help and clarification.)Clapperclaw
No probs, I think it is much easier than you think. Simply do not make any serialization calls and return SearchUtility.SearchData(searchTerm) or OK(SearchUtility.SearchData(searchTerm)) the default serializer will kick in as in my example above. Good luck. :)Stark
I just removed all serialization and returned the ArrayList... it returns the Json Object. WTH?.. I am used to making things happen not just relying solely on framework that I have no idea what it does or at least telling it what I want it to do. Now I need to work on my Ajax function.Clapperclaw
Underneath it uses a model binder that serializes your object to xml or json depending on the client content type specified. Please upvote and accept the answer. I'd use jQuery getJson for your call. Good luck with the rest. :)Stark
I'm marking this as the answer given that the response shows the answer specific to the technology and the details are stated clearly by hutchonoid.Clapperclaw
Thanks, I will update the question with info about model binder later for others. :)Stark
@hutchonoid: I believe it is MediaTypeFormatter that handles the serialization when a result is returned from a Web API action. Model Binders come into play when client request comes in and you need to read complex types from querystring and bind them to CLR types which are action method params.Selina
In other words, return it, and it will go. No serialization needed, since it will do this "under the covers".Scheer
G
2

I usually serialize to JSON using this extension method:

    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+)([\+-]\d{4})?\)\\/""";

            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, @"([\+-]\d{1,2}\:\d{2})", " $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
    }

Don't forget to add the using and reference to:

System.Runtime.Serialization.Json;
Goodlooking answered 16/12, 2013 at 21:16 Comment(1)
You don't need this unless you need to customize the JSON formatting. MediaTypeFormatter instance in the Http pipeline of Web API handles the serialization to JSON/XML and de-serialization back to CLR types.Selina

© 2022 - 2024 — McMap. All rights reserved.