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.
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. –