шаблон репозитория c #, как получить доступ к значениям из внедренного класса зависимостей - PullRequest
0 голосов
/ 05 июля 2019

У меня есть проект 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 вводится, и это работает отлично, но я хочу получить значения класса _appState в моем SecurityRepository без необходимости каждый раз передавать в каждый метод 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));


        }

Любой совет или пример кода, которому я могу следовать?

1 Ответ

0 голосов
/ 05 июля 2019

Итак, вам просто нужно как-то передать значение из сессии в ваш репозиторий. На самом деле есть много способов достичь этого.

Одним из способов может быть метод типа 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
}

Легко реализовать, но добавить жесткую статическую зависимость в ваш репозиторий - забудьте о модульном тестировании.


Еще один способ (который является комбинацией 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 и может быть легко протестирован модулем.

...