Подтвердить что ты не робот

ASP.NET MVC - установка ViewData для главной страницы в базовом контроллере

Я использую masterpage в моем проекте ASP.NET MVC. Эта главная страница ожидает, что некоторые ViewData будут присутствовать, что отображает это на каждой странице.

Если я не устанавливаю этот ключ ViewData в своих контроллерах, я получаю сообщение об ошибке, которое он не может найти. Однако я не хочу устанавливать ViewData в каждом контроллере (я не хочу сказать ViewData["foo"] = GetFoo(); в каждом контроллере).

Итак, я подумывал установить это в базовом контроллере, и каждый контроллер наследует этот базовый контроллер. В конструкторе по умолчанию базового контроллера я устанавливаю ViewData. Я нашел аналогичный подход здесь: http://www.asp.net/learn/MVC/tutorial-13-cs.aspx. До сих пор это так хорошо, но проблема в том, что эти данные поступают из где-то в базе данных.

Теперь, когда я хочу Unit Test мои контроллеры, те, которые наследуют от базового контроллера, вызывают его конструктор по умолчанию. В конструкторе по умолчанию я инициализирую свой класс репозитория для получения этих данных из базы данных. Результат: мои модульные тесты терпят неудачу, поскольку они не могут получить доступ к данным (и я, конечно, не хочу, чтобы они обращались к этим данным).

Я также не хочу передавать правильный класс репозитория (или DataContext, независимо от того, что он назовет его) для каждого контроллера, который, в свою очередь, передает его контроллеру по умолчанию, который я мог бы затем высмеять мои модульные тесты. Контроллеры, в свою очередь, полагаются на другие классы репозитория, и я бы закончил передачу нескольких параметров конструктору. Слишком много работы для моего чувства, или я ошибаюсь? Есть ли другое решение?

Я пробовал использовать StructureMap, но в конце концов мне не хотелось, чтобы это исправляло мою проблему, поскольку каждому контроллеру все равно придется вызывать базовый конструктор, который инициализирует класс репозитория, поэтому я не могу издеваться над ним.

Этот вопрос является аналогичным, но я не нашел удовлетворительного ответа. Могу ли я решить эту проблему аккуратным способом, возможно, используя StructureMap в качестве решения? Или мне нужно сосать его и передать репозиторий каждому контроллеру и передать его снова базовому контроллеру? Опять же, похоже, что так много работы для чего-то такого простого. Спасибо!

4b9b3361

Ответ 1

Я вижу два варианта:

Во-первых:

Установите ViewData для MasterPage в YourBaseController.OnActionExecuting() или YourBaseController.OnActionExecuted():

public class YourBaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Optional: Work only for GET request
        if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
            return;

        // Optional: Do not work with AjaxRequests
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
            return;

        ...

        filterContext.Controller.ViewData["foo"] = ...
    }
}

Второе:

Или создайте собственный фильтр:

public class DataForMasterPageAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Optional: Work only for GET request
        if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
            return;

        // Optional: Do not work with AjaxRequests
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
            return;

        ...

        filterContext.Controller.ViewData["foo"] = ...
    }
}

а затем примените к вашим контроллерам:

[DataForMasterPage]
public class YourController : YourBaseController
{
    ...
}

Я думаю, что второе решение именно для вашего случая.