注入不同的 project/assembly
Injecting into a different project/assembly
我已经研究这个主题好几个小时了,所以我决定写信寻求帮助。
这个论坛上已经有很多答案,我可以确定它们是我的问题的解决方案,但我无法将脑海中的所有点联系起来;我还没完成。
我正在尝试更改大型 MVC 应用程序上的注入器,从 StructureMap 更改为 SimpleInjector。
我需要正确地将 HttpContext 的当前用户传递给同一解决方案中的另一个项目,该解决方案包含所有存储库和 DBContext,因此当我执行一些 CRUD 操作时它可以是 used/written。
我显然不明白 StructureMap 是如何连线的;我发现它很复杂。我在 MVC 项目上有这个(可以提供更多信息,因为有很多 classes 使用 StructureMap):
public class GlobalRegistry : StructureMap.Registry
{
public GlobalRegistry()
{
For<INotificationRepository>().Use<NotificationRepository>();
...
和存储库 project/class:
public class NotificationRepository : BaseRepository,INotificationRepository
{
public NotificationRepository(string userContext) : base(userContext) { }
(...魔术...)构造函数将采用 userContext 参数稍后在被调用方法中使用。
换成SimpleInjector后,不明白这个参数是怎么注入的
出于测试目的,这有效:
container.Register<INotificationRepository>(() => new NotificationRepository("username"),
Lifestyle.Singleton);
我读到我不应该在构造函数中注入 HttpContext
,因为它是一个运行时变量,我明白为什么。
接下来我尝试了 IUserContextFactory
,但它也没有用。
在同一个 MVC 项目上,我有他的 class:
public static class ObjectFactory
{
private static SimpleInjector.Container _container;
public static void SetContainer(Container container)
{
ObjectFactory._container = container;
}
public static T GetInstance<T>() where T : class
{
return _container.GetInstance<T>();
}
}
我正在使用这个 class 在 container.Verify();
之后存储容器
ObjectFactory.SetContainer(container);
在任何 MVC 控制器上,我都是这样使用的:
IUserContext ctxUser = ObjectFactory.GetInstance<IUserContext>();
在整个尝试过程中,我还在存储库中尝试了类似以下内容,但我总是以空值结束 UserName
。
public NotificationRepository(IUserContext userContext) : base(userContext) { }
(MVC 项目和存储库项目之间的通用接口)
public interface IUserContext
{
string Username { get; set; }
}
比了解解决方案更重要的是,我想了解解决方案的工作原理,并克服过去几个小时试图理解和解决这个问题时遇到的困难。
将 运行 时间原始值作为参数传递给构造函数在 Simple Inject 中不能直接使用。相反,您可以注入一个允许您在 运行 时间获得该值的组件,因此您使用 IUserContext
的方法似乎是个好方法,它应该有效。修改 class 以在构造函数中添加该组件,而不是 userName
字符串。注册新组件,让你容器在调用构造函数时自动注入。
示例实现:
class HttpSessionUserContext : IUserContext
{
//Your specific implementation of getting the user name from your context
public string CurrentUserName => (string)HttpContext.Session["userName"];
}
报名人数:
container.Register<IUserContext, HttpSessionUserContext>(Lifestyle.Scoped);
container.Register<INotificationRepository, NotificationRepository> (Lifestyle.Scoped);
Here 你有更多关于为什么在 Simple Inject 中没有实现将原始 运行-time 参数传递给构造函数的原因的信息。
关于生活方式范围:您可能不应该使用 Lifestyle.Singleton
作为此组件的范围,因为它只会被实例化一次并作为单例重复使用。在 Web 应用程序中,您通常希望应用 Per-HttpRequest 范围。您可以这样做:创建容器后,将其默认范围定义为 WebRequestLifestyle
,或 WebApiRequestLifestyle
:
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
然后当您注册组件时使用值 Lifestyle.Scoped
,这将应用默认范围内的生活方式:
container.Register<SomeInterface, SomeClass>(Lifestyle.Scoped);
编辑: 根据 Steven 的评论,在这种情况下最好将 HttpSessionUserContext
注册为 Singleton
,因为它是无国籍的。一般来说,Singleton
性能更好,因为它只实例化一次并共享,但要小心那些不是无状态或对其他组件有依赖的组件。
此外,请确保您已注册 MVC 控制器并将容器实例分配给 MVC DependencyResolver
。这才是真正能够在控制器的构造函数中自动解析和注入参数的原因。我猜你是在 Application_Start
事件处理程序中这样做的。
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
我已经研究这个主题好几个小时了,所以我决定写信寻求帮助。
这个论坛上已经有很多答案,我可以确定它们是我的问题的解决方案,但我无法将脑海中的所有点联系起来;我还没完成。
我正在尝试更改大型 MVC 应用程序上的注入器,从 StructureMap 更改为 SimpleInjector。
我需要正确地将 HttpContext 的当前用户传递给同一解决方案中的另一个项目,该解决方案包含所有存储库和 DBContext,因此当我执行一些 CRUD 操作时它可以是 used/written。
我显然不明白 StructureMap 是如何连线的;我发现它很复杂。我在 MVC 项目上有这个(可以提供更多信息,因为有很多 classes 使用 StructureMap):
public class GlobalRegistry : StructureMap.Registry
{
public GlobalRegistry()
{
For<INotificationRepository>().Use<NotificationRepository>();
...
和存储库 project/class:
public class NotificationRepository : BaseRepository,INotificationRepository
{
public NotificationRepository(string userContext) : base(userContext) { }
(...魔术...)构造函数将采用 userContext 参数稍后在被调用方法中使用。
换成SimpleInjector后,不明白这个参数是怎么注入的
出于测试目的,这有效:
container.Register<INotificationRepository>(() => new NotificationRepository("username"),
Lifestyle.Singleton);
我读到我不应该在构造函数中注入 HttpContext
,因为它是一个运行时变量,我明白为什么。
接下来我尝试了 IUserContextFactory
,但它也没有用。
在同一个 MVC 项目上,我有他的 class:
public static class ObjectFactory
{
private static SimpleInjector.Container _container;
public static void SetContainer(Container container)
{
ObjectFactory._container = container;
}
public static T GetInstance<T>() where T : class
{
return _container.GetInstance<T>();
}
}
我正在使用这个 class 在 container.Verify();
ObjectFactory.SetContainer(container);
在任何 MVC 控制器上,我都是这样使用的:
IUserContext ctxUser = ObjectFactory.GetInstance<IUserContext>();
在整个尝试过程中,我还在存储库中尝试了类似以下内容,但我总是以空值结束 UserName
。
public NotificationRepository(IUserContext userContext) : base(userContext) { }
(MVC 项目和存储库项目之间的通用接口)
public interface IUserContext
{
string Username { get; set; }
}
比了解解决方案更重要的是,我想了解解决方案的工作原理,并克服过去几个小时试图理解和解决这个问题时遇到的困难。
将 运行 时间原始值作为参数传递给构造函数在 Simple Inject 中不能直接使用。相反,您可以注入一个允许您在 运行 时间获得该值的组件,因此您使用 IUserContext
的方法似乎是个好方法,它应该有效。修改 class 以在构造函数中添加该组件,而不是 userName
字符串。注册新组件,让你容器在调用构造函数时自动注入。
示例实现:
class HttpSessionUserContext : IUserContext
{
//Your specific implementation of getting the user name from your context
public string CurrentUserName => (string)HttpContext.Session["userName"];
}
报名人数:
container.Register<IUserContext, HttpSessionUserContext>(Lifestyle.Scoped);
container.Register<INotificationRepository, NotificationRepository> (Lifestyle.Scoped);
Here 你有更多关于为什么在 Simple Inject 中没有实现将原始 运行-time 参数传递给构造函数的原因的信息。
关于生活方式范围:您可能不应该使用 Lifestyle.Singleton
作为此组件的范围,因为它只会被实例化一次并作为单例重复使用。在 Web 应用程序中,您通常希望应用 Per-HttpRequest 范围。您可以这样做:创建容器后,将其默认范围定义为 WebRequestLifestyle
,或 WebApiRequestLifestyle
:
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
然后当您注册组件时使用值 Lifestyle.Scoped
,这将应用默认范围内的生活方式:
container.Register<SomeInterface, SomeClass>(Lifestyle.Scoped);
编辑: 根据 Steven 的评论,在这种情况下最好将 HttpSessionUserContext
注册为 Singleton
,因为它是无国籍的。一般来说,Singleton
性能更好,因为它只实例化一次并共享,但要小心那些不是无状态或对其他组件有依赖的组件。
此外,请确保您已注册 MVC 控制器并将容器实例分配给 MVC DependencyResolver
。这才是真正能够在控制器的构造函数中自动解析和注入参数的原因。我猜你是在 Application_Start
事件处理程序中这样做的。
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));