Search code examples
c#.net-coredotnet-httpclientcookiecontainerhttpclientfactory

cookieContainer with Typed Clients


Need to make a request to server which need specific cookies. Able to do this using HTTP client and handler with cookiecontainer. By using Typed clients, not able to find a way to set cookiecontainer.

Using httpclient:

var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (HttpClient client = new HttpClient(handler))
{
    //.....

    // Used below method to add cookies
    AddCookies(cookieContainer);

    var response = client.GetAsync('/').Result;
} 

Using HttpClientFactory:

In startup.cs

services.AddHttpClient<TypedClient>().
           ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
           {
               CookieContainer = new CookieContainer()
            });

In controller class

// Need to call AddCookie method here
var response =_typedclient.client.GetAsync('/').Result;

In Addcookie method, I need to add cookies to container. Any suggestions how to do this.


Solution

  • Create an abstraction to provide access to an instance of CookieContainer

    For example

    public interface ICookieContainerAccessor {
        CookieContainer CookieContainer { get; }
    }
    
    public class DefaultCookieContainerAccessor : ICookieContainerAccessor {
        private static Lazy<CookieContainer> container = new Lazy<CookieContainer>();
        public CookieContainer CookieContainer => container.Value;
    }
    

    Add cookie container to service collection during startup and use it to configure primary HTTP message handler

    Startup.ConfigureServices

    //create cookie container separately            
    //and register it as a singleton to be accesed later
    services.AddSingleton<ICookieContainerAccessor, DefaultCookieContainerAccessor>();
    
    services.AddHttpClient<TypedClient>()
        .ConfigurePrimaryHttpMessageHandler(sp =>
            new HttpClientHandler {
                //pass the container to the handler
                CookieContainer = sp.GetRequiredService<ICookieContainerAccessor>().CookieContainer
            }
        );
    

    And lastly, inject abstraction where needed

    For example

    public class MyClass{
        private readonly ICookieContainerAccessor accessor;
        private readonly TypedClient typedClient;
    
        public MyClass(TypedClient typedClient, ICookieContainerAccessor accessor) {
            this.accessor = accessor;
            this.typedClient = typedClient;
        }
    
        public async Task SomeMethodAsync() {
            // Need to call AddCookie method here           
            var cookieContainer = accessor.CookieContainer;
            AddCookies(cookieContainer);
    
            var response = await typedclient.client.GetAsync('/');
    
            //...
        }
    
        //...
    }