Параметр маршрута, привязка пользовательской модели или фильтр действий? - PullRequest
5 голосов
/ 24 мая 2011

Наше приложение ASP.NET MVC позволяет аутентифицированному пользователю управлять одним или несколькими "сайтами", связанными с его учетной записью.

Наши URL являются весьма предположительными, так как мы используем удобное для сайта имя в URL, а не Id, например:

/sites/mysite/
/sites/mysite/settings

/sites/mysite/blog/posts
/sites/mysite/pages/create

Как видите, нам нужен доступ к названию сайта по ряду маршрутов.

Нам нужно выполнить одинаковое поведение для всех этих действий:

  1. Поиск сайта с указанным идентификатором на текущей учетной записи
  2. Если возвращаемый сайт имеет значение null, вернуть 404 (или пользовательское представление)
  3. Если сайт НЕ является нулевым (действительным), мы можем продолжить выполнение действия

Текущая учетная запись всегда доступна для нас через объект ISiteContext. Вот как я могу добиться всего вышеперечисленного, используя обычный параметр маршрута и выполняя запрос непосредственно в моем действии:

private readonly ISiteContext siteContext;
private readonly IRepository<Site> siteRepository;

public SitesController(ISiteContext siteContext, IRepository<Site> siteRepository)
{
    this.siteContext = siteContext;
    this.siteRepository = siteRepository;
}

[HttpGet]
public ActionResult Details(string id)
{
    var site =
        siteRepository.Get(
            s => s.Account == siteContext.Account && s.SystemName == id
        );

    if (site == null)
        return HttpNotFound();

    return Content("Viewing details for site " + site.Name);
}

Это не так уж плохо, но мне нужно будет сделать это примерно на 20 методах действий, поэтому я хочу, чтобы все было сухо, насколько это возможно.

Я не так много сделал с пользовательскими моделями, так что мне интересно, подходит ли эта работа для них лучше? Ключевое требование заключается в том, что я могу внедрить свои зависимости в связыватель модели (для ISiteContext и IRepository - при необходимости я могу прибегнуть к DependencyResolver).

Большое спасибо,

Ben

Обновление

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

  1. Должен ли я попасть в свою базу данных из связывателя моделей
  2. I может на самом деле выполнять как извлечение объекта, так и проверку нуля из фильтра действий. Что лучше?

Модель Binder:

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    if (!controllerContext.RouteData.Values.ContainsKey("siteid"))
        return null;

    var siteId = controllerContext.RouteData.GetRequiredString("siteid");

    var site =
        siteRepository.Get(
            s => s.Account == siteContext.Account && s.SystemName == siteId
        );

    return site;
}

Фильтр действий:

public class ValidateSiteAttribute : ActionFilterAttribute
{       
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {           
        var site = filterContext.ActionParameters["site"];

        if (site == null || site.GetType() != typeof(Site))
            filterContext.Result = new HttpNotFoundResult();

        base.OnActionExecuting(filterContext);
    }
}

Действия контроллера:

[HttpGet]
[ValidateSite]
public ActionResult Settings(Site site)
{
    var blog = site.GetFeature<BlogFeature>();
    var settings = settingsProvider.GetSettings<BlogSettings>(blog.Id);

    return View(settings);
}

[HttpPost]
[ValidateSite]
[UnitOfWork]
public ActionResult Settings(Site site, BlogSettings settings)
{
    if (ModelState.IsValid)
    {
        var blog = site.GetFeature<BlogFeature>();
        settingsProvider.SaveSettings(settings, blog.Id);
        return RedirectToAction("Settings");
    }

    return View(settings);
}

Ответы [ 2 ]

1 голос
/ 24 мая 2011

Это определенно звучит как работа для фильтра действий. Вы можете сделать DI с фильтрами действий не проблема.

Так что да, просто превратите существующую функциональность в фильтр действий, а затем примените его к каждому действию ИЛИ контроллеру ИЛИ базовому контроллеру, от которого вы унаследовали.

Я не совсем знаю, как работает ваш сайт, но вы могли бы использовать глобальный фильтр действий, который проверяет наличие определенного значения маршрута, например, 'Название сайта'. Если это значение маршрута существует, это означает, что вам нужно проверить, существует ли сайт ...

1 голос
/ 24 мая 2011

Пользовательская модель подшивки для вашего типа сайта звучит как хорошая идея для меня. Вы, вероятно, также захотите фильтр действий, чтобы ловить «ноль» и возвращать не найдено.

...