serializar - web service xml c#
¿Cómo optimizar WCF CreateFactory en System.ServiceModel.ChannelFactory? (1)
No conozco ningún mecanismo que le permita evitar el comportamiento que está viendo aquí. Esto es intrínsecamente cómo se diseñó ChannelFactory
: hace los altos costos de la reflexión y la composición de la pila de canales para darle una rutina barata para crear instancias de canal. Debe reutilizar la fábrica si desea guardar sus 9 segundos.
Normalmente sugeriría usar el almacenamiento en caché integrado de ChannelFactory
asociado con las instancias del cliente, pero esto se invalida en el momento en que toca la propiedad ClientCredentials
.
Le sugiero que realmente necesite considerar el almacenamiento en caché de cada ChannelFactory
por cliente. A menos que tenga decenas de miles de conjuntos de credenciales, no es una perspectiva poco realista. De hecho, así es como funcionan los sistemas HTTP en .NET para autorizar previamente las solicitudes.
Mi implementación actual es utilizar la clase ClientBase para crear un canal para llamadas WCF realizadas a una API de terceros. Esta API de terceros requiere un certificado X509Certificate2 y ClientCredentials para autenticarse.
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);
}
}
}
La instanciación y solicitud del cliente se puede ver aquí:
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);
Desafortunadamente, el proceso de creación de un canal para la llamada WCF tarda más de 9 segundos en completarse. Usando el generador de perfiles DoTrace de ReSharper puedo ver que el código se está reteniendo en el siguiente método: System.ServiceModel.Description.XmlSerializer.OperationBehavior + Reflecto.EnsureMessageInfos
A continuación se puede ver un seguimiento completo de las llamadas realizadas en 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
Ya he intentado usar sgen.exe para crear un conjunto de serialización XML con la esperanza de que mejore el rendimiento del serializador. Desafortunadamente, no tuvo efecto.
También he encontrado varios enfoques en línea que recomiendan el almacenamiento en caché de canales o fábricas de canales, como aquí http://www.itprotoday.com/microsoft-visual-studio/wcf-proxies-cache-or-not-cache . Sin embargo, estos enfoques no funcionan para esta implementación debido a que Channel Factory tiene credenciales de cliente asociadas. Esto requeriría el almacenamiento en caché de un Channel Factory o Channel para cada cliente, lo que no es realista.
¿Alguien sabe de alguna manera de evitar que ChannelFactory se refleje en los objetos de solicitud y respuesta cuando se crea? Cualquier ayuda que alguien pueda proporcionar sobre este tema sería muy apreciada.