You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在MAUI项目中读取外部DLL并注册其中服务与接口的实现方法咨询

在MAUI项目中读取外部DLL并注册其中服务与接口的实现方法咨询

你好呀,针对你想要在MAUI项目里加载Resources/Raw目录下的LibraryA.dll,并自动注册其中所有服务与接口的需求,我整理了一套可行的实现方案,咱们一步步来:

第一步:读取并加载嵌入的DLL文件

因为你把LibraryA.dll放在了Resources/Raw目录下,这个目录的文件默认会被嵌入到MAUI项目的程序集中,所以首先得从资源里读取文件流,再加载成程序集。这里要注意资源的命名规则是「你的MAUI项目默认命名空间.Resources.Raw.LibraryA.dll」,记得替换成你自己项目的命名空间哦。

第二步:自动扫描并注册服务与接口

加载完程序集后,我们需要遍历里面的所有类型,筛选出那些实现了接口的非抽象类,然后把它们以「接口→实现类」的对应关系注册到DI容器里。

完整的MauiProgram代码示例

using System.Reflection;
using Microsoft.Extensions.DependencyInjection;

namespace YourMauiProjectNamespace; // 替换成你的项目命名空间

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiCommunityToolkit()
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                fonts.AddFont("Roboto-Regular.ttf", "RobotoRegular");
                fonts.AddFont("Roboto-Medium.ttf", "RobotoMedium");
                fonts.AddFont("Roboto-Light.ttf", "RobotoLight");
            });

        // 加载LibraryA.dll并注册服务
        try
        {
            // 1. 读取嵌入的DLL资源流
            var resourceName = "YourMauiProjectNamespace.Resources.Raw.LibraryA.dll"; // 替换成你的资源全名
            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
            if (stream == null)
            {
                throw new FileNotFoundException("未能找到嵌入的LibraryA.dll资源", resourceName);
            }

            // 2. 将流转换为字节数组并加载程序集
            var assemblyBytes = new byte[stream.Length];
            stream.Read(assemblyBytes, 0, assemblyBytes.Length);
            var libraryAssembly = Assembly.Load(assemblyBytes);

            // 3. 扫描程序集并注册所有服务与接口
            RegisterServicesFromAssembly(builder.Services, libraryAssembly);
        }
        catch (Exception ex)
        {
            // 这里可以根据需求添加异常处理逻辑,比如日志记录
            Console.WriteLine($"加载或注册LibraryA.dll时出错:{ex.Message}");
        }

        return builder.Build();
    }

    /// <summary>
    /// 从指定程序集中扫描并注册服务与接口
    /// </summary>
    private static void RegisterServicesFromAssembly(IServiceCollection services, Assembly assembly)
    {
        // 获取程序集中所有非抽象、非接口、非泛型的公共类型
        var serviceTypes = assembly.GetTypes()
            .Where(t => !t.IsAbstract && !t.IsInterface && !t.IsGenericTypeDefinition && t.IsPublic);

        foreach (var type in serviceTypes)
        {
            // 获取该类型实现的所有公共接口
            var interfaces = type.GetInterfaces()
                .Where(i => i.IsPublic);

            foreach (var @interface in interfaces)
            {
                // 这里默认用AddTransient,你可以根据需求改成AddScoped或AddSingleton
                services.AddTransient(@interface, type);
                Console.WriteLine($"已注册服务:{@interface.Name} → {type.Name}");
            }
        }
    }
}

一些需要注意的细节

  • 确认资源名称的正确性:如果不确定资源的全名,可以右键项目→查看项目文件,找到LibraryA.dll对应的<EmbeddedResource>节点,查看LogicalName属性的值。
  • 生命周期选择:示例中用的是AddTransient(每次请求都创建新实例),你可以根据业务需求替换成AddScoped(每个作用域内实例唯一)或AddSingleton(全局唯一实例)。
  • 依赖兼容性:确保LibraryA.dll里的服务类有公共的无参构造函数,或者构造函数的依赖项已经在DI容器中注册,否则会出现实例化失败的问题。

备注:内容来源于stack exchange,提问作者infinitesimal

火山引擎 最新活动