Конфликт зависимостей при загрузке сборки
У меня возникли некоторые проблемы при попытке написать обработчик плагина.
У меня есть основное приложение "AppA", которое ссылается на "AssemblyX".
AppA также загружает несколько сборок плагинов, которые реализуют интерфейс "IPlugin". Тем не менее, эти плагины могут также ссылаться на "AssemblyX", и это может быть даже более старая версия.
Поэтому первоначальной проблемой был конфликт с AssemblyX, возникший при загрузке плагинов через Assembly.LoadFrom().
После небольшого исследования я попытался загрузить плагины в новый домен приложений. Само по себе это не решило проблему. Затем я создал класс ProxyDomain, унаследованный от MarshalByRefObject. Все еще нет радости.
Наконец, я сделал, чтобы сами плагины наследовали от MarshalByRefObject, что привело к большему успеху, но когда я попытался связать List с ListView, он пожаловался, что "System.MarshalByRefObject" не содержит свойства с именем "SomeProperty".
Пожалуйста, кто-нибудь может взглянуть на мой код и посмотреть, могут ли быть внесены какие-либо изменения:
public partial class WebForm1 : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
AssemblyX x = new AssemblyX();
x.GetStuff("a", "b");
lstConfig.DataSource = PluginLoader.Load(Path.Combine(PluginLoader.GetPluginFolderPath(), "ExamplePlugins.dll"));
lstConfig.DataBind();
}
}
public class PluginLoader
{
public static List<IPlugin> Load(string file)
{
var plugins = new List<IPlugin>();
ProxyDomain pd = new ProxyDomain();
Assembly ass = pd.GetAssembly(file);
try
{
AppDomainSetup adSetup = new AppDomainSetup();
string fileName = Path.GetFileName(file);
string path = file.Replace(fileName, "");
adSetup.ApplicationBase = path;
AppDomain crmAppDomain = AppDomain.CreateDomain("ProxyDomain", null, adSetup);
foreach (Type t in ass.GetTypes())
{
Type hasInterface = t.GetInterface(typeof(IPlugin).FullName, true);
if (hasInterface != null && !t.IsInterface)
{
IPlugin plugin = (IPlugin)crmAppDomain.CreateInstanceAndUnwrap(ass.FullName, t.FullName);
plugins.Add(plugin);
}
}
}
catch (Exception ex)
{
}
return plugins;
}
public class ProxyDomain : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
try
{
return Assembly.LoadFrom(assemblyPath);
}
catch (Exception ex)
{
throw ex;
}
}
}
public interface IPlugin
{
string SomeProperty { get; set; }
void DoSomething();
}
[Serializable]
public class ExamplePlugin : MarshalByRefObject, IPlugin
{
public string SomeValue
{
get
{
AssemblyX x = new AssemblyX(); // Referencing a previouus version of AssemblyX
return x.GetStuff("c");
}
set
{
}
}
public void DoSomething() { }
}
Примечание. PluginExamples.dll может содержать несколько классов плагинов.
1 ответ
Если я вас правильно понял, вы можете указать конкретные версии для AssemblyX, как это в вашем app.config:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="AssemblyX" publicKeyToken="3d67ed1f87d44c89" />
<codeBase version="3.0" href=".\ver30\AssemblyX.dll"/>
<codeBase version="5.0" href=".\ver50\AssemblyX.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Если токен открытого ключа отличается для версий, вам нужно будет указать 2 отдельные записи.