是否可以通过 IContext 在 Ninject 工厂方法中解析调用者实例?
Is it possible to resolve the caller instance in a Ninject factory method via IContext?
我想这是我正在努力实现的一个非常简单的场景。
我只是想知道是否可以在 Ninject 工厂方法中获取调用实例。
public static class Program
{
public static void Main(params string[] args)
{
var standardKernelCaller = new StandardKernelCaller();
standardKernelCaller.Call();
Console.ReadKey();
}
}
public interface IA
{
}
public class A : IA
{
public int Parameter { get; }
public A(int parameter)
{
Parameter = parameter;
}
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<IA>().ToMethod(Create);
}
private static A Create(IContext context)
{
var number = // resolve the caller (StandardKernelCaller) Magic Number using context...
return new A(number);
}
}
public class StandardKernelCaller
{
public const int MagicNumber = 42;
public void Call()
{
var standardKernel = new StandardKernel(new Module());
var stuff = standardKernel.Get<IA>();
}
}
我不太确定这是否是一个好习惯。目前在相关的生产代码中我使用的是:
public abstract class BusinessApiController<TBusinessLogic> : ApiController
where TBusinessLogic : class, IBusinessLogic
{
protected TBusinessLogic BusinessLogic { get; private set; }
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
BusinessLogic = CreateBusinessLogic();
}
protected virtual TBusinessLogic CreateBusinessLogic()
{
var businessLogic = BusinessLogicFactory.Create<TBusinessLogic>(this.GetOwinContext());
return businessLogic;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (BusinessLogic != null)
{
BusinessLogic.Dispose();
BusinessLogic = null;
}
}
base.Dispose(disposing);
}
}
public abstract class BusinessController<TBusinessLogic> : Controller
where TBusinessLogic : class, IBusinessLogic
{
protected TBusinessLogic BusinessLogic { get; private set; }
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
BusinessLogic = CreateBusinessLogic();
}
protected virtual TBusinessLogic CreateBusinessLogic()
{
var businessLogic = BusinessLogicFactory.Create<TBusinessLogic>(this.GetOwinContext());
return businessLogic;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (BusinessLogic != null)
{
BusinessLogic.Dispose();
BusinessLogic = null;
}
}
base.Dispose(disposing);
}
}
但我不太喜欢下面工厂中硬编码的 "owinContext" 参数名称:
public static class BusinessLogicFactory
{
// Potentially obsolete readonly / configuration kernel in upcoming Ninject versions
private static readonly StandardKernel StandardKernel = new StandardKernel(new BusinessLogicsNinjectModule());
public static TBusinessLogic Create<TBusinessLogic>(IOwinContext owinContext)
{
// Potential refactoring: get the argument name via expression binding or use Ninject providers
var businessLogic = StandardKernel.Get<TBusinessLogic>(new ConstructorArgument("owinContext", owinContext));
return businessLogic;
}
}
下面是 Ninject 模块的简化版本示例:
public class BusinessLogicsNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IUserManagementBusinessLogic>().To<UserManagementBusinessLogic>();
Bind<IAppointmentManagementBusinessLogic>().To<AppointmentManagementBusinessLogic>();
Bind<ITeamAppointmentManagementBusinessLogic>().To<TeamAppointmentManagementBusinessLogic>();
}
}
顺便说一句,如果有更好的 BusinessLogic 注入方法或更好的整体设计,我很想知道更多。
首先,使用 Ninject.Web.Common+Ninject.Web.WebApi 扩展,这样您的控制器就不会依赖于服务定位器:https://github.com/ninject/Ninject.Web.Common/wiki
其次,您的业务逻辑依赖于 owinContext
似乎是一种设计味道。应该遵循关注点分离,这里你似乎在混合 infrastructure/business 层。
第三,如果你真的想要它,你可以通过owinContext
方法调用作为参数传递。
第四,如果你真的想让它通过构造函数传递,你可以使用Ninject.Extensions.Factory:
https://github.com/ninject/Ninject.Extensions.Factory/wiki
public interface IBusinessLogicFactory<TBusinessLogic>
{
TBusinessLogic Create(IOwinContext owinContext);
}
var factory = kernel.Bind<IBusinessLogicFactory<TBusinessLogic>>().ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());
...
var businessLogic = kernel.Get<IBusinessLogicFactory<TBusinessLogic>>().Create(owinContext);
为了知道,让我回答你的第一个问题:
在您的示例中,无法从 IContext
.
确定 StandardKernelCaller
的实例或类型
如果你注入(ctor注入,属性注入)值到StandardKernelCaller
而不是resolve (Get
) 它,那么你将从 IContext
收集类型 StandardKernelCaller
。
如果应用 属性-注入,也许你甚至可以获得 StandardKernelCaller
的实例(我怀疑它不可用)。
但是,您可以将参数传递给 Get
调用:命名绑定的名称(字符串)(解析为使用相同名称注册的绑定,如果没有可用的匹配绑定则抛出)和 IParameter
的。 IParameter
已在 IContext
上可用。
我想这是我正在努力实现的一个非常简单的场景。
我只是想知道是否可以在 Ninject 工厂方法中获取调用实例。
public static class Program
{
public static void Main(params string[] args)
{
var standardKernelCaller = new StandardKernelCaller();
standardKernelCaller.Call();
Console.ReadKey();
}
}
public interface IA
{
}
public class A : IA
{
public int Parameter { get; }
public A(int parameter)
{
Parameter = parameter;
}
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<IA>().ToMethod(Create);
}
private static A Create(IContext context)
{
var number = // resolve the caller (StandardKernelCaller) Magic Number using context...
return new A(number);
}
}
public class StandardKernelCaller
{
public const int MagicNumber = 42;
public void Call()
{
var standardKernel = new StandardKernel(new Module());
var stuff = standardKernel.Get<IA>();
}
}
我不太确定这是否是一个好习惯。目前在相关的生产代码中我使用的是:
public abstract class BusinessApiController<TBusinessLogic> : ApiController
where TBusinessLogic : class, IBusinessLogic
{
protected TBusinessLogic BusinessLogic { get; private set; }
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
BusinessLogic = CreateBusinessLogic();
}
protected virtual TBusinessLogic CreateBusinessLogic()
{
var businessLogic = BusinessLogicFactory.Create<TBusinessLogic>(this.GetOwinContext());
return businessLogic;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (BusinessLogic != null)
{
BusinessLogic.Dispose();
BusinessLogic = null;
}
}
base.Dispose(disposing);
}
}
public abstract class BusinessController<TBusinessLogic> : Controller
where TBusinessLogic : class, IBusinessLogic
{
protected TBusinessLogic BusinessLogic { get; private set; }
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
BusinessLogic = CreateBusinessLogic();
}
protected virtual TBusinessLogic CreateBusinessLogic()
{
var businessLogic = BusinessLogicFactory.Create<TBusinessLogic>(this.GetOwinContext());
return businessLogic;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (BusinessLogic != null)
{
BusinessLogic.Dispose();
BusinessLogic = null;
}
}
base.Dispose(disposing);
}
}
但我不太喜欢下面工厂中硬编码的 "owinContext" 参数名称:
public static class BusinessLogicFactory
{
// Potentially obsolete readonly / configuration kernel in upcoming Ninject versions
private static readonly StandardKernel StandardKernel = new StandardKernel(new BusinessLogicsNinjectModule());
public static TBusinessLogic Create<TBusinessLogic>(IOwinContext owinContext)
{
// Potential refactoring: get the argument name via expression binding or use Ninject providers
var businessLogic = StandardKernel.Get<TBusinessLogic>(new ConstructorArgument("owinContext", owinContext));
return businessLogic;
}
}
下面是 Ninject 模块的简化版本示例:
public class BusinessLogicsNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IUserManagementBusinessLogic>().To<UserManagementBusinessLogic>();
Bind<IAppointmentManagementBusinessLogic>().To<AppointmentManagementBusinessLogic>();
Bind<ITeamAppointmentManagementBusinessLogic>().To<TeamAppointmentManagementBusinessLogic>();
}
}
顺便说一句,如果有更好的 BusinessLogic 注入方法或更好的整体设计,我很想知道更多。
首先,使用 Ninject.Web.Common+Ninject.Web.WebApi 扩展,这样您的控制器就不会依赖于服务定位器:https://github.com/ninject/Ninject.Web.Common/wiki
其次,您的业务逻辑依赖于 owinContext
似乎是一种设计味道。应该遵循关注点分离,这里你似乎在混合 infrastructure/business 层。
第三,如果你真的想要它,你可以通过owinContext
方法调用作为参数传递。
第四,如果你真的想让它通过构造函数传递,你可以使用Ninject.Extensions.Factory: https://github.com/ninject/Ninject.Extensions.Factory/wiki
public interface IBusinessLogicFactory<TBusinessLogic>
{
TBusinessLogic Create(IOwinContext owinContext);
}
var factory = kernel.Bind<IBusinessLogicFactory<TBusinessLogic>>().ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());
...
var businessLogic = kernel.Get<IBusinessLogicFactory<TBusinessLogic>>().Create(owinContext);
为了知道,让我回答你的第一个问题:
在您的示例中,无法从 IContext
.
StandardKernelCaller
的实例或类型
如果你注入(ctor注入,属性注入)值到StandardKernelCaller
而不是resolve (Get
) 它,那么你将从 IContext
收集类型 StandardKernelCaller
。
如果应用 属性-注入,也许你甚至可以获得 StandardKernelCaller
的实例(我怀疑它不可用)。
但是,您可以将参数传递给 Get
调用:命名绑定的名称(字符串)(解析为使用相同名称注册的绑定,如果没有可用的匹配绑定则抛出)和 IParameter
的。 IParameter
已在 IContext
上可用。