C#存储库模式如何从依赖项注入类访问值

时间:2019-07-05 01:57:05

标签: c# dependency-injection inversion-of-control ninject

我有一个c#aspnet mvc(不是核心)项目,其中,我使用存储库模式和依赖项注入(ninject)。

这是控制器的示例:

data1=df.groupBy('_c0').agg(collect_list('_c1')).show()
print(data1.count())

data1=df.groupBy('_c0').apply(collect_list('_c1')).show()

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,而无需传递给每个方法{每次{1}}和_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;
    }
}

我可以遵循的任何建议或示例代码吗?

1 个答案:

答案 0 :(得分:0)

因此,您只需要以某种方式将会话中的值传递给存储库即可。其实有很多方法可以达到这个目的。

一种方法是在存储库类中(当然,在存储库接口中)某种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);
}

另一种方法-您可以处理在action filter中设置依赖项的问题。只需添加某种访问器即可:

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
}

易于实现,但向存储库添加了静态静态依赖-无需进行单元测试。


还有一种类似于this answer的方式(感谢@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完全分离,并且可以轻松进行单元测试。