Post Binary array to Web API Controller - asp.net-web-api

I am trying to POST form data which consists of few string variable and binary array.
Below is the Model for the form data.
public class FileModel
{
public string Path { get; set; }
public byte[] File { get; set; }
}
Below is my Web API Controller.
[Route("")]
public IHttpActionResult Post([FromBody]FileModel media)
{
// Can I use ??
byte[] requestFile = media.File;
string requestFilePath = media.Path;
//Process the above variables
return Ok();
}
I would like to know Can I use the following code to de-serialize the following code snippet to to read the values from the JSON payload including the binary data?
byte[] requestFile = media.File;
string requestFilePath = media.Path;
If Yes, Do I need to define any formatter class to get it working?
I normally use POSTMAN to test my RESTful endpoints.
Is it possible to use POSTMAN still to POST binary array? May be not need to write my own client

You'll need to use a serializer to serialize complex objects (multiple fields) as content for a Http Request.
For your code snippet to read the object from the content you can use this:
var requestContent = Request.Content.ReadAsAsync<FileModel>(GetJsonSerializer()).Result;
Here's the serializer boilerplate code.
private JsonMediaTypeFormatter GetJsonSerializer()
{
JsonSerializerSettings settings = new JsonSerializerSettings()
{
PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All,
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All
};
return new JsonMediaTypeFormatter() { SerializerSettings = settings };
}
I'm not sure how to use POSTMAN to test this. A simple .net client would be:
var Client = new HttpClient();
Client.BaseAddress = new Uri("localhost"); //whatever your endpoint is
FileModel objectToSend = new FileModel();
var objectContent = new ObjectContent<FileModel>(objectToSend, GetJsonSerializer() );
var response = Client.PostAsync("uri", objectContent);

You are able to use POSTMAN to test binary file input. Selecting the body tab, you can then pick the radio button "binary" and then choose file.

Related

Passing muliple parameters in get method of web api

I have web api get method with following parameters
public DataSet Get([FromUri] EloQuaParameters paramss)
{
Hive9Common obj = new Hive9Common();
obj.credentials = paramss.credentials;
obj.fromDate = paramss.fromDate;
obj.toDate = paramss.toDate;
obj.fieldMap = paramss.fieldMap;
//Credential & fieldmap always remain null
}
EloquaParameters is class as below:
public class EloQuaParameters
{
public Dictionary<string, string> credentials { get; set; }
public DateTime? fromDate { get; set; }
public DateTime? toDate { get; set; }
public Dictionary<string, string> fieldMap { get; set; }
}
I am calling this method from my application as below:
HttpClient client;
string url = "http://localhost:54371/api/values/Get?credentials=" + credentialDictionary + "&fromDate=" + fromDate + "&toDate=" + toDate + "&fieldMap=" + fieldmpa;
client = new HttpClient();
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
}
In webApi method fromdate & todate parameter is receive proper value but both dictionary parameter is always remain null. how I can able to get values of that dictionary parameters.?
Please help
You really can't. A dictionary is not designed to be passed in a url. Think about what would happen if you had a large number of items in the dictionary.
You should really use a POST for this method for several reasons:
First, it will provide a way to specify your parameters in a single object, which can have its advantages. Second, sending the parameters in a POST places those parameters in the body of the request, which will allow them to be sent over HTTPS, which you should really use anyway because you are passing credentials. These days, there is no reason to NOT use HTTPS for everything.
It would really be a trivial change to send the parameters as a POST.
Hope that helps.

How to pass a complex type parameter (DTO object) to GET requests?

