Reputation: 10071
The problem: Is it possible using httpclient to post a HttpPostedFileBase(only available in memory, not on disk.) to another endpoint?
What I've tried:
I have the following controller, we are posting in a file from our frontend and it binds to the file parameter.
public class HomeController : Controller
{
[System.Web.Http.HttpPost]
public async Task<Stream> Index(HttpPostedFileBase file)
{
//file is not null here, everything works as it should.
//Here im preparing a multipart/form-data request to my api endpoint
var fileStreamContent = new StreamContent(file.InputStream);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
var response = await client.PostAsync("http://restapi.dev/api/files/add", formData);
var result = await response.Content.ReadAsStreamAsync();
return result;
}
}
}
I need to pass this request on to another application that's not publicly available(so we can't post directly from the client) That controller looks like this:
[RoutePrefix("api/files")]
public class FilesController : ApiController
{
[HttpPost]
[Route("add")]
public async Task<HttpResponseMessage> Add(HttpPostedFileBase file)
{
//This is the problem, file is always null when I post from my backend.
var files = HttpContext.Current.Request.Files.Count > 0 ? HttpContext.Current.Request.Files[0] : null;
return Request.CreateResponse(HttpStatusCode.OK);
}
}
file
is always null, so are files
.
What am I missing? When I use postman and post directly to the API endpoint, it works. So im guessing that im doing something wrong in my HomeController
?
Upvotes: 2
Views: 3255
Reputation: 120380
You can improve on this with newer tech.
In webapi, you can write a controller method like this:
//[Route("api/Foo")] //maybe?
[HttpPost]
public async Task<HttpResponseMessage> MyResourceProxy(HttpRequestMessage request)
now you can take that request and rewrite its RequestUri
property:
request.RequestUri = new Uri(blah);
new up an HttpClient
and forward the request:
HttpClient client = new HttpClient();
//make sure that this fails if it's hung for more than 30 seconds
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
response = await client.SendAsync(request,
HttpCompletionOption.ResponseHeadersRead,
cts.Token);
}
catch (TaskCanceledException)
{
response = new HttpResponseMessage(HttpStatusCode.GatewayTimeout);
}
make sure that everything gets disposed:
request.RegisterForDispose(new IDisposable[] {request, client, cts, response});
and then return the response
return response;
I added a timeout mechanism in that might not be appropriate for you needs.
Upvotes: 1