1

I'm trying to create a SelfHost WebApi 2.0 (not .net Core) for reverse proxy purposes. The api does not have any controller, instead I've created a DelegatingHandler that will proxy the request to some other place.

Here is the proxy handler

class ProxyHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return await RedirectRequest(request, cancellationToken).ConfigureAwait(false);
    }

    private async Task<HttpResponseMessage> RedirectRequest(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var redirectLocation = "http://localhost:8099";

        using (var client = new HttpClient())
        {
            using (var cloned = await CloneHttpRequestMessageAsync(request).ConfigureAwait(false))
            {
                cloned.RequestUri = new Uri($"{redirectLocation}{request.RequestUri.PathAndQuery}");
                return await client.SendAsync(cloned, cancellationToken).ConfigureAwait(false);
            }
        }
    }

    private async Task<HttpRequestMessage> CloneHttpRequestMessageAsync(HttpRequestMessage request)
    {
        var clone = new HttpRequestMessage(request.Method, request.RequestUri);

        if (request.Content != null)
        {
            var stream = new MemoryStream();
            await request.Content.CopyToAsync(stream).ConfigureAwait(false);
            stream.Position = 0;

            if ((stream.Length > 0 || request.Content.Headers.Any()) && clone.Method != HttpMethod.Get)
            {
                clone.Content = new StreamContent(stream);

                if (request.Content.Headers != null)
                    foreach (var h in request.Content.Headers)
                        clone.Content.Headers.Add(h.Key, h.Value);
            }
        }

        clone.Version = request.Version;

        foreach (var prop in request.Properties)
            clone.Properties.Add(prop);

        foreach (var header in request.Headers)
            clone.Headers.TryAddWithoutValidation(header.Key, header.Value);

        return clone;
    }

}

However, I couldn't make a "catch all" route in configuration, I've tried: config.MessageHandlers.Add(new ProxyHandler()); or

var handler = HttpClientFactory.CreatePipeline(new HttpClientHandler(), new[] { new ProxyHandler() });
config.Routes.MapHttpRoute("default", "{*path}", null, null, handler);

The ProxyHandler is called, however the client gets 404 http error: no route data was found for this request.

How can I create a configuration that doesn't need a controller and all requests goes to ProxyHandler?

JobaDiniz
  • 862
  • 1
  • 14
  • 32
  • If you're not planning to use controllers, why use Web API at all? Seems like you should be building on something lower level, like [HttpListener](https://learn.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=netframework-4.7.2) perhaps. – mason Jan 22 '19 at 16:48
  • It seems there are few [issues](https://stackoverflow.com/a/806406/1830639) with that approach. And WebApi already does several things for you, my reverse proxy should be simple. – JobaDiniz Jan 22 '19 at 17:04
  • I'm not saying necessarily to use HttpListener. I'm saying that you should use a lower level. You don't need all the overhead of Web API to create a reverse proxy. – mason Jan 22 '19 at 18:28

0 Answers0