c# .net wcf channel channelfactory

c# - Canal WCF y ChannelFactory Caching



.net (3)

Crear el Canal cuesta tanto el rendimiento. en realidad, WCF ya tiene el mecanismo de caché para ChannelFactory si usa ClientBase en el cliente en lugar de ChannelFactory puro. Pero la memoria caché caducará si realiza algunas operaciones adicionales (si lo desea, busque en Google para más detalles). Para el problema de ErOx tengo otra solución, creo que es mejor. vea abajo:

namespace ChannelFactoryCacheDemo { public static class ChannelFactoryInitiator { private static Hashtable channelFactories = new Hashtable(); public static ChannelFactory Initiate(string endpointName) { ChannelFactory channelFactory = null; if (channelFactories.ContainsKey(endpointName))//already cached, get from the table { channelFactory = channelFactories[endpointName] as ChannelFactory; } else // not cached, create and cache then { channelFactory = new ChannelFactory(endpointName); lock (channelFactories.SyncRoot) { channelFactories[endpointName] = channelFactory; } } return channelFactory; } } class AppWhereUseTheChannel { static void Main(string[] args) { ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint"); } } interface IMyContract { } }

usted puede personalizar la lógica y los parámetros del método Initiate si tiene otro requisito. pero esta clase de iniciador no está limitada a un solo punto final. Es potente para todos los puntos finales en su aplicación. Ojalá. funciona bien para ti Por cierto Esta solución no es de mí. conseguí esto de un libro

Así que decidí aumentar el rendimiento un poco en mi aplicación WCF e intentar almacenar en caché los canales y el ChannelFactory. Tengo dos preguntas sobre todo esto que debo aclarar antes de comenzar.

1) ¿Debería implementarse ChannelFactory como un singleton?

2) No estoy seguro de cómo almacenar en caché / reutilizar canales individuales. ¿Tienes algún ejemplo de cómo hacer esto que puedas compartir?

Probablemente sea importante tener en cuenta que mi servicio WCF se está implementando como una aplicación independiente, con un solo punto final.

EDITAR:

Gracias por las respuestas. Todavía tengo algunas preguntas aunque ...

1) Supongo que estoy confundido en cuanto a dónde debería ocurrir el caché Estoy entregando una API de cliente que usa este código a otro departamento de nuestra empresa. ¿Ocurre este almacenamiento en caché en el cliente?

2) La API del cliente se usará como parte de una aplicación de Silverlight, ¿esto cambia algo? En particular, ¿qué mecanismos de caché están disponibles en tal escenario?

3) Todavía no tengo claro el diseño del método GetChannelFactory. Si solo tengo un servicio, ¿solo se debe crear y almacenar en caché un ChannelFactory?

Todavía no he implementado ninguna función de almacenamiento en caché (¡porque estoy completamente confundido acerca de cómo se debe hacer!), Pero esto es lo que tengo hasta ahora para el proxy del cliente:

namespace MyCompany.MyProject.Proxies { static readonly ChannelFactory<IMyService> channelFactory = new ChannelFactory<IMyService>("IMyService"); public Response DoSomething(Request request) { var channel = channelFactory.CreateChannel(); try { Response response = channel.DoSomethingWithService(request); ((ICommunicationObject)channel).Close(); return response; } catch(Exception exception) { ((ICommenicationObject)channel).Abort(); } } }


Siempre puede hacer que su ChannelFactory sea estática para cada contrato de WCF ...

Debe tener en cuenta que, desde .Net 3.5, la fábrica de canales agrupa los objetos proxy por razones de rendimiento. Al llamar al método ICommunicationObject.Close() , el objeto se devuelve al grupo con la esperanza de que se pueda reutilizar.

Me gustaría ver el generador de perfiles si desea realizar alguna optimización, si puede evitar que solo se realice una llamada de IO en su código, esto podría superar con creces cualquier optimización que realice con la fábrica de canales. No elija un área para optimizar, use el generador de perfiles para encontrar dónde puede orientar una optimización. Por ejemplo, si tiene una base de datos SQL, es probable que encuentre alguna ventaja en sus consultas que le permita aumentar el rendimiento de órdenes de magnitud si éstas aún no se han optimizado.