I have an n-tier application, whereas the core web service is built with Web API. many of the web service's methods are set as HTTPGET and accept a DTO object as parameter. my client app, built with MVC 5 is using HttpClient to call this API.
so it seems that by using client.PostAsJsonAsync() I can pass an object, whereas client.GetAsync() doesn't allow me to do that. this forces me to explicitly specify the properties of DTO in the URL, which works, but seem a bit redundant.
Can somebody explain why this is not possible through a GET call and suggest a better practice?
Why does passing data in the URI seem redundant? The HTTP spec says that GET methods are not to use content sent in the body. This is primarily to facilitate caches being able to cache responses based only on the URI, method and headers. Requiring caches to parse the body of a message to identify a resource would be very inefficient.
Here is an basic extension method that will do the grunt work for you,
public static class UriExtensions
{
public static Uri AddToQuery<T>(this Uri requestUri,T dto)
{
Type t = typeof (T);
var properties = t.GetProperties();
var dictionary = properties.ToDictionary(info => info.Name,
info => info.GetValue(dto, null).ToString());
var formContent = new FormUrlEncodedContent(dictionary);
var uriBuilder = new UriBuilder(requestUri) {Query = formContent.ReadAsStringAsync().Result};
return uriBuilder.Uri;
}
}
and assuming you have a DTO like this,
public class Foo
{
public string Bar { get; set; }
public int Baz { get; set; }
}
you can use it like this.
[Fact]
public void Foo()
{
var foo = new Foo()
{
Bar = "hello world",
Baz = 10
};
var uri = new Uri("http://example.org/blah");
var uri2 = uri.AddToQuery(foo);
Assert.Equal("http://example.org/blah?Bar=hello+world&Baz=10", uri2.AbsoluteUri);
}

How do you read POST data in an ASP.Net MVC 3 Web API 2.1 controller?

