Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 其他程序集的依赖项注册器_C#_.net_Asp.net Mvc 4_Dependency Injection_Autofac - Fatal编程技术网

C# 其他程序集的依赖项注册器

C# 其他程序集的依赖项注册器,c#,.net,asp.net-mvc-4,dependency-injection,autofac,C#,.net,Asp.net Mvc 4,Dependency Injection,Autofac,我有一个关于受抚养人登记的简单问题 我正在开发一个全新的web应用程序,它使用带有Autofac容器的引擎上下文范例。对于解决方案中的任何库,我都有一个类实现了idependencyregister,它实现了一个通用的Register方法,这是因为在一些接口和组件的特定实现中添加了一个容器 这样,一个基本核心库(在应用程序启动时运行)提供了一个RegisterDependencies方法,该方法可以查找每个正在执行的程序集,以发现应用程序使用的所有DDL,并将它们注册到Autofac容器中 提供

我有一个关于受抚养人登记的简单问题

我正在开发一个全新的web应用程序,它使用带有Autofac容器的引擎上下文范例。对于解决方案中的任何库,我都有一个类实现了
idependencyregister
,它实现了一个通用的
Register
方法,这是因为在一些接口和组件的特定实现中添加了一个容器

这样,一个基本核心库(在应用程序启动时运行)提供了一个
RegisterDependencies
方法,该方法可以查找每个正在执行的程序集,以发现应用程序使用的所有DDL,并将它们注册到Autofac容器中

提供此行为的代码是:

 builder = new ContainerBuilder();
        var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
        var drInstances = new List<IDependencyRegistrar>();
        foreach (var drType in drTypes)
            drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
        //sort
        drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
        foreach (var dependencyRegistrar in drInstances)
            dependencyRegistrar.Register(builder, typeFinder, config);
        builder.Update(container);
问题是:当我在mysolution中添加MVC项目(前端)时,我只引用了直接访问库(服务层和一些基础结构组件),而没有引用数据层组件和其他DLL。由于MVC没有直接引用某些深层库,因此我的引擎上下文没有看到其他子组件,也没有在Autofac容器上注册它们,导致

“无注册服务”

执行时对其发出显式请求时发生异常

如果我从MVC项目中添加对任何库的引用,整个系统都可以工作,但是,对于分层架构的应用程序,这不是一个最佳实践:我的MVC不需要了解数据层或其他低层服务

但是,通过这种方式,不会发现任何可执行性,因此不再注册依赖项


在不直接引用主MVC项目中的所有组件的情况下,解决这种情况的最佳方法是什么?

Autofac文档中描述了您尝试执行的组件扫描,请查看。基本上,要获取IIS托管应用程序中的所有程序集,您需要以下代码:

var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
另外,在您应该设置的解决方案属性中,该Web项目“依赖”于所有其他项目。它将确保所有其他的图书馆都是在Web之前建立的。它不会在这些程序集之间添加任何引用

然后,在应用程序启动期间,您应该在bin文件夹中搜索程序集并注册每个程序集模块,如下所示:

var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterControllers(typeof(MvcApplication).Assembly);

var libFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/bin"));
var libFiles = libFolder.GetFiles("*.dll", SearchOption.AllDirectories);
foreach (var lib in libFiles)
{
     var asm = Assembly.LoadFrom(lib.FullName);
     containerBuilder.RegisterAssemblyModules(asm);
}

var container = containerBuilder.Build();
您可能希望在
libFolder.GetFiles()
中添加一些过滤器,以便仅检索程序集,而不是全部从bin中检索

如果您的其他程序集包含Mvc控制器,您应该了解如何管理这种情况(请参见
初始值设定项
class)。基本上,在应用程序的预启动阶段,您需要将程序集添加到
BuildManager
。否则,上面的代码应该可以正常工作。

如果您正在从事一个非web的项目,那么我的答案可能会有所帮助

在Ioc类中添加一个方法,即:

    public static void SetIocForTesting(bool forUnitTesting)
    {
        _testContext = forUnitTesting;
    }
示例容器设置代码,委托将组件加载到生成器中的责任。i、 e GetModules():

扫描程序集时,打开testContext变量:

    private static IEnumerable<Assembly> GetModules()
    {
        if (_testContext)
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        var currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (currentPath == null)
        {
            throw new NullReferenceException("Unable to build the container because currentPath variable is null.");
        }
        // XXXX = assign a wild card
        var libFolder = new DirectoryInfo(currentPath);
        var libFiles = libFolder.GetFiles("XXXX.*.dll", SearchOption.TopDirectoryOnly);
        return libFiles.Select(lib => Assembly.LoadFrom(lib.FullName)).ToList();
    }
。。您有一个切换IoC的方法,以确保它与测试项目引用和加载的所有程序集正确工作。上面的方法存在于我用于BDD风格单元测试的抽象基类中

您的测试项目通常会引用大量程序集,这意味着解析服务的成功率更高

最后,对于非单元测试代码,添加一个静态构造函数:

static IocProvider()
{
    _testContext = false;
}
这将确保生产代码的默认工作流程


请随意使用上述格式,以满足您的需要;我希望上面的问题和答案对我有所帮助。

非常感谢你。我很快就会尝试这个,我保证会给你一个关于你答案的反馈。很抱歉,tdragon,你的解决方案不起作用:如果我删除对我的子层库(例如,DAL)的直接引用,容器就不会注册它。问题是,如果MVC项目没有引用这些库,这些库就没有复制到bin目录,因此,以这种方式,GetReferencedAssembly无法扫描它,也无法注册。我认为,问题是从项目配置内部开始的。我怎么能告诉VisualStudio复制解决方案的任何库,而不考虑主项目引用了这样的库?非常感谢@DanielGrandis没事,现在我明白你的意思了。是-您必须自己将所有DLL复制到bin。我认为最好的方法是在每个.csproj中使用生成后操作来复制这些文件-您可以使用Windows的xcopycommand@DanielGrandis我编辑了我的答案以反映你的情况。我发现这个问题可能是由另一个问题引起的。我的DAL库没有被模型库(模型类和服务类的混合)引用,但已配置为反向依赖。我的模型库有一个DAL接口,DAL项目引用模型,实现这些接口。因此,依赖项是:MVC-->模型我在autofac和控制台应用程序中遇到了完全相同的问题。对于web项目来说似乎更容易,但对于非web项目,我找不到一个好方法来检测和加载所有可传递的依赖项。
    public static void SetIocForTesting(bool forUnitTesting)
    {
        _testContext = forUnitTesting;
    }
    public static IContainer Container
    {
        get
        {
            if (_container != null)
            {
                return _container;
            }

            var builder = new ContainerBuilder();

            foreach (var lib in GetModules())
            {
                builder.RegisterAssemblyModules(lib);
            }

            _container = builder.Build();
            return _container;
        }
    }
    private static IEnumerable<Assembly> GetModules()
    {
        if (_testContext)
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        var currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (currentPath == null)
        {
            throw new NullReferenceException("Unable to build the container because currentPath variable is null.");
        }
        // XXXX = assign a wild card
        var libFolder = new DirectoryInfo(currentPath);
        var libFiles = libFolder.GetFiles("XXXX.*.dll", SearchOption.TopDirectoryOnly);
        return libFiles.Select(lib => Assembly.LoadFrom(lib.FullName)).ToList();
    }
    protected virtual void GivenThat()
    {
        IocProvider.SetIocForTesting(true);
    }
static IocProvider()
{
    _testContext = false;
}