Connect to a WCF service from Android - getting 405 - Method not allowed
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();
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.
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...
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?
精彩评论