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"
Related
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
I try to mirror images on my own image hoster, which contains a simple API that accepts default form data uploads like this:
-----------------------------149841124823007
Content-Disposition: form-data; name="file"; filename="ZMVdEwM.png"
Content-Type: image/png
<Binary image data...>
This upload was tested using a simple html form and works well. Now I want to use this API in an .NET Core Standard application. Found different examples:
string url = "https://i.imgur.com/0acC9nr.png";
var client = new HttpClient();
var imageData = client.GetByteArrayAsync(url).Result;
var content = new MultipartFormDataContent($"-----------------------------{DateTime.Now.Ticks}");
content.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
string fileName = new Uri(url).LocalPath.Replace("/", "");
content.Add(new ByteArrayContent(imageData), "file", fileName);
var postResp = client.PostAsync("https://my-image-hoster/api.php", content).Result;
string resp = postResp.Content.ReadAsStringAsync().Result;
Console.WriteLine(resp);
I'm downloading the test image https://i.imgur.com/0acC9nr.png as byte array and try to build the same form-data upload. But it fails here on my api:
if (!isset($_FILES['file'])) {
echo json_encode(array('errorcode' => 'no_image_transfered'));
}
While investigation the problem, I inspected the MultipartFormDataContent instance called content since it's responsible for building the request body. It shows a ContentDisposition property containing the file name twice: The first one is correct, but the second one looks maleformed:
What's wrong with my POST request?
Found out that MultipartFormDataContent.Headers.ContentType is the value of the HTTP header:
Content-Type: multipart/form-data; boundary=--------------149841124823007
This was taken from the example, which breaks my API since it expects multipart/form-data. So it's better to dismiss the type, unless your API checks the provided file type in $_FILES['file'][0]['type'] because this is empty. The type came from the body:
Content-Disposition: form-data; name="file"; filename="ZMVdEwM.png"
Content-Type: image/png <--- type
Since it's a value provided by the client, we shouldn't trust this data and fetch the mime-type on the server side. If you have an API that checks this value (and no influence on the API itself) just set it for the body like this:
content.ElementAt(0).Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
Otherwise if you're fine with a multipart/form-data upload that doesn't contain the mime type, do your upload like this:
string url = "https://i.imgur.com/0acC9nr.png";
var client = new HttpClient();
var imageData = client.GetByteArrayAsync(url).Result;
var content = new MultipartFormDataContent();
string fileName = new Uri(url).LocalPath.Replace("/", "");
content.Add(new ByteArrayContent(imageData), "file", fileName);
// Optionally when the Content-Type body field is required
// content.ElementAt(0).Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
var postResp = client.PostAsync("https://my-image-hoster/api.php", content).Result;
var resp = postResp.Content.ReadAsStringAsync().Result;
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.
I followed this guide http://jaliyaudagedara.blogspot.com/2014/08/how-to-directly-upload-files-to-amazon.html and I was able to successfully upload files to Amazon S3 in my Web API Project. Happy with the results I decided to add the remaining logic which was JSON from the client. The screen is a create user screen that also has a file uploader. I'd like to send all the user data and uploaded file at once instead of using multiple calls.
Is this possible? If so how should I should tweak the referenced example so it can accept both JSON and the uploaded file?
[HttpPost]
[Route("Employees/Upload")]
public async Task<HttpResponseMessage> Upload()
{
StorageService storageService = new StorageService();
if (!Request.Content.IsMimeMultipartContent())
{
this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
InMemoryMultipartStreamProvider provider = await Request.Content.ReadAsMultipartAsync<InMemoryMultipartStreamProvider>(new InMemoryMultipartStreamProvider());
NameValueCollection formData = provider.FormData;
string userName = formData["UserName"];
IList<HttpContent> files = provider.Files;
HttpContent file = files[0];
Stream fileStream = await file.ReadAsStreamAsync();
storageService.UploadFile("your bucketname", userName, fileStream);
string preSignedUrl = storageService.GeneratePreSignedURL("your bucketname", userName, 3000);
return this.Request.CreateResponse(HttpStatusCode.OK, new { preSignedUrl });
}
Yes, it is possible to capture form data on the POST as well as the file, though not as JSON, like other API calls.
Take a look at the form post in Fiddler. You should see something like this on the text view tab:
------WebKitFormBoundary9j1TS9WuwcTWV7OX
Content-Disposition: form-data; name="RecordTypeId"
120
------WebKitFormBoundary9j1TS9WuwcTWV7OX
Content-Disposition: form-data; name="RecordId"
1251857
------WebKitFormBoundary9j1TS9WuwcTWV7OX
Content-Disposition: form-data; name="Tags"
------WebKitFormBoundary9j1TS9WuwcTWV7OX
Content-Disposition: form-data; name="Resource"; filename="sampleUpload1.txt"
Content-Type: text/plain
Sample upload file 1
------WebKitFormBoundary9j1TS9WuwcTWV7OX--
In this example, my form has a "RecordTypeId", "RecordId" and "Tags" field on the form. So you can read that data from the "provider.FormData", just like you did with the username.
So, each piece of the data that would have been in your JSON object, would show up in the form data.
I am fairly new at android development. Here is my problem:
I have this endpoint: http://bdzservice.apphb.com/api/Image which accepts POST requests
The body of the request is a String, example:
/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030
Invalid example: {"/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
Invalid example2: {mapHref : "/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
Invalid example3: {"mapHref" : "/SearchServlet?action=showMap&id1=25&date=09/12/2013&st1=5216000&st2=5229030"}
this is the code I've written so far:
HttpClient client = new DefaultHttpClient();
String message;
HttpPost httpPost = new HttpPost("http://bdzservice.apphb.com/api/Image");
try
{
message = url;
StringEntity se = new StringEntity(message, "UTF8");
se.setContentType("application/json");
httpPost.setEntity(se);
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = client.execute(httpPost);
if (resp != null)
{
if (resp.getStatusLine().getStatusCode() == 204)
result = true;
}
Log.d("Status line", "" + resp.getStatusLine().getStatusCode());
}
I always get an error when trying to post data, but when I manually (through a REST client) post data I get an OK result.
Can someone help me with this?
EDIT
This is the endpoint, It is written in C# (Web Api)
EDIT 2: Tried modifying the service to return body it recieved (see the comment in the url) and it retruns null, so the problem is it is not getting the body (or just reading it wrong)
I have created a library here for .NET Standard that does POST and PUT. I have tested it thoroughly on Android. There are quick start samples to get going quickly. The sample only has a PUT, but the principle should be the same:
https://bitbucket.org/MelbourneDeveloper/restclient-.net/overview