7

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.

1
  • Thanks for this Q&A! you save my day! Commented Oct 31, 2020 at 19:44

1 Answer 1

4

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);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.