How to send a file inside JSON to a service?
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json)]
public string Upload(UploadRequest request)
{
return request.FileBytes.Length.ToString();
//return request.FileName;
}
[DataContract]
public class UploadRequest
{
[DataMember]
public int ProfileID { get; set; }
[DataMember]
public string FileName { get; set; }
[DataMember]
public byte[] FileBytes { get; set; }
}
I tried FileBytes as Stream, but received and error: "cannot create instance of an abstract class".
$('#file2').change(function () {
var request =
{
"ProfileID": 1,
"FileName": this.files[0].name,
"FileBytes": this.files[0]
}
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:45039/Files.svc/Upload', true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.onreadystatechange = function (aEvt) {
if (this.readyState == 4) {
if (this.status == 200)
$("#status").html(this.responseText);
else
$("#status").html("Error " + this.status.toString() + ": " + this.responseText);
}
};
xhr.send(JSON.stringify(request));
});
If the file is sent directly (xhr.send(this.files[0]) with Upload(Stream myfile), then WCF converts the posted file to a Stream. Is there a way to do that with the Stream inside the DataContract?
It turns out the answer is yes. You have to define the class as a MessageContract rather than a DataContract with only one property allowed to be a [MessageBodyMember]. The other properties to be [MessageHeader].
WCF will not map multi-part form data to a DataContract or MessageContract. Apparently this is due to WCF not buffering the message body and streaming it instead. The message body could be quite large so that does make sense.
Related
globally, I have the following object:
public class Geraet
{
public long Geraetenr { get; set; }
public int Typ { get; set; }
public string Platz { get; set; }
public string Bezeichnung { get; set; }
public int Tr { get; set; }
public string Ip { get; set; }
public string Bespielt { get; set; }
}
I populate a list of those objects, serialize them and send them via webservice:
[HttpGet]
public IHttpActionResult Get_Feedback()
{
List<Geraet> geraeteliste = null;
try
{
geraeteliste = GetSpielgeraeteFromDatabase();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
if (geraeteliste == null)
{
return Ok("No record found!");
}
else
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(geraeteliste);
return Json(json);
}
}
The data received by webservice looks like the following:
"[{\"Geraetenr\":123456789,\"Typ\":61,\"Platz\":\"1-01\",\"Bezeichnung\":\"CSII ADM430\",\"Tr\":3,\"Ip\":\"123.123.123.123\",\"Bespielt\":\"0\"},{\"Geraetenr\":987654321,\"Typ\":61,\"Platz\":\"2-12\",\"Bezeichnung\":\"M-BOX PUR+ GOLD\",\"Tr\":3,\"Ip\":\"124.124.124.124\",\"Bespielt\":\"0\"}]"
In my Xamarin App, I have the same object given above and trying to deserialize it:
private List<Geraet> GetSpielgeraeteFromWebservice()
{
List<Geraet> geraeteliste;
var request = HttpWebRequest.Create(Constants.GeraetelistServicePath);
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var json = reader.ReadToEnd();
geraeteliste = JsonConvert.DeserializeObject<List<Geraet>>(json);
}
}
return geraeteliste;
}
Unfortunately, I get an runtime error in the line geraeteliste = JsonConvert.DeserializeObject<List<Geraet>>(json); saying:
Unhandled Exception:
Newtonsoft.Json.JsonSerializationException: Error converting value "[{"Geraetenr":123456789,"Typ":61,"Platz":"1-01","Bezeichnung":"CSII ADM430","Tr":3,"Ip":"123.123.123.123","Bespielt":"0"},{"Geraetenr":987654321,"Typ":61,"Platz":"2-12","Bezeichnung":"M-BOX PUR+ GOLD","Tr":3,"Ip":"124.124.124.124","Bespielt":"0"}]" to type 'System.Collections.Generic.List`1[GroceryList.Classes.Geraet]'. Path '', line 1, position 3421.
The sending / retrieving stuff does work, otherwise error message would be in the line var json = reader.ReadToEnd(); or I wouldn't have gotten the right values in the error message. So something with the deserialization does not work.
Can anyone maybe help and tell me what is or could be the problem? Why can't he convert? It is the right order and the right values?
Best regards
I am trying to get the json data from an external rest url(http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3) and display it on my web page in my asp.net mvc application. For that I have written some code i.e.
Controleer---
namespace MyMVCApplication.Controllers
{
public class EmployeeController : Controller
{
string Baseurl = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3";
public async Task<ActionResult> StateDetails()
{
List<State> listStateInfo = new List<State>();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = await client.GetAsync(Baseurl);
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var StateResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
listStateInfo = JsonConvert.DeserializeObject<List<State>>(StateResponse);
}
return View(listStateInfo);
}
}
}
}
Model----
namespace MyMVCApplication.Models
{
public class State
{
public int ObjectID { get; set; }
public string StateName { get; set; }
public int Black { get; set; }
public int Population { get; set; }
}
}
While debugging the code getting the error: "Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 10, position 1" at
JsonConvert.DeserializeObject.
Please suggest me how to solve this issue.
Replace your url with http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3?f=pjson to get the json version of the web service
We are using 3rd party api kraken.io to optimize our images.
The results of optimized image is posted in a Webhook.
In their api document it states: After the optimization is over Kraken will POST a message to the callback_url specified in your request in a JSON format application/json.
I am using ngrok to allow remote webhooks to send data to my development machine, using this article.
Results posted to the Callback URL:
HTTP/1.1 200 OK
{
"id": "18fede37617a787649c3f60b9f1f280d",
"success": true,
"file_name": "header.jpg",
"original_size": 324520,
"kraked_size": 165358,
"saved_bytes": 159162,
"kraked_url": "http://dl.kraken.io/18/fe/de/37617a787649c3f60b9f1f280d/header.jpg"
}
Class to Map
public class KrakenOptimizedResults
{
public string id { get; set; }
public bool success { get; set; }
public string file_name { get; set; }
public int original_size { get; set; }
public int kraked_size { get; set; }
public int saved_bytes { get; set; }
public string kraked_url { get; set; }
}
Action Method
[HttpPost]
public ActionResult OptimizedWebHook()
{
Request.InputStream.Position = 0;
string jsonString = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
KrakenOptimizedResults obj = new JavaScriptSerializer().Deserialize<KrakenOptimizedResults>
(jsonString);
return Json(obj);
}
But When I debug the received jsonString in Html Visualizer it looks like key and value pairs instead of Json format.
Received Results not Json Formatted:
file_name=header.jpeg&original_size=118066&kraked_size=102459&saved_bytes=15607
I guess the received data content-type: is application/x-www-form-urlencoded.
Why i am receiving key and value pairs instead of Json format ? how can I deserialize Json data in asp.net mvc ?
Co-founder of https://kraken.io here.
There is a glaring omission in our documentation which I will fix today. To get JSON back, you need to set a "json": true flag in the request. Omitting that flag or setting "json": false will return URLEncoded. Example cURL request:
curl http://api.kraken.io/v1/upload -X POST --form data='{"auth":{"api_key":"YOUR_KEY", "api_secret":"YOUR_SECRET"}, "wait": true, "lossy": true, "callback_url": "http://requestb.in/wbhi63wb", "json": true}' --form upload=#test.jpg
Sorry for the inconvenience :-(
I was able to convert Query String Key and Value pairs to Json Format using this and this post ,there is some delay to convert form Dictionary to Json, so If there is better answers, then do post and advice, below is my solution.
Action Method
[HttpPost]
public ActionResult OptimizedWebHook()
{
Request.InputStream.Position = 0;
string data = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
var dict = HttpUtility.ParseQueryString(data);
var json = new JavaScriptSerializer().Serialize(dict.AllKeys.ToDictionary(k => k, k =>
dict[k]));
KrakenOptimizedResults obj = new JavaScriptSerializer().Deserialize<KrakenOptimizedResults>
(json);
return Json(obj);
}
Recieving JSON formated optimized results from kraken API.
As mentioned by #karim79, To get JSON back, you need to set a "json": true flag in the request.
As Kraken .Net/C# SDK didn't have option to set "json": true, so i have to extend their base class.
Extended Base Class:
public class OptimizeRequestBaseExtended : OptimizeRequestBase,
IOptimizeUploadRequest, IRequest
{
public OptimizeRequestBaseExtended(Uri callbackUrl)
{
CallbackUrl = callbackUrl;
}
[JsonProperty("callback_url")]
public Uri CallbackUrl { get; set; }
[JsonProperty("json")]
public bool JsonFormat { get; set; }
}
Request Kraken API:
var callbackUrl = new Uri("http://localhost:0000/Home/OptimizedWebHook");
OptimizeRequestBaseExtended settings = new OptimizeRequestBaseExtended(callbackUrl);
settings.Lossy = true;
settings.JsonFormat = true;
var response = client.Optimize(image: image, filename: filename, optimizeRequest: settings);
Action Method
[HttpPost]
public ActionResult OptimizedWebHook()
{
Request.InputStream.Position = 0;
string jsonString = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
KrakenOptimizedResults obj = JsonConvert.DeserializeObject<KrakenOptimizedResults>
(jsonString);
return Json(obj);
}
Step 1:
Create an aspx page. This page must be able to accept HTTP POST request.
Step 2:
Add this code to get HTTP POST data.File: default.aspx.cs
File: default.aspx.cs
var reader = new StreamReader(Request.InputStream);
var json = reader.ReadToEnd();
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
ostrm = new FileStream(#"C:\logfile4webhook.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(ostrm);
Console.SetOut(writer);
Console.Write(DateTime.Now + " ");
Console.WriteLine(json.ToString() + " ");
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
Step 3:
Create webhook. This code can be linked to a button on click event.File:default.aspx.cs
AuthenticationDetails auth = new ApiKeyAuthenticationDetails("your api key");
string listID = "";
listID = "your list id";
List list = new List(auth, listID);
List<string> events = new List<string>();
events.Add("Update");
string postback = list.CreateWebhook(events, "URL", "json");
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
ostrm = new FileStream(#"C:\logfile4webhook.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(ostrm);
Console.SetOut(writer);
Console.Write(DateTime.Now + " ");
Console.WriteLine(postback + " ");
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
Step 4:
Activate webhook. Copy that webhook id from the text file and past it to the code below.
File:default.aspx.cs
AuthenticationDetails auth = new ApiKeyAuthenticationDetails("your api key");
string listID = "";
listID = "your list id";
List list = new List(auth, listID);
list.ActivateWebhook("webhook id");
Step 5:
Test weebhook.File: default.aspx.cs
AuthenticationDetails auth = new ApiKeyAuthenticationDetails("your api key");
string listID = "";
listID = "your list id";
List list = new List(auth, listID);
string postback = list.TestWebhook("webhook id").ToString();
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
ostrm = new FileStream(#"C:\logfile4webhook.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(ostrm);
Console.SetOut(writer);
Console.Write(DateTime.Now + " ");
Console.WriteLine(postback + " ");
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
Step 6:
Deserialize body of JSON object. We need to create class structure based on JSON data. I put sample json here and it created required classes
public class CustomField
{
public string Key { get; set; }
public string Value { get; set; }
}
public class Event
{
public List<CustomField> CustomFields { get; set; }
public string Date { get; set; }
public string EmailAddress { get; set; }
public string Name { get; set; }
public string SignupIPAddress { get; set; }
public string Type { get; set; }
}
public class RootObject
{
public List<Event> Events { get; set; }
public string ListID { get; set; }
}
Once you have created your class, append the code from step 2 after
var json = reader.ReadToEnd();
to deserialize and parse json.
RootObject myClass = JsonConvert.DeserializeObject(json);
if (myClass != null)
{
List<Event> t = myClass.Events;
string old_email = "", new_email = "";
old_email = t[0].OldEmailAddress;
new_email = t[0].EmailAddress;
//now you can do your logic with old_email and new_email
}
I have a POST method in my Web API controller that looks like this
public class StudentsController : ApiController {
public HttpResponseMessage Post(ApiStudent apiModel) {
// does processing here
}
}
public class ApiStudent {
public long Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int GraduationClass { get; set; }
// other fields omitted for brevity
}
In cilent 1, I'm adding an ApiStudent directly to the body of the REST client, which results in JSON that does not have escape characters. This correctly automatically deserializes on the server side, but with client 2, when I send over JSON content with escape characters, the ApiStudent deserialized as NULL.
// DESERIALIZES PROPERLY ON SERVER
public void Client1() {
var student = new ApiStudent();
student.Id = 0; // new student since it's a post
student.FirstName = "Homer";
student.LastName = "Simpson";
student.GraduationClass = 2014;
var jsonRequest = new RestRequest("http://www.mydomain.com/api/students", Method.POST);
jsonRequest.RequestFormat = DataFormat.Json;
jsonRequest.AddBody(student);
IRestResponse jsonResponse = client.Execute(jsonRequest);
return jsonResponse;
}
// DESERIALIZES AS NULL ON SERVER
public void Client2() {
var jsonContent = "{ \"FirstName\": \"Api\", \"LastName\": \"Test\", \"GraduationClass\": 2014, \"Id\": 0 }";
var jsonRequest = new RestRequest("http://www.mydomain.com/api/students", Method.POST);
jsonRequest.RequestFormat = DataFormat.Json;
jsonRequest.AddBody(jsonContent);
IRestResponse jsonResponse = client.Execute(jsonRequest);
return jsonResponse;
}
Using fidder, I can see that client 1 sends over the following:
{ "FirstName": "Api", "LastName": "Test", "GraduationClass": 2014, "Id": 0 }
I can see that client 2 sends over the following:
{ \"FirstName\": \"Api\", \"LastName\": \"Test\", \"GraduationClass\": 2014, \"Id\": 0 }
Is there a way to either strip out the escape characters, or have them parsed properly on the server side?
I found a workaround for this, and I hope it helps somebody.
// NOW DESERIALIZES PROPERLY ON THE SERVER
public void Client2() {
var jsonContent = "{ \"FirstName\": \"Api\", \"LastName\": \"Test\", \"GraduationClass\": 2014, \"Id\": 0 }";
var jsonRequest = new RestRequest("http://www.mydomain.com/api/students", Method.POST);
jsonRequest.AddParameter("text/json", jsonContent, ParameterType.RequestBody);
IRestResponse jsonResponse = client.Execute(jsonRequest);
return jsonResponse;
}
The subject is selfexplanatory. I've developer and production environments. Developer env. is my localhost machine. I've action methods in contolers that sets response status code to 500 when something wents wrong (error occured, or logical inconsistance) and returns Json-answer. My common method looks like that:
[HttpPost]
public ActionResult DoSomething(int id)
{
try
{
// some useful code
}
catch(Exception ex)
{
Response.StatusCode = 500;
Json(new { message = "error" }, JsonBehaviour.AllowGet)
}
}
On the client side in production env. when such an error occured ajax.response looks like an HTML-code, instead of expected JSON.
Consider this:
<div class="content-container">
<fieldset>
<h2>500 - Internal server error.</h2>
<h3>There is a problem with the resource you are looking for, and it cannot be displayed.</h3>
</fieldset>
</div>
Filter context is not an option. I think it is some sort of IIS or web.config issue.
SOLUTION:
We decided to add TrySkipIisCustomErrors in BeginRequest in Global.asax and it is solved problems in each method in our application.
I guess that IIS is serving some friendly error page. You could try skipping this page by setting the TrySkipIisCustomErrors property on the response:
catch(Exception ex)
{
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true;
return Json(new { message = "error" }, JsonBehaviour.AllowGet)
}
Is your IIS configured to treat application/json as a valid mime-type? You may check that in properties for the server in IIS Manager and click MIME Types. If json is not there then click "New", enter "JSON" for the extension, and "application/json" for the MIME type.
I solved this by writing a custom json result, which uses json.net as the serializer. This is overkill for just the IIS fix but it means it's reusable.
public class JsonNetResult : JsonResult
{
//public Encoding ContentEncoding { get; set; }
//public string ContentType { get; set; }
public object Response { get; set; }
public HttpStatusCode HttpStatusCode { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult(HttpStatusCode httpStatusCode = HttpStatusCode.OK)
{
Formatting = Formatting.Indented;
SerializerSettings = new JsonSerializerSettings { };
SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
HttpStatusCode = httpStatusCode;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.TrySkipIisCustomErrors = true;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
response.StatusCode = (int) HttpStatusCode;
if (Response != null)
{
JsonTextWriter writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Response);
writer.Flush();
}
}
}
Use:
try
{
return new JsonNetResult()
{
Response = "response data here"
};
}
catch (Exception ex)
{
return new JsonNetResult(HttpStatusCode.InternalServerError)
{
Response = new JsonResponseModel
{
Messages = new List<string> { ex.Message },
Success = false,
}
};
}