Как оптимизировать WCF CreateFactory в System.ServiceModel.ChannelFactory?

В моей текущей реализации используется класс ClientBase для создания канала для вызовов WCF, сделанных сторонним API. Для этого стороннего API требуется сертификат X509Certificate2, а также ClientCredentials для аутентификации.

public class HeaderAdder : ContextBoundObject, IClientMessageInspector
{
    public bool RequestFailedDueToAuthentication;

    public string UserName { get; set; }
    public string Password { get; set; }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var property = new UserNameHeader
        {
            Password = Password,
            UserName = UserName
        };
        request.Headers.Add(MessageHeader.CreateHeader("UserNameHeader", "test", property));
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        RequestFailedDueToAuthentication = reply.ToString().Contains("ErrorCode>-4<");
    }
}

public class CustomEndpointBehavior : IEndpointBehavior
{
    private readonly HeaderAdder _headerAdder;

    public CustomEndpointBehavior(HeaderAdder headerAdder)
    {
        _headerAdder = headerAdder;
    }

    public void Validate(ServiceEndpoint endpoint)
    {
        //throw new NotImplementedException();
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        //throw new NotImplementedException();
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        //throw new NotImplementedException();
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        var credentials = endpoint.Behaviors.Find<ClientCredentials>();
        if (!string.IsNullOrEmpty(credentials.UserName.Password))
        {
            _headerAdder.UserName = credentials.UserName.UserName;
            _headerAdder.Password = credentials.UserName.Password;
            clientRuntime.ClientMessageInspectors.Add(_headerAdder);
        }
    }
}

Клиентский экземпляр и запрос можно увидеть здесь:

var client = new TestClient()
{
    ClientCredentials =
    {
        UserName =
        {
            UserName = "testing",
            Password = "testing"
        },
        UseIdentityConfiguration = true
    }
};
client.ClientCredentials?.ClientCertificate.SetCertificate(
    StoreLocation.LocalMachine, 
    StoreName.My,
    X509FindType.FindByIssuerName, 
    "Testing");
client.ChannelFactory.Endpoint.EndpointBehaviors.Add(
   new CustomEndpointBehavior(new HeaderAdder()));
var request = new Request();
client.Get(request);

К сожалению, для создания канала для вызова WCF требуется более 9 секунд. Используя профилировщик ReSharper doTrace, я могу видеть, что код поддерживается вверх по следующему методу: System.ServiceModel.Description.XmlSerializer.OperationBehavior + Reflecto.EnsureMessageInfos

Полная трассировка стека вызовов, выполняемых в System.ServiceModel, приведена ниже.

System.ServiceModel.ClientBase'1.get_Channel
System.ServiceModel.ClientBase'1.CreateChannelInternal
System.ServiceModel.ClientBase'1.CreateChannel
System.ServiceModel.ChannelFactory'1.CreateChannel
System.ServiceModel.ChannelFactory'1.CreateChannel(EndpointAddress, Uri)
System.ServiceModel.ChannelFactory.EnsureOpened
System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan)
System.ServiceModel.ChannelFactory.OnOpening
System.ServiceModel.ChannelFactory.CreateFactory
System.ServiceModel.Channels.ServiceChannelFactory.BuildChannelFactory(ServiceEndpoint, Boolean)
System.ServiceModel.Description.DispatcherBuilder.BuildProxyBehavior(ServiceEndpoint, out BindingParameterCollection)
System.ServiceModel.Description.DispatcherBuilder.ApplyClientBehavior(ServiceEndpoint, ClientRuntime)
System.ServiceModel.Description.DispatcherBuilder.BindOperations(ContractDescription, ClientRuntime, DispatchRuntime)
System.ServiceModel.Description.XmlSerializerOperationBehavior.ApplyClientBehavior(OperationDescription, ClientOperation)
System.ServiceModel.Description.XmlSerializerOperationBehavior.CreateFormatter
System.ServiceModel.Description.XmlSerializerOperationBehavior+Reflector.EnsureMessageInfos

Я уже пытался использовать sgen.exe для создания сборки сериализации XML в надежде, что это улучшит производительность сериализатора. К сожалению, это не повлияло.

Я также нашел несколько подходов в Интернете, которые рекомендуют кэшировать каналы, или Канальные фабрики, например, здесь http://www.itprotoday.com/microsoft-visual-studio/wcf-proxies-cache-or-not-cache. Однако эти подходы не работают для этой реализации, потому что у Factory Channel есть связанные с ним учетные данные клиента. Для этого потребуется кэширование фабрики каналов или канала для каждого клиента, что нереально.

Кто-нибудь знает, как предотвратить отражение ChannelFactory над объектами Request and Response при его создании? Любая помощь, которую любой человек может предоставить по этому вопросу, получит большую оценку.

Ответы