Deserialize JSON object sent from Android app to WCF webservice
Asked Answered
C

1

0

I'm trying to send a JSON object to my webservice method, the method is defined like this:

public String SendTransaction(string trans)
{
            var json_serializer = new JavaScriptSerializer();
            Transaction transObj = json_serializer.Deserialize<Transaction>(trans);
            return transObj.FileName;       
}

Where I want to return the FileName of this JSON string that I got as a parameter.

The code for the android application:

HttpPost request = new HttpPost(
                "http://10.118.18.88:8080/Service.svc/SendTransaction");
        request.setHeader("Accept", "application/json");
        request.setHeader("Content-type", "application/json");

        // Build JSON string
        JSONStringer jsonString;

        jsonString = new JSONStringer()
                .object().key("imei").value("2323232323").key("filename")
                .value("Finger.NST").endObject();

        Log.i("JSON STRING: ", jsonString.toString());

        StringEntity entity;

        entity = new StringEntity(jsonString.toString(), "UTF-8");

        entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
                "application/json"));
        entity.setContentType("application/json");

        request.setEntity(entity);

        // Send request to WCF service
        DefaultHttpClient httpClient = new DefaultHttpClient();

        HttpResponse response = httpClient.execute(request);
        HttpEntity httpEntity = response.getEntity();
        String xml = EntityUtils.toString(httpEntity);

        Log.i("Response: ", xml);
        Log.d("WebInvoke", "Status : " + response.getStatusLine());

I only get a long html file out, which tells me The server has encountered an error processing the request. And the status code is HTTP/1.1 400 Bad Request

My Transaction class is defined in C# like this:

 [DataContract]
public class Transaction
{
    [DataMember(Name ="imei")]
    public string Imei { get; set; }

    [DataMember (Name="filename")]
    public string FileName { get; set; }
}

How can I accomplish this in the right way?

EDIT, this is my web.config

 <?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>

          <endpointBehaviors>
            <behavior name="httpBehavior">
                <webHttp />
            </behavior >
        </endpointBehaviors>

      <serviceBehaviors>
        <behavior name="">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
    <services>
      <service name="Service.Service">
        <endpoint address="" behaviorConfiguration="httpBehavior" binding="webHttpBinding" contract="Service.IService"/>
      </service>
    </services>

    <protocolMapping>
        <add binding="webHttpBinding" scheme="http" />
    </protocolMapping>

    <!--<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />-->
  </system.serviceModel>
  <system.webServer>
  <!-- <modules runAllManagedModulesForAllRequests="true"/>-->
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>
Concrete answered 31/10, 2012 at 18:43 Comment(6)
My guess: it is related with your service's configurationDrunkard
could you please take a look at my edit?Concrete
Well, it has always been hard for me to read config files. Have you tried decorating your method like [OperationContract] [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)] public String SendTransaction(string trans) { }Drunkard
Yeah, that is exactly what I did.Concrete
And I would also try changing your method as public String SendTransaction(Transaction transObj) { return transObj.FileName; } Deserialization should be handled by WCF.Drunkard
No luck with that either, but thanks! :)Concrete
D
2

@Tobias, This is not an answer. But since it was a little bit long for comment, I post it here. Maybe it can help to diagnose your problem. [A full working code].

public void TestWCFService()
{
    //Start Server
    Task.Factory.StartNew(
        (_) =>{
            Uri baseAddress = new Uri("http://localhost:8080/Test");
            WebServiceHost host = new WebServiceHost(typeof(TestService), baseAddress);
            host.Open();
        },null,TaskCreationOptions.LongRunning).Wait();


    //Client
    var jsonString = new JavaScriptSerializer().Serialize(new { xaction = new { Imei = "121212", FileName = "Finger.NST" } });
    WebClient wc = new WebClient();
    wc.Headers.Add("Content-Type", "application/json");
    var result = wc.UploadString("http://localhost:8080/Test/Hello", jsonString);
}

[ServiceContract]
public class TestService
{
    [OperationContract]
    [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
    public User Hello(Transaction xaction)
    {
        return new User() { Id = 1, Name = "Joe", Xaction = xaction };
    }

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Transaction Xaction { get; set; }
    }

    public class Transaction
    {
        public string Imei { get; set; }
        public string FileName { get; set; }
    }
}
Drunkard answered 31/10, 2012 at 19:40 Comment(4)
Where do you define your UriTemplate in the wcf service? In order to access it from the browser I think that every method in the webservice has to define this. And second, what type of method are you using? PUT, POST, GET ?Concrete
@TobiasMoeThorstensen UriTemplate is optional. Required if you want to use another uri other than the default one(Which is methodname). UploadString method uses POST. DownloadString uses GET(WebInvoke attributes defines it as POST, WebGet for GET)Drunkard
I've finally got a step further, I actually get a response from my webservice, but the Transaction object that the service returns is null I suspect that this is has something to do with the Client side.Concrete
Got this working now, the Keys in the JSON object from java has to be the same as the Name of the Datamembers in the DataContract, further on I removed the BodyStyle = WebMessageBodyStyle.Wrapped From the WebInvoke declaration. I will accept your answer because it gave me good idea where to start! ThanksConcrete

© 2022 - 2024 — McMap. All rights reserved.