Search code examples
c#.net-corechannelfactory

Managing Credentials Within ChannelFactory Cache


I've converted an old library to .NET Core and implemented a ChannelFactory caching solution. The services which it connects to require basic authorization added to each request's HTTP headers. The header is added to each request with a ClientMesageInspector. Because the ClientMessageInspector is immutable once the first channel is created the ChannelFactory cache stores each instance in a dictionary with a key based on the ChannelFactory endpoint, username and password combination. Also, due to the overhead of creating the ChannelFactory I do not dispose of them. My concern is the usernames and passwords are kept in memory within the dictionary keys and also within the ClientMesageInspector added to the ChannelFactory. Is there a better solution to this? I've already asked the question over on the dotnet/wcf GitHub page and wanted to open it up to a bigger audience.

Thanks in advance.

Bob.


Solution

  • I had some great help from the dotnet/wcf team via my question. After some discussion I ended up using AsyncLocal variables to store the username and password.

    In the wrapper class we have the two AsyncLocal variables which are set via the constructor.

    internal static AsyncLocal<string> Username = new AsyncLocal<string>();
    internal static AsyncLocal<string> Password = new AsyncLocal<string>();
    
    public WCFWrapper(string username, string password) : this()
    {
        Username.Value = username;
        Password.Value = password;
    }
    

    In the IClientMessageInspector BeforeSendRequest method, we simply use the variables.

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
        httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] =  
            "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(WCFWrapper.Username.Value + ":" + WCFWrapper.Password.Value));
        request.Properties[HttpRequestMessageProperty.Name] = httpRequestProperty;
    
        return null;
    }