Android connecting - WCF Service should return JSON - c#

Iam connecting my Android app to a wcf service, and in my Log.i I can see that it return data correct, The only thing I want to handle it as JSON but my service sends as XML-(I think): this is how the code in the app looks like:
if (entity != null)
{
InputStream instream = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null){
sb.append(line + "n");
}
String result = sb.toString();
Log.i(TAG,result);
instream.close();
JSONObject json=new JSONObject(result);
JSONArray nameArray=json.names();
JSONArray valArray=json.toJSONArray(nameArray);
and my example method looks like this, I don't know how to return correct JSON data from the WCF webserivce:
/// <returns>An enumeration of the (id, item) pairs. Returns null if no items are present</returns>
protected override IEnumerable<KeyValuePair<string, SampleItem>> OnGetItems()
{
// TODO: Change the sample implementation here
if (items.Count == 0)
{
items.Add("A", new SampleItem() { Value = "A" });
items.Add("B", new SampleItem() { Value = "B" });
items.Add("C", new SampleItem() { Value = "C" });
}
return this.items;
}
This is the error I get:
09-12 17:11:04.924: WARN/System.err(437): org.json.JSONException: Value <ItemInfoList of type java.lang.String cannot be converted to JSONObject

Add:
[WebGet(ResponseFormat = WebMessageFormat.Json)]
As an attribute over your WCF service method. Change WebGet to WebInvoke if you are not using GET requests to call the service.

This looks like the code from WCF REST Starter Kit, the REST Collection template, so it should already support both XML and JSON. It's the service URI you specify on the client side that returns either XML or JSON representation. By default it sends XML but if you put "?format=json" at the and of the service URI it sends the resource in JSON format.
You can get helpful information by using built-in description of the service returned in ATOM (if I remember well) with /help after service URI
something like:
http://localhost/servicetest/Service.svc/help

This is how the wcf serivce method looks like: this returns a collection of values. I added the [WebGet(ResponseFormat = WebMessageFormat.Json)] but still it is not working.
[WebGet(ResponseFormat = WebMessageFormat.Json)]
protected override IEnumerable<KeyValuePair<string, SampleItem>> OnGetItems()
{
// TODO: Change the sample implementation here
if (items.Count == 0)
{
items.Add("A", new SampleItem() { Value = "A" });
items.Add("B", new SampleItem() { Value = "B" });
items.Add("C", new SampleItem() { Value = "C" });
}
return this.items;
}

Related

Consuming .asmx service in asp.net web api application

