web-dev-qa-db-fra.com

Publier des fichiers de l’API Web principale ASP.NET sur une autre API Web ASP.NET principale

Nous sommes en train de créer une application Web composée d’un frontal Angular2, d’un backend public pour l’API Web Core ASP.NET et d’un backend privé pour l’API Web Core.

Le téléchargement de fichiers d’Angular2 vers le backend public fonctionne. Mais nous préférerions les envoyer au backend privé.

Code de travail actuel

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

De là, je peux enregistrer le fichier sur le disque en utilisant file.CopyTo (fileStream);

Cependant, je souhaite renvoyer ce ou ces fichiers ou, idéalement, la totalité de la demande à mon deuxième noyau d'API Web.

Je ne sais pas comment y parvenir avec la classe HttpClient de base asp.net.

J'ai essayé toutes sortes de choses telles que

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

Mais mon second serveur reçoit un fichier IFormFile vide.

J'ai l'impression qu'il est possible d'envoyer le ou les fichiers sous forme de flux et de les reconstruire de l'autre côté, mais je ne peux pas le faire fonctionner.

La solution doit utiliser deux API Web.

7
Dave

Solution

Backend public en 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
    }
}

Backend privé 

[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

Salut j'ai eu le même problème et c'est ce qui a fonctionné pour moi:

Ma configuration est netCore MVC netCoreApi.

Mon contrôleur MVC ressemble à: 

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

Méthode DataProvider:

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

Et moins mon contrôleur WebApi:

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

Pour voir le code complet, voici ma méthode Post RestClient:

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

// Oui, je sais que je ne reçois pas HttpStatusCode.Created back;)

bonne codage;)

3
minohimself

En ignorant HttpClient lorsque vous appelez l'API backend privée, pouvez-vous référencer le projet API Core privé à partir du projet API Core public et appeler le contrôleur directement à partir du projet API Core? Voir la demande est toujours null/vide. Si la demande émet une valeur, le problème provient de l'utilisation de HttpClient.

Idéalement, vous souhaitez créer une bibliothèque de packages (type de SDK) pour votre API Core privée que vous souhaitez distribuer aux clients consommateurs. Cela agit comme un wrapper/proxy. De cette façon, vous pouvez isoler le système backend privé et le dépanner de manière isolée. Ainsi, votre projet Core API public (qui est le client backend privé) peut le référencer en tant que package Nuget.

0
alltej