Use ChannelFactory para crear una instancia de la fábrica, luego guarde esa instancia. A continuación, puede crear canales de comunicación según sea necesario / deseado desde la instancia en caché.

¿Tiene una necesidad de fábricas de múltiples canales (es decir, hay múltiples servicios)? En mi experiencia, ahí es donde verá el mayor beneficio en el rendimiento. Crear un canal es una tarea bastante barata; Está configurando todo al principio que lleva tiempo.

No almacenaría en caché canales individuales: los crearía, los utilizaría para una operación y luego los cerraría. Si los almacena en caché, es posible que se agote el tiempo de espera y que el canal presente un error, entonces tendrá que abortar y crear uno nuevo de todos modos.

No estoy seguro de por qué querría usar Singleton para implementar ChannelFactory, especialmente si va a crearlo y almacenarlo en caché, y solo hay un punto final.

Publicaré un código de ejemplo más tarde cuando tenga un poco más de tiempo.

ACTUALIZACIÓN: Ejemplos de código

Aquí hay un ejemplo de cómo implementé esto para un proyecto en el trabajo. Utilicé ChannelFactory<T> , ya que la aplicación que estaba desarrollando es una aplicación de n niveles con varios servicios, y se agregarán más. El objetivo era tener una forma sencilla de crear un cliente una vez por vida de la aplicación, y luego crear canales de comunicación según sea necesario. Los conceptos básicos de la idea no son míos (los obtuve de un artículo en la web), aunque modifiqué la implementación según mis necesidades.

Tengo una clase de ayuda estática en mi aplicación, y dentro de esa clase tengo un diccionario y un método para crear canales de comunicación desde la fábrica de canales.

El diccionario es el siguiente (objeto es el valor, ya que contendrá diferentes fábricas de canales, una para cada servicio). Pongo "Caché" en el ejemplo como una especie de marcador de posición: reemplaza la sintaxis con cualquier mecanismo de almacenamiento en caché que estés usando.

public static Dictionary<string, object> OpenChannels { get { if (Cache["OpenChannels"] == null) { Cache["OpenChannels"] = new Dictionary<string, object>(); } return (Dictionary<string, object>)Cache["OpenChannels"]; } set { Cache["OpenChannels"] = value; } }

El siguiente es un método para crear un canal de comunicación desde la instancia de fábrica. El método verifica si la fábrica existe primero; si no existe, la crea, la coloca en el diccionario y luego genera el canal. De lo contrario, simplemente genera un canal desde la instancia en caché de la fábrica.

public static T GetFactoryChannel<T>(string address) { string key = typeof(T.Name); if (!OpenChannels.ContainsKey(key)) { ChannelFactory<T> factory = new ChannelFactory<T>(); factory.Endpoint.Address = new EndpointAddress(new System.Uri(address)); factory.Endpoint.Binding = new BasicHttpBinding(); OpenChannels.Add(key, factory); } T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel(); ((IClientChannel)channel).Open(); return channel; }

He quitado este ejemplo de lo que uso en el trabajo. Hay muchas cosas que puede hacer con este método: puede manejar varios enlaces, asignar credenciales para la autenticación, etc. Es prácticamente su centro de ventanilla única para generar un cliente.

Finalmente, cuando lo uso en la aplicación, generalmente creo un canal, hago mi negocio y lo cierro (o lo aborto si es necesario). Por ejemplo:

IMyServiceContract client; try { client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress"); client.DoSomething(); // This is another helper method that will safely close the channel, // handling any exceptions that may occurr trying to close. // Shouldn''t be any, but it doesn''t hurt. Helper.CloseChannel(client); } catch (Exception ex) { // Something went wrong; need to abort the channel // I also do logging of some sort here Helper.AbortChannel(client); }

Esperemos que los ejemplos anteriores le den algo para continuar. He estado usando algo similar a esto desde hace aproximadamente un año en un entorno de producción y ha funcionado muy bien. El 99% de los problemas que hemos encontrado generalmente se han relacionado con algo fuera de la aplicación (ya sea clientes externos o fuentes de datos que no están bajo nuestro control directo).

Déjeme saber si algo no está claro o si tiene más preguntas.