繁体   English   中英

将文件从 ASP.NET Core web api 发布到另一个 ASP.NET Core web api

[英]Post files from ASP.NET Core web api to another ASP.NET Core web api

我们正在构建一个 Web 应用程序,它由一个 Angular2 前端、一个 ASP.NET Core Web api 公共后端和一个 ASP.NET Core Web api 专用后端组成。

将文件从 Angular2 上传到公共后端工作。 但我们更愿意将它们转发到私有后端。

当前工作代码

[HttpPost]
public StatusCodeResult Post(IFormFile file)
{
  ...
}

从那里我可以使用 file.CopyTo(fileStream); 将文件保存到磁盘。

但是,我想将那个文件或那些文件,或者理想情况下,将整个请求重新发送到我的第二个 web api 核心。

我不确定如何使用 HttpClient 类的 asp.net core 来实现这一点。

我已经尝试了各种事情,例如

StreamContent ss = new StreamContent(HttpContext.Request.Body);
var result = client.PostAsync("api/Values", ss).Result;

但是我的第二个后端得到一个空的 IFormFile。

我有一种感觉可以将文件作为流发送并在另一端重建它们,但无法使其工作。

该解决方案必须使用两个 web api 核心。

解决方案

DMZ 中的公共后端

[HttpPost]
public StatusCodeResult Post(IFormFile file)
{
    try
    {
        if (file != null && file.Length > 0)
        {
            using (var client = new HttpClient())
            {
                try
                {
                    client.BaseAddress = new Uri(currentPrivateBackendAddress);
                    
                    byte[] data;
                    using (var br = new BinaryReader(file.OpenReadStream()))
                        data = br.ReadBytes((int)file.OpenReadStream().Length);

                    ByteArrayContent bytes = new ByteArrayContent(data);

                    
                    MultipartFormDataContent multiContent = new MultipartFormDataContent();
                    
                    multiContent.Add(bytes, "file", file.FileName);

                    var result = client.PostAsync("api/Values", multiContent).Result;
                    

                    return StatusCode((int)result.StatusCode); //201 Created the request has been fulfilled, resulting in the creation of a new resource.
                                                
                }
                catch (Exception)
                {
                    return StatusCode(500); // 500 is generic server error
                }
            }
        }

        return StatusCode(400); // 400 is bad request

    }
    catch (Exception)
    {
        return StatusCode(500); // 500 is generic server error
    }
}

私人后端

[HttpPost]
public void Post()
{
    //Stream bodyStream = HttpContext.Request.Body;

    if (Request.HasFormContentType)
    {
        var form = Request.Form;
        foreach (var formFile in form.Files)
        {
            var targetDirectory = Path.Combine(_appEnvironment.WebRootPath, "uploads");

            var fileName = GetFileName(formFile);

            var savePath = Path.Combine(targetDirectory, fileName);

            using (var fileStream = new FileStream(savePath, FileMode.Create))
            {
                formFile.CopyTo(fileStream);
            }                   
        }
    }          
}

嗨,我遇到了同样的问题,这对我有用:

我的设置是 netCore MVC netCoreApi。

我的 MVC 控制器看起来像:

[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
    Sp4RestClient dataPovider = new Sp4RestClient("http://localhost:60077/");

    long size = files.Sum(f => f.Length);

    foreach (var file in files)
    {
       await dataPovider.ImportFile(file);
    }

    return Ok();
}

数据提供者方法:

public async Task ImportFile(IFormFile file)
    {
        RestClient restClient = new RestClient(_queryBulder.BuildImportFileRequest());

        using (var content = new MultipartFormDataContent())
        {
            content.Add(new StreamContent(file.OpenReadStream())
            {
                Headers =
                {
                    ContentLength = file.Length,
                    ContentType = new MediaTypeHeaderValue(file.ContentType)
                }
            }, "File", "FileImport");

            var response = await restClient.Post<IFormFile>(content);
        }
    }

