1
\$\begingroup\$

Just a very simplified and stright-forward way of serialize/deserialize to/from JSON using standard .NET 4+ libs. I was trying to avoid "complexity", so get rid of 3rd part libs and heavy-infrastructured standard libs.

    #region JSON API

    public static string ObjectToJson(object o, Type t, Type[] pTypes = null)
    {
        DataContractJsonSerializer serializer = (pTypes != null ? new DataContractJsonSerializer(t, pTypes) : new DataContractJsonSerializer(t));
        MemoryStream mStrm = new MemoryStream();
        serializer.WriteObject(mStrm, o);
        mStrm.Position = 0;
        using (var sr = new StreamReader(mStrm, Encoding.UTF8))
        {
            return sr.ReadToEnd();
        }
    }

    public static object JsonToObject(string json, Type t, Type[] pTypes = null)
    {
        DataContractJsonSerializer serializer = (pTypes != null ? new DataContractJsonSerializer(t, pTypes) : new DataContractJsonSerializer(t));
        using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        {
            return serializer.ReadObject(stream);
        }
    }

    #endregion // JSON  API

And an example of its usage:

    public bool ListOfGames(bool pMyGames, bool pGamesITookPartIn)
    {
        this.GamesListInfo = null;
        this.LastErrorInfo = null;
        try
        {
            string formValues =
                "&playerId=" + this.LogonInfo.userId.ToString() +
                "&createdBy=" + pMyGames.ToString() +
                "&tookPartIn=" + pGamesITookPartIn.ToString() +
                "";

            WebRequest request = createRequest("myGamesList", formValues);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string responseText = sr.ReadToEnd();

                if (responseText.Contains("\"errType\":"))
                    this.LastErrorInfo = (ErrorInfoContract)JsonToObject(responseText, typeof(ErrorInfoContract));
                else
                    this.GamesListInfo = (GamesListContract)JsonToObject(responseText, typeof(GamesListContract), new Type[] { typeof(GameInfoContract) });

                Trace.WriteLineIf(TrcLvl.TraceInfo, TrcLvl.TraceInfo ? string.Format("NewGame.ListOfGames: {0}{1}",
                    (this.LogonInfo != null ? this.LogonInfo.ToString() : ""), (this.LastErrorInfo != null ? this.LastErrorInfo.ToString() : "")) : "");
            }
        }
        catch (Exception exc)
        {
            this.LastErrorInfo = new ErrorInfoContract()
                {
                    errType = exc.GetType().ToString(),
                    message = exc.Message,
                    stackTrace = exc.StackTrace,
                    timestamp = StrUtils.NskTimestampOf(DateTime.Now)
                };
        }
        return (this.LogonInfo != null && this.LogonInfo.userId > 0 && this.LogonInfo.authKey > 0);
    }

    private WebRequest createRequest(string pAction, string pFormValues)
    {
        WebRequest request = WebRequest.Create(this.ServerUrl + "?action=" + pAction);

        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = pFormValues.Length;

        byte[] data = Encoding.UTF8.GetBytes(pFormValues);
        using (Stream strm = request.GetRequestStream())
        {
            strm.Write(data, 0, data.Length);
        }
        return request; 
    }

Just searched where to publish a code and example (for some purposes).

I do not expect any inputs but if you would like to - welcome, would be appreciated. :)

\$\endgroup\$
  • \$\begingroup\$ This doesn't really look simpler. I'd be great if you could write more about what you are doing here and why. We also need more context like what is DataContractJsonSerializer? Complete classes were better than just some random methods. \$\endgroup\$ – t3chb0t Apr 26 at 17:16
  • \$\begingroup\$ Sorry. Full class name is System.Runtime.Serialization.Json.DataContractJsonSerializer it resides in System.Runtime.Serialization.dll, v4.0.0.0. It is part of .NET. I'm doing client-server communication for primitive online game. There is very simple web server with *.ashx which handle HTTP requests and returns JSON. \$\endgroup\$ – dmitry_bond Apr 26 at 18:01
  • \$\begingroup\$ Please upload the real code, as-written, not a simplified version of what you've made. \$\endgroup\$ – Mast Apr 26 at 19:58
  • \$\begingroup\$ This is real piece of code which is currently working inside a solution. It is not "simplified version". By using word "simplified" in my post I mean - to keep solution simple and minimalistic, that was my goal when I was developing it. \$\endgroup\$ – dmitry_bond Apr 27 at 6:37
