Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HttpClient enable cache on server

I'm trying to enable client caching of the System.Net.HttpClient. I have an endpoint at http://localhost:83/api/test that takes 1 second to respond and it sends cache headers back.

If I have this code

static async Task MainAsync()
{
    var client = new HttpClient(new WebRequestHandler { CachePolicy = new HttpRequestCachePolicy() }) { BaseAddress = new Uri("http://localhost:83/api/") };
    for (int i = 0; i < 20; i++)
    {
        var response = await client.GetAsync("test");
        var res = await response.Content.ReadAsStringAsync();
        Console.WriteLine(res);
    }
}

It takes one second to execute.

If I put the same code into an api controller

    static HttpClient client = new HttpClient(new WebRequestHandler {CachePolicy = new HttpRequestCachePolicy() }) { BaseAddress = new Uri("http://localhost:83/api/") };
    public async Task<string> Get()
    {
        for (int i = 0; i < 20; i++)
        {
            var response = await client.GetAsync("test");
            var res = await response.Content.ReadAsStringAsync();
        }
        return "ok";
    }

And host it in IIS it takes 20 seconds to respond.

What do I need to do in order to enable client cache from server applications?

like image 906
Esben Skov Pedersen Avatar asked Jul 21 '26 00:07

Esben Skov Pedersen


1 Answers

Probably you should switch to WinHTTP and use another HTTP caching implementation.

There are two HTTP client APIs that .NET Framework uses. One provided by WinINet and another by WinHTTP. .NET Framework uses WinINet by default. But WinINet was developed to work in client applications and it is not suppose to work in server environment. Relevant quote from Windows Internet page on MSDN:

Where applicable

WinINet does not support server implementations. In addition, it should not be used from a service. For server implementations or services use Microsoft Windows HTTP Services (WinHTTP).

So in your Web API you need to use WinHTTP. The only way to switch that I know is to use WinHttpHandler from System.Net.Http.WinHttpHandler NuGet package. But currently this handler do not use HTTP caching. It has no way to set cache policy and it ignores all settings that HttpClientHandler respect. See How do I utilize HTTP caching with WinHttpHandler and HttpClient? issue on GitHub.

To fix this you can implement your own caching mechanism or use existing one like CacheCow project. It has built-in in-memory storage and it's own implementation of DelagatingHandler for HttpClient. Note that currently there are some compatibility issues and you need to manually remove reference to .NET Framework System.Net.Http from your Web API project before installing System.Net.Http.WinHttpHandler and CacheCow.Clien NuGet packages. Following code snipped demonstrates usage of WinHttpHandler and CachingHandler from CacheCow.Clien NuGet package:

static HttpClient client = new HttpClient(new CachingHandler { InnerHandler = new WinHttpHandler() })
{
    BaseAddress = new Uri("http://localhost:83/api/")
};

For more information check:

  • Under the Hood: WinINet and Under the Hood: WinHTTP articles by CC Hameed
  • CacheCow.Client, using the benefits of HTTP Caching on the client article by Aliostad
  • Caching in .NET Framework Applications page on MSDN
like image 155
Leonid Vasilev Avatar answered Jul 22 '26 12:07

Leonid Vasilev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!