I am consuming the .asmx service in my asp.net web api application like this :
[
but this service returns nothing, but in turn writes response in HTTP response object like this:
` [WebMethod(EnableSession = true)]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void GetResearchDocsBySector(int pageCode, int resultsPerPage, string subTypeIds, int timeframe)
{
JavaScriptSerializer js = new JavaScriptSerializer();
IRatingsDirectDataMgr dataMgr = RemoteUtil.GetRemote();
List<ResearchDocumentDisplay> results = dataMgr.GetSolrResults(pageCode, resultsPerPage, subTypeIds, timeframe, false);
List<ResearchDocumentWidgetDisplay> resultList = new List<ResearchDocumentWidgetDisplay>();
foreach (var item in results)
{
var obj = ObjMapper<ResearchDocumentDisplay, ResearchDocumentWidgetDisplay>.Map(item);
obj.ArticleTypeName = Constants.TypeMappings[obj.ArticleTypeId];
resultList.Add(obj);
}
HttpContext.Current.Response.Write(js.Serialize(resultList));
}`
I want to consume the result obtained from the service in my webapi application in json format how can we go about it ?
Note : I can't change the .asmx service code at all !!
Set GetResearchDocsBySector to return your List rather than having a void return type and injecting it into the Current http content. TO do this you will need to mark ResearchDocumentWidgetDisplay as Serialisable which you do by adding [Serialisable] above your class ResearchDocumentWidgetDisplay.

Is it possible to pass 2 types of objects to Restsharp?

We have scenario where external API returns either User XML or Error XML based on whether request succeed or failed.
At the moment I'm passing User POCO to the restsharp and works fine. But if it fails, this object is NULL. And we won't know why it failed unless we parse the Error XML manually.
Is there a way to workaround this?
e.g.
var restClient = new RestClient(baseURL);
var request = new RestRequest(uri);
request.Method = Method.POST;
var response = restClient.Execute<User>(request);
On execution of above method the API can return Error xml object. How do I get Error object on fail and User on success?
This is possible, although the code is a little ugly. RestSharp allows you to specify your own XML deserializer, so we'll need to do that in order to make this work.
First, though, you need a data type that can store either an Error or a User (I made it generic so it works for more than just Users):
public class Result<T>
{
public T Data { get; set; }
public Error Error { get; set; }
}
So the idea is, now when you execute the request, you ask RestSharp for a Result<User> instead of just a User, i.e.:
var result = client.Execute<Result<User>>(request);
Now here's the magic required to deserialize as either an Error or a User. It's a custom deserializer that inherits from RestSharp's XmlDeserializer. Warning: this code is not tested at all, but it can hopefully point you in the right direction.
public class XmlResultDeserializer : XmlDeserializer
{
public override T Deserialize<T>(IRestResponse response)
{
if (!typeof(T).IsGenericType || typeof(T).GetGenericTypeDefinition() != typeof(Result<>))
return base.Deserialize<T>(response);
// Determine whether the response contains an error or normal data.
var doc = XDocument.Parse(response.Content);
var result = Activator.CreateInstance<T>();
if (doc.Root != null && doc.Root.Name == "Error")
{
// It's an error
var error = base.Deserialize<Error>(response);
var errorProperty = result.GetType().GetProperty("Error");
errorProperty.SetValue(result, error);
}
else
{
// It's just normal data
var innerType = typeof(T).GetGenericArguments()[0];
var deserializeMethod = typeof(XmlDeserializer)
.GetMethod("Deserialize", new[] { typeof(IRestResponse) })
.MakeGenericMethod(innerType);
var data = deserializeMethod.Invoke(this, new object[] { response });
var dataProperty = result.GetType().GetProperty("Data");
dataProperty.SetValue(result, data);
}
return result;
}
}
Then you would wire it all up like this:
var restClient = new RestClient(baseURL);
client.AddHandler("application/xml", new XmlResultDeserializer());
var request = new RestRequest(uri);
request.Method = Method.POST;
var result = restClient.Execute<Result<User>>(request);
if (response.Data.Data != null)
{
var user = response.Data.Data;
// Do something with the user...
}
else if (response.Data.Error != null)
{
var error = response.Data.Error;
// Handle error...
}

Content Negotiation in ASP.NET Web API

I'm migrating a web service to ASP.NET Web Api 2, and hitting trouble at almost the first hurdle.
I want to do this:
public class SomeController : ApiController
{
[Route("some\url")]
public object Get()
{
return { Message = "Hello" };
}
}
And be able to ask the service for either "application/json" or "application/xml" (or indeed any other potential format, such as Message Pack), and get a serialized response. But it seems it only works for JSON.
I've read this and seen the documentation which states clearly that the framework cannot handle serialization of anonymous types into XML (seriously) and that the solution is to not use XML (seriously).
When I attempt to call this and request XML as response type, I get
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
I'm not removing support for clients wanting to ask for XML - but I genuinely can't find a work around for this - what can I do?
Edit
I've added these:
System.Web.Http.GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
config.Formatters.Insert(0, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
config.Formatters.Insert(0, new System.Net.Http.Formatting.XmlMediaTypeFormatter());
as per Dalorzo's answer, but it made no difference.
For clarification, the service works absolutely fine when I call it using an accept header of application/json, but bombs when I call it with an accept header of application/xml.
You have 3 options:
Create a class with a proper name and return the object instead of an anonymous type.
Or if you want to return the anonymous instance, you should remove XML formatter, because anonymous types are not supported by XML Formatter
Create your own formatter inheriting from MediaTypeFormatter or BufferedMediaTypeFormatter
You can do it by following code :
public HttpResponseMessage GetTestData()
{
var testdata = (from u in context.TestRepository.Get().ToList()
select
new Message
{
msgText = u.msgText
});
return ActionContext.Request.CreateResponse(HttpStatusCode.OK, testdata);
}
// This Code Is Used To Change Contents In Api
public HttpResponseMessage GetAllcarDetails( string formate)
{
CarModel ST = new CarModel();
CarModel ST1 = new CarModel();
List<CarModel> li = new List<CarModel>();
ST.CarName = "Maruti Waganor";
ST.CarPrice = 400000;
ST.CarModeles = "VXI";
ST.CarColor = "Brown";
ST1.CarName = "Maruti Swift";
ST1.CarPrice = 500000;
ST1.CarModeles = "VXI";
ST1.CarColor = "RED";
li.Add(ST);
li.Add(ST1);
// return li;
this.Request.Headers.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));
//For Json Use "application/json"
IContentNegotiator negotiator =
this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult result = negotiator.Negotiate(
typeof(List<CarModel>), this.Request, this.Configuration.Formatters);
if (result == null) {
var response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
throw new HttpResponseException(response);
}
return new HttpResponseMessage() {
Content = new ObjectContent<List<CarModel>>(
li, // What we are serializing
result.Formatter, // The media formatter
result.MediaType.MediaType // The MIME type
)
};
}
Please browse your API route on Chrome. Chrome, by default shows output in XML format. If that doesn't happen, it means that your service is preventing XML format using media formatting.
And in that case, you should search your WebApiConfig. If nothing is present there, add this file to your project
using System.Net.Http.Formatting;
using System.Collections.Generic;
using System.Net.Http;
using System;
using System.Linq;
using System.Net.Http.Headers;
namespace ExampleApp.Infrastructure
{
public class CustomNegotiator : DefaultContentNegotiator
{
public override ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
if(request.Headers.UserAgent.Where(x=>x.Product!=null&& x.Product.Name.ToLower().Equals("chrome")).Count() > 0)
{
return new ContentNegotiationResult(new JsonMediaTypeFormatter(), new MediaTypeHeaderValue("application/xml"));
}
else
{
return base.Negotiate(type, request, formatters);
}
}
}
}
and, in WebApiConfig.cs, add:
config.Services.Replace(typeof(IContentNegotiator), new CustomNegotiator());

How to force ASP.NET Web API to return JSON or XML data based on my input?

I try to get the output XML or JSON data based on my input. I used the below WEB API code but not able to exact output.
public string Get(int id)
{
if (GlobalConfiguration.Configuration.Formatters.XmlFormatter == null)
{
GlobalConfiguration.Configuration.Formatters.Add(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
}
if (GlobalConfiguration.Configuration.Formatters.JsonFormatter == null)
{
GlobalConfiguration.Configuration.Formatters.Add(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
}
if (id == 1)
{
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
}
else
{
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;
}
return "value";
}
Add the below code app_start event in global.asax file. In API Url add the query string:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
new QueryStringMapping("type", "json", new MediaTypeHeaderValue("application/json")));
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(
new QueryStringMapping("type", "xml", new MediaTypeHeaderValue("application/xml")));
e.g.:
for xml : http://localhost:49533/api/?type=xml
for json: http://localhost:49533/api/?type=json
What you are trying to do will not work in a multi-threaded environment. You cannot add to and remove from the formatters collection on a per-request basis. Here is a better way of accomplishing what you want.
public HttpResponseMessage Get(int id)
{
Foo foo = new Foo();
var content = new ObjectContent<Foo>(foo,
((id == 1) ? Configuration.Formatters.XmlFormatter :
Configuration.Formatters.JsonFormatter));
return new HttpResponseMessage()
{
Content = content
};
}
Looked into this a bit more, and found your answer in another post:
public HttpResponseMessage Get(int id)
{
string content = "value";
if (id == 1)
{
return Request.CreateResponse<string>(HttpStatusCode.OK, content, Configuration.Formatters.JsonFormatter);
}
return Request.CreateResponse<string>(HttpStatusCode.OK, content, Configuration.Formatters.XmlFormatter);
}
It also works to force the accept headers. Great option if you aren't always returning HttpResponseMessage's. I.e
Request.Headers.Add("Accept", "text/json");
return Request.CreateResponse(HttpStatusCode.OK, yourobject);
or
Request.Headers.Add("Accept", "application/xml");
return new Rss20FeedFormatter(feed);
If your request specifies the mime type, for example application/json, then web api will format the response appropriately.
If you are attempting to debug your web api manually, use a tool like Fiddler 2 to specify the type.
This article describes the concept.
QueryStringMapping` is nice solution but I need a default value for type.
for xml : localhost:49533/api/?type=xml
for json: localhost:49533/api/
I solve that situation like that:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
var jSettings = new JsonSerializerSettings();
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", new MediaTypeHeaderValue("application/xml")));
While the accepted answer by vijayjan15 seems the best way to go for your specific situation (that is, using the MediaTypeMappings), you could alternatively have two different methods, one that returns XML and one that returns JSON. To do that, you can instantiate a controller-specific HttpConfiguration (to avoid modifying the one in GlobalConfiguration.Configuration):
public MyReturnType GetMyTypeAsXml() {
Configuration = new HttpConfiguration();
Configuration.Formatters.Clear();
Configuration.Formatters.Add(new XmlMediaTypeFormatter());
return new MyReturnType();
}
public MyReturnType GetMyTypeAsJson() {
Configuration = new HttpConfiguration();
Configuration.Formatters.Clear();
Configuration.Formatters.Add(new JsonMediaTypeFormatter());
return new MyReturnType();
}
I'm not sure how much overhead there is in spinning up a new instance of HttpConfiguration (I suspect not a lot), but the new instance comes with the Formatters collection filled by default, which is why you have to clear it right after instantiating it. Note that it if you don't use Configuration = new HttpConfiguration(), and instead modify Configuration directly, it modifies the GlobalConfiguration.Configuration property (so, it would impact all your other WebApi methods - bad!).

Android -- How to access data in an ASP.NET database via app?

I have a Windows web server already set up with a website (unlimited application pools) and I want to be able to access a database on that server via the Android app I'm developing. How can I do this? Can someone point me to a tutorial or give code example of how this cross-platform (Android/Java to ASP.NET/C#) communication can be done?
(I'm trying to create a leader board or global scoreboard for my Android game on my server.)
Thanks.
Your app should expose a webservice.
There is no native support for .net soap based webservices. But you can use the ksoap android port:
http://code.google.com/p/ksoap2-android/
which allows an android app to consume a .net asmx webservice.
However the deserialisation of complex on the client side involves lot of code writing for every object you want so pass to the client.
I tried it for a project and there were some problems I ran into (either I could get result back to the client but the parameters i passed where always null or the other way - I could pass arguments but the result was null).
Here is an example I posted for getting an int: How to call a .NET Webservice from Android using KSOAP2?
However, from my current knowlege I would suggest using a .asmx webservice that returns a json string and use a java json serialiser to parse the output. The advantages:
Write less code
Faster, since mobile devices don't always have good internet connections and the xml overhead from soap is bigger than json.
Quickstart:
Create a new asmx Webservice in your .net webapp.
Include a reference to System.Web.
Decorate your webservice class with [ScriptService] and your method with [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string HelloAndroid()
{
return "Hello Android";
}
}
(I think you have to add a reference to System.Web.Extension.dll which is available since .net 3.5).
Your webservice will still return XML (so you can use it with a soap client) unless you make a HTTPPost request with content-type "application/json".
use this code to contact the webservice from android:
private JSONObject sendJsonRequest(string host, int port,
String uri, JSONObject param)
throws ClientProtocolException, IOException, JSONException
{
HttpClient httpClient = new DefaultHttpClient();
HttpHost httpHost = new HttpHost(host, port);
HttpPost httpPost = new HttpPost(uri);
httpPost.addHeader("Content-Type", "application/json; charset=utf-8");
if (param != null)
{
HttpEntity bodyEntity = new StringEntity(param.toString(), "utf8");
httpPost.setEntity(bodyEntity);
}
HttpResponse response = httpClient.execute(httpHost, httpPost);
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
InputStream instream = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(instream));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
sb.append(line + "\n");
result = sb.toString();
instream.close();
}
httpPost.abort();
return result != null ? new JSONObject(result) : null;
}
if your webservice methods looks like this:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public User GetUser(string name, int age)
{
return new User { Name = name, Age = age; }
}
You can call it this way from android:
public void getUser() {
// if you put a json object to the server
// the properties are automagically mapped to the methods' input parameters
JSONObject param = new JSONObject();
param.put("name", "John Doe");
param.put("age", 47);
JSONObject result = sendJsonRequest("server", 80,
"http://server:80/service1.asmx/GetUser", param);
if (result != null) {
JSONObject user = new JSONObject(result.getString("d"));
// .net webservices always return the result
// wrapped in a parameter named "d"
system.out.println(user.getString("name"));
system.out.println(user.getInt("age").toString());
}
}
Handling server exceptions on the client side:
Add this class to your project:
import org.json.JSONException;
import org.json.JSONObject;
public class JSONExceptionHelper {
private static final String KEY_MESSAGE = "Message";
private static final String KEY_EXCEPTIONTYPE = "ExceptionType";
private static final String KEY_STACKTRACE = "StackTrace";
public static boolean isException(JSONObject json) {
return json == null
? false
: json.has(KEY_MESSAGE) &&
json.has(KEY_EXCEPTIONTYPE) &&
json.has(KEY_STACKTRACE);
}
public static void ThrowJsonException(JSONObject json) throws JSONException {
String message = json.getString(KEY_MESSAGE);
String exceptiontype = json.getString(KEY_EXCEPTIONTYPE);
String stacktrace = json.getString(KEY_STACKTRACE);
StringBuilder sb = new StringBuilder();
sb.append(exceptiontype);
sb.append(": ");
sb.append(message);
sb.append(System.getProperty("line.separator"));
sb.append(stacktrace);
throw new JSONException(sb.toString());
}
}
Now replace the return statement from the sendJSONRequest with:
JSONObject json = result != null ? new JSONObject(result) : null
if (JSONExceptionHelper.isException(json))
JSONExceptionHelper.ThrowJsonException(json);
return json;
Please note: The exception is passed to the client only if connection comes from localhost.
Otherwise you get an http error 500 (or 501? I can't remember). You have to configure your IIS to send error 500 to the client.
Try it out and create a webservice that always throws an exception.
Sounds like a job for Web Services.
Start by creating a Web Service on the Windows web server, you can do this with ASP.NET (or maybe this might be more current).
On the Java side you can call the webservice and use the results that you get back. I think this question may help you get started on this side.
In case you have trouble writing web methods which return array of objects, you may want to refer here:
ksoap android web-service tutorial
Hope it helps.

Categories