Autofac装配体扫描仪模式-自定义属性

时间:2018-06-24 13:32:06

标签: c# .net-core autofac

我想使用Assembly Scanner Pattern并向另一个程序集中的Attribute注册类

项目:AssemblyScanner

using System;

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

        }
    }
}

项目:Domian.Service

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

项目:UnitTests

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出现了问题

enter image description here

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

enter image description here

更新

这是更好的情况,现在我写这篇文章时得到了正确的对象

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;
        }
    }
}

1 个答案:

答案 0 :(得分: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

一些提示:

希望这会有所帮助。