至少我的 WebApi 控制器:

[HttpPost]
[Route("ImportData")]
public IActionResult Import(IFormFile file)
{         
    return Ok();
}

要在此处查看完整代码,请使用我的 RestClient Post 方法:

public async Task<RestResult<T>> Post<T>(HttpContent content)
    {
        using (HttpClient httpClient = new HttpClient())
        {
            HttpResponseMessage response = await httpClient.PostAsync(Endpoint, content);
            if (response.StatusCode == HttpStatusCode.Created)
            {
                T result = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
                return new RestResult<T> { Result = result, ResultCode = HttpStatusCode.OK };
            }
            RestResult<T> nonOkResult =
                new RestResult<T> { Result = default(T), ResultCode = response.StatusCode, Message = await response.Content.ReadAsStringAsync() };
            return nonOkResult;
        }
    }

// 是的,我知道我没有得到 HttpStatusCode.Created ;)

快乐编码;)

接口代码

 [Route("api/upload/{id}")]
    [HttpPost]
    public async Task<IActionResult> Post(string id)
    {
        var filePath = @"D:\" + id; //+ Guid.NewGuid() + ".png";
        if (Request.HasFormContentType)
        {
            var form = Request.Form;
            foreach (var formFile in form.Files)
            {
                if (formFile.Length > 0)
                {
                    using (var stream = new FileStream(filePath, FileMode.Create))
                    {
                        await formFile.CopyToAsync(stream);
                    }
                }
            }
        }
        return Ok(new { Path = filePath });
    }

后端

        [Route("home/UploadFile")]
    [HttpPost]
    public IActionResult UploadFile(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return Content("file not selected");

        var client = new HttpClient();

        byte[] data;
        using (var br = new BinaryReader(file.OpenReadStream()))
            data = br.ReadBytes((int)file.OpenReadStream().Length);
        ByteArrayContent bytes = new ByteArrayContent(data);
        MultipartFormDataContent multiContent = new MultipartFormDataContent
        {
            { bytes, "file", file.FileName }
        };
        var result = client.PostAsync("http://localhost:2821/api/upload/" + file.FileName, multiContent).Result;
        return RedirectToAction("file");
    }

下载源

我遇到了类似的情况 - 我需要一个代理方法来转发文件和 JSON 数据等等。 我不想对我的代理中的数据进行任何分析,让最终的接收者处理它。

因此,在@Anton Tykhyy 的帮助下,我得出了以下可行的解决方案:

byte[] arr = null;
using (var mems = new MemoryStream())
{
    // read entire body into memory first because it might be chunked with unknown length
    await request.Body.CopyToAsync(mems);
    await mems.FlushAsync(); // not sure if needed after CopyToAsync - better safe then sorry
    arr = mems.ToArray();
}

msg.Content = new ByteArrayContent(arr);
msg.Content.Headers.ContentLength = arr.Length;

// keep content-type header "as is" to preserve multipart boundaries etc.
msg.Content.Headers.TryAddWithoutValidation("Content-Type", request.ContentType);

var response = await _httpClient.SendAsync(msg);


我使用包含带有 JSON 字段和多个附加文件的多部分表单数据的复杂请求对其进行了测试,并且所有数据都毫无问题地到达了我的后端服务器。

调用私有后端API时忽略HttpClient,是否可以从公共Core API项目中引用私有Core API项目,直接从Core API项目中调用控制器? 查看请求仍然为空/空。 如果请求带有值,则问题在于 HttpClient 的使用。

理想情况下,您希望为您想要分发给消费客户端的私有核心 API 创建一个包库(一种 SDK)。 这就像一个包装器/代理。 通过这种方式,您可以隔离私有后端系统,并且可以隔离地对其进行故障排除。 因此,您的公共核心 API 项目(即私有后端客户端)可以将其引用为 nuget 包。

暂无
暂无

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

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