Consuming RESTful C# Web Service through Java Android - c#

Dears,
I know that the title seems popular and easy but what I'm facing is too strange.
Simply, I have a RESTful C# .NET 4.0 web service published on the server, and I want to consume it through Java in my Android application, easy?
The problem is: whenever I call the .NET web service and get the response, java could not parse the return string into Json.
Error message:
org.json.JSONException: Value {lhs:"1 Euro",rhs: "1.3711 U.S. dollars",error: "",icc: true} of type java.lang.String cannot be converted to JSONObject
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONObject.<init>(JSONObject.java:158)
at org.json.JSONObject.<init>(JSONObject.java:171)
at com.itrack21.mobileapp.LoginActivity.getUserInfo(LoginActivity.java:151)
at com.itrack21.mobileapp.LoginActivity$1$1.run(LoginActivity.java:114)
at java.lang.Thread.run(Thread.java:841)
threadid=17: thread exiting with uncaught exception (group=0x4164d700)
Java Code:
public void getRate(String link) {
try {
URL url = new URL(link);
URLConnection connection = url.openConnection();
InputStream str = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(str);
BufferedReader bufReader = new BufferedReader(reader);
String line=new String();
StringBuffer buffer = new StringBuffer();
while( (line=bufReader.readLine()) != null) {
buffer.append(line);
}
JSONObject obj = null;
try {
obj = new JSONObject(buffer.toString());
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String rhs = "";
try {
rhs = obj.getString("rhs");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i("getRate","Converted Currency = " + rhs.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Debugging:
I did many debugging scenarios but with no luck, here I will use strangest one to describe the problem.
I use my java code to consume Google web service for currency converting using the following link http://www.google.com/ig/calculator?hl=en&q=1USD=?EUR and I got the response as follows: {lhs: "1 U.S. dollar",rhs: "0.726321906 Euros",error: "",icc: true}. And here my code is working perfectly.
I copy exact Json value return from Google web service and working fine with my code, and return it as a HARD CODED String in my RESTful C# service as follows:
C# Code:
public string GetInfo()
{
return "{lhs:\"1 Euro\",rhs: \"1.3711 U.S. dollars\",error: \"\",icc: true}";
}
I request my C# .NET web service using the same code used to invoke Google web service bu I got error listed above org.json.JSONException: Value {lhs:"1 Euro",rhs: "1.3711 U.S. dollars",error: "",icc: true} of type java.lang.String cannot be converted to JSONObject at org.json.JSON.typeMismatch(JSON.java:111).
When I copy and paste the return value into my code as a HARD CODE, it works just fine.
JSONObject obj = null;
try {
obj = new JSONObject("{lhs:\"1 Euro\",rhs: \"1.3711 U.S. dollars\",error: \"\",icc: true}");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Many "Crazy" debugging scenario done including changing the server itself, but with no luck.
What I'm doing wrong?
Regards,

In JSON, you need to wrap the keys in quotation marks too. So for this:
{lhs: "1 U.S. dollar",rhs: "0.726321906 Euros",error: "",icc: true},
you will have to do this:
{"lhs": "1 U.S. dollar","rhs": "0.726321906 Euros","error": "","icc": "true"}
You can check your JSON online at : http://jsonlint.com/

After long debugging process, I got the cause, and then the solution. Here we go:
Visit Google Maps Web Service through Chrome browser, and you will get Json response. For debugging purpose, right click on page and select View page source. Note that the string of Json is pure Json with no additions.
When you repeat same procedure with the C# .NET response through Chrome browser, you will notice that the response is NOT pure Json, it is surrounded by this: <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{JSON String HERE}</string>.
Solution:
To remove this string surrounding the response, you have to return Json string as System.IO.Stream. Here the required code changes:
public System.IO.Stream GetInfo()
{
OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse;
context.ContentType = "text/plain";
return new System.IO.MemoryStream(ASCIIEncoding.Default.GetBytes("{lhs:\"1 Euro\",rhs: \"1.3711 U.S. dollars\",error: \"\",icc: true}"));
}
This solution works fine with me, but is it optimal solution? converting from object to Json, and then from Json string to bytes is little overhead, what do think? suggestions?

Related

Prevent error if txt/json file is not in the right format (corrupted) before reading it

I have an app that reads and rights to a txt file in a json format. Everything is working fine except that from time to time the txt/json file for some reason becomes corrupted and the app crashes when trying to read it.
Here is the code...
User Class
public class User
{
public string UserName { get; set; }
}
usersFile.txt (json)
[{"UserName":"someUserName"}]
Reading Class
public static string myUsersFolder = #"c:\myUsersFilder";
string usersFile = Path.Combine(myUsersFolder, "usersFile.txt");
public void readUsersFromFile()
{
try
{
if (!File.Exists(usersFile))
throw new FileNotFoundException();// throws an exception if the file is not found
string jsonContent = File.ReadAllText(Path.Combine(myUsersFolder, usersFile));
List<User> users = JsonConvert.DeserializeObject<List<User>>(jsonContent);
foreach (var u in users)
{
User user = new User();
user.UserName = u.UserName;
UsersObservableCollection.Add(user);
}
}
catch (FileNotFoundException f)
{
Console.WriteLine("Couldn't read users from file: " + f.Message);
}
}
Error
'The invocation of the constructor on type 'MyProgramName.ViewModel.ViewModelLocator' that matches the specified binding constraints threw an exception.'
The issue is that if at some point the file usersFile.txt becomes corrupted, where the format is not right, for instance missing a } curly bracket, the app crashes.
[{"UserName":"someUserName"] // missing a curly bracket, app crashes
How can I prevent the app from crashing if the file is in the wrong format?
You should use the .NET JSON serializer (System.Text.Json). The .NET JSON library has a modern async API (How to serialize and deserialize (marshal and unmarshal) JSON in .NET.
The original exception you are experiencing is the result of the failed deserialization. You could (but shouldn't) wrap the deserialization part alone into a try-catch block. Also don't explicitly throw an exception (FileNotFoundException) just to catch it (even in the same context). Rather show the error message directly (or log it).
Exceptions are very expensive. You would always try to avoid them. Checking if the file exists successfully avoids the FileNotFoundException. Job done.
For this sake, the correct approach would be to validate the JSON before you try to deserialize it: avoid the exception instead of handling it.
The following example shows a fixed version of your code. It also incorporates JSON validation to avoid any malformed input related exceptions.
The example also uses the StreamReader to read from the file asynchronously. this helps to avoid freezing your application during file handling. Generally use async APIs where possible.
public async Task readUsersFromFileAsync()
{
if (!File.Exists(usersFile))
{
Console.WriteLine("Couldn't read users from file: " + f.Message);
}
using var fileReader = new StreamReader(Path.Combine(myUsersFolder, usersFile));
string jsonContent = await fileReader.ReadToEndAsync();
if (!await TryValidateJsonInputAsync(jsonContent, out IList<string> errorMessages))
{
foreach (string errorMessage in errorMessages)
{
Console.WriteLine(errorMessage);
}
return;
}
List<User> users = JsonConvert.DeserializeObject<List<User>>(jsonContent);
foreach (var u in users)
{
User user = new User();
user.UserName = u.UserName;
UsersObservableCollection.Add(user);
}
}
private Task<bool> TryValidateJsonInputAsync(string jsonContentToValidate, out IList<string> messages)
{
var jsonSchemaText = new StreamReader("json_schema.txt");
JSchema jsonSchema = JSchema.Parse(jsonSchemaText);
JObject jsonToValidate = JObject.Parse(jsonContentToValidate);
return jsonToValidate.IsValid(jsonSchema, out messages);
}
The example JSON schema used in the example (json_schema.txt file).
{
'description': 'A person',
'type': 'object',
'properties': {
'name': {'type': 'string'},
'hobbies': {
'type': 'array',
'items': {'type': 'string'}
}
}
}
See the Newtonsoft documentation Validating JSON to get more detailed information on how to validate JSON input.
But again, I recommend the JsonSerializer from the System.Text.Json namespace as it offers an async API.

Session getting null reference

i'm working on a project where i am using sessions for storing message alerts. when new item is added in a database i store success message in Session["message"] and which is used to show a simple message to user. all this is working file every time new message is stored in this session. but when i moved to another page i want to destroy session and after that i want to show new page.
Function for creating sessions:-
public void Send_Response(string message, string status)
{
Session["message"] = message;
Session["status"] = status;
}
i can access this session in whole code but when i going to destroy this session it throws null reference exception.
here is the code to setting sessions to null:-
public void Set_Null_Session()
{
try
{
Response.Cookies["message"].Value = string.Empty; //not working
//Session.Abandon(); //not working
//Session.Remove("message"); //not working
//Session.Remove("status"); //not working
Session["message"] = " "; //not working
Session["status"] = " "; //not working
Session["message"] = null; //not working
Session["status"] = null; //not working
}
catch (Exception ex)
{
var error = ex.ToString();
}
}
i used Session.Remove("message") , session.Abandon() but nothing is working.
i called Set_Null_Session method in my controller before moving to another page as i want to destroy previous session.
It sounds like Set_Null_Session does not have access to the Session object. Where is that method defined? And where is it called from? You might need to pass the Session or Request object into the method.

MVC Backload File Upload failing in production

I've got a .NET 4.5 MVC 5 web application that utilizes Backload 2.0 to help with uploading an Excel file. The controller method works great in my development environment. However, when I moved to my production server, the same method is now failing.
It's failing because handler.Services.POST is null. All of the other properties off handler.Services are null as well, e.g. GET, etc.
What might cause this to happen? Is it an IIS setting? Web.config? What else can I check??
Most of this code was copied from an example that ships with Backload.
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post | HttpVerbs.Put | HttpVerbs.Delete | HttpVerbs.Options)]
public async Task<ActionResult> FileHandler()
{
try
{
// Create and initialize the handler
var handler = Backload.FileHandler.Create();
handler.Init(HttpContext.Request);
// Call the appropriate request handlers
if (handler.Context.HttpMethod == "POST")
{
// Get the posted file with meta data from the request
handler.FileStatus = await handler.Services.POST.GetPostedFiles();
if (handler.FileStatus != null)
{
var file = handler.FileStatus.Files[0];
DateTime spreadsheetDate;
using (var memoryStream = new MemoryStream((int)file.FileSize))
{
await file.FileStream.CopyToAsync(memoryStream);
//TODO: do some stuff...
}
}
// Create client plugin specific result and return an ActionResult
IBackloadResult result = handler.Services.Core.CreatePluginResult();
return ResultCreator.Create((IFileStatusResult)result);
}
// other http methods may also be handled
return new EmptyResult();
}
catch (Exception ex)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
}
Direct api calls (Services namespace) is a Pro feature and only works with the Pro Edition.
In your case I think you can switch to events with the same result. For example you can use the StoreFileRequestStarted event. Don't forget to enable events in the Web.Backload.config like described here:
https://github.com/blackcity/backload/wiki/Example-12
The demo package also includes an events example:
https://github.com/blackcity/Backload/releases/download/v2.1.0.0/Backload.Standard.2.1.Full.zip

Passing date to ASMX web service

I use asmx web service writes in c# over android device.
I make connection and when in some web method I need integer or string like input param,all work great, but problem is when web method need date, I try to send date in many format but always I have problem to get answer.
I need to send date object, or like string? It is possible that web service view date like something else?
This is method for "communication" with web service:
public void connectSOAP()
{
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
String dateStr = "04/05/2010";
Date dateObj=null;
SimpleDateFormat curFormater = new SimpleDateFormat("dd/mmm/yyyy");
try
{
dateObj = curFormater.parse(dateStr);
}
catch (java.text.ParseException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
request.addProperty("dtFrom",dateObj);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.dotNet = true;
try
{
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
if (envelope.getResponse() != null)
{
if (envelope.bodyIn instanceof SoapFault)
{
String str = ((SoapFault) envelope.bodyIn).faultstring;
Log.i("", str);
}
else
{
SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
Log.d("WS", String.valueOf(resultsRequestSOAP));
}
};
}
catch (Exception e)
{
Log.d("WS","sss");
}
}
When i change web method(something with out date it work),I get response in log) But when is this way with date i just get catch ("sss" ) in log,i debug and find that it brake on:
androidHttpTransport.call(SOAP_ACTION, envelope);
But i not find anything about that in log except catch that i set...
For me this looks like the dateObj which you want to give to the webservice can not be parsed, thats why the exception occurre at this line:
androidHttpTransport.call(SOAP_ACTION, envelope);
But as your formatter has this format:
SimpleDateFormat curFormater = new SimpleDateFormat("dd/mmm/yyyy");
Maybe the (three!)"mmm" are causing the error?? I am pretty sure this will produce something like e.g. "Feb" for February and so on.. (e.g. "11/Feb/2014"):
Try something like:
SimpleDateFormat curFormater = new SimpleDateFormat("dd/mm/yyyy");
or
SimpleDateFormat curFormater = new SimpleDateFormat("dd/MM/yyyy");
Btw, to avoid localisation and interoperability issues, i often use DateTime objects accurately formatted to Strings for giving that objects over to WebService. Because many times i had problems by interoperability between e.g. .asmx Webservice and J2EE web service (e.g. the range of DateTime is not the same for J2EE and .NET and if it's a null/nil value you also run in troubles).

Get SOAP request in C#

In my console application I added a service reference to http://www.ibanbic.be/IBANBIC.asmx .
The operations in it I need to use.
Now, this is my little piece of code, and from what I saw in tutorials, this should be enough to connect to it and get a value. But the only value I get is "String is Empty".
using (BANBICSoapClient WebService = new BANBICSoapClient())
{
string bban = "*****";
try
{
string resultIban = WebService.BBANtoIBAN(bban);
if (resultIban != string.Empty)
{
Console.WriteLine(resultIban);
}
else
{
Console.WriteLine("String is empty.");
}
}
catch(Exception msg)
{
Console.WriteLine(msg);
}
}
Console.ReadLine();
Can anyone give me some more information about what is wrong?
Are you passing a valid BBAN or just the string of asterixes? Do you have a sample of valid data?
Calling the web service with data I just mocked up, e.g. (12345, *) looks to return an empty string, so that's what it might return in the event of invalid data.

Categories

Resources