I have a webservice that returns json array (JArray) in string format, but I do not understand how to add state value to that operation and get it in the application that consumes the service.
My question is, should I return a json object with a message and inside a json array? Or just an array? hich is more convenient ?
my ws:
public string getList(string strSalary)
{
List<Employee> listJson = null;
JObject jsonResp = "";
JArray array = null;
try
{
listJson = ReportBLL.getInstance.listEmployees(int.Parse(strSalary));
array = JArray.FromObject(listJson);
//set array status ?: ej
//array status = "succes";
}
catch (Exception ex)
{
//set error message
// array status = "error";
//array message = ex.Message or "Not found employees";
}
return JsonConvert.SerializeObject(array);
}
client call (other asp app):
public static List<Employee> listEmployeeClient(string salary)
{
JObject jo = null; //or arrayjson ?
string strData = "";
strData = webService.getList(salary);
jo = JObject.Parse(strData);
//how to evalue status request ?
/* example
if(jo.status == "error") {
throw new Exception(jo.message);
} else {
iterate array inside json object ?
}
*/
}
Is this logic correct ?
You can create a new entity for API Response and use it for all your API responses, You can test it out by the following example.
In server:
Class APIResponse<T>
{
public bool IsError;
public int ErrorCode;
public string ErrorMessage;
public T ReponseData;
}
public string getList(string strSalary)
{
List<Employee> listJson = null;
APIResponse<Employee> responseString = new APIResponse<Employee>();
try
{
listJson = ReportBLL.getInstance.listEmployees(int.Parse(strSalary));
responseString.isError = false;
responseString.data = JArray.FromObject(listJson);
}
catch (Exception ex)
{
responseString.IsError = true;
responseString.ErrorCode = 404; //You can add custom error codes
responseString.ErrorMessage = ex;
}
return JsonConvert.SerializeObject(responseString);
}
In Client:
public static List<Employee> listEmployeeClient(APIResponse<Employee> salary)
{
//You can access the model here
}
There are many options. If you have REST apis you can use the HTTPStatusCodes, for each request, e.g. 200 for OK, 400 bad request, etc.
If you want more fine tuning, you can have a general structure of your response objects, e.g.
responseDto:
status: any code, error or success
message: any error message
data: any expected data
use a Dictionary<string,object> before serializing, and use dynamic to conveniently get the various fields after deserializing. jArray.ToObject<List<Employee>>() will convert JArray object back to the proper type.
Example below:
class Employee
{
public string Name { get; set; }
}
// serializing
var employees = new List<Employee>()
{
new Employee() {Name = "john"},
new Employee() {Name = "alex"},
new Employee() {Name = "susan"},
new Employee() {Name = "bryan"},
};
var dict = new Dictionary<string, object>
{
["employees"] = employees,
["status"] = "error",
["errormessage"] = "Not found employees"
};
var json = JsonConvert.SerializeObject(dict);
// deserializing
dynamic deserialized = JsonConvert.DeserializeObject(json);
string status = deserialized.status;
string errorMessage = deserialized.errormessage;
JArray jArray = deserialized.employees;
List<Employee> deserializedEmployee = jArray.ToObject<List<Employee>>();
Related
I have the following working controller method, which returns the JSON in a simple text format.
[HttpPost]
public IActionResult DecodeBarcode(string productCodeScheme, string productCode, string serialNumber, string batch, string expirationDate, int commandStatusCode) {
string TextAreaResult = string.Empty;
try {
TextAreaResult = string.Format("{0} {1} {2}", request.getHttpInformation(), request.getHttpWarning(), request.getHttpResponseCode());
} catch (Exception exc) {
TextAreaResult = "Exception: " + exc.Message;
}
return Json(TextAreaResult);
}
The output after the above method is run looks something like
"The pack is active No warning 200"
whereas
request.getHttpInformation() is The pack is active
request.getHttpWarning() is No warning
request.getHttpResponseCode() is 200
Now, I am trying to split the response into 3 different key-value pairs so that my response will look like
{
httpInformation: "The pack is active",
httpWarning: "No Warning",
httpResponseCode: "200"
}
How do I pass the additional params in return Json(TextAreaResult) call?
If I do like the following it won't work
[HttpPost]
public IActionResult DecodeBarcode(string productCodeScheme, string productCode, string serialNumber, string batch, string expirationDate, int commandStatusCode) {
string TextAreaResult = string.Empty;
string TextAreaResultHttpInformation = string.Empty;
string TextAreaResultHttpWarning = string.Empty;
string TextAreaResultHttpResponseCode = string.Empty;
try {
TextAreaResultHttpInformation = string.Format("{0}}", request.getHttpInformation());
TextAreaResultHttpWarning = string.Format("{1}}", request.getHttpWarning());
TextAreaResultHttpResponseCode = string.Format("{2}}", request.getHttpResponseCode());
} catch (Exception exc) {
TextAreaResult = "Exception: " + exc.Message;
}
return Json(TextAreaResultHttpInformation, TextAreaResultHttpInformation, TextAreaResultHttpResponseCode);
}
How do I construct the key-value pairs and return as JSON? Perhaps, Json method is not the right choice over here, but being new to C#, I am not aware of any other c# inbuilt methods for constructing JSON
Assuming you actually want to consume the response as JSON, you could achieve this by doing
return Json(new
{
HttpInformation = TextAreaResultHttpInformation,
HttpWarning = TextAreaResultHttpWarning,
StatusCode = TextAreaResultHttpResponseCode
});
You can make wrapper class for these properties and return it.
public class BarcodeResultDto
{
[JsonProperty("httpInformation")]
public string HttpInformation { get; set; }
[JsonProperty("httpWarning")]
public string HttpWarning { get; set; }
[JsonProperty("httpResponseCode")]
public int GetHttpResponseCode { get; set; }
}
public IActionResult DecodeBarcode(string productCodeScheme, string productCode, string serialNumber,
string batch, string expirationDate, int commandStatusCode)
{
var barcodeResult = new BarcodeResultDto
{
GetHttpResponseCode = 200,
HttpInformation = "The pack is active",
HttpWarning = "No Warning"
};
// your code here
return Ok(barcodeResult);
}
Or you can change retuned value from IActionResult to JsonResult
If you want a different approach then you can use JsonSerializer in the following way :
// Creating BlogSites object
BlogSites bsObj = new BlogSites()
{
Name = "test-name",
Description = "test-description"
};
// Serializing object to json data
JavaScriptSerializer js = new JavaScriptSerializer();
string jsonData = js.Serialize(bsObj); // {"Name":"test-name","Description":"test-description"}
You will just need to create a class and store value in its objects then serialize it. If you have a list then you can use List of that class and then serialize.
i need an advice about how to return an error message caught on server to client. I am creating WCF Restfull service and able to returning an error message while using GET method. But hardly find the proper way to return error message from POST method.
EDITED
For #Abd:
I have tried using throw WebFaultException, like below code:
try
{
newbudgetid = _service.Create(budgettrx);
}
catch (Exception ex)
{
error_message = ex.Message;
MyCustomErrorDetail customerror = new MyCustomErrorDetail(
"Error", error_message);
throw new WebFaultException<MyCustomErrorDetail>(customerror, HttpStatusCode.NotFound);
}
And this is the class definition:
public class MyCustomErrorDetail
{
public MyCustomErrorDetail(string errorInfo, string errorDetails)
{
ErrorInfo = errorInfo;
ErrorDetails = errorDetails;
}
[DataMember]
public string ErrorInfo { get; private set; }
[DataMember]
public string ErrorDetails { get; private set; }
}
On client code, how should i write the error output from server ?
BudgetTransactionRequest bt = new BudgetTransactionRequest
{
transaction_code = "7PRM007690 ",
category = "Expenses",
claim_status = "Presales ID",
amount = "320000.00000",
application_type = "Payment Request",
opportunity = "BSMD000586",
project = null,
request_date = new DateTime(2013, 03, 09),
request_status = "Validated",
owner = "nurul.wiiyanti",
};
WebClient proxy = new WebClient();
proxy.Headers["Content-Type"] = "application/json";
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer serialize = new DataContractJsonSerializer(typeof(BudgetTransactionRequest));
serialize.WriteObject(ms, bt);
byte[] data = proxy.UploadData("http://10.10.64.19:8082/Service1.svc/CreateBudgetTransaction/", "POST", ms.ToArray());
Stream stream = new MemoryStream(data);
DataContractJsonSerializer obj = new DataContractJsonSerializer(typeof(BudgetTransactionRequest));
You can create a ServiceResult class and use it for all Get and Post methods. In this class you can use properties such as Generic Result, HasException, ExceptionMessage etc.
throw a WebFaultException(T errorDetail, HttpResponseCode code)
Here you set your response type to another object type, which makes sense, and also you set the ResponseCode that you want.
The errorDetail must be serializable
this link could be useful, or this link
Is there a way to make a function return the type of object I pass in? I would like to call the one method below to return the type I pass in. Is that possible? Should I even be trying to do this? Is there a better way...short of having two different methods?
Currently, I tried the first two calls and I get back (with the first call) what looks like a dictionary with a system.object[] in the value part of the dictionary. Screen shot below might show it better than my explanation. I ask this as I might have more types that I need to deserialize and don't want to have a different method for each.
var firstTry = this.Deserialize(path, typeof(ObservableCollection<ListItemPair>();
var secondTry = this.Deserialize(path, typeof(ListItemPair));
var thirdTry = this.Deserialize(path, typeof(SomeOtherObject));
public static object Deserialize(string jsonFile, object type)
{
var myObject = new object();
try
{
using (StreamReader r = new StreamReader(jsonFile))
{
var serializer = new JavaScriptSerializer();
string json = r.ReadToEnd();
myObject = serializer.Deserialize<object>(json);
}
}
catch (Exception ex)
{
}
return myObject ;
}
public class ListItemPair
{
public string Name
{
get;
set;
}
public object Value
{
get;
set;
}
}
object created:
Yes, you can create a generic method. Your Deserialize() method would look something like this:
public static T Deserialize<T>(string jsonFile)
{
T myObject = default(T);
try
{
using (var r = new StreamReader(jsonFile))
{
var serializer = new JavaScriptSerializer();
string json = r.ReadToEnd();
myObject = serializer.Deserialize<T>(json);
}
}
catch (Exception ex)
{
}
return myObject;
}
In this example T is a type parameter. When invoking this method, you can pass the type like this:
var firstTry = Deserialize<ObservableCollection<ListItemPair>>(path);
var secondTry = Deserialize<ListItemPair>(path);
var thirdTry = Deserialize<SomeOtherObject>(path);
One side note: I wouldn't recommend silently swallowing an exception. In this case, it is expected that the deserialization can fail. Therefore, I would change it to a TryDeserialize() method:
public static bool TryDeserialize<T>(string jsonFile, out T myObject)
{
try
{
using (var r = new StreamReader(jsonFile))
{
var serializer = new JavaScriptSerializer();
string json = r.ReadToEnd();
myObject = serializer.Deserialize<T>(json);
}
}
catch (Exception ex)
{
myObject = default(T);
return false;
}
return true;
}
When using MVC, returning adhoc Json was easy.
return Json(new { Message = "Hello"});
I'm looking for this functionality with the new Web API.
public HttpResponseMessage<object> Test()
{
return new HttpResponseMessage<object>(new { Message = "Hello" }, HttpStatusCode.OK);
}
This throws an exception as the DataContractJsonSerializer can't handle anonymous types.
I have replaced this with this JsonNetFormatter based on Json.Net.
This works if I use
public object Test()
{
return new { Message = "Hello" };
}
but I don't see the point of using Web API if I'm not returning HttpResponseMessage, I would be better off sticking with vanilla MVC. If I try and use:
public HttpResponseMessage<object> Test()
{
return new HttpResponseMessage<object>(new { Message = "Hello" }, HttpStatusCode.OK);
}
It serializes the whole HttpResponseMessage.
Can anyone guide me to a solution where I can return anonymous types within a HttpResponseMessage?
This doesn't work in the Beta release, but it does in the latest bits (built from http://aspnetwebstack.codeplex.com), so it will likely be the way for RC. You can do
public HttpResponseMessage Get()
{
return this.Request.CreateResponse(
HttpStatusCode.OK,
new { Message = "Hello", Value = 123 });
}
This answer may come bit late but as of today WebApi 2 is already out and now it is easier to do what you want, you would just have to do:
public object Message()
{
return new { Message = "hello" };
}
and along the pipeline, it will be serialized to xml or json according to client's preferences (the Accept header). Hope this helps anyone stumbling upon this question
In web API 2 you can use the new IHttpActionResult which is a replacement for HttpResponseMessage and then return a simple Json object: (Similiar to MVC)
public IHttpActionResult GetJson()
{
return Json(new { Message = "Hello"});
}
you can use JsonObject for this:
dynamic json = new JsonObject();
json.Message = "Hello";
json.Value = 123;
return new HttpResponseMessage<JsonObject>(json);
You could use an ExpandoObject. (add using System.Dynamic;)
[Route("api/message")]
[HttpGet]
public object Message()
{
dynamic expando = new ExpandoObject();
expando.message = "Hello";
expando.message2 = "World";
return expando;
}
You may also try:
var request = new HttpRequestMessage(HttpMethod.Post, "http://leojh.com");
var requestModel = new {User = "User", Password = "Password"};
request.Content = new ObjectContent(typeof(object), requestModel, new JsonMediaTypeFormatter());
In ASP.NET Web API 2.1 you can do it in a simpler way:
public dynamic Get(int id)
{
return new
{
Id = id,
Name = "X"
};
}
You can read more about this on https://www.strathweb.com/2014/02/dynamic-action-return-web-api-2-1/
public IEnumerable<object> GetList()
{
using (var context = new DBContext())
{
return context.SPersonal.Select(m =>
new
{
FirstName= m.FirstName ,
LastName = m.LastName
}).Take(5).ToList();
}
}
}
You should be able to get this to work if you use generics, as it will give you a "type" for your anonymous type. You can then bind the serializer to that.
public HttpResponseMessage<T> MakeResponse(T object, HttpStatusCode code)
{
return new HttpResponseMessage<T>(object, code);
}
If there are no DataContract or DataMebmer attributes on your class, it will fall back on serializing all public properties, which should do exactly what you're looking for.
(I won't have a chance to test this until later today, let me know if something doesn't work.)
You can encapsulate dynamic object in returning object like
public class GenericResponse : BaseResponse
{
public dynamic Data { get; set; }
}
and then in WebAPI; do something like:
[Route("api/MethodReturingDynamicData")]
[HttpPost]
public HttpResponseMessage MethodReturingDynamicData(RequestDTO request)
{
HttpResponseMessage response;
try
{
GenericResponse result = new GenericResponse();
dynamic data = new ExpandoObject();
data.Name = "Subodh";
result.Data = data;// OR assign any dynamic data here;//
response = Request.CreateResponse<dynamic>(HttpStatusCode.OK, result);
}
catch (Exception ex)
{
ApplicationLogger.LogCompleteException(ex, "GetAllListMetadataForApp", "Post");
HttpError myCustomError = new HttpError(ex.Message) { { "IsSuccess", false } };
return Request.CreateErrorResponse(HttpStatusCode.OK, myCustomError);
}
return response;
}
My code is below. I am not able to extract the 'name' and 'query' lists
from the JSON via a DataContracted Class (below)
I have spent a long time trying to work this one out, and could really do
with some help...
My Json string:
{"as_of":1266853488,"trends":{"2010-02-22
15:44:48":[{"name":"#nowplaying","query":"#nowplaying"},{"name":"#musicmonday","query":"#musicmonday"},{"name":"#WeGoTogetherLike","query":"#WeGoTogetherLike"},{"name":"#imcurious","query":"#imcurious"},{"name":"#mm","query":"#mm"},{"name":"#HumanoidCityTour","query":"#HumanoidCityTour"},{"name":"#awesomeindianthings","query":"#awesomeindianthings"},{"name":"#officeformac","query":"#officeformac"},{"name":"Justin
Bieber","query":"\"Justin Bieber\""},{"name":"National
Margarita","query":"\"National Margarita\""}]}}
My code:
WebClient wc = new WebClient();
wc.Credentials = new NetworkCredential(this.Auth.UserName, this.Auth.Password);
string res = wc.DownloadString(new Uri(link));
//the download string gives me the above JSON string - no problems
Trends trends = new Trends();
Trends obj = Deserialise<Trends>(res);
private T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
DataContractJsonSerializer serialiser = new DataContractJsonSerializer(obj.GetType());
obj = (T)serialiser.ReadObject(ms);
ms.Close();
return obj;
}
}
[DataContract]
public class Trends
{
[DataMember(Name = "as_of")]
public string AsOf { get; set; }
//The As_OF value is returned - But how do I get the
//multidimensional array of Names and Queries from the JSON here?
}
I've run into this very issue while developing Twitterizer. The issue is that the dataset isn't in a traditional object-oriented design.
If you were to map that as objects, you would see:
object root
int as_of
object trends
array[object] <date value of as_of>
string query
string name
As you can see, the trend object has a property that's name changes. The name is based on the as_of date value. As such, it can't be automatically deserialized.
My first solution was to use System.Web.Script.Serialization.JavaScriptSerializer.DeserializeObject(). That method returns a hierarchy of weakly typed, nested dictionary instances. I then stepped through the results myself.
internal static TwitterTrendTimeframe ConvertWeakTrend(object value)
{
Dictionary<string, object> valueDictionary = (Dictionary<string, object>)value;
DateTime date = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds((int)valueDictionary["as_of"]);
object[] trends = (object[])((Dictionary<string, object>)valueDictionary["trends"])[date.ToString("yyyy-MM-dd HH:mm:ss")];
TwitterTrendTimeframe convertedResult = new TwitterTrendTimeframe()
{
EffectiveDate = date,
Trends = new Collection<TwitterTrend>()
};
for (int i = 0; i < trends.Length; i++)
{
Dictionary<string, object> item = (Dictionary<string, object>)trends[i];
TwitterTrend trend = new TwitterTrend()
{
Name = (string)item["name"]
};
if (item.ContainsKey("url"))
{
trend.Address = (string)item["url"];
}
if (item.ContainsKey("query"))
{
trend.SearchQuery = (string)item["query"];
}
convertedResult.Trends.Add(trend);
}
return convertedResult;
}
It's ugly, but it worked.
I've since embraced the use of Json.NET for it's speed and simplicity.
have you considered using JSON.net ?
Consider this example:
public struct TwitterResponse
{
public int32 as_of;
public Trend[] Trends;
}
public struct Trends
{
public String name;
public String query;
}
Trend[] obj = JavaScriptConvert.DeserializeObject<TwitterResponse>( res ).Trends;
Probably needs finetuning, but that's the general idea on how to do it.