Creating Wcf Channelfactory<T>

creating WCF ChannelFactoryT

Yes, if you want to create something like this - a static class to hold all those ChannelFactory<T> instances - you definitely have to make sure this class is 100% thread-safe and cannot stumble when accessed concurrently. I haven't used .NET 4's features much yet, so I cannot comment on those specifically - but I would definitely recommend to make this as safe as possible.

As for your second (minor) question: the ChannelFactory itself is a static class - so you cannot really call a .Close() method on it. If you meant to ask whether or not to call the .Close() method on the actual IChannel, then again: yes, try your best to be a good citizen and close those channels if you ever can. If you miss one, .NET will take care of it - but don't just toss your unused channels on the floor and go on - clean up after yourself! :-)

Creating WCF ChannelFactory without an endpoint?

ChannelFactory<TChannel> derives from abstract class ChannelFactory. Create a custom derived class and use the InitializeEndpoint call to initialize the endpoint.

For example:

public class SomeChannelFactory : ChannelFactory
{
public SomeChannelFactory()
{
InitializeEndpoint( new BasicHttpBinding() , new EndpointAddress( "http://localhost/service" ) );
}

protected override ServiceEndpoint CreateDescription()
{
return new ServiceEndpoint( new ContractDescription( nameof( SomeChannelFactory ) ) );
}
}

How does ChannelFactory (WCF/C#) use an Interface as a type?

Internally, ChannelFactory<TChannel> creates an object of type ServiceChannelProxy, which derives from System.Runtime.Remoting.Proxies.RealProxy, allowing it to create a transparent proxy over the TChannel interface.

WCF channel Factory caching

This is a complex topic with a lot of details to go over, but here it goes.

First, as a general rule you should be caching a ChannelFactory and not an individual Channel. A ChannelFactory is expensive to construct as well as thread-safe so it is a great candidate for caching. A Channel is cheap to construct and it is generally recommended to only create channels on an as-needed basis and to close them as early as possible. Additionally, when you cache a Channel then you have to worry about it timing out which will cause it to fault which invalidates the entire benefit of caching it in the first place.

The article you linked to by Michele Leroux Bustamante is one of the best resources out there. As she states, there are differences to consider between Windows clients and server-side clients. Mostly only Windows clients benefit from caching as typically the credentials differ from thread to thread on server-side clients. For your typical Windows clients, there are two main options: Caching the references yourself or leveraging the MRU cache.

Leveraging the MRU cache: Essentially this means that you are letting Microsoft take the wheel. The ClientBase class will use an MRU cache for the internal ChannelFactory instance. The caching behavior is controlled via a CacheSetting property and by default caching will be disabled if any of the "security-sensitive" properties are accessed. ClientBase properties which will invalidate and remove a ChannelFactory from the MRU cache when accessed include the Endpoint, ClientCredentials or the ChannelFactory itself. There is a way to override this behavior by setting the CacheSettings property to CacheSettings.AlwaysOn. Additionally, if the Binding is run-time defined then the ChannelFactory is no longer a candidate for the MRU cache. See more details here.

Caching the references yourself: This means that you are going to keep a collection of ChannelFactory references yourself. The snippet you provide in your question uses this approach. The best approach I have ever seen and admittedly use a modified version of at work is by Darin Dimitrov via this related SO question. For those of us who like to have more fine-grained control over the caching mechanism then this is the approach to use. This is typically used when credentials must be set at run-time like is often required by internet services.

Quite similarly, client proxies can be cached to improve performance - Wenlong Dong has an article about this topic.

(Update) Server-side clients as noted before are quite limited in their options when it comes to ChannelFactory caching. For this brief discussion, we will assume that our deployment scenario looks like this:

Client -> Service A -> Service B

The most likely method to use in order to leverage ChannelFactory caching in this scenario is to cache the references yourself for the session between the Client and Service A. This way Service A does not have to construct a different ChannelFactory instance every time Service A needs to call into Service B. However, if the properties of the ChannelFactory need change for each call, then this is no longer going to be appropriate.

Of course this also holds if Service A is a Singleton and each call to the downstream service (Service B) does not require new credentials, but Singleton services have their own set of performance problems.

Using ChannelFactoryT To Create Channels with Different Credentials

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...

WCF Cannot create channel factory with given endpoint name

You need to add an <endpoint> under a <client> element to be able to call it from ChannelFactory:

Add the following code under <system.serviceModel>:

  <client>
<endpoint address="net.tcp://localhost:8090/TexasHoldem" binding="netTcpBinding" bindingConfiguration="" contract="Service.ITexasHoldemService" name="TexasHoldem">
</endpoint>
</client>

ChannelFactory: creating and disposing

Thanks Daniel, didn't see that post. So I guess that the following may be a good approach:

public class ProjectStudioServiceFactory : IDisposable
{
private static IProjectStudioService _projectStudioService;
private static ChannelFactory<IProjectStudioService> _channelFactory;

public IProjectStudioService Instance
{
get
{
if (_projectStudioService == null)
{
_channelFactory = new ChannelFactory<IProjectStudioService>("ProjectStudioServiceEndPoint");
_projectStudioService = _channelFactory.CreateChannel();
((IClientChannel)_projectStudioService).Open();
}
return _projectStudioService;
}
}

public void Dispose()
{
//((IClientChannel)_projectStudioService).Close();
//_channelFactory.Close();
}
}


Related Topics



Leave a reply



Submit