How to limit the scope of a logical call context
I have placed some data on the call context (CallContext.SetData(key,data)
) where data is of a type that implements ILogicalThr开发者_高级运维eadAffinative
. The reason that it implements ILogicalThreadAffinative is that it must be shared across multiple threads in the current application.
However, the application also makes remote calls to another service, and this is where the problem comes in. My ILogicalThreadAffinative implementation is not serializeable and should not be. Even if I were to mark it serializable, the remote application does not have access to the assembly in which the type is declared so it would not be able to deserialize it.
So how do I share call context data within my application (AppDomain) but not with every external application it happens to need to talk to?
Ultimately I solved this by implementing a custom IMessageSink which I inserted before the formatter sink on the client side of the remoting call. The sink strips out the call context data before it goes across the wire. Below is the relevant method.
private static void SanitizeCallContext(IMessage msg)
{
var callContext = msg.Properties["__CallContext"] as LogicalCallContext;
if (callContext == null) return;
var sanitizedContext = (LogicalCallContext) callContext.Clone();
var prop = typeof (LogicalCallContext).GetProperty("Datastore",
BindingFlags.Instance | BindingFlags.NonPublic);
var dataStore = (Hashtable) prop.GetValue(sanitizedContext, null);
foreach (var key in dataStore.Keys.Cast<string>().ToArray())
sanitizedContext.FreeNamedDataSlot(key);
msg.Properties["__CallContext"] = sanitizedContext;
}
I don't especially like this solution. It seems more than a little hackish, but it is the best solution I have been able to come up with.
My understanding, which might be wrong, is that putting data in the CallContext is sufficient to cause it to be flowed across multiple threads. Implementing ILogicalThreadAffinative (or putting the data into the CallContext via LogicalSetData) is only required if you want it to flow "automatically" across AppDomains. So it seems that if you put your data in the CallContext but don't implement ILogicalThreadAffinative it should do what you want (flow within your application but NOT across Appdomains)?
Here are some links that I found regarding CallContext and ILogicalThreadAffinative (or LogicalSetData):
http://social.msdn.microsoft.com/forums/en-US/netfxremoting/thread/aec8dda5-102e-44eb-9a41-0a5d8b8b96e9
Another link that apparently references the information from the above link: http://dotnetmustard.blogspot.com/2008/08/identifying-differences-between.html
(See Nicko Cadell's reply in this link for an explanation of how log4net uses CallContext):
http://www.l4ndash.com/Log4NetMailArchive%2Ftabid%2F70%2Fforumid%2F1%2Fpostid%2F15288%2Fview%2Ftopic%2FDefault.aspx
Good luck!
精彩评论