【问题标题】:Autofac Assembly Scanner Pattern - Custom AttributeAutofac 程序集扫描仪模式 - 自定义属性
【发布时间】:2018-06-24 13:32:06
【问题描述】:

我想使用程序集扫描器模式并使用另一个程序集的属性注册类

项目:AssemblyScanner

using System;

namespace AssemblyScanner
{
    public class RegisterScope : Attribute
    {
        public RegisterScope()
        {

        }
    }
}

项目:Domian.Service

namespace Domain.Service.Test
{
    [RegisterScope]
    public class CarService
    {
    }
}

项目:单元测试

using AssemblyScanner;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Domain.Service.Test;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Xunit;

namespace UnitTests
{
    public class AssemblyScannerTests
    {
        [Fact]
        public void AssemblyScannerTest()
        {
            var t = AssemblyScannerPattern().GetService<CarService>();

            //AssemblyScannerPattern -> https://stackoverflow.com/questions/33811015/autofac-how-to-load-assemblies-that-are-referenced-but-not-directly-used
            //Other Example -> https://www.codeproject.com/Articles/1201502/Dependency-Injection-in-ASP-NET-Web-API-using-Auto
        }

        public AutofacServiceProvider AssemblyScannerPattern()
        {
            var serviceCollection = new ServiceCollection();

            ContainerBuilder builder = new ContainerBuilder();

            string[] assemblyScanerPattern = new[] { @"Domain.Service*.dll" };

            // Make sure process paths are sane...
            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

            //  begin setup of autofac >>

            // 1. Scan for assemblies containing autofac modules in the bin folder
            List<Assembly> assemblies = new List<Assembly>();
            assemblies.AddRange(
                Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories)
                         .Where(filename => assemblyScanerPattern.Any(pattern => Regex.IsMatch(filename, pattern)))
                         .Select(Assembly.LoadFrom)
                );

            foreach (var assembly in assemblies)
            {
                builder.RegisterAssemblyTypes(assembly)
                    .AsImplementedInterfaces();
            }

            foreach (var assembly in assemblies)
            {
                foreach (var attributeClass in assembly.ExportedTypes)
                {
                    foreach (var registerScope in attributeClass.CustomAttributes.Where(s => s.AttributeType.Name.Contains("RegisterScope")))
                    {
                          var importedClassFromAssembly = GetInstance(attributeClass.Namespace + "." + attributeClass.Name);

                          //builder.RegisterType<importedClassFromAssembly.GetType>().As(importedClassFromAssembly);
                    }
                }

            }

            var container = builder.Build();

            var serviceProvider = new AutofacServiceProvider(container);

            return serviceProvider;
        }

        public object GetInstance(string strFullyQualifiedName)
        {
            Type type = Type.GetType(strFullyQualifiedName);
            if (type != null)
                return Activator.CreateInstance(type);
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = asm.GetType(strFullyQualifiedName);
                if (type != null)
                    return Activator.CreateInstance(type);
            }
            return null;
        }
    }
}

我找到了属性为“RegisterScope”的类,但我遇到了 builder.RegisterType 的问题

在这里我得到 null 但我想得到实例类

更新

当我写这篇文章时,我现在得到正确的对象会更好

builder.RegisterInstance(importedClassFromAssembly).As<CarService>();

但我想要这样的东西 - 错误

builder.RegisterInstance(importedClassFromAssembly).As<importedClassFromAssembly.GetType>();

我也试试这个(但这在 GetService() 中给了我 null;)

builder.RegisterInstance(importedClassFromAssembly).As<dynamic>();

当前代码存在最后一个小问题

using AssemblyScanner;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Domain.Service.Test;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Xunit;

namespace UnitTests
{
    public class AssemblyScannerTests
    {
        [Fact]
        public void AssemblyScannerTest()
        {
            var t = AssemblyScannerPattern().GetService<CarService>();

            //AssemblyScannerPattern -> https://stackoverflow.com/questions/33811015/autofac-how-to-load-assemblies-that-are-referenced-but-not-directly-used
            //Other Example -> https://www.codeproject.com/Articles/1201502/Dependency-Injection-in-ASP-NET-Web-API-using-Auto
        }

        public AutofacServiceProvider AssemblyScannerPattern()
        {
            var serviceCollection = new ServiceCollection();

            ContainerBuilder builder = new ContainerBuilder();

            string[] assemblyScanerPattern = new[] { @"Domain.Service*.dll" };

            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

            List<Assembly> assemblies = new List<Assembly>();
            assemblies.AddRange(
                Directory.EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories)
                         .Where(filename => assemblyScanerPattern.Any(pattern => Regex.IsMatch(filename, pattern)))
                         .Select(Assembly.LoadFrom)
                );

            foreach (var assembly in assemblies)
            {
                foreach (var attributeClass in assembly.ExportedTypes)
                {
                    if(attributeClass.CustomAttributes.Where(s => s.AttributeType.Name.Contains("RegisterScope")).Any())
                    {
                        var importedClassFromAssembly = GetInstance(attributeClass.FullName);

                        builder.RegisterInstance(importedClassFromAssembly).As<CarService>();
                    }
                }
            }

            var container = builder.Build();

            var serviceProvider = new AutofacServiceProvider(container);

            return serviceProvider;
        }

        public object GetInstance(string strFullyQualifiedName)
        {
            Type type = Type.GetType(strFullyQualifiedName);
            if (type != null)
                return Activator.CreateInstance(type);
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = asm.GetType(strFullyQualifiedName);
                if (type != null)
                    return Activator.CreateInstance(type);
            }
            return null;
        }
    }
}

【问题讨论】:

    标签: c# .net-core autofac


    【解决方案1】:

    如果我理解你的例子,你应该可以这样做:

    foreach (var assembly in assemblies) {
        foreach (var attributeClass in assembly.ExportedTypes) {
              if (attributeClass.CustomAttributes.Any(s => s.AttributeType.Name.Contains("RegisterScope"))) {
                  builder.RegisterType(attributeClass).AsSelf();
              }
         }
    }
    

    Autofac 将为您进行实例化,您可能需要添加“.SingleInstance()”以确保只提供一个实例。

    另一种解决方案,在我看来更好,是使用 Autofac 本身的程序集扫描:

    foreach (var assembly in assemblies) {
        builder
            .RegisterAssemblyTypes(assembly)
            .Where(t => t.CustomAttributes.Any(s => s.AttributeType.Name.Contains("RegisterScope")))
            .AsSelf();
    }
    

    在此处阅读更多信息:http://autofaccn.readthedocs.io/en/latest/register/scanning.html

    一些提示:

    希望这会有所帮助。

    【讨论】:

    • 我实际上在一个库上工作,它基于我为 Greenshot 编写的 Autofac,以简化插件的使用。 github.com/dapplo/Dapplo.Addons 文档上还需要做很多工作...
    • 非常感谢我接受了你的回答并给了你积分。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多