asp.net C#中调用类方法前如何检查程序集是否存在

tquggr8v  于 2023-02-26  发布在  .NET
关注(0)|答案(2)|浏览(193)

我正在项目中使用两个支持DLL的应用程序。ClassLibrary1.dllClassLibrary2.dll。ClassLibrary2.dll是可选的,仅由ClassLibrary1.dll使用。应用程序具有显式导入DLL的功能。如果我将两个DLL导入应用程序,则一切正常。
当我不导入可选的ClassLibrary2.dll时,问题就出现了。
在应用程序启动时,我检查程序集是否存在:

var assemblyName = "ClassLibrary2.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var assembly = (from a in assemblies
                where a.FullName == assemblyName
                select a).SingleOrDefault();

// this IsClassLibrary2Exists property become true when the DLL exists
if (assembly != null)
{
    Props.IsClassLibrary2Exists = true;          
}

下面是我如何在ClassLibrary1中调用ClassLibrary2方法

if(Props.IsClassLibrary2Exists){
      ClassLibrary2.SpecialProduct.GetSpecialProduct(Id);
}

程序集不存在时出现错误:
“系统.IO.文件未找到异常:“未能加载文件或程序集”ClassLibrary2,版本=1.0.0.0,区域性=中性,PublicKeyToken=null“或它的某个依赖项。系统找不到指定的文件。”“

b1payxdu

b1payxdu1#

我同意Dai的评论,即根本问题是ClassLibrary1ClassLibrary2有一个硬编码的依赖关系,因此问题福尔斯在如何将其解耦上。
一种对我有效的方法是建立一个Interface类库,它只包含应用程序可能尝试使用的插件接口(但同时可能没有附加示例),插件服务器和客户端都可以引用它。

Interface类库

namespace Interface
{
    /// <summary>
    /// To be a plugin for this app requires IPlugin at minimum .
    /// </summary>
    public interface IPlugin { }
    public interface ISpecialProduct : IPlugin
    {
        string GetSpecialProduct(string id);
    }
}

类库1

SpecialProduct成员与ClassLibrary2解耦,因为它是接口而不是类。

using Interface; // But 'not' ClassLibrary2
namespace ClassLibrary1
{
    public class Product
    {
        public ISpecialProduct SpecialProduct { get; set; }
    }
}

类库2

using Interface; // The only dependency
namespace ClassLibrary2
{
    public class SpecialProduct : ISpecialProduct
    {
        public string GetSpecialProduct(string id) => Guid.NewGuid().ToString();
    }
}

测试(使用控制台应用程序进行概念验证)

可用的插件位于应用程序运行目录的Plugins子文件夹中。ClassLibrary2最初未被引用或加载。

using Interface;
using ClassLibrary1; // But 'not' ClassLibrary2
internal class Program
{
    static void Main(string[] args)
    {
        Console.Title = "Test optional lib";
        Assembly assySpecial;
        Product product = new Product(); // In ClassLibrary1

        #region N O T    L O A D E D
        // Try get assy (not strong named or picky about version)
        assySpecial =
            AppDomain
            .CurrentDomain
            .GetAssemblies()
            .FirstOrDefault(_ => _.GetName().Name.Equals("ClassLibrary2"));
        Debug.Assert(assySpecial == null, "Expecting assy not loaded");
        Debug.Assert(product.SpecialProduct == null, "Expecting null SpecialProduct");
        if(product.SpecialProduct == null)
        {
            Console.WriteLine("SpecialProduct is not loaded yet.");
        }
        #endregion N O T    L O A D E D

        #region L O A D
        var pluginPath = Path.Combine(
            AppDomain.CurrentDomain.BaseDirectory,
            "Plugins",
            "ClassLibrary2.dll");
        if(File.Exists(pluginPath)) 
        {
            Assembly.LoadFrom(pluginPath);
        }
        #endregion L O A D

        #region L O A D E D
        assySpecial =
            AppDomain
            .CurrentDomain
            .GetAssemblies()
            .FirstOrDefault(_ => _.GetName().Name.Equals("ClassLibrary2"));

        Debug.Assert(assySpecial != null, "Expecting assy loaded");

        if (assySpecial != null)
        {
            product.SpecialProduct = 
                (ISpecialProduct)
                Activator.CreateInstance(
                    assySpecial
                    .GetTypes()
                    .First(_ => _.Name.Equals("SpecialProduct")));
        }

        Console.WriteLine($"SpecialProduct: {product.SpecialProduct?.GetSpecialProduct("123")}");

        Console.ReadKey();
        #endregion L O A D E D
    }
}

rmbxnbpk

rmbxnbpk2#

要成功阻止一个程序集请求另一个程序集,您需要通过未执行的 * 方法 * 完成对“程序集2”的所有访问。使用if保护访问是不够的,因为整个方法需要首先进行JIT,这需要加载另一个程序集。
什么 * 可能 * 会起作用:

... 
   if (Props.IsClassLibrary2Exists)
       DoThingsWithLibrary2();
   ...

   void DoThingsWithLibrary2()
   {
     // access to Library2 feature must be scoped to methods
     // that are not executed
     ClassLibrary2.SpecialProduct.GetSpecialProduct(Id);
   }

请注意,以一种很难/不可能在运行时修复的方式使用“另一个库”是非常容易的-静态属性/构造函数可以在任何时候调用,因此从另一个库引用任何东西都会失败,从另一个库引用字段/属性/方法参数/返回使用类型甚至通过反射都会失败......以及许多其他情况。
如果可能的话,最好动态加载程序集并让它实现共享接口,这样您就可以将反射限制在示例化部分,但要通过强类型接口使用这些类。

相关问题