【发布时间】:2015-07-22 06:42:58
【问题描述】:
我有一个 Windows 服务,它在运行时将程序集加载到另一个 AppDomain 中。然后它执行它们并最终卸载 AppDomain。问题是插件中的执行方法是异步任务,我得到了 SerializationException,因为 Task 没有从 MarshalByRefObject 继承。
我将插件封装在一个继承自 MarshalByRefObject 的代理中,但我不知道如何摆脱 SerializationException?
public interface IPlugin : IDisposable
{
Guid GUID { get; }
string Name { get; }
string Description { get; }
Task Execute(PluginPanel panel, string user);
}
代理:
[Serializable()]
public class PluginProxy : MarshalByRefObject, IPlugin
{
private IPlugin m_Plugin;
public bool Init(string file)
{
Assembly ass = Assembly.Load(AssemblyName.GetAssemblyName(file));
if (ass == null || ass.GetTypes() == null || ass.GetTypes().Length == 0)
return false;
foreach (Type type in ass.GetTypes())
{
if (type.IsInterface || type.IsAbstract)
continue;
if (type.GetInterface(typeof(IPlugin).FullName) != null)
{
m_Plugin = (IPlugin)Activator.CreateInstance(type);
return true;
}
}
return false;
}
public Guid GUID { get { return m_Plugin.GUID; } }
public string Name { get { return m_Plugin.Name; } }
public string Description { get { return m_Plugin.Description; } }
// I debugged and found out the error happens AFTER m_Plugin.Execute
// so the method runs well, but the return back to the pProxy.Execute is throwing the SerializationException
public async Task Execute(PluginPanel panel, string user) { await m_Plugin.Execute(panel, user); }
}
以及加载程序集并获取 SerializationException 的方法:
AppDomainSetup setup = new AppDomainSetup();
// some setup stuff
AppDomain dom = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null, setup);
PluginProxy pProxy = (PluginProxy)dom.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().CodeBase, typeof(PluginProxy).FullName);
pProxy.Init(app.Apppath);
// I await the task later in code, because the user can cancel the execution
try { tExe = pProxy.Execute(panel, user.Username); }
catch (System.Runtime.Serialization.SerializationException e)
{
// runs always in this catch, even if no Exception from the plugin was thrown
}
catch (Exception e) { AddToErrorLog(panel.PanelName, e); }
finally
{
pProxy.Dispose();
AppDomain.Unload(dom);
}
也许我加载插件的整个概念是错误的?
【问题讨论】:
-
您的
Execute也返回Task。在你的包装器中同步等待Execute。 -
so 而不是 await m_Plugin.Execute(panel, user);我应该这样做:m_Plugin.Execute(panel, user);?或者这个:m_Plugin.Execute(panel, user).Wait();?但是 Wait() 会阻塞整个线程?
-
好的,看看 Stephen Toub post。你应该为你的情况做些小改动。
-
谢谢,我查看了帖子,但没有异步?他创建了一个返回 Task
的静态 Task 方法。但是我需要一个异步方法,所以我可以等待它并且我不能在异步任务方法中返回一些东西。我对整个异步事情很陌生,所以也许我只是忽略了一些东西。 -
您可以等待
DoWorkInOtherDomain返回的Task。
标签: c# asynchronous task appdomain