This does not seem to be as easy as I thought. I found some solutions on the web, but they are not working for me. I have an ASP.Net MVC 3 project with the Microsoft ASP.Net Web API 2.1 nuget package installed. Now, I want to be able to read data posted to a web api controller. The data sent will vary, so I cannot used a strongly typed ViewModel.
Here are the solutions I tried:
public void Post([FromBody]string value)
{
...
}
public void Post([FromBody]List<string> values)
{
...
}
public void Post([FromBody]NameValueCollection values)
{
...
}
But my value or values variables are always empty. I know the controller is receiving data however because I can check it by accessing (System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"].Request.Form. It does not look like the proper way to retrieve the data though. There ought to be a cleaner way.
UPDATE:
Here is how I am posting the information:
I am posting the data from another controller in the same web application:
public ActionResult SendEmailUsingService()
{
dynamic email = new ExpandoObject();
email.ViewName = "EmailTest";
email.From = "fromaddress#yahoo.com";
email.To = "toaddress#gmail.com";
email.Fullname = "John Smith";
email.Url = "www.mysite.com";
IDictionary<string, object> data = email;
using (var wb = new WebClient())
{
string url = BaseUrlNoTrailingSlash + Url.RouteUrl("DefaultApi", new { httproute = "", controller = "Emailer" });
var response = wb.UploadValues(url, "POST", data.ToNameValueCollection());
}
return View();
}
And here is what I am getting in my Post web api controller if I declare an httpContext variable like this:
var httpContext = (System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"];
httpContext.Request.Form =
{ViewName=EmailTest&From=fromaddress%40yahoo.com&To=toaddress%40gmail.com&Fullname=John+Smith&Url=www.mysite.com}
httpContext.Request.Form is a System.Collections.Specialized.NameValueCollection {System.Web.HttpValueCollection}
I finally found the answer to my question here:
Web API Form Data Collection
The solution is to use FormDataCollection:
public void Post([FromBody]FormDataCollection formData)
{
...
}

Null parameter in web api call when using class containing System.Xml.Serialization attributes

I have created a class from a schema using xsd.exe. This class contains System.Xml.Serialization attributes.
I have used this class as a parameter for a web api method. I need to serialise the parameter to xml so I can validate against schema and create a Oracle xmltype.
My web api method is as follows
[HttpPost]
public HttpResponseMessage Create([FromBody]MyClass obj)
I switched the default Serializer to XmlSerializer in webapi.config as follows
config.Formatters.XmlFormatter.UseXmlSerializer = true;
From the client using HttpWebRequest or WebClient I can successfully serialise (XmlSerializer) an instance of the class and post it to the web api using application/xml content type. So far so good.
However, if I try to send application/json content type the parameter object proerties at the web api is always null. The parameter itself is not null just the properties within.
I create the json content as follows
MyClass data = new MyClass();
// assign some values
string json = new JavaScriptSerializer().Serialize(data);
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json);
The instance of the class serialises to JSON ok and contains values assigned, however, when I post the byte array, always null at web api.
I am sure it is something to do with the System.Xml.Serialization attributes in the class at the web api.
Does anyone have any suggestion on how to get around this?
Ade
Update
My class generated with xsd
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://Ade.interface")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://Ade.interface", IsNullable = false)]
public partial class MyClass
{
private string nameField;
/// <remarks/>
public string Name
{
get
{
return this.nameField;
}
set
{
this.nameField = value;
}
}
}
Web api
[HttpPost]
public HttpResponseMessage Create([FromBody]MyClass payload)
{
// payload.Name is null
}
Fiddler
POST http://myhostname/Create HTTP/1.1
Content-Type: application/json
Host: myhostname
Content-Length: 14
Expect: 100-continue
{"Name":"Ade"}
Client
string json = new JavaScriptSerializer().Serialize(data);
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://myhostname/Create");
request.Method = "POST";
request.ContentLength = bytes.Length;
request.ContentType = "application/json";
try
{
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
// code removed
} catch (WebException we)
{
// code removed
}
This worked for me using version="4.0.20710.0" of Microsoft.AspNet.WebApi.Core
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
json.SerializerSettings.ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
IgnoreSerializableAttribute = true
};
Based on the repro, I noticed that Json formatter works fine if your request body was rather {"nameField":"Ade"}...
You can change this behavior by modifying the serialization settings on the contract resolver. After this change, you should be able to use {"Name":"Ade"}
Example:
JsonContractResolver resolver = (JsonContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver;
resolver.IgnoreSerializableAttribute = true; // default is 'false'

ASP.NET MVC 3 Parse JSon object and display data

I have a class
public class ConversionResultModel
{
public string ProcessId { get; set; }
public bool Result { get; set; }
public string Message { get; set; }
}
sending it to view using JSon
public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> clientUpload)
{
string destinationPath = "";
JsonResult result = null;
var fileModel = new ConversionResultModel();
fileModel.ProcessId = "4558-95559-554";
fileModel.Result = true;
fileModel.Message = "test.pdf";
result = Json(new { fileModel }, "text/plain");
return result;
}
How to parse such JSon object at client side using JS or jQuery and read values?
I have tried to parse JSon object with code below but get Undefined error in alert
var obj = $.parseJSON(e.response);
alert(e.obj);
I receive JSon object like this
{"fileModel":{"ProcessId":"4558-95559-554","Result":true,"Message":null,"SourceFile":null,"ConvertedFileName":"test.pdf","ConvertedFileSize":1233444,"DownloadUrl":"http://localhost:2008/download?path=4558-95559-554","DeleteUrl":"http://localhost:2008/download?path=4558-95559-554"}}
You do not need to parse it. Just set data type to JSON during ajax request and then use received data object like entity and you easily can access to any property:
var id = data.ProcessId;
Anyway, using jQuery you can parse JSON string:
var data = jQuery.parseJSON(stringData);
P.S:
Use the following code sample for converting object to JSON in ASP.NET MVC:
return this.Json(fileModel);
http://api.jquery.com/jQuery.parseJSON/
In your case, I think you're getting back the correct JSON, but your alert is looking at the wrong object. Try alert(obj.SomeProperty) rather than alert(e.obj). e.obj doesn't exist, which is likely why you're getting an "undefined" error. For example, alert(obj.fileModel.ProcessId); should work.

Resources