如何在不引用程序集(或其中的类型)的情况下使用 Ninject Conventions 扩展

发布于 2024-09-28 20:34:43 字数 3165 浏览 0 评论 0原文

提前抱歉问了这么长的问题,之所以这么长,是因为我一整天都在研究这个问题。

一般问题:

我有一个 ASP.Net MVC2 应用程序,其中包含以下项目:MyApp.Web、MyApp.Services、MyApp.Data。

我们对接口进行编码并利用 Ninject 2 进行 DI/IoC。

然而,我对打字感到非常厌倦(并且忘记打字):

Bind<ISomeService>.To<SomeService>;

因此,了解 Ninject.Extensions.Convensions,我尝试使用它来自动扫描和注册模块以及简单的依赖项类型 IXxxx => xxx。

我尝试过的方法有效(但还不够):

我可以使用以下代码来设置 Ninject,一切似乎都按预期连接起来。

    public static IKernel Initialize()
    {
        var kernel = new StandardKernel();

        kernel.Scan(a => {
                        a.FromAssemblyContaining<MyApp.Data.SomeDataClass>();
                        a.FromAssemblyContaining<MyApp.Services.SomeServiceClass>();
                        a.AutoLoadModules();
                        a.BindWithDefaultConventions();
                        a.InTransientScope();
                    });

        return kernel;
    }

我想要实现的目标是:

但是......我想以我认为受支持的方式更进一步,但我似乎无法让它发挥作用。

由于我们的 MyApp.Web 项目根本不(直接)使用 MyApp.Data 中的任何内容,因此我试图避免引用 MyApp.Data。使用上面的代码,我必须从MyApp.Web引用MyApp.Data,因为编译时引用了SomeDataClass。

我更愿意指定 Ninject 扫描和注册的程序集的名称。似乎 Conventions 扩展通过采用字符串(或可枚举字符串)的 From 重载来支持这一点。

我尝试过的以及它是如何中断的:

所以,我尝试了 From 重载的几种变体:

    public static IKernel Initialize()
    {
        var kernel = new StandardKernel();

        kernel.Scan(a => {
                        a.From("MyApp.Data");
                        a.From("MyApp.Services.dll");
                        a.From("AnotherDependency, Version=1.0.0.0, PublicKeyToken=null"); //etc., etc. with the From(...)'s
                        a.AutoLoadModules();
                        a.BindWithDefaultConventions();
                        a.InTransientScope();
                    });

        return kernel;
    }

但是我收到 FileNotFoundExceptions 并显示如下消息:

无法加载文件或程序集 '文件:///C:\程序文件 (x86)\通用文件\微软 共享\DevServer\10.0\MyApp.Data' 或其依赖项之一。系统 找不到该文件 指定。":"file:///C:\Program Files (x86)\通用文件\微软 共享\DevServer\10.0\

我发现自己试图解决这个问题:

我已经检查了 Ninject.Extensions.Conventions 的源代码,我承认我完全迷失了它应该如何工作,但是我可以看到它在做什么。

当我们调用各种 FromXXX 方法时,程序集扫描器会构建要扫描的程序集列表。

当我调用 From("AssemblyName") 方法时,它首先检查列表中是否已包含 assembly.AssemblyName.Name 等于我传入的名称的任何程序集(并且 AssemblyName.Name 是简单名称,即 MyApp.Data,根据 MSDN)。

Flow 通过几个不重要的方法,最终到达 FindAssemblies 方法。此方法采用我传入的名称(我们已经看到它应该是一个简单程序集名称)。然后,它创建一个新的 AssemblyName,并将我们传入的名称用作 AssemblyName.CodeBase。

然后,它尝试将程序集加载到临时 AppDomain 中。这是因上述异常而失败的步骤。

显然,它搜索的路径是错误的,但我无法通过 From() 方法提供路径。那也行不通。

我已经尝试了其他一些 FromXXX 方法,但我一无所获,并且已经在这方面花费了太多时间。 FromAssembliesInPath 和 FromAssembliesMatching 也不起作用,因为它再次在完全错误的目录中搜索。

呃..又是什么问题:

谁能解释一下如何让 Ninject Conventions 按名称加载程序集,而不创建对程序集的引用并通过指定包含的类型加载它?请。

我已经搜索了 Ninject google group 的各个页面,并且阅读了它只有(看起来)相关文档并且无法解决它..还。

Sorry in advance for the long question, it's long because I've been digging at this all day.

The general problem:

I have an ASP.Net MVC2 application with the following projects: MyApp.Web, MyApp.Services, MyApp.Data.

We code to interfaces and utilize Ninject 2 for DI/IoC.

However, I'm getting awfully tired of typing (and forgetting to type):

Bind<ISomeService>.To<SomeService>;

So, knowing about Ninject.Extensions.Convensions, I have attempted to use it to automatically scan and register modules and simple dependencies of the type IXxxx => Xxxx.

