C# .NET远程处理和HttpContext.Current
我们有一个插件系统,其中插件代码运行在与主进程分离的AppDomain上,使用.NET远程处理对象进行通信 有一个类类似于HttpContext.Current(它也有问题)(编辑,实际实现): 然后,我们有一个从MarshalByRefObject继承的通信对象:C# .NET远程处理和HttpContext.Current,c#,.net,remoting,appdomain,C#,.net,Remoting,Appdomain,我们有一个插件系统,其中插件代码运行在与主进程分离的AppDomain上,使用.NET远程处理对象进行通信 有一个类类似于HttpContext.Current(它也有问题)(编辑,实际实现): 然后,我们有一个从MarshalByRefObject继承的通信对象: public class CommunicatingClass : MarshalByRefObject, ICommunicatingClass { public void DoSomething() {
public class CommunicatingClass : MarshalByRefObject, ICommunicatingClass
{
public void DoSomething()
{
MyClass.Instance.DoSomething();
}
}
通信类是在主AppDomain上创建的,可以正常工作。然后是plugin类,它是在AppDomain上创建的,并给出了CommunicationClass的一个实例:
public class PluginClass
{
public void DoSomething(ICommunicatingClass communicatingClass)
{
communicatingClass.DoSomething();
}
}
问题是,即使CommunicationClass驻留在主appdomain上(通过即时窗口验证),所有静态数据(如MyClass.Instance和HttpContext.Current)都已消失且为空。我感觉MyClass.Instance是从插件AppDomain中检索出来的,但我不确定如何解决这个问题
我看到另一个问题建议使用RemotingServices.Marshal
,但这似乎没有帮助,或者我用错了。有没有一种方法可以让CommunicationClass像主AppDomain中的任何其他类一样访问所有静态方法和属性
编辑:
PluginClass的实例如下所示:
public static PluginClass Create()
{
var appDomain = GetNewAppDomain();
var instance = (PluginClass)appDomain.CreateInstanceAndUnwrap(assembly, type);
instance.Communicator = new CommunicatingClass();
return instance;
}
编辑2:
可能已经找到了问题的根源。实例存储在HttpContext.Current.Items中(请参见上面的编辑)
有没有办法让HttpContext.Current访问正确的HttpContext?我仍然想知道为什么,即使它是在HttpContext中运行的。Current的AppDomain,CommunicationingClass.DoSomething,在调用MyClass.Instance时,从PluginClass的AppDomain检索内容(如果有意义的话)。我相信你也需要从MarshallByRefObject派生MyClass。所以我的同事和我解决了这个问题,最后,在Reflector的帮助下 主要问题是当通过远程调用访问HttpContext.Current时,它是空的 HttpContext.Current属性存储在一个有趣的庄园中。通过几个嵌套的setter,您可以到达
CallContext.HostContext
。这是CallContext
上的静态对象属性
设置CallContext时,它首先检查该值是否为
- 如果是,则将该值存储在当前线程的
中LogicalCallContext
- 如果不是,则将该值存储在当前线程的
中不合逻辑的callcontext
HttpContext
不是一个ILogicalThreadAffinitive
,因此它存储在iLogicalCallContext
中
然后是远程处理。 我们没有深入研究它的源代码,但它的功能是从其他函数推断出来的 当从不同的AppDomain对远程对象进行调用时,调用不会直接代理到在完全相同的执行上下文中运行的原始线程 首先,原始线程的
ExecutionContext
(包含HttpContext.Current
)通过ExecutionContext.Capture
(稍后将详细介绍)捕获
然后,从Capture
返回的ExecutionContext
作为第一个参数传递给ExecutionContext。运行,本质上形成代码:
Delegate myRemoteCall; //Assigned somewhere else in remoting
ExecutionContext.Run(ExecutionContext.Capture(), x => { myRemoteCall() }, null);
然后,完全透明地访问远程对象中的代码
不幸的是,HttpContext.Current
未在ExecutionContext.Capture()中捕获
这里是不合逻辑的调用上下文
和逻辑调用上下文
之间的本质区别
Capture
创建一个全新的ExecutionContext
,基本上将所有成员(如LogicalCallContext
)复制到新对象中。但是,它不会复制不合逻辑的调用上下文
因此,由于HttpContext
不是iLogicThreadAffinative
,因此它不能被ExecutionContext.Capture
捕获
解决方案?
HttpContext不是MarshallByRefObject或[Serializable](可能是出于正当理由),因此无法将其传递到新的AppDomain
但是,它可以毫无问题地跨执行上下文
因此,在主AppDomain的MarshallByRefObject(作为另一个AppDomain的代理)中,在构造函数中为其提供HttpContext.Current
的实例
然后,在新对象的每个方法调用中(很遗憾),运行:
它将毫无问题地被设定。由于HttpContext.Current与ExecutionContext
的IllogicalCallContext
绑定,因此它不会渗入到ASP.NET可能创建的任何其他线程中,并将在释放副本ExecutionContext
时被清除
(不过,我在这一点上可能大错特错。这都是猜测和反思)如果你不知道:远程处理已经被弃用,取而代之的是WCF。如果你在PluginClass应用程序域中包含用于获取对CommunicationClass的引用的代码,可能会有所帮助。@John Saunders,WCF如何与跨应用程序域通信协同工作?当客户机和服务器分开时,这是有意义的,但在这种情况下,它似乎不像透明的远程代理那么容易。我从来没有使用过WCF,只是看看它。@Snea:它很管用。它完全取代了远程处理。@John Saunders,您是否有关于如何使用远程处理将跨appdomain通信迁移到WCF的文章或其他问题,或者我应该问另一个这样的问题?是的,所有依赖于对远程对象的特定引用的类(即本例中的单例类)还需要从MarshallByRefObject
扩展,否则它们会在应用程序域的另一端丢失
Delegate myRemoteCall; //Assigned somewhere else in remoting
ExecutionContext.Run(ExecutionContext.Capture(), x => { myRemoteCall() }, null);
private HttpContext _context;
private void SyncContext()
{
if(HttpContext.Current == null)
HttpContext.Current = _context;
}