c# - c#存储库模式如何访问依赖注入类中的值
问题描述
我有 ac#aspnet mvc(不是核心)项目,我在其中使用存储库模式和依赖注入(ninject)。
这是控制器的示例:
public class MainController : Controller
{
ISecurityRepository _securityRepo = default(ISecurityRepository);
AppState _appState;
public MainController(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
_appState = (AppState)Session["appstate"];
}
public ActionResult Employee(int employeeId)
{
var permissions = _securityRepo.GetEmployeePermissions(
employeeId,
_appState.userId,
_appState.sessionId);
return View(permissions);
}
public ActionResult Leave(int leaveId, int employeeId)
{
var permissions = _securityRepo.GetEmployeeLeavePermissions(
leaveId,
employeeId,
_appState.userId,
_appState.sessionId);
return View(permissions);
}
public ActionResult Holiday(int holidayId, int employeeId)
{
var permissions = _securityRepo.GetEmployeeHolidayPermissions(
holidayId,
employeeId,
_appState.userId,
_appState.sessionId);
return View(permissions);
}
}
ISecurityRepository
正在注入并且工作完美,但我想要做的是获取我SecurityRepository
的类值,而_appState
无需每次都传递给每个方法。userId
companyId
这是我的SecurityRepository.cs
public class SecurityRepository : ISecurityRepository
{
public EmployeePermissions GetEmployeePermissions(int employeeId, int userId, int sessionId)
{
// ... some code here
return employeePermissions;
}
public EmployeeLeavePermissions GetEmployeeLeavePermissions(int leaveId, int employeeId, int userId, int sessionId)
{
// ... some code here
return employeeLeavePermissions;
}
public EmployeeHolidayPermissions GetEmployeeHolidayPermissions(int holidayId, int employeeId, int userId, int sessionId)
{
// ... some code here
return employeeHolidayPermissions;
}
// ... some more methods
}
我想做的是有这样的事情:
public class SecurityRepository : ISecurityRepository
{
// here have maybe a constructor that receives the AppState variable from MainController, or a public property
public EmployeePermissions GetEmployeePermissions(int employeeId)
{
// a way that I can user _appState here!!
return employeePermissions;
}
}
注入在NinjectWebCommon
课堂内完成
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(typeof(ISecurityRepository)).To(typeof(Data.SecurityRepository));
}
我可以遵循的任何建议或示例代码?
解决方案
因此,您只需要以某种方式将值从会话传递到您的存储库。实际上有很多方法可以实现这一点。
一种方法是在您的存储库类中使用某种Initialize
方法(当然,在您的存储库接口中):
public class SecurityRepository : ISecurityRepository
{
public void Initialize(AppState appState)
{
_userId = appState.userId;
_sessionId = appState.sessionId;
}
// some other methods
}
然后你可以在你的控制器构造函数中调用它:
public MainController(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
_securityRepo.Initialize(Session["appstate"] as AppState);
}
另一种方式 - 您可以在操作过滤器中设置您的依赖项。只需添加某种访问器:
public class AppStateAccessor
{
public AppState AppState { get; set; }
}
然后将其设置在您的过滤器中:
public class RequestScopeDependencySetupFilter : ActionFilterAttribute
{
private readonly IKernel _kernel;
public RequestScopeDependencySetupFilter(IKernel kernel)
{
_kernel = kernel;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
var accessor = _kernel.Get<AppStateAccessor>();
accessor.AppState = context.HttpContext.Session["appstate"] as AppState;
}
}
然后将此过滤器注册为全局:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
var kernel = /* get your IKernel somehow */
filters.Add(new RequestScopeDependencySetupFilter(kernel));
}
最后在您的存储库中使用它:
public class SecurityRepository : ISecurityRepository
{
public SecurityRepository(AppStateAccessor accessor)
{
_userId = accessor.AppState.userId;
_sessionId = accessor.AppState.sessionId;
}
// some other methods
}
只是不要忘记正确绑定您的依赖项。此方法的关键是您的AppStateAccessor
实例是瞬态的并且存在于请求范围内。Ninject(特别是Ninject.Extensions.ContextPreservation
扩展)允许您为请求范围绑定 DI 容器中的对象实例:
private static void RegisterServices(IKernel kernel)
{
// bind AppStateAccessor in request scope
kernel.Bind<AppStateAccessor>().ToSelf().InRequestScope();
// transient repository
kernel.Bind<ISecurityRepository>().To<Data.SecurityRepository>();
// other dependencies...
}
还有一种方法。只需HttpContext.Current
在存储库中使用静态属性:
public class SecurityRepository : ISecurityRepository
{
public SecurityRepository()
{
var appState = HttpContext.Current.Session["appstate"] as AppState;
_userId = appState.userId;
_sessionId = appState.sessionId;
}
// some other methods
}
易于实现,但向您的存储库添加了一个硬静态依赖项 - 忘记单元测试。
与此答案类似的另一种方式(这是第 2 和第 3 的组合,感谢@Nkosi)。提取接口AppStateAccessor
:
public interface IAppStateAccessor
{
AppState AppState { get; }
}
然后稍微改变AppStateAccessor
一下:
public class AppStateAccessor
{
public AppState AppState { get; }
= HttpContext.Current.Session["appstate"] as AppState;
}
然后在您的存储库中使用此接口:
public class SecurityRepository : ISecurityRepository
{
public SecurityRepository(IAppStateAccessor accessor)
{
_userId = accessor.AppState.userId;
_sessionId = accessor.AppState.sessionId;
}
// some other methods
}
这次你的服务完全解耦HttpContext
并且可以很容易地进行单元测试。
推荐阅读
- python-3.x - 为什么网格只在最后一个子图上打开?
- html - 如何使按钮居中
- c++ - 错误:在 '(' 标记 WSAStartup (versionWanted, &wsaData); 之前的预期构造函数、析构函数或类型转换;
- asp.net-core - Razor 组件和标签助手,为什么?如何?
- angular - 可观察的数组角度 rxjs
- java - 如何以编程方式更改 ConstraintLayout 中的 layout_gravity?
- python - 我每次都用 python random.randint 得到相同的数字
- android - 在片段中动态添加视图
- php - 学说 OneToMany - 级联持续不工作
- c# - ServiceStack.Redis 无法连接到 Digitalocean 托管的 redis 实例