3

I wanto to forward an incoming POST request to my asp.net core controller "as is" (including headers, body, from-data) to a different URL without using a middleware.

I found an example for doing that for asp.net: https://philsversion.com/2012/09/06/creating-a-proxy-with-apicontroller/

But this does not work for asp.net core, since the call to return await http.SendAsync(this.Request); in asp.net core accepts an HttpRequestMessage and the Request object is of type HttpRequest.

I also found some code, which creates a HttpRequestMessage from an HttpRequest, see: Convert Microsoft.AspNetCore.Http.HttpRequest to HttpRequestMessage

Using this code, the receiving endpoint (to which I forward to) gets the Body, but it does not get Form fields.

Checking the class HttpRequestMessage I saw that it does not contain a property for FormFields.

[Microsoft.AspNetCore.Mvc.HttpPost]
[NrgsRoute("api/redirect-v1/{key}")]
public async Task<HttpResponseMessage> Forward(
   [FromUri] string key,
   CancellationToken cancellationToken)
{
   // the URL was shortened, we need to get the original URL to which we want to forward the POST request
   var url = await _shortenUrlService.GetUrlFromToken(key, cancellationToken).ConfigureAwait(false);

     using (var httpClient = new HttpClient())
     {
         var forwardUrl = new Uri(url);
         Request.Path = new PathString(forwardUrl.PathAndQuery);

         // see: https://stackoverflow.com/questions/45759417/convert-microsoft-aspnetcore-http-httprequest-to-httprequestmessage
         var requestMessage = Request.ToHttpRequestMessage();
         return await httpClient.SendAsync(requestMessage, cancellationToken);

         // Problem: Forwards header and body but NOT form fields
     }
 }

Expected result would be that at my receiving endpoint I have the same - headers - body - form fields as in the original POST request.

HannesB
  • 51
  • 1
  • 6

1 Answers1

2

I ended up doing the following:

[HttpPost]
[NrgsRoute("api/redirect-v1/{key}")]
public async Task<RedirectResult> Forward(string key, CancellationToken cancellationToken)
{
    var url = await _shortenUrlService.GetUrlFromToken(key, cancellationToken).ConfigureAwait(false);
    if (string.IsNullOrEmpty(url))
        throw new BadRequestException($"Could not create forward URL from parameter {key}", "redirect-error");

    using (var httpClient = new HttpClient())
    {
        var forwardUrl = new Uri(url);
        Request.Path = new PathString(forwardUrl.PathAndQuery);

        HttpResponseMessage responseMessage;
        if (Request.HasFormContentType)
            responseMessage = await ForwardFormData(key, httpClient, forwardUrl, cancellationToken);
        else
            responseMessage = await ForwardBody(key, httpClient, cancellationToken);

        var queryParams = forwardUrl.GetQueryStringParams();
        var lUlr = queryParams["lurl"];
        return new RedirectResult(lUlr);
    }
}

private async Task<HttpResponseMessage> ForwardFormData(string key, HttpClient httpClient, Uri forwardUrl, CancellationToken cancellationToken)
{
    var formContent = new List<KeyValuePair<string, string>>();
    HttpResponseMessage result;

    if (Request.ContentType == "application/x-www-form-urlencoded")
    {
        foreach (var formKey in Request.Form.Keys)
        {
            var content = Request.Form[formKey].FirstOrDefault();
            if (content != null)
                formContent.Add(new KeyValuePair<string, string>(formKey, content));
        }
        var formUrlEncodedContent = new FormUrlEncodedContent(formContent);
        result = await httpClient.PostAsync(forwardUrl, formUrlEncodedContent, cancellationToken);
    }
    else
    {
        var multipartFormDataContent = new MultipartFormDataContent();
        foreach (var formKey in Request.Form.Keys)
        {
            var content = Request.Form[formKey].FirstOrDefault();
            if (content != null)
                multipartFormDataContent.Add(new StringContent(content), formKey);
        }

        result = await httpClient.PostAsync(forwardUrl, multipartFormDataContent, cancellationToken);
    }

    return result;
}

private async Task<HttpResponseMessage> ForwardBody(string key, HttpClient httpClient, CancellationToken cancellationToken)
{
    // we do not have direct access to Content, see: https://stackoverflow.com/questions/41508664/net-core-forward-a-local-api-form-data-post-request-to-remote-api

    var requestMessage = Request.ToHttpRequestMessage();
    return await httpClient.SendAsync(requestMessage, cancellationToken);
}
Jeremy Caney
  • 4,585
  • 13
  • 32
  • 54
HannesB
  • 51
  • 1
  • 6