我想使用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出现了问题
在这里我得到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;
}
}
}
答案 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
一些提示:
希望这会有所帮助。