Custom ChannelFactory Creation


Just the other day, Derik Whitaker ran into some issues setting up his ChannelFactory to handle large object graphs being returned to his clients (post is here). After some back and forth through email, we came up with a solution. Instead of use the default ChannelFactory<T>, we created a new class that inherits from ChannelFactory<T> and sets the DataContractSerializerBehavior to handle int.MaxValue objects in the graph.

The trick is to override the ChannelFactory<T>.OnOpening method. This method is called as the ChannelFactory is opened and allows a derived class to alter the behavior at the last minute. All OperationDescriptions have a DataContractSerializerOperationBehavior attached to them. What we want to do is pull out that behavior and set the MaxItemsInObjectGraph property to int.MaxValue so that it allows all content to be serialized in. Derik’s use case was valid-he owned the client and server and wanted to incur any penalty associated with reading ALL data. If you are in a similar situation and need to remove that safety net/throttle in your code, here is what you need. Note that the constructors aren’t interesting other than they preserve the signatures made available through ChannelFactory<T> and make them visible in my DerikChannelFactory<T>.

 

public class DerikChannelFactory<T> : ChannelFactory<T>
{
    public DerikChannelFactory(Binding binding) :
        base(binding) { }

    public DerikChannelFactory(ServiceEndpoint endpoint) :
        base(endpoint) { }

    public DerikChannelFactory(string endpointConfigurationName) :
        base(endpointConfigurationName) { }

    public DerikChannelFactory(Binding binding, EndpointAddress remoteAddress) :
        base(binding, remoteAddress) { }

    public DerikChannelFactory(Binding binding, string remoteAddress) :
        base(binding, remoteAddress) { }

    public DerikChannelFactory(string endpointConfigurationName,
        EndpointAddress remoteAddress) :
        base(endpointConfigurationName, remoteAddress) { }

    protected override void OnOpening()
    {
        foreach (var operation in Endpoint.Contract.Operations)
        {
            var behavior =
                operation.Behaviors.
                    Find<DataContractSerializerOperationBehavior>();
            if (behavior != null)
            {
                behavior.MaxItemsInObjectGraph = int.MaxValue;
            }
        }
        base.OnOpening();
    }
}

 

The OnOpening override is also a good place to inject behaviors or other items if you want to make sure that all ChannelFactory instances have the same setup without resorting to configuration or code for each instance.

%d bloggers like this: