I have an AJAX form which post a form-data to a local API url: /api/document
. It contains a file and a custom Id. We simply want to take the exact received Request and forward it to a remote API at example.com:8000/document/upload
.
Is there a simple way of achieve this "forward" (or proxy?) of the Request to a remote API using Asp.NET Core?
Below we had the idea to simply use Web API Http client to get the request and then resend it (by doing so we want to be able to for example append a private api key from the backend), but it seems not to work properly, the PostAsync
doesn't accept the Request
.
POST http://localhost:62640/api/document HTTP/1.1
Host: localhost:62640
Connection: keep-alive
Content-Length: 77424
Accept: application/json
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryn1BS5IFplQcUklyt
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,fr;q=0.6
------WebKitFormBoundaryn1BS5IFplQcUklyt
Content-Disposition: form-data; name="fileToUpload"; filename="test-document.pdf"
Content-Type: application/pdf
...
------WebKitFormBoundaryn1BS5IFplQcUklyt
Content-Disposition: form-data; name="id"
someid
------WebKitFormBoundaryn1BS5IFplQcUklyt--
Our .NET Core backend has a simple "forward to another API" purpose.
public class DocumentUploadResult
{
public int errorCode;
public string docId;
}
[Route("api/[controller]")]
public class DocumentController : Controller
{
// POST api/document
[HttpPost]
public async Task<DocumentUploadResult> Post()
{
client.BaseAddress = new Uri("http://example.com:8000");
client.DefaultRequestHeaders.Accept.Clear();
HttpResponseMessage response = await client.PostAsync("/document/upload", Request.Form);
if (response.IsSuccessStatusCode)
{
retValue = await response.Content.ReadAsAsync<DocumentUploadResult>();
}
return retValue;
}
}
We have a GET request (not reproduced here) which works just fine. As it doesn't have to fetch data from locally POSTed data.
How to simply pass the incoming local HttpPost request and forwarding it to the remote API?
I searched A LOT on stackoverflow or on the web but all are old resources talking about forwarding Request.Content
to the remote.
But on Asp.NET Core 1.0, we don't have access to Content
. We only are able to retrieve Request.Form
(nor Request.Body
) which is then not accepted as an argument of PostAsync
method:
Cannot convert from Microsoft.AspNetCore.Http.IformCollection to System.Net.Http.HttpContent
I had the idea to directly pass the request to the postAsync:
Cannot convert from Microsoft.AspNetCore.Http.HttpRequest to System.Net.Http.HttpContent
I don't know how to rebuild expected HttpContent
from the local request I receive.
For information, When we post a valid form-data with the custom Id
and the uploaded file, the remote (example.com) API response is:
{
"errorCode": 0
"docId": "585846a1afe8ad12e46a4e60"
}
Ok first create a view model to hold form information. Since file upload is involved, include IFormFile
in the model.
public class FormData {
public int id { get; set; }
public IFormFile fileToUpload { get; set; }
}
The model binder should pick up the types and populate the model with the incoming data.
Update controller action to accept the model and proxy the data forward by copying content to new request.
[Route("api/[controller]")]
public class DocumentController : Controller {
// POST api/document
[HttpPost]
public async Task<IActionResult> Post(FormData formData) {
if(formData != null && ModelState.IsValid) {
client.BaseAddress = new Uri("http://example.com:8000");
client.DefaultRequestHeaders.Accept.Clear();
var multiContent = new MultipartFormDataContent();
var file = formData.fileToUpload;
if(file != null) {
var fileStreamContent = new StreamContent(file.OpenReadStream());
multiContent.Add(fileStreamContent, "fileToUpload", file.FileName);
}
multiContent.Add(new StringContent(formData.id.ToString()), "id");
var response = await client.PostAsync("/document/upload", multiContent);
if (response.IsSuccessStatusCode) {
var retValue = await response.Content.ReadAsAsync<DocumentUploadResult>();
return Ok(reyValue);
}
}
//if we get this far something Failed.
return BadRequest();
}
}
You can include the necessary exception handlers as needed but this is a minimal example of how to pass the form data forward.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With