Search code examples
.netwcfchannelfactory

Using ChannelFactory<T> To Create Channels with Different Credentials


I am using the ChannelFactory<T> type to create channels into a WsHttpBinding WCF web service, and the service uses a username/password combination to authenticate. While I have the authentication working using my custom validator, I am having difficulty creating channels with differing credentials.

Given the overhead of creating ChannelFactory<T>, I'm trying to cache a single instance of it and share it for the creation of multiple channels over the lifetime of my application. Unfortunately, it seems like the credentials are directly tied to the factory and cannot be changed after a channel has been created.

In other words, if I try this:

factory.Credentials.UserName.UserName = "Bob";
factory.Credentials.UserName.Password = "password";

var channel1 = factory.CreateChannel();

factory.Credentials.UserName.UserName = "Alice"; // exception here
factory.Credentials.UserName.Password = "password";

var channel1 = factory.CreateChannel();

I get an exception telling me that the UserName property is now read-only.

Is it possible to implement any sort of caching here, or am I essentially going to have to cache an instance of ChannelFactory for every username?


Solution

  • As documented on MSDN this is not directly possible (Credentials become readonly upon Open of the ChannelFactory)... if you really want to do this you will need to trick the ChannelFactory like this:

    // step one - find and remove default endpoint behavior 
    var defaultCredentials = factory.Endpoint.Behaviors.Find<ClientCredentials>();
    factory.Endpoint.Behaviors.Remove(defaultCredentials); 
    
    
    // step two - instantiate your credentials
    ClientCredentials loginCredentials = new ClientCredentials();
    loginCredentials.UserName.UserName = "Username";
    loginCredentials.UserName.Password = "Password123";
    
    
    // step three - set that as new endpoint behavior on factory
    factory.Endpoint.Behaviors.Add(loginCredentials); //add required ones
    

    Another option seems to be to Close() the ChannelFactory before trying to change the Credentials .

    Otherwise just stick with caching different ChannelFactories for different Credentials...