What I tried that works (but isn't quite enough):

I can use the following code to setup Ninject, and everything seems to get wired up as expected.

    public static IKernel Initialize()
    {
        var kernel = new StandardKernel();

        kernel.Scan(a => {
                        a.FromAssemblyContaining<MyApp.Data.SomeDataClass>();
                        a.FromAssemblyContaining<MyApp.Services.SomeServiceClass>();
                        a.AutoLoadModules();
                        a.BindWithDefaultConventions();
                        a.InTransientScope();
                    });

        return kernel;
    }

What I want to accomplish instead:

However ... I'd like to take this a bit further in a way I think is supported, but I cannot seem to get it working.

Since our MyApp.Web project uses nothing at all (directly) from MyApp.Data, I am trying to avoid a reference to MyApp.Data. With the above code, I must reference MyApp.Data from MyApp.Web because of the compile time reference to SomeDataClass.

I would prefer to specify the name of an assembly for Ninject to scan and register. It seems the Conventions extension supports this through the From overloads that take a string (or enumerable of strings).

What I tried and how it breaks:

So, I've tried several variations on the From overloads:

    public static IKernel Initialize()
    {
        var kernel = new StandardKernel();

        kernel.Scan(a => {
                        a.From("MyApp.Data");
                        a.From("MyApp.Services.dll");
                        a.From("AnotherDependency, Version=1.0.0.0, PublicKeyToken=null"); //etc., etc. with the From(...)'s
                        a.AutoLoadModules();
                        a.BindWithDefaultConventions();
                        a.InTransientScope();
                    });

        return kernel;
    }

But I receive FileNotFoundExceptions with a message like:

Could not load file or assembly
'file:///C:\Program Files
(x86)\Common Files\Microsoft
Shared\DevServer\10.0\MyApp.Data'
or one of its dependencies. The system
cannot find the file
specified.":"file:///C:\Program Files
(x86)\Common Files\Microsoft
Shared\DevServer\10.0\

What I've found trying to solve this myself:

I've checked out the source for Ninject.Extensions.Conventions, and I'll admit I get totally lost as to how this is supposed to work, but I can see what it is doing.

The assembly scanner builds up a list of assemblies to scan as we call various FromXXX methods.

When I call the From("assemblyName") method, it first checks if the list already contains any assemblies where the assembly.AssemblyName.Name equals the name I passed in (and AssemblyName.Name is the simple name, i.e. MyApp.Data, according to MSDN).

Flow passes through a couple unimportant methods, landing in the FindAssemblies method. This method takes the name I passed in (which we already saw is supposed to be a simple assembly name). It then creates a new AssemblyName, with our passed in name used as the AssemblyName.CodeBase.

Then, it attempts to Load the assembly into a temporary AppDomain. This is the step that fails with the above exception.

Obviously, the path it's searching is wrong, but I cannot supply a path through the From() method. That doesn't work either.

I've tried some of the other FromXXX methods, but I've gotten nowhere and spent too much time on this already. The FromAssembliesInPath and FromAssembliesMatching also do not work because, again, it is searching in the completely wrong directory.

Uh .. what was the question again:

Can anyone explain how to get Ninject Conventions to load assemblies by name, without creating a reference to the assembly and loading it by specifying a contained type? Please.

I've already searched through pages and pages of the Ninject google group, and I've read it's only (so it seems) relevant documentation and have not been able to solve it .. yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷︶言冷语的世界 2024-10-05 20:34:43

这个问题在邮件列表上得到了回答。 http://groups.google.com/group/ninject/browse_thread/thread/a7f2163e060a6d64

简而言之:

  1. Form(path) 采用工作目录的相对路径或绝对路径。
  2. 程序集在加载到加载上下文时必须驻留在探测路径中,以避免切换加载上下文时出现其他问题。
  3. 开发服务器使一切变得复杂,因为它将所有程序集复制到它们自己的目录中,这使得无法使用调用程序集来创建路径。这意味着 Web 应用程序使用开发服务器的唯一方法。
  4. 我们将在未来版本中添加对程序集的完整限定名称的支持,以使这变得更容易。

This question was answerd on the mailing list. http://groups.google.com/group/ninject/browse_thread/thread/a7f2163e060a6d64

In Short:

  1. Form(path) takes a path either relative from the working directory or absolute
  2. The assembly must reside in a probing path as it is loaded into the load context to avoid other problems with switching the loading context.
  3. The development server makes all complicated as it copies all assemblies into their own directory, which makes it impossible to use the calling assembly to create the path. This means the only way for web apps using the development server.
  4. We will add support for full qualified names of assemblies in a future version to make this easier.
老街孤人 2024-10-05 20:34:43

我不确定这在您的示例中是否是一个拼写错误,但我确实注意到您写了

kernel.Scan(a => {
    a.From("MyApp.Data");
    // etc.
}

但不应该是

kernel.Scan(a => {
    a.From("MyApp.Data.dll")
    // etc.
});

因为如果我在示例项目中包含 .dll 部分,它就可以工作,但如果我将其省略我收到 FileNotFoundException。

I'm not sure if this is a typo in your example, but I did notice that you've written

kernel.Scan(a => {
    a.From("MyApp.Data");
    // etc.
}

But shouldn't that be

kernel.Scan(a => {
    a.From("MyApp.Data.dll")
    // etc.
});

Because if I include the .dll part in my example project it works, but if I leave it out I receive a FileNotFoundException.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文