I created a web API using the ASP.NET Core Web API project template in Visual Studio to allow clients to upload files to my application. I created the controller which handles request from clients that want to upload PDF reports to the server. Here is the code for the action method:
[HttpPost("Report/{reportId")]
public async Task<IActionResult> AttachReport(string reportId)
{
Reporter client = new Reporter();
await client.AttachReportToRequest(reportId);
return
}
This is the method that actually sends the request to my application server.
public async Task<HttpResponseMessage> AttachReportToRequest(string reportId)
{
try
{
if (authToken is null)
{
authToken = await login("username", "passw0rd");
}
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, "/api/to/app/server/reportInfo");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("app-JWT", authToken);
string scanReportFile = $"{Directory.GetCurrentDirectory()}\Reports\sample_report.pdf";
MultipartFormDataContent requestBody = new MultipartFormDataContent();
//Create values JSON payload
requestBody.Add(new StringContent($""values":{{
"ReportId":"{reportId}",
"Description":"test",
"Submitter":"John Smith",
"Number of Attachment":"1"
}}"), "entry");
requestBody.Add(new StreamContent(File.OpenRead("C:/Users/myuser/Documents/ReporterApp/myreport.pdf")), "file-attachment", "C:/Users/myuser/Documents/ReporterApp/myreport.pdf");
requestMessage.Content = requestBody;
HttpResponseMessage attachmentResponse = await httpClient.SendAsync(requestMessage);
return attachmentResponse;
}
catch (Exception)
{
throw;
}
}
The issue I’m having is that every time the httpClient tries to send the request the client times out. I never receive any kind of HTTP response from the server. I tried hitting the same application using the same endpoint and the same multipart/form-data content type from Postman and it works. Is there any particular reason why the SendAsync method would be timing out when sending the request?
I tried putting the FileStream in a using block and tried sending different file types but none of those things worked.
2
Answers
After many, many long hours, I was finally able to figure it out. It turns out there are actually a few things wrong with my code. I initially thought there was an issue with the boundary parameter of the Content-Type header. As it turns out, the .NET Framework automatically takes care of generating the boundary for you.
The first thing I missed was that, even though MultipartFormDataContent is a subclass of HttpContent, it is actually a container of HttpContent objects. A key difference between attaching a single HttpContent object to your request and attaching an object of type MultipartFormDataContent is that for every object you add to the container you need to specify a Content-Type header; without that header for each object the server won't know what the type of each part is. For example, in the first call to requestBody.Add() I am passing it a StringContent object with the JSON payload string. However, the StringContent constructor has an overload where you can specify the encoding and media type. Without the "application/json", the StringContent object defaults to a media type of "text/plain", which won't work if the server is expecting JSON. Doing this solves the first problem:
The second issue was pretty much the same as the first. Rather than create the StreamContent object inline with the call to requestBody.Add(), I could first assign the StreamContent object to a variable and then add the necessary headers to it. Since the type of file I'm sending is a pdf, the correct media type is "application/octet-stream". This is what worked for me.
Once I did this, the HttpClient sent the request successfully and no longer timed out. You could also do something like this with the File.ReadAllBytes() method:
This should also work.
try different approach (or use RestSharp library – much cleaner)