我想这是一个我想要实现的非常简单的场景。
我只是想知道是否可以在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注入或更好的整体设计,我很想知道更多。
答案 0 :(得分:1)
首先,使用Ninject.Web.Common + Ninject.Web.WebApi扩展,以便您的控制器不依赖于服务定位器:https://github.com/ninject/Ninject.Web.Common/wiki
其次,您的业务逻辑依赖于owinContext
似乎是一种设计气味。应该遵循关注点分离,这里似乎是混合基础架构/业务层。
第三,如果你真的想要它,你可以通过方法调用作为参数传递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);
答案 1 :(得分:1)
要知道,让我回答你的第一个问题:
在您的示例中,无法从StandardKernelCaller
确定IContext
的实例或类型。
如果你将注入(ctor-injection,property injection)的值改为StandardKernelCaller
而不是 resolve (Get
),那么您将从StandardKernelCaller
收集IContext
类型。
如果应用了属性注入,也许你甚至可以获得StandardKernelCaller
的实例(我怀疑它虽然不可用)。
但是,您可以将参数传递给Get
调用:命名绑定的名称(字符串)(解析为使用相同名称注册的绑定,如果没有匹配的绑定则抛出)和IParameter
& #39; S。 IParameter
上提供了IContext
。