significado - wcf vs web api
¿Dónde almacenar datos para la llamada WCF actual? ¿Es seguro ThreadStatic? (2)
Descubrí que extrañamos los datos o el contexto actual cuando realizamos una llamada asíncrona con el cambio de múltiples hilos. Para manejar ese escenario, puede intentar usar CallContext. Se supone que debe usarse en .NET remoting, pero también debería funcionar en dicho escenario.
Establezca los datos en CallContext:
DataObject data = new DataObject() { RequestId = "1234" };
CallContext.SetData("DataSet", data);
Recuperando datos compartidos del CallContext:
var data = CallContext.GetData("DataSet") as DataObject;
// Shared data object has to implement ILogicalThreadAffinative
public class DataObject : ILogicalThreadAffinative
{
public string Message { get; set; }
public string Status { get; set; }
}
¿Por qué ILogicalThreadAffinative?
Cuando se realiza una llamada a un método remoto a un objeto en otro dominio de aplicación, la clase CallContext actual genera un LogicalCallContext que viaja junto con la llamada a la ubicación remota.
Solo los objetos que exponen la interfaz ILogicalThreadAffinative y se almacenan en CallContext se propagan fuera de AppDomain.
Mientras mi servicio se ejecuta, muchas clases necesitarán acceder a User.Current (esa es mi propia clase User). ¿Puedo almacenar _currentUser de forma segura en una variable [ThreadStatic]
? ¿WCF reutiliza sus hilos? Si ese es el caso, ¿cuándo limpiará los datos de ThreadStatic? Si usar ThreadStatic no es seguro, ¿dónde debería poner esos datos? ¿Hay algún lugar dentro de OperationContext.Current donde pueda almacenar ese tipo de datos?
Editar 14/12/2009: Puedo afirmar que usar una variable ThreadStatic no es seguro. Los subprocesos de WCF están en un grupo de subprocesos y la variable ThreadStatic nunca se reinicializa.
Hay una publicación post blog que sugiere implementar un IExtension<T>
. También puedes echar un vistazo a esta discussion .
Aquí hay una implementación sugerida:
public class WcfOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private WcfOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static WcfOperationContext Current
{
get
{
WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>();
if (context == null)
{
context = new WcfOperationContext();
OperationContext.Current.Extensions.Add(context);
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
Que podrías usar así:
WcfOperationContext.Current.Items["user"] = _currentUser;
var user = WcfOperationContext.Current.Items["user"] as MyUser;