Создание ViewResults за пределами Контроллеров в ASP.NET MVC

Несколько из моих действий контроллера имеют стандартный набор обрабатывающего отказ поведения. В целом я хочу:

  • Загрузите основанное на объектах на Данных маршрутов (идентификаторы и т.п.)
    • Если Данные маршрутов не указывают на доступный объект (исключая: посредством взламывания URL), тогда сообщают пользователю о проблеме и возвращают HTTP 404, Не Найденный
  • Проверьте это, у текущего пользователя есть верные полномочия на объекте
    • Если у пользователя нет разрешения, сообщите пользователю о проблеме и возвратите Запрещенный HTTP 403
  • Если вышеупомянутое успешно, то сделайте что-то с тем объектом, это является определенным для действия (т.е.: представьте его в представлении).

Эти шаги так стандартизированы, что я хочу иметь повторно используемый код для реализации поведения.

Мой текущий план нападения состоял в том, чтобы иметь вспомогательный метод сделать что-то вроде этого:

public static ActionResult HandleMyObject(this Controller controller, 
    Func<MyObject,ActionResult> onSuccess) {
  var myObject = MyObject.LoadFrom(controller.RouteData).
  if ( myObject == null ) return NotFound(controller);
  if ( myObject.IsNotAllowed(controller.User)) return NotAllowed(controller);
  return onSuccess(myObject);
}

# NotAllowed() is pretty much the same as this
public static NotFound(Controller controller){
    controller.HttpContext.Response.StatusCode = 404
    # NotFound.aspx is a shared view.
    ViewResult result = controller.View("NotFound");
    return result;
}

Проблемой здесь является тот Контроллер. Представление () является защищенным методом и так не доступно от помощника. Я посмотрел на создание нового экземпляра ViewResult явно, но существует достаточно свойств для установки этого, я осторожен о выполнении так, не зная ловушки сначала.

Что лучший способ состоит в том, чтобы создать ViewResult снаружи конкретного Контроллера?

10
задан Craig Walker 22 February 2010 в 19:26
поделиться

3 ответа

Когда я писал это, я придумал один способ.

Вместо того, чтобы иметь приведенный выше код в помощнике, я мог бы поместить его в подкласс Controller, а затем создать подкласс этого класса для моих реальных контроллеров. Это позволило бы мне вызвать защищенный метод View ().

Мне это не очень нравится, потому что для работы требуется наследование , но это все же вариант.

4
ответ дан 4 December 2019 в 01:00
поделиться

Другим способом было бы использование декораторов:

public class StatusCodeViewResultDecorator : ViewResult {
  ViewResult wrapped;
  int code;
  string description;

  public StatusCodeViewResultDecorator( ViewResult wrapped, int code, string description ) {
    this.wrapped = wrapped;
    this.code = code;
    this.description = description;
  }

  public override void ExecuteResult(ControllerContext context) {
    wrapped.ExecuteResult(context);
    context.RequestContext.HttpContext.Response.StatusCode = code;
    context.RequestContext.HttpContext.Response.StatusDescription = description;
  }
}

И, возможно, метода расширения, чтобы сделать его чище:

public static class ViewResultExtensions {
  public static ViewResult WithStatus( this ViewResult viewResult, int code, string description ) {
    return new StatusCodeViewResultDecorator(viewResult,code,description);
  }
}

Тогда вы могли бы просто сказать:

return View("MyView").WithStatus(404,"Not found");

в своем контроллере.

0
ответ дан 4 December 2019 в 01:00
поделиться

У меня был тот же вопрос, но я ответил по-разному. Я действительно не хотел использовать для этого наследование, поэтому вместо этого использовал лямбду.

Во-первых, у меня есть объект, который я передаю от моего контроллера методу, который я хочу вернуть в виде:

public struct MyControllerContext
{
    public HttpRequestBase Request { get; set; }
    public HttpResponseBase Response { get; set; }
    public DocsController Controller { get; set; }

    public Func<string, object, ViewResult> ViewResult;
    public ViewResult View(string viewName, object model)
    {
        return this.ViewResult(viewName, model);
    }
}

Я создаю его экземпляр и передаю его в качестве параметра методу, который вернет результат:

// In the controller
var context = new DocsControllerContext()
{
    Request = Request,
    Response = Response,
    Controller = this,
    ViewResult = (viewName, model) =>
    {
        return View(viewName, model);
    }
};

var returnValue = methodInfo.Invoke(toInvoke, new object[] { context });
return returnValue;

Затем в вызванном мной методе я могу вызвать context.View ("ViewName", model); . Может быть много вариантов, основная идея - использовать обратный вызов.

1
ответ дан 4 December 2019 в 01:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: