httppostedfilebase receive null in Web API when requested from Postman - asp.net-web-api

I was trying to send a post request to my API controller. It receives all input except file input. I tried few solutions but nothing is working. I created same form in MVC and it worked but doesn't work in API where am I lacking.
My Blogger Controller / Create action
public HttpResponseMessage Create(Blogger objBlogger)
{
}
My Blogger Model
public class Blogger
{
public string Blogger_Id { get; set; }
[Required]
public string BloggerName { get; set; }
[Required]
public string BloggerUserName { get; set; }
[Required]
[RegularExpression(#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$")]
public string BloggerEmail { get; set; }
[Required]
[RegularExpression("^[0-9]*$")]
public string BloggerMobileNumber { get; set; }
public string BloggerProfilePicture { get; set; }
[Required]
public string BloggerPassword { get; set; }
public HttpPostedFileBase UploadProfilePicture { get; set; }
}
My Postman Code
POST /api/Blogger/Create HTTP/1.1
Host: localhost:3694
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 8097929a-bc93-42a4-8bc8-0e9ea98a279e
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="BloggerName"
DemoName
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="BloggerUserName"
DemoUserName
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="BloggerEmail"
DemoEmail#gmail.com
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="BloggerMobileNumber"
9999999999
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="UploadProfilePicture"; filename="asset.JPG"
Content-Type: image/jpeg
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="BloggerPassword"
DemoPassword
------WebKitFormBoundary7MA4YWxkTrZu0gW--

For Web API use something like this:
[HttpPost]
public async Task<HttpResponseMessage> Create()
{
if (!Request.Content.IsMimeMultipartContent())
{
this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/temp");
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
// Files
foreach (MultipartFileData file in provider.FileData)
{
Debug.WriteLine(file.Headers.ContentDisposition.FileName);
Debug.WriteLine("File path: " + file.LocalFileName);
}
// Form data
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
// your Blogger obj
...
}
}
...
}

Related

How to return 404 in case of action argument's type mismatch in web api?

I have a web api application and I have an http post action taking dto as following :
public class Account
{
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
But using Postman I can pass it like this:
{"Name":"Simple Code",Email:"SimpleCode#gmail.com",Age:null}
When I send the request it sends Age as null.
How can I get my web api returning 404 without sending the request or am I forced to validate that inside my code?
Hi the most fast way for me is:
Mark as [Required] your DTO
public class Account
{
public string Name { get; set; }
[Required(AllowEmptyString = false)]
public string Email { get; set; }
[Required]
public int Age { get; set; }
}
then in your API method
public IHttpActionResult Post([FromBody] mydto){
// if model is not validated return 400 bad request
if(!ModelState.IsValid) return BadRequest(ModelState);
//or if is here it's ok
//return 200 OK
Ok(mydto);
}

Accepting application/xml content in webapi controller

I want to create an action that will accept application/xml content.
Basically I have created this so far.
namespace App.Areas.Test.Controllers
{
public class UserModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class TestController : ApiController
{
[HttpPost]
public UserModel Test([FromBody] UserModel um)
{
return um;
}
}
}
When I post the following content
<?xml version="1.0" encoding="UTF-8" ?>
<UserModel>
<FirstName>Some Name</FirstName>
<LastName>Some Last Name</LastName>
<Age>30</Age>
</UserModel>
I end up with this response
<UserModel i:nil="true" />
I tried removing FromBody attribute, but that did not help either. For some reason content is not binding to the existing model.
Did you add the Content-Type : application\xml header? You need to inform the serialiser what format the body is in.
this will do the trick...
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;

Web API parameter binding not working

I have two entity classes Donor and User. Donor is subclass of User as given below
public abstract class User {
[Key]
public long Id { get; set; }
...
}
public class Donor : User {
public string AlternateMobileNumber { get; set; }
...
}
A web api controller action shown below receives POST request with JSON data in the body
public class DonorsController : ApiController {
//POST: api/Donors/EditDonor
[HttpPost]
public HttpResponseMessage EditDonor([FromBody] Donor donor) {
...
}
}
Here is how the post request looks like
POST http://localhost:xxxxx/Donor/api/Donors/EditDonor HTTP/1.1
Content-Length: 477
Cache-Control: no-cache
Content-Type: application/json;charset=UTF-8
Accept: */*
...
{"Id":12,"UserId":"donor9#abc.com","FirstName":"firstname9c","MiddleName":"M","LastName":"lastname9","Gender":"Male","MobileNumber":"7777777777","BloodGroup":"A+ve","OfficeLocality":{"Id":2,"Name":"Malad"},"ResidenceLocality":{"Id":2,"Name":"Malad"},"Organization":"organization9","Designation":"designation9","TimesDonated":1,"DateLastDonated":"Mon Dec 01 00:00:00 GMT+05:30 2014","LastDonatedAt":"Hosp 1","IsSDPDonor":false,"IsIntrestedDonor":false,"Comments":"Some Comment"}
The issue is that the Donor object is empty (not null but empty, without values applied to properties of Donor).
If I change Donor object and use a Data Transfer Object (DonorDO) with the same properties but without any inheritance, then the properties are correctly populated in that Data object. For example the Donor Data Object is like below.
//Plain Data Transfer Object without inheritance
public class DonorDO {
public long Id { get; set; }
public string AlternateMobileNumber { get; set; }
...
}
Why does DonorDO get its property values bound correctly, while the Donor Entity object remains empty with none of the properties bound. Is it related to inheritance or some other issue.
I've noticed that you are POSTing to "http: // localhost : xxxxx/Donor/api/Donors/EditDonor" which is wrong, you need to POST to "http: // localhost : xxxxx/api/Donors" (you need to POST to the controller base address only, and controller name should be after "api" not before).
This code is 100% working :
using System.Net;
using System.Net.Http;
using System.Web.Http;
//[Authorize]
public class DonorsController : ApiController
{
[HttpGet]
public Donor Get(int id)
{
return new Donor
{
Id = id,
AlternateMobileNumber = "0000",
};
}
//POST: api/Donors/EditDonor
[HttpPost]
public HttpResponseMessage EditDonor([FromBody] Donor donor)
{
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
public abstract class User
{
public long Id { get; set; }
}
public class Donor : User
{
public string AlternateMobileNumber { get; set; }
}
Now, using fiddler I called this method as you can see in the bellow image, and on the controller side you can see the passed donor argument.
Hope this helps.

Web API FormURLEncoded media type formatter not working for complex type

I have the following ComplexType which I have defined on the PUT action for my controller as follows:
[DataContract(Namespace = "http://schemas.abc.com/formurl", Name = "ComplexData")]
public class ComplexData {
[DataMember] public string Name { get; set; }
[DataMember] public Int32 ID { get; set; }
[DataMember] public DataExchangeList DataExchange { get; set; }
}
[DataContract(Namespace = "http://schemas.abc.com/formurl", Name = "DataItem")]
public class DataItem {
[DataMember] public string Name { get; set; }
[DataMember] public string Value { get; set; }
}
[CollectionDataContract(Namespace = "http://schemas.abc.com/formurl", Name = "DataExchange")]
public class DataExchangeList : List<DataItem> {
}
Here's my controller:
public class ValuesController : ApiController
{
// PUT api/values
public HttpResponseMessage Put(ComplexData data)
{
return Request.CreateResponse<ComplexData>(HttpStatusCode.OK, data);
}
}
When trying to pass the ComplexData type on PUT, the collection DataExchange does not bind properly:
PUT http://localhost:53954/api/values HTTP/1.1
User-Agent: Fiddler
Content-Type: application/x-www-form-urlencoded
Accept: application/xml
Host: localhost:53954
Content-Length: 106
Id=123456789&Name=Complex&DataExchange[0][Name]=Data&DataExchange[0][Value]=ComplexType
The response which simply returns back the data shows the collection is empty:
<ComplexData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.abc.com/formurl">
<DataExchange />
<ID>123456789</ID>
<Name>Complex</Name>
</ComplexData>
Isn't this supposed to work with the FormUrlEncodedMediaTypeFormatter?
Is there anything wrong with the way I'm passing the Collection data as follows?
DataExchange[0][Name]=Data&DataExchange[0][Value]=ComplexType
Any suggestions would be appreciated.
Thanks,
Sid

MVC4 issue binding List sent via AJAX to a controller model

I've been getting a weird binding issue trying to send list data to an MVC4 controller in an ajax post request via JSON payload.
The payload we're sending is
{
"assignmentId":"AssignmentId2",
"shiftId":null,
"startDate":null,
"startTime":{
"hours":0,
"minutes":0
},
"endTime":{
"hours":0,
"minutes":0
},
"breaksDuration":{
"hours":0,
"minutes":0
},
"authorised":false,
"authorisedName":null,
"mileageDescription":null,
"mileage":0,
"expenses":[
{
"description":"DADADDAADADADAD",
"total":"5"
}
],
"billableDuration":{
"hours":0,
"minutes":0
},
"expensesComplete":true,
"expensesTotal":5
}
The expenses list items are not getting bound to the following model structure
public class ShiftApiModel
{
public string assignmentId { get; set; }
public string shiftId { get; set; }
[Required]
public DateTime startDate { get; set; }
[Required]
public ShortTimeSpan startTime { get; set; }
[Required]
public ShortTimeSpan endTime { get; set; }
public bool authorised { get; set; }
public string authorisedName { get; set; }
public ShortTimeSpan breaksDuration { get; set; }
public decimal mileage { get; set; }
public string mileageDescription { get; set; }
private IList<ExpenseApiModel> _expenses = new List<ExpenseApiModel>();
public IList<ExpenseApiModel> expenses { get { return _expenses; } set { _expenses = value; } }
}
public class ExpenseApiModel
{
public string description { get; set; }
public double total { get; set; }
}
The actual ajax request is as follows:
$.ajax({
type: type,
url: serviceUrl,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: (props.data) ? props.data : null,
success: function (jqXHR, textStatus) {
this.serviceCallComplete(jqXHR, props.complete, props.error);
}.bind(this),
error: function (jqXHR, textStatus, errorThrown) {
this.serviceCallFailure(jqXHR, props.error);
}.bind(this)
});
Where props.data is the JSON payload described above.
I've been scratching my head on this and can't see any obvious reason as to why the expenses item wouldn't be getting bound.
Any ideas/ suggestions ?
You can't bind to an interface. Use List versus IList:
private List<ExpenseApiModel> _expenses = new List<ExpenseApiModel>();
public List<ExpenseApiModel> expenses { get { return _expenses; } set { _expenses = value; } }
I've had a very similar problem to yours with MVC4 model binding. I have a solution, but without access to the model binder source, I can only speculate on the answer. Probably the solution to your problem is changing the names of "expensesComplete" and "expensesTotal" to something else not starting with "expenses".
My model (yes you can bind to an interface, replacing the IEnumerable with a list or array makes no difference, I see the model binder actually just sticks a List in here) & action stripped down to their barest form:
[Serializable]
public class InvolvedPartyDetails
{
public long? Key { get; set; }
}
[Serializable]
public class IncidentDetails
{
public long IncidentNo { get; set; }
public string InvDisp { get; set; }
public string ChangeDetails { get; set; }
public IEnumerable<InvolvedPartyDetails> Inv { get; set; }
}
[HttpPost]
public ActionResult SubmitData(IncidentDetails incident)
{
...
If I submit the following JSON (header included for info, will be the same from here on in). Also JSON put on multiple lines for clarity:
POST http://johnapi.com/AngularTest/SubmitData HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: http://johnapi.com/AngularTest/MVCCrazy/
Accept-Language: en-GB,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; MDDCJS; rv:11.0) like Gecko
Host: johnapi.com
Content-Length: 72
DNT: 1
Connection: Keep-Alive
Pragma: no-cache
{"IncidentNo":0,
"InvDisp":"Boo",
"ChangeDetails":"COD",
"Inv":[{"Key":0}]}
incident.Inv would be null.
While there were many confusing side effects, I found that re-naming the InvDisp property in the IncidentDetails model so as not to start with Inv solved the problem.
The following JSON, with InvDisp renames to InxDisp in the model resulted in a list of 1 element for incident.Inv:
{"IncidentNo":0,
"InxDisp":"Boo",
"ChangeDetails":"COD",
"Inv":[{"Key":0}]}
An example of confusing side effects is that I could remove the ChangeDetails property from the IncidentDetails class and add a couple of properties to the InvolvedPartyDetails class and it would suddenly start working, e.g. the following JSON would give me incident.Inv with a single item:
{"IncidentNo":0,
"InvDisp":"Boo",
"Inv":[{"LinkType":null,"Key":0,"Name":null}]}
But removing either property in the InvolvedPartyDetails or putting back the ChangeDetails would again prevent binding, equally, sometimes sending more than one InvolvedPartyDetails in the array would cause things to work, dependent on the other properties present.
However, the single robust solution is the naming.

Resources