每个请求热交换绑定

时间:2013-01-09 13:51:23

标签: asp.net-web-api ninject

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

实施例。两位客户使用我们的restful api。两者都获得相同的功能。第三位客户已支付我们api的超级版本。他发出请求,我们加载超级dll并将超级实现绑定到标准接口。

基本上我希望看​​到的是我们可以加载DLL并使用Web API和Ninject交换每个请求的绑定。

编辑:

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

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

热插拔不是最好的方法吗?我们已经足够新了,因此这可能是一种常见的事情,它以与我们正在考虑的方式不同的方式实施。

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

编辑2:

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

我们希望这样做,所以我们可以删除文件,而不是在项目中引用它。

3 个答案:

答案 0 :(得分:2)

使用条件绑定:

Bind<IMyService>().To<MyService>();
Bind<IMyService>().To<MyServiceForVIPs>().When(ctx => CurrentPrincipalIsVIP());

答案 1 :(得分:2)

我不介意你可以为每个请求换出绑定。但你可以做的是使用条件绑定。

示例 - 默认绑定:

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

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

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

    return kernel;
}

它会(在需要IService的地方)为一些基本用户注入BasicService,为VIP用户注入ExtraService

有关条件绑定的各种方法的详细信息,请参阅Ninject - Contextual binding

修改

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

加载模块:

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时使用。

编辑2

您可以从某个地方下载该DLL。加载它,然后测试它是否实现了您的注册界面。然后打电话给那个注册,你就完成了。我看到的唯一问题是:在哪里存储对IKernel的引用 - 可能HttpApplication中的一些静态属性就足够了。您还应该跟踪已加载的dll。

或者在Ninject的更高版本中,我建议扩展NinjectModule,然后使用kernel.Load(..)方法将其加载到内核中。看看这个Modules and kernel - 特别是部分动态模块加载 - 也许这就是你要找的东西。

答案 2 :(得分:1)

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

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