10

En nuestro entorno SharePoint/ASP.NET tenemos una serie de clases de recuperadores de datos que todos derivan de una interfaz común. Se me asignó la tarea de crear un recuperador de datos que pudiera comunicarse de forma remota con otras granjas de SharePoint mediante WCF. La forma en que lo tengo implementado en este momento es un singleton ChannelFactory<T> se crea en un constructor estático y luego se reutiliza por cada instancia del recuperador de datos remoto para crear una instancia de proxy individual. Pensé que esto funcionaría bien porque entonces el ChannelFactory solo se instancia una vez en un dominio de aplicación y su creación es guaranteed to be thread-safe. Mi código se parece a esto:Creación de un singleton ChannelFactory <T> y reutilización para conexiones de clientes

public class RemoteDataRetriever : IDataRetriever 
{ 
    protected static readonly ChannelFactory<IRemoteDataProvider> 
     RequestChannelFactory; 

    protected IRemoteDataProvider _channel; 

    static RemoteDataRetriever() 
    { 
     WSHttpBinding binding = new WSHttpBinding(
      SecurityMode.TransportWithMessageCredential, true); 

     binding.Security.Transport.ClientCredentialType = 
      HttpClientCredentialType.None; 

     binding.Security.Message.ClientCredentialType = 
      MessageCredentialType.Windows; 

     RequestChannelFactory = 
      new ChannelFactory<IRemoteDataProvider>(binding); 
    } 

    public RemoteDataRetriever(string endpointAddress) 
    { 
     _channel = RemoteDataRetriever.RequestChannelFactory. 
      CreateChannel(new EndpointAddress(endpointAddress)); 
    } 
} 

Mi pregunta es, ¿es este un buen diseño? Pensé que una vez que se creó el ChannelFactory no tengo que preocuparme por la seguridad de los hilos porque simplemente lo estoy usando para llamar al CreateChannel(), pero ¿me equivoco? ¿Está cambiando el estado o haciendo algo funky detrás de escena que podría causar problemas de enhebrado? Además, ¿necesito poner algún código en algún lugar (finalizador estático?) Que elimine manualmente el ChannelFactory o ¿puedo suponer que cada vez que se reinicie IIS, todo el trabajo de limpieza me servirá?

relacionadas: ChannelFactory Reuse Strategies

Respuesta

3

Desde un "es este diseño único bueno" bien, su implementación de Singleton está bien. Es seguro para subprocesos y el ChannelFactory<T> también es seguro para subprocesos.

Tampoco tiene que preocuparse por la limpieza de los recursos. Suponiendo que el ChannelFactory<T> sigue a Microsoft's guidelines for implementing IDisposable, entonces no tendrá un problema con una fuga de algún tipo. Cuando se derriba un dominio de la aplicación, se creará una recolección de basura, y todo se limpiará en ese punto. El finalizador en ChannelFactory<T> hará la limpieza que uno normalmente haría en la llamada a Dispose.

Sin embargo, desde un punto de vista "¿Debería estar en caché el ChannelFactory<T>?", Es difícil de decir, porque no indica en qué versión de .NET está. Sin embargo, el artículo que señala indica que si usa .NET 3.0 SP1 o superior, realmente no necesita hacer esto, puede crear sus proxies (suponiendo que derivan de ClientBase<T>) donde lo necesita en el código del cliente y no a través de un patrón de fábrica como este.

+0

He encontrado un artículo rubia das que parece indicar la misma cosa - http://www.dasblonde.net/PermaLink.aspx?guid=c7922cb4-26d4-408b-b029-cfadd75ff954. Sin embargo, las palabras "generadas para usted" me desalentaron un poco en el enfoque de ClientBase . Aún así, creo que estás en el blanco con esto. –

+0

Mientras investigaba otro problema de WCF, descubrí una buena razón para favorecer ChannelFactory sobre ClientBase - http://stackoverflow.com/questions/2252747/what-is-system-servicemodel-diagnostics-callbackexception-and-why-cant -i-handle –

+0

@Repo Man: si lo prefiere, pero volver a envolver excepciones no es una buena práctica a menos que tenga una buena razón para hacerlo. Para errores de esta naturaleza en WCF, no creo que califique para el reenvío de excepciones. – casperOne

0

Mientras su "Singleton" es simplemente volviendo canales de nueva construcción, que no es necesario preocuparse por la seguridad hilo. Siempre puede arrojar la palabra clave volátil en la declaración estática si así lo desea, para evitar cualquier optimización del compilador que pueda perjudicarlo, pero no creo que sea necesario en este caso.

Simplemente intente hacerse preguntas sobre la flexibilidad a largo plazo. Por ejemplo, ¿qué ocurre si más adelante decide agregar algún estado a este método CreateChannel? Tal vez haga algo así como crear hasta 10 canales, luego comience a reutilizarlos después de eso. ¿Podría modificar fácilmente su singleton para hacer esto?

Probablemente su respuesta sea afirmativa, pero ¿y si luego escala verticalmente a varios servidores? Un singleton podría no ser suficiente. Necesitará alguna forma de compartir estado entre las instancias/servidores (por ejemplo, base de datos, memoria caché distribuida); eso podría ser difícil de hacer en un contexto estático, dependiendo de cómo haya decidido compartir el estado.

0

I this article, Daniel Vaughan recomienda almacenar en caché los canales en un objeto de administrador Singleton pero nunca almacenar en la memoria caché un ChannelFactory. Hemos estado utilizando este enfoque sin éxito hasta ahora ...

Los beneficios de hacerlo son:

"Cuando el canal entra en un estado de fallo se elimina de la memoria caché y se recrea cuando se solicita la próxima ..."

  • negociación de seguridad es solamente realizado una vez.
  • Evita tener que cerrar explícitamente un canal en cada uso.
  • Podemos agregar funcionalidad de inicialización adicional.
  • Podemos fallar anticipadamente si el proxy no puede comunicarse con el servidor.
+1

Sé que es viejo ... pero, ¿no sería esto también el caché de ChannelFactory? Desde la liberación de la fábrica cierra sus canales. – Tracker1

Cuestiones relacionadas