1

我们有一个使用 Ninject 进行 DI 的 ASP.NET Web API 应用程序。这非常适合使用。我们正在考虑的改进之一是能够根据某种唯一标识符交换每个请求的部分功能。

例子。两个客户使用我们的 restful api。两者都具有相同的功能。第三个客户已经为我们的 api 的超级版本付费。他提出请求,我们加载超级 dll 并将超级实现绑定到标准接口。

本质上,我希望看到的是我们能否加载一个 DLL 并使用 Web API 和 Ninject 为每个请求换出绑定。

编辑:

因此,对于原始问题,两个答案都是正确的,但我的意图不同,没有正确解释是我的错。我们拥有的是每个人都能获得的基础功能层。最重要的是,我们还能够基于每个客户实现覆盖此功能的自定义逻辑。此逻辑在 Azure Blob 存储中存储为 DLL。

我们想做的是,当客户提出请求时,获取 DLL,绑定所有自定义服务,然后使用这些新绑定为请求提供服务。

热插拔不是最好的方法吗?我们对 ninject 足够新,所以这可能是一个常见的事情,它的实现方式与我们正在考虑的不同。

对某些人来说,我们希望能够为每个客户提供自定义绑定服务。

编辑2:

我们对项目使用条件绑定,如果我们知道我们有替代实现,但在上面的场景中,直到我们获得客户信息并扫描我们不知道是否有替代绑定的 dll。我们甚至不知道是否有dll。

我们希望这样做,以便我们可以将文件放入而不是在项目中引用它。

4

3 回答 3

2

使用条件绑定:

Bind<IMyService>().To<MyService>();
Bind<IMyService>().To<MyServiceForVIPs>().When(ctx => CurrentPrincipalIsVIP());
于 2013-01-09T16:31:17.607 回答
2

我不介意您可以根据请求换出绑定。但是您可以做的是使用条件绑定。

示例 - 默认绑定:

protected override Ninject.IKernel CreateKernel()
{
    var kernel = new StandardKernel();

    kernel.Bind<IAuthorizationService>()
        .To<AuthorizationService>()
        .InRequestScope();

    kernel.Bind<IService>()
        .To<BasicService>();

    return kernel;
}

它将为一些基本用户和VIP 用户注入(在IService需要的地方) 。BasicServiceExtraService

有关条件绑定的各种方式的更多信息,请参阅Ninject-Contextual binding

编辑

我认为您仍然可以使用条件绑定。您只需将 传播IKernel到要从新 dll 注册组件的位置。例如,我在我global.asax的动态加载 dll 模块中有这个 - 它在应用程序启动时运行。

加载模块:

private void LoadAssemblies(IKernel kernel) {
    foreach (var fileName in Directory.GetFiles(Server.MapPath("~/App_Data"), "*.dll")) {
        Assembly loadedAssembly = Assembly.LoadFile(fileName);
        try {
            var moduleRegistrations = loadedAssembly.GetTypes()
                .Where(t => t.IsClass && t.IsAbstract == false && typeof (IMyModuleRegistration).IsAssignableFrom(t));

            foreach (var moduleRegType in moduleRegistrations ) {
                IMyModuleRegistration moduleReg = (IMyModuleRegistration) Activator.CreateInstance(moduleRegType);
                moduleReg.RegisterComponents(kernel);
            }
        }
        catch (ReflectionTypeLoadException exception) {
            ....
        }
    }
}

模块定义:

public class MyExtraModule : IMyModuleRegistration
{
     public void RegisterComponents(IKernel kernel)
     {
         kernel.Bind<IService>()
               .To<ExtraService>()
               .When(x => x.ParentContext
                           .Kernel.Get<IAuthorizationService>()
                           .IsVIPUser());
     }
}

ExtraService仅在MyExtraModule加载 dll with 时使用。

编辑 2

您可以从某处下载该 dll。加载它,然后测试它是否实现了您的注册接口。然后调用该注册,您就完成了。我看到的唯一问题是:在哪里存储引用IKernel- 可能一些静态属性HttpApplication就足够了。您还应该跟踪已加载的 dll。

或者在以后的版本中,Ninject我可以建议扩展NinjectModule,然后使用kernel.Load(..)方法将其加载到内核中。看看这个模块和内核——特别是动态模块加载——也许这就是你要找的。

于 2013-01-09T16:35:22.723 回答
1

我假设您知道核心 ninject 模块。您可以将所有核心 ninject 模块加载到内核中。当特殊用户到达时,您可以卸载核心模块并将用户特定模块加载到内核中。

更好的方法是在插件区域有一个特殊的内核。所以实际上每个插件的内核方法加载所需的核心模块并添加用户特定的模块(如果有)。但这可能会对性能产生影响!

于 2013-01-10T07:49:53.280 回答