簡體   English   中英

如何在System.ServiceModel.ChannelFactory中優化WCF CreateFactory?

[英]How to optimize WCF CreateFactory in System.ServiceModel.ChannelFactory?

我當前的實現是利用ClientBase類為第三方API的WCF調用創建一個通道。 此第三方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調用創建Channel的過程需要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 但是,這些方法不適用於此實現,因為Channel Factory具有與之關聯的客戶端憑據。 這將需要為每個客戶端緩存一個Channel Factory或Channel,這是不現實的。

有沒有人知道一種方法來阻止ChannelFactory在創建時反映請求和響應對象? 任何人都可以在這個問題上提供的任何幫助將非常感謝。

我不知道任何機制會讓你繞過你在這里看到的行為。 這本質上是ChannelFactory設計方式:它可以完成一次性的反射和組合通道堆棧,為您提供創建通道實例的便宜例程。 如果要保存9秒鍾, 必須重新使用工廠。

通常我建議使用與客戶端實例關聯的ChannelFactory內置緩存 ,但是當您觸摸ClientCredentials屬性時,這將無效。

我建議你真的需要考慮緩存每個ChannelFactory在每個客戶端的基礎。 除非你有數以萬計的證書,否則這不是一個不切實際的前景。 實際上,這就是.NET中的HTTP系統如何預先授權請求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM