gpt4 book ai didi

c# - AppDomain 等待异步任务防止 SerializationException

转载 作者:太空狗 更新时间:2023-10-29 23:38:03 25 4
gpt4 key购买 nike

我有一个 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);
}

也许我加载插件的整个概念是错误的?

最佳答案

感谢 Hamlet Hakobyan 和 Stephen Toub 的帖子,我想我能够解决问题。

我替换了来电者的线路

 try { tExe = pProxy.Execute(panel, user.Username); }

 tExe = DoWorkInOtherDomain(pProxy, panel, user.Username);

和 DoWorkInOtherDomain 方法:

private Task DoWorkInOtherDomain(PluginProxy pProxy, PluginPanel panel, string user)
{
var ch = new MarshaledResultSetter<string>();
pProxy.Execute(panel, user, ch);
return ch.Task;
}

最后是代理类:

 Task.Run(() =>
{
try
{
m_Plugin.Execute(panel, user).Wait();
}
catch (AggregateException e)
{
if (e.InnerExceptions != null)
foreach (Exception ein in e.InnerExceptions)
AddToErrorLog(panel.PanelName, ein);
}
catch (Exception e) { AddToErrorLog(panel.PanelName, e); }
finally { ch.SetResult(AppDomain.CurrentDomain.FriendlyName); }
});

我需要调用 Wait()

m_Plugin.Execute(panel, user).Wait();

它从插件中捕获异常,所以一切正常。 Wait() 调用应该只阻塞 Task.Run 而不是其他任务。

谁能告诉我这是一个好的解决方案还是我应该改变什么?我不需要结果,所以我只是这样做:

 ch.SetResult(AppDomain.CurrentDomain.FriendlyName);

因为没有结果我不知道该怎么做。

关于c# - AppDomain 等待异步任务防止 SerializationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31555702/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com