1
\$\begingroup\$

Frame challenge

I was trying to avoid "complexity", so get rid of 3rd part libs

Although it's not strictly code review, I would like to start by challenging this goal. There are many many official Microsoft libraries with dependencies on Newtonsoft.Json. (See this answer on our software engineering sister site).


Core code

    public static string ObjectToJson(object o, Type t, Type[] pTypes = null)

This absolutely needs documentation comments explaining what t and pTypes are for. As a maintenance programmer this signature is unhelpful on two counts:

  1. I have no idea why I need to pass types at all. If ObjectToJson needs the type of the object for some reason it can call o.GetType().
  2. The names are not helpful. I'm guessing that t is the type of o, but that's a pure guess. As for pTypes, is that Hungarian notation for "pointer to type"? That has no place in C# code unless you're using unsafe and actual pointers (and even there the name should tell you what the variable is for and not just what its type is).

With respect to point 1, I would suggest that in addition to improving the names and adding documentation you consider two further refactorings: either making t an optional parameter with default null and calling o.GetType() if necessary; or changing the signature to public static string ObjectToJson<T>(T obj, IEnumerable<Type> whateverPTypesShouldBeCalled) so that the compiler can infer the type but the caller can impose a supertype if that's necessary for some bizarre reason. (In case you don't know: you can use typeof(T) with T a type variable to get a Type object).


        DataContractJsonSerializer serializer = (pTypes != null ? new DataContractJsonSerializer(t, pTypes) : new DataContractJsonSerializer(t));

Might it make more sense to use new DataContractJsonSerializer(t, pTypes ?? Enumerable.Empty<Type>())?


        MemoryStream mStrm = new MemoryStream();
        ...
        using (var sr = new StreamReader(mStrm, Encoding.UTF8))

This is inconsistent: . I would favour the approach of always using using with IDisposable, even when you know that it doesn't use any unmanaged resources.

A comment explaining why Encoding.UTF8 is correct would be an improvement.


    public static object JsonToObject(string json, Type t, Type[] pTypes = null)
    {
        DataContractJsonSerializer serializer = (pTypes != null ? new DataContractJsonSerializer(t, pTypes) : new DataContractJsonSerializer(t));
        using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        {
            return serializer.ReadObject(stream);
        }
    }

I think all of the comments on ObjectToJson apply equally to JsonToObject with one exception: this time the signature makes a much stronger argument for use of generics. As it stands you probably have to cast the return value almost every time you use this method.


Usage example

This is again marginally off-topic, so I won't do a detailed review of the example usage code, but I think it's important to address a couple of points.

    private WebRequest createRequest(string pAction, string pFormValues)

Every caller of this method is expected to compose pFormValues. That's the antithesis of Don't Repeat Yourself. The method which factors out the commonalities of requests should be the one place which composes the query string, and unlike the example

            string formValues =
                "&playerId=" + this.LogonInfo.userId.ToString() +
                "&createdBy=" + pMyGames.ToString() +
                "&tookPartIn=" + pGamesITookPartIn.ToString() +
                "";

it should take care to escape the values.


            WebRequest request = createRequest("myGamesList", formValues);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string responseText = sr.ReadToEnd();

                if (responseText.Contains("\"errType\":"))

Again, I would hope that the web service on the other end is consistent enough that handling the response can be done in one place rather than being repeated for every single call. And I would hope that it uses HTTP well enough that you don't have to do heuristic guessing to figure out whether there was a problem. Instead of looking for "errType": it should switch on response.StatusCode.


        WebRequest request = WebRequest.Create(this.ServerUrl + "?action=" + pAction);

        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = pFormValues.Length;

I find it bizarre that the form values are split between the URL and the request body.

\$\endgroup\$
  • \$\begingroup\$ It looks like the built-in json-serializer uses the additional types for validating msdn says: , with a collection of known types that may be present in the object graph \$\endgroup\$ – t3chb0t Apr 30 at 15:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.