3

I've created a WCF service which I intend to use when sending data from an Android app to a MSSQL database.

The service is already hosted and contains 2 methods.. Data() and GetData(). The Data method is used to POST JSON to and GetData just returns a string.

I've tried the following:

My Data Contract:

[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "/Data",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped)]
string Data(Data test);

My Android code:

HttpPost request = new HttpPost("http://lino.herter.dk/Service.svc/Data");
try {
JSONObject json = new JSONObject();
json.put("year", 2011);
StringEntity entity = new StringEntity(json.toString());

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

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
Log.i("!!! WebInvoke", response.getStatusLine().toString());

if(response!=null) {
InputStream in = response.getEntity().getContent(); //Get the data in the entity'
Log.i("TEST", convertStreamToString(in));
}

A similar method works just fine with GetData.. but calling the Data method returns:

400 Bad Request
The server encountered an error processing the request. The exception message is 'Object reference not set to an instance of an object.'.

the Web.Config looks like this:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <customErrors mode="Off"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <services>
      <service name="WcfEA.Service">
        <endpoint address="" behaviorConfiguration="jsonBehavior" binding="webHttpBinding" contract="WcfEA.IService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

The Data method is set to receive a "Data" object:

[DataContract]
public class Data
{
    [DataMember(Name = "year")]
    public int Year
    {
        get;
        set;
    }
}

and the Data method only does 1 operation:

return data.year.toString();
Linora
  • 10,418
  • 9
  • 38
  • 49

3 Answers3

1

When I did this in the past, I used Fiddler2 to tell the difference between what my .Net test application was sending as a request and what my Android app was sending. There may be a discrepancy in the headers, the way your post params are being packaged, etc. Also, Fiddler2 will show you the response and response codes. This should give you all the information you need to figure it out.

http://www.fiddler2.com/fiddler2/

EDIT

After speaking back and forth in the comments, here is an updated answer for what I believe your issue is.

I wasn't able to find the code for the original POC I did for communicating between Android client and WCF service, but I did find some other code where I post json data. What I'm doing differently than you seems to be that I'm passing my payload as a name/value pair so it's keyed when it gets to the service. You seem to be passing just a raw string of json data, so it's possible that the service is expecting your json data as the value of a name-value pair that is keyed by the name of the argument in your service.

To paraphrase the two approaches, here is the method you're using of passing raw string data as the entity.

JSONObject json = new JSONObject();
json.put("year", 2011);
StringEntity entity = new StringEntity(json.toString());
request.setEntity(entity);

Here is an example of my data that I'm posting as a NameValuePair

List<NameValuePair> params = new ArrayList<NameValuePair>(1);
params.add(new BasicNameValuePair("SomeKey", someJsonString));
request.setEntity(new UrlEncodedFormEntity(params));

If you want to pass a complex object, you can build it up as a json string as my example makes use of above. OR...you can simply pass "year" as the key and "2011" as the value, and that should be the value of your string arg when it gets to your WCF web method.

Rich
  • 36,270
  • 31
  • 115
  • 154
  • Hi.. I've changed the original post, but your comment is still very valid.. But how do I see what my android app requests? Fiddler doesnt seem to catch it.. :/ – Linora Mar 27 '11 at 21:27
  • I don't know any way of catching data on an Android device the way Fiddler works on a pc, but you can do some kind of logging on your webserver inside the Data method. Quick and dirty way to do it is to dump the value parameter and loop through the Headers dumping that to a string as well. Write that to a text file on teh webserver and set up a regular aspx page that reads and outputs that file. Request from your test app, then refresh the page. Request from your Android app and refresh again. You'll be able to see the differences in the different requests. – Rich Mar 28 '11 at 10:25
  • But I'm still getting Bad Requests and I cant see why.. :/ – Linora Mar 28 '11 at 10:40
  • maybe there's some extra whitespace where there shouldn't be? Maybe you're missing some needed boilerplate stuff like an declaration? Not sure. Sounds like a whitespace thing. Are you checking all your http request headers? – Rich Mar 28 '11 at 10:43
  • to be honest, I wouldnt really know what to check for.. :/ – Linora Mar 28 '11 at 10:52
  • I've come past the empty 400 Bad Request error now and I'm getting a more detailed error now.. original post updated – Linora Apr 04 '11 at 13:06
  • That error "Object ref not set to an instance..." means you're attempting to access a property or method of an object that is not instantiated or a null string. The error is going to be in the Data method, which is the only code you haven't provided. My guess is that you're performing some kind of action on the string arg you're expecting to receive, but it's not packaged correctly on your client side (android code that posts the data), so the string arg is being set to null by WCF. I should have some code I did for my Android-to-WCF POC and see if I can find anything that stands out – Rich Apr 04 '11 at 13:20
  • I've update the original post.. I think what you say is correct. The "Data" object isnt created and therefore it is null. the question is then WHY is it null?.. hopefully you can help me solve this.. – Linora Apr 04 '11 at 13:28
  • Updated my answer with why I believe your service is getting a null string. Hope that helps...please let me know. – Rich Apr 04 '11 at 13:48
1

Shouldn't there be a line-feed after <?xml version=\"1.0\"?>?

Also, unless you really need to validate the XML before you send to the server, suggest that you simply attach the entity as text (skip the xml content type etc.) and parse the XML on the server.

That is because you always would be parsing and validating in-coming data on the server anyway, otherwise it opens up huge security risks. Unless you want to save a request round-trip by rejecting improperly-formatted XML off-hand like this...

Also, are you sure your XML is in valid SOAP request XML format? Since your header indicates the message to be SOAP, the content should be properly-formatted SOAP XML...

Stephen Chung
  • 14,497
  • 1
  • 35
  • 48
1

Could you post your web.config from you c# WCF? Some time I created a WCF server which acts as WebService and I had the same problems and it was all about the configuration. Apart from the actuakl configuration if you are hosting a a WCF service using a wsHttpBinding by default it will enbale 'Windows' autentification. How are you creating the service?

Moss
  • 6,002
  • 1
  • 35
  • 40