it-swarm.com.de

Veröffentlichen Sie Dateien von ASP.NET Core-Web-API zu einer anderen ASP.NET Core-Web-API

Wir erstellen eine Webanwendung, die aus einem Angular2-Frontend, einem öffentlichen Backend für ASP.NET Core-Web-API und einem privaten ASP.NET Core-Web-API-Backend besteht.

Das Hochladen von Dateien aus Angular2 in das öffentliche Backend funktioniert. Wir würden es aber vorziehen, sie an das private Backend weiterzuleiten.

Aktueller Arbeitscode

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

Von dort kann ich die Datei mit file.CopyTo (fileStream) auf Festplatte speichern.

Ich möchte jedoch diese Datei oder diese Dateien oder idealerweise die gesamte Anforderung an meinen zweiten Web-API-Kern senden.

Ich bin nicht sicher, wie ich dies mit der HttpClient-Klasse von asp.net core erreichen kann.

Ich habe alle möglichen Dinge ausprobiert

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

Mein zweites Backend erhält jedoch eine leere IFormFile.

Ich habe das Gefühl, dass es möglich ist, die Datei (en) als Stream zu senden und sie auf der anderen Seite zu rekonstruieren, aber sie funktioniert nicht.

Die Lösung muss zwei Web-API-Cores verwenden.

7
Dave

Lösung

Öffentliches Backend in 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
    }
}

Privates Backend 

[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);
            }                   
        }
    }          
}
11
Dave

Hi, ich hatte das gleiche Problem und das hat bei mir funktioniert:

Mein Setup ist netCore MVC netCoreApi.

Mein MVC-Controller sieht folgendermaßen aus: 

[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();
}

DataProvider-Methode:

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);
        }
    }

Und mindestens mein WebApi Controller:

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

Den vollständigen Code finden Sie hier meine RestClient Post-Methode:

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;
        }
    }

// Ja, ich weiß, ich bekomme HttpStatusCode.Created nicht zurück;)

glückliche Codierung;)

3
minohimself

API-Code

 [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 });
    }

Backend

        [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");
    }

Download-Quelle

2
Godly Mathew

Können Sie beim Aufruf der privaten Backend-API den HttpClient ignorieren, können Sie auf das private Core-API-Projekt aus dem öffentlichen Core-API-Projekt verweisen und den Controller direkt aus dem Core-API-Projekt aufrufen? Siehe die Anforderung ist noch null/leer. Wenn die Anforderung einen Wert ausgibt, liegt das Problem bei der Verwendung des HttpClient.

Idealerweise möchten Sie eine Paketbibliothek (Art des SDK) für Ihre private Core-API erstellen, die Sie an konsumierende Clients verteilen möchten. Dies wirkt wie ein Wrapper/Proxy. Auf diese Weise können Sie das private Backend-System isolieren und es isoliert behandeln. Ihr öffentliches Core-API-Projekt (also der private Backend-Client) kann es als Nuget-Paket referenzieren.

0
alltej