![](/img/trans.png)
[英]How to solve System.ServiceModel.ServerTooBusyException in WCF?
[英]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.