2009-04-07 16 views
8

Mi aplicación utiliza el almacenamiento en caché de la empresa del lado del cliente; Me gustaría evitar escribir código para cada llamada almacenable en caché y me pregunté si existe una solución para que las llamadas del lado del cliente WCF puedan almacenarse en caché, incluso para llamadas asíncronas.¿Cableado del almacenamiento en caché del lado del cliente WCF?

se puede hacer esto con un "comportamiento" WCF o algún otro medio? Ejemplos de código?

Respuesta

0

Por desgracia, creo que tendrá que rodar su propia. No creo WCF tiene un mecanismo de almacenamiento en caché del lado del cliente incorporado.

La respuesta a this question también puede ayudar.

+0

Lo sé; Se puede hacer, simplemente no sé cómo implementar IOperationInvoker en un cliente (no servidor). Específicamente, no sé cómo codificar ApplyClientBehavior en IOperationBehaviour de modo que se invoque el método InvokeBegin en IOperationInvoker, en lugar del método predeterminado. –

-2

Si quieren almacenamiento en caché sin tener que implementar explícitamente en cada llamada de servicio, considerar el almacenamiento en caché Handler en el bloque de aplicación de inyección Política. Puede marcar sus llamadas con un atributo y el bloque de inyección de políticas manejará el almacenamiento en caché por usted.

http://msdn.microsoft.com/en-us/library/cc511757.aspx

+0

Estoy buscando una solución del lado del cliente, no una solución del lado del host. –

3

lo hice el otro día con los métodos de extensión genérica en el cliente de servicio WCF (DataServiceClient). Utiliza acciones y funciones para pasar las llamadas de ServiceClient reales. La sintaxis final de uso del cliente es un poco raro (si no te gusta lambdas), pero este método hace FaultException/Abortar embalaje y almacenamiento en caché:

public static class ProxyWrapper 
{ 
    // start with a void wrapper, no parameters 
    public static void Wrap(this DataServiceClient _svc, Action operation) 
    { 
     bool success = false; 

     try 
     { 
      _svc.Open(); 
      operation.Invoke(); 
      _svc.Close(); 

      success = true; 
     } 
     finally 
     { 
      if (!success) 
       _svc.Abort(); 
     } 
    } 

    // next, a void wrapper with one generic parameter 
    public static void Wrap<T>(this DataServiceClient _svc, Action<T> operation, T p1) 
    { 
     bool success = false; 

     try 
     { 
      _svc.Open(); 
      operation.Invoke(p1); 
      _svc.Close(); 

      success = true; 
     } 
     finally 
     { 
      if (!success) 
       _svc.Abort(); 
     } 
    } 

    // non-void wrappers also work, but take Func instead of Action 
    public static TResult Wrap<T, TResult>(this DataServiceClient _svc, Func<T, TResult> operation, T p1) 
    { 
     TResult result = default(TResult); 

     bool success = false; 

     try 
     { 
      _svc.Open(); 
      result = operation.Invoke(p1); 
      _svc.Close(); 

      success = true; 
     } 
     finally 
     { 
      if (!success) 
       _svc.Abort(); 
     } 

     return result; 
    } 
} 

En el lado del cliente, tenemos que llamarlos así:

internal static DBUser GetUserData(User u) 
    { 
     DataServiceClient _svc = new DataServiceClient(); 

     Func<int, DBUser> fun = (x) => _svc.GetUserById(x); 

     return _svc.Wrap<int, DBUser>(fun, u.UserId); 
    } 

Ver el plan aquí? Ahora que tenemos un conjunto genérico de contenedores para llamadas WCF, podemos usar la misma idea para inyectar algo de caché. Me puse "low tech" aquí y comencé a buscar cadenas para el nombre de la clave de caché ... Sin duda, podrías hacer algo más elegante con la reflexión.

public static TResult Cache<TResult>(this DataServiceClient _svc, string key, Func<TResult> operation) 
    { 
     TResult result = (TResult)HttpRuntime.Cache.Get(key); 

     if (result != null) 
      return result; 

     bool success = false; 

     try 
     { 
      _svc.Open(); 
      result = operation.Invoke(); 
      _svc.Close(); 

      success = true; 
     } 
     finally 
     { 
      if (!success) 
       _svc.Abort(); 
     } 

     HttpRuntime.Cache.Insert(key, result); 

     return result; 
    } 

    // uncaching is just as easy 
    public static void Uncache<T>(this DataServiceClient _svc, string key, Action<T> operation, T p1) 
    { 
     bool success = false; 

     try 
     { 
      _svc.Open(); 
      operation.Invoke(p1); 
      _svc.Close(); 

      success = true; 
     } 
     finally 
     { 
      if (!success) 
       _svc.Abort(); 
     } 

     HttpRuntime.Cache.Remove(key); 
    } 

Ahora acaba de llamar en su caché Lee y uncache en su Crear/Actualizar/eliminaciones:

// note the parameterless lambda? this was the only tricky part. 
    public static IEnumerable<DBUser> GetAllDBUsers() 
    { 
     DataServiceClient _svc = new DataServiceClient(); 

     Func<DBUser[]> fun =() => _svc.GetAllUsers(); 

     return _svc.Cache<DBUser[]>("AllUsers", fun); 
    } 

Me gusta este método porque no tenía que recodificar el lado del servidor nada, sólo mi Llamadas de proxy de WCF (que sin duda eran un poco frágiles/malolientes por haberse dispersado en todas partes).

Sustituto en sus propias convenciones de proxy WCF y procedimientos de almacenamiento en caché estándar, y ya está bueno para ir. También es mucho trabajo crear todas las plantillas de contenedor genérico, pero solo fui a dos parámetros y ayuda a que todas mis operaciones de almacenamiento en caché compartan una sola firma de función (por ahora). Avíseme si esto funciona para usted o si tiene alguna mejora.

0

similares a la solución anterior, echa un vistazo a http://www.acorns.com.au/blog/?p=85 (PolicyInjection de servicios WCF). Puede especificar la política para que coincida con su nombre de servicio.

Cuestiones relacionadas