简体   繁体   English

使用 HttpClient 从流中发布多部分/表单数据文件

[英]Post multipart/form-data file from stream with HttpClient

The problem: Is it possible using httpclient to post a HttpPostedFileBase(only available in memory, not on disk.) to another endpoint?问题:是否可以使用 httpclient 将 HttpPostedFileBase(仅在内存中可用,而不在磁盘上)发布到另一个端点?

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<string> 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.ReadAsStringAsync();
            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 . file始终为空, files也是如此。 What am I missing?我错过了什么? When I use postman and post directly to the API endpoint, it works.当我使用邮递员并直接发布到 API 端点时,它可以工作。 So im guessing that im doing something wrong in my HomeController ?所以我猜我在我的HomeController做错了什么?

You can improve on this with newer tech.您可以使用更新的技术对此进行改进。

In webapi, you can write a controller method like this:在 webapi 中,您可以编写这样的控制器方法:

//[Route("api/Foo")] //maybe?
[HttpPost]
public async Task<HttpResponseMessage> MyResourceProxy(HttpRequestMessage request)

now you can take that request and rewrite its RequestUri property:现在您可以接受该请求并重写其RequestUri属性:

request.RequestUri = new Uri(blah);

new up an HttpClient and forward the request:新建一个HttpClient并转发请求:

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然后返回response

return response;

I added a timeout mechanism in that might not be appropriate for you needs.我添加了一个超时机制,这可能不适合您的需要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM