none
Any advice or rectification for my code to pass json data with WCF REST POST RRS feed

  • Question

  • I have a WCF REST POST that has JSON data as input,

    IService.cs:

     [OperationContract]
        [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]     
        void ImportJSON(Stream request);

    IService.svc:

     public void ImportJSON(Stream request)
            {
                using (var reader = new StreamReader(request))
                {
    
                    var resultStream = reader.ReadToEnd();
                    var model = JsonConvert.DeserializeObject<dynamic>(resultStream);
                    var resHeaders = model.Headers;
                    var resValues = model.Values;
                    string str = "";
                    string strValues = "";
                    foreach (var item in resHeaders)
                    {
                        str = str + item.Header + ";";
                    }
                    var stringBuilder = new StringBuilder();
                    stringBuilder.AppendLine(str);
                    foreach (var item in resValues)
                    {
                        strValues = item.value + ";";
                        stringBuilder.AppendLine(strValues);
                        strValues = "";
                    }
                    System.Guid guid = Guid.NewGuid();
                    var path = HttpContext.Current.Server.MapPath("~/App_Data/tmp/" + guid.ToString() + ".csv");
                    using (StreamWriter writetext = new StreamWriter(path))
                    {
                        writetext.WriteLine(stringBuilder);
                    }             
                }
            }

    An exemple of JSON data:

    {
            "Headers": [{"Header":"CA"},{"Header":"PE"},{"Header":"AMOUNT"}],
            "Values": [{"value":"toto;tata;titi"}, {"value":"A;2019;S100"}, {"value":"A;2019;S100"}, {"value":"A;2019;S300"},
                        {"value":"A;2013;S23"}, {"value":"A;2013;S200"}, {"value":"A;2013;S200"}, {"value":"A;2019;S100"}]  
    }

    In fact, I don't use any classe : I use anonyme data directly, and I use dynamic on the Deserialization JSON,

    I have my result as I wish : I get all the data from JSON then I saved all data in a txt/csv  file, My result:

    CA;PE;AMOUNT;
    toto;tata;titi;
    A;2019;S100;
    A;2019;S100;
    A;2019;S300;
    A;2013;S23;
    A;2013;S200;
    A;2013;S200;
    A;2019;S100;

    Are there any impact affect performance ?

    And is there any problem if I have very long JSON data ?

    And if there are any advise or feedback for my code,

    Thanks in advance for your help,

    Thursday, December 19, 2019 1:54 PM

All replies

  • Hi,
    I don't recommend you do this. In WCF, an explicit Data contract type is usually used to tell the serializer how to serialize data on the client and server. Once the service boundary is crossed, we don't know how to serialize and deserialize the data. Data contract is designed to solve this issue. 
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts
    In my opinion, this operating contract has violated this criterion, so I do not think we should not define the operation contract like above.
    Here is a related discussion about this.
    https://stackoverflow.com/questions/4836683/when-to-use-datacontract-and-datamember-attributes
    Feel free to let me know if there is anything I can help with.
    Best Regards
    Abraham
    Friday, December 20, 2019 3:22 AM
    Moderator
  • Thanks a lot for the explanation,it is very clear, I understand well now the mportance of Data Contract,

    I rectify my code:

    IService.svc:

       public void ImportJSON(Stream request)
        {
               using (var reader = new StreamReader(request))
                {                
                    var model = JsonConvert.DeserializeObject<DataImportJsonObject>(reader.ReadToEnd());
                    var stringBuilder = new StringBuilder(string.Empty);
                    foreach (var item in model.Headers)
                    {                   
                        stringBuilder.Append($"{item.header};");
                    }
                    stringBuilder.AppendLine();
                    foreach (var item in model.Values)
                    {
                        stringBuilder.AppendLine($"{item.value};");
                    }
                    var path = HttpContext.Current.Server.MapPath($"~/App_Data/tmp/{Guid.NewGuid().ToString()}.csv");               
                    if (stringBuilder.ToString().EndsWith(Environment.NewLine))
                    {
                        stringBuilder.Remove(stringBuilder.Length - Environment.NewLine.Length, Environment.NewLine.Length);
                    }
                    using (var writetext = new StreamWriter(path))
                    {
                        writetext.WriteLine(stringBuilder);
                    }
                }
            }
         }

    And the classes:

     [DataContract]
            public class Header
            {
                [DataMember]
                public string header { get; set; }
            }
            [DataContract]
            public class Value
            {
                [DataMember]
                public string value { get; set; }
            }
            [DataContract]
            public class DataImportJsonObject
            {
                [DataMember]
                public List<Header> Headers { get; set; }
                [DataMember]
                public List<Value> Values { get; set; }
            }


    • Edited by Thabetidris Friday, December 20, 2019 10:44 AM
    Friday, December 20, 2019 10:44 AM
  • Hi,

    DataImportJsonObject should be a Data contact instead of transferring the data by Stream. It has itself namespace, assembly, how could the client–side and the server-side know the serialization and deserialization?  Hence we should define data contract that are shared between clients and servers.

    it could have itself namespace and name and other information in details.

    [DataContract(Namespace ="mycompary",Name ="mycontract")]
        public class Product
        {
            [DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
        }

    Best Regards

    Abraham

    Monday, December 23, 2019 3:02 AM
    Moderator
  • Thanks for your reply,

    sorry but I did not understand well

    And the DataImportJsonObject is DataContract and the details are fro each class : string header  and string value,

    So what is exactly the problem? and how I should fix it? Thanks in advance ,

    Monday, December 23, 2019 8:50 AM
  • Hi,

    Can you properly deserialize the stream and get the DataImportJsonObject object? Unless we can get the object then the Foreach will be OK.

    I advise you to take a data contract class as the input parameter instead of stream.

    Best Regards

    Abraham

    Tuesday, December 24, 2019 6:17 AM
    Moderator
  • Hi,

    you are right, I don't understand in the first time, but now it is very clear! Thanks a lot:

    Service.csv:

     public void ImportJSON(DataImportJsonObject request)
            {         
    
                   
                    var stringBuilder = new StringBuilder(string.Empty);
                    foreach (var item in request.Headers)
                    {
                        stringBuilder.Append($"{item.header};");
                    }
                    stringBuilder.AppendLine();
                    foreach (var item in request.Values)
    //...

    classe:

       [DataContract]
            public class Header
            {
                [DataMember]
                public string header { get; set; }
            }
            [DataContract]
            public class Value
            {
                [DataMember]
                public string value { get; set; }
            }
    
            [DataContract]
            public class DataImportJsonObject
            {
                [DataMember]
                public List<Header> Headers { get; set; }
                [DataMember]
                public List<Value> Values { get; set; }
            }

    My JSON exp:

    {
        "Headers": [ {"header": "First"}, {"header":"Second" }, { "header":"Third"}, {"header":"Foruth" }, {"header":"EndStep" }],
        "Values":[{"value":"A;2019.12;S200;100"},{"value":"A;2019.10;S200;1"},{"value":"A;2019.12;S200;100"},{"value":"A;2019.10;S200;100"}]
    }

    Now I think all it is very very well

    Thank you for your perfect explanation  @Abraham Qian

    Tuesday, December 24, 2019 9:31 AM