Creating a proxy to another web api with Asp.net core Creating a proxy to another web api with Asp.net core asp.net asp.net

Creating a proxy to another web api with Asp.net core


If anyone is interested, I took the Microsoft.AspNetCore.Proxy code and made it a little better with middleware.

Check it out here: https://github.com/twitchax/AspNetCore.Proxy. NuGet here: https://www.nuget.org/packages/AspNetCore.Proxy/. Microsoft archived the other one mentioned in this post, and I plan on responding to any issues on this project.

Basically, it makes reverse proxying another web server a lot easier by allowing you to use attributes on methods that take a route with args and compute the proxied address.

[ProxyRoute("api/searchgoogle/{query}")]public static Task<string> SearchGoogleProxy(string query){    // Get the proxied address.    return Task.FromResult($"https://www.google.com/search?q={query}");}


I ended up implementing a proxy middleware inspired by a project in Asp.Net's GitHub.

It basically implements a middleware that reads the request received, creates a copy from it and sends it back to a configured service, reads the response from the service and sends it back to the caller.


This post talks about writing a simple HTTP proxy logic in C# or ASP.NET Core. And allowing your project to proxy the request to any other URL. It is not about deploying a proxy server for your ASP.NET Core project.

Add the following code anywhere of your project.

        public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri)        {            var request = context.Request;            var requestMessage = new HttpRequestMessage();            var requestMethod = request.Method;            if (!HttpMethods.IsGet(requestMethod) &&                !HttpMethods.IsHead(requestMethod) &&                !HttpMethods.IsDelete(requestMethod) &&                !HttpMethods.IsTrace(requestMethod))            {                var streamContent = new StreamContent(request.Body);                requestMessage.Content = streamContent;            }            // Copy the request headers            foreach (var header in request.Headers)            {                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null)                {                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());                }            }            requestMessage.Headers.Host = uri.Authority;            requestMessage.RequestUri = uri;            requestMessage.Method = new HttpMethod(request.Method);            return requestMessage;        }

This method covert user sends HttpContext.Request to a reusable HttpRequestMessage. So you can send this message to the target server.

After your target server response, you need to copy the responded HttpResponseMessage to the HttpContext.Response so the user's browser just gets it.

        public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)        {            if (responseMessage == null)            {                throw new ArgumentNullException(nameof(responseMessage));            }            var response = context.Response;            response.StatusCode = (int)responseMessage.StatusCode;            foreach (var header in responseMessage.Headers)            {                response.Headers[header.Key] = header.Value.ToArray();            }            foreach (var header in responseMessage.Content.Headers)            {                response.Headers[header.Key] = header.Value.ToArray();            }            // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.            response.Headers.Remove("transfer-encoding");            using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())            {                await responseStream.CopyToAsync(response.Body, _streamCopyBufferSize, context.RequestAborted);            }        }

And now the preparation is complete. Back to our controller:

    private readonly HttpClient _client;    public YourController()    {        _client = new HttpClient(new HttpClientHandler()        {            AllowAutoRedirect = false        });    }        public async Task<IActionResult> Rewrite()        {            var request = HttpContext.CreateProxyHttpRequest(new Uri("https://www.google.com"));            var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, HttpContext.RequestAborted);            await HttpContext.CopyProxyHttpResponse(response);            return Ok();        }

And try to access it. It will be proxied to google.com

![](/uploads/img-f2dd7ca2-79e4-4846-a7d0-6685f9b33ff4.png)