So I have to make a method in asp.net for an API that accepts 2 files via PUT (1 json and 1 xml for processing data, not saving- because I have to, OK? :) ), sending the request via fiddler..
Right now I'm sending the request like this on fiddler (PUT METHOD):
Content-Type: multipart/form-data
Authorization: XXXXX
Host: XXXX
Request body:
<#INCLUDE *C:\Users\ZZZZ.json*#>
<#INCLUDE *C:\Users\XXXX.xml*#>
Here's what I've tried inside the controller so far:
[HttpPut, Route("api/Student/{studentId}/Classes/{classId}")]
public async Task<string> Put(int studentId, int classId)
{
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
Stream fileContent = await this.Request.Content.ReadAsStreamAsync();
MediaTypeHeaderValue contentTypeHeader = this.Request.Content.Headers.ContentType;
if (fileContent != null)
return "ok";
return "not ok";
}
So far the file is not being uploaded nor appears within the request (everything's null). I've also tried the "Request" variable and HttpContext.
Tried the exact same thing but with a POST Method (including the boundaries) and the same happens.
What would you do in order to make this work? I really have to send a json object and another in xml, I really can't change languages or send everything in json ('cause that I could make it work)...
PS: The files don't have a defined structure, it has to be dynamic
PS2 : How would you then attempt to read those files without actually saving them?
You don't have to use a stream to read the file content. You can just try using the HttpPostedFile.
[HttpPut, Route("api/student/{studentId}/classes/{classId}")]
public async Task<string> Put(int studentId, int classId)
{
if (HttpContext.Current.Request.Files.Count == 0)
throw new HttpResponseException(new HttpResponseMessage()
{
ReasonPhrase = "Files are required",
StatusCode = HttpStatusCode.BadRequest
});
foreach (string file in HttpContext.Current.Request.Files)
{
var postedFile = HttpContext.Current.Request.Files[file];
if (!(postedFile.ContentType == "application/json" || postedFile.ContentType == "application/xml"))
{
throw new System.Web.Http.HttpResponseException(new HttpResponseMessage()
{
ReasonPhrase = "Wrong content type",
StatusCode = HttpStatusCode.BadRequest
});
}
}
return "OK";
}
POSTMAN
My POSTMAN:
enter image description here
Fiddler
Related
So I'm doing an API where I have to send a huge json file and a name for a variable to the database. Currently am sending and reading the file with my code, and it's working fine.
Then thing is that I have to send a string for a service name (may have "/" characters, that's why I didn't put it as the file name, or query string.
I tried sending this request (HTTP POST) :
---------------------------32r23rfewfwfaedef
Content-Disposition: form-data; name="fieldNameHere"; filename="XXXXXX.json"
Content-Type: application/json
{"name":"test"}
<#INCLUDE *C:\....\XXXXXX.json*#>
---------------------------32r23rfewfwfaedef--
The thing is that I can't find that variable anywhere in my controller... My code is like this:
public HttpResponseMessage Post()
{
if (HttpContext.Current.Request.Files.Count != 1)
throw new HttpResponseException(new HttpResponseMessage()
{
ReasonPhrase = "One file is required, a json in order to create the Swagger.",
StatusCode = HttpStatusCode.BadRequest
});
SwaggerSaveModel model = new SwaggerSaveModel();
HttpPostedFile postedFile = HttpContext.Current.Request.Files[0];
using (System.IO.StreamReader myFile = new System.IO.StreamReader(postedFile.InputStream))
{
var XmlObj = new StreamReader(postedFile.InputStream).ReadToEnd();
model.SwaggerJson = XmlObj.ToString();
}
return Request.CreateResponse(HttpStatusCode.Created, "blabla");
}
The file reading is fine, but I can't find the "name" variable... I also canĀ“t change that json file, because it's a swagger and it has to be used exactly as it is being sent.
Please help..
For future doubts like mine, I figured out how to do this. I'm sending my request like this:
parameter: FileName
And accessing on my controller like this:
HttpContext.Current.Request.Params["HTTP_PARAMETER"]
Then it returns "FileName"
I faced problem like this.
I have method in controller, that receive data in body of POST request.
Here is method.
// POST: api/StartWorkingDays
[ResponseType(typeof(StartWorkingDay))]
public IHttpActionResult PostStartWorkingDay(StartWorkingDay startWorkingDay)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.StartWorkingDays.Add(startWorkingDay);
db.SaveChanges();
return Json(new { Result = "Success", Message = "Saved Successfully"});
//return CreatedAtRoute("DefaultApi", new { id = startWorkingDay.Id }, startWorkingDay);
}
How I can see body of request that I receive?
Thank's for help.
[HttpPost]
public HttpResponseMessage PostStartWorkingDay([FromBody] StartWorkingDay startWorkingDay)
{
//here above startWorkingDay is body your mobile developer will send
//you and data can be viewed while debugging ,
//tell mobile developer to set content-type header should be JSON.
return Request.CreateResponse(HttpStatusCode.Created, "Success");
}
Why your return type is Json ? you should use HttpResponse . I believe you are using Web api 2 . With Attribute routing and if you want to send response in json format then remove Xml formatter from WebApiConfig.cs file inside App_Start folder
So, i'm trying to pass multiple parameters from fiddler to my web api, using FormDataCollection.ReadAsNameValueCollection().
Problem is everytime is send my data, formData comes back as null. I'm not sure what I'm doing wrong here. I've tried decorating formData with a [FromBody] attribute. Also registered JsonMediaTypeFormatter() in the global.asax class.
Any help would be much appreciated.
Please see code below:
[HttpPost]
public HttpResponseMessage PostAccount([FromBody]FormDataCollection formData)
{
if (formData != null)
{
var nValueCol = formData.ReadAsNameValueCollection();
var account = new Account()
{
Email = nValueCol["email"],
Password = nValueCol["password"],
AgreedToTerms = Convert.ToBoolean(nValueCol["agreesToTerms"]),
//LocationAccountCreated = DbGeography.FromText(nValueCol["userLocation"])
};
var userProfile = new UserProfile()
{
FirstName = nValueCol["firstName"],
LastName = nValueCol["lastName"],
DateOfBirth = Convert.ToDateTime(nValueCol["dateOfBirth"])
};
var newAcc = _accountService.CreateAccount(account.Email, userProfile.FirstName, userProfile.LastName,
userProfile.DateOfBirth, account.Email, account.AgreedToTerms,
account.LocationAccountCreated);
var response = Request.CreateResponse(HttpStatusCode.Created);
return response;
}
else
return Request.CreateResponse(HttpStatusCode.NotAcceptable);
}
Sample request:
FormDataCollection is normally associated with application/x-www-form-urlencoded media type.
Your screen shot shows you are trying to send json data. If you don't have a concrete data type for your data and you want to send it as Json you can use an IDictionary<string,string> which will be mapped by the model binder successfully.
You action will look something like...
[HttpPost]
public HttpResponseMessage PostAccount([FromBody]IDictionary<string, string> formData) {
if (formData != null) {
var nValueCol = formData;
//...other code removed for brevity, but can basically stay the same
var response = Request.CreateResponse(HttpStatusCode.Created);
return response;
} else
return Request.CreateResponse(HttpStatusCode.NotAcceptable);
}
Based on your code and the information from your fiddler screen shot, a TestController was created, a request was tested with fiddler like...
POST http://localhost:35979/api/account/create HTTP/1.1
User-Agent: Fiddler
Host: localhost:35979
Content-Type: application/json
Content-Length: 76
{"email":"myemail#email.com",
"firstname":"myFName",
"lastName":"myLName"}
...and the formData was populate with the 3 fields and their data.
I want to upload an image as a HttpPost to a method.
I tried the following code:
[HttpPost]
public HttpResponseMessage Image(int id)
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count == 1) //do something
return Request.CreateResponse(HttpStatusCode.Created);
}
Then i use postman and added a image as a binary to the body.
However httpRequest.Files.Count is 0.
What am i doing wrong?
Try this above code.
Try in the google chrome rest client.. easy to test
i hope that may help you
public async Task<HttpResponseMessage> Image(int id)
{
string filepath = #"e:\testing\file";
if (Request.Content.IsMimeMultipartContent())
{
var streamProvider = new MultipartFormDataStreamProvider(filepath);
await Request.Content.ReadAsMultipartAsync(streamProvider);
foreach (MultipartFileData fileData in streamProvider.FileData)
{
if (string.IsNullOrEmpty(fileData.Headers.ContentDisposition.FileName))
{
return Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted");
}
string fileName = fileData.Headers.ContentDisposition.FileName;
if (fileName.StartsWith("\"") && fileName.EndsWith("\""))
{
fileName = fileName.Trim('"');
}
if (fileName.Contains(#"/") || fileName.Contains(#"\"))
{
fileName = Path.GetFileName(fileName);
}
File.Move(fileData.LocalFileName, Path.Combine(filepath, fileName));
}
return Request.CreateResponse(HttpStatusCode.OK);
}
For More details check this Tutorial
You should verify that your Content-Type is multipart/form-data when you do the post (and application/octet-stream in the data part) as well as proper boundaries. It will also help if you add headers/body of your request to the question.
This one works for me:
Header:
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrhNuQUPgZKD8RxKq
Payload:
------WebKitFormBoundaryrhNuQUPgZKD8RxKq
Content-Disposition: form-data; name="filename"; filename="filename.txt"
Content-Type: application/octet-stream
------WebKitFormBoundaryrhNuQUPgZKD8RxKq--
I've been having this problem all day, and i'm pretty lost as to why it happens.
I'm posting a file (a .xls file) from the client side in a React JS component in response to a click on a button like this:
upload: function (e) {
e.preventDefault();
var model = this.state.model;
var xlsFile = this.refs.xlsFile.getDOMNode();
var file = xlsFile.files[0];
var fd = new FormData();
fd.append('file', file);
var request = {
groupId: this.state.vkNumber,
payload: fd
};
model.importRequest = request;
model.setImportProcessing();
MultiOrderActions.updateUsers(request);
this.setState(model.toState());
}
The request as it appears in Chrome (POST-request):
Accept:/
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8,da;q=0.6
Connection:keep-alive
Content-Length:3799243
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryBVYYdSXRza1yRuW4
And the payload of the request:
------WebKitFormBoundaryBVYYdSXRza1yRuW4
Content-Disposition: form-data; name="file"; filename="bruger_caas.xls"
Content-Type: application/vnd.ms-excel
------WebKitFormBoundaryBVYYdSXRza1yRuW4--
Should there not be any binary data in the request? The content length is correct, and so is the content-type and filename.
In WebAPI i'm doing the following, where the ReadAsMultiPartAsync never returns:
[HttpPost]
[Route("bc/s/{*url}")]
public async Task<IHttpActionResult> Post(string url)
{
var service = CreateClient<GenericService>();
if (Request.Content.IsMimeMultipartContent())
{
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var content in provider.Contents)
{
//Do stuff
;
}
}
catch (Exception e)
{
;
}
}
return InternalServerError();
}
When it reaches the await keyword it just dies, and times out after 2 minutes, because Chrome cancels the request.
What am i doing wrong here? I'm really not to sure if the problem is that the file is never really sent from the client side, or if it's my server side code that's the problem.
Any input would be much appreciated.
for those googling...
I was also troubleshooting timeouts for file uploads.
In my case, I was getting a deadlocked thread when using the MultipartMemoryStreamProvider and ReadAsMultipartAsync
In the end this other post had a solution for me:
Request.Content.ReadAsMultipartAsync never returns
which uses "TaskCreationOptions.LongRunning" to ensure a distinct thread and prevent a deadlock. The comments of that issue have a helpful explanation.