2010-02-22 2 views
10

내 컨트롤러 동작 중 일부에는 표준 오류 처리 동작 집합이 있습니다. 일반적으로, 내가 원하는 :ASP.NET MVC에서 컨트롤러 외부에서 ViewResults 만들기

  • 로드 경로 데이터 (IDS 등)
    • 에 따라 객체 국도 데이터가 유효한 개체를 가리 키지 않는 경우 (예 : URL이 해킹을 통해) 다음 문제를 사용자에게 정보를 제공하고 사용자가 권한이없는 경우 현재 사용자가 객체
      • 에 적절한 권한이 있는지
    • 유효성 HTTP 404 찾을 수 없음을 반환, 사용자에게 문제를 알리고 금지 된 HTTP를 반환하십시오.
  • 위 작업이 성공적으로 수행 된 경우 해당 특정 객체 (예 :보기에서 렌더링)로 작업하십시오.

이 단계는 너무 표준화되어 있으므로이 동작을 구현하기 위해 재사용 가능한 코드가 필요합니다.

공격의 나의 현재 계획은 이런 일을 할 수있는 도우미 메서드를 가지고 있었다 :

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; 
} 

여기서 문제는 Controller.View()를 보호 방법 등 도우미에서 액세스 할 수없는 것입니다 . 새로운 ViewResult 인스턴스를 명시 적으로 생성하는 방법을 살펴 보았지만, 함정을 먼저 모른 채주의해야한다는 것을 충분히 설정할 수있는 속성이 있습니다.

특정 컨트롤러 외부에서 ViewResult를 만드는 가장 좋은 방법은 무엇입니까?

답변

4

나는 이것을 쓰면서 나는 한 가지 방법을 생각했다.

위의 코드를 도우미로 사용하는 대신 컨트롤러의 하위 클래스에 넣은 다음 실제 컨트롤러에이 클래스를 서브 클래스로 만들 수 있습니다. 이렇게하면 보호 된 View() 메서드를 호출 할 수 있습니다.

requires inheritance to work이기 때문에 특히 좋아하지 않지만 여전히 옵션입니다.

+0

+1 : 그게 내가하는 방법입니다. –

+0

내가 싫어하는 점은 컨트롤러가 공유 액션 동작 세트를 하나만 가질 수 있다는 것입니다. 즉, 컨트롤러가 하나의 공유 동작 동작 만 가질 수 있다는 것입니다. 이 특정 예에서는 문제가 아니지만 프로젝트가 커짐에 따라 다루기 힘들어지는 것을 알 수 있습니다. –

+0

나는 당신의 질문이 세살이라는 것을 알고 있지만, 나는 또 다른 가능성을 언급 할 것이라고 생각했습니다. 기본 컨트롤러에서'GetView()'라는 공개 버전의'View()'를 노출하면 다른 클래스에 도우미를 유지할 수 있습니다. 컨트롤러를 도우미에 전달해야 할 필요가 있습니다. 약간 어색하지만 상속 대신 컴포지션을 허용합니다. – devuxer

0

또 다른 방법은 장식 사용하는 것입니다 :

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

당신은 단순히 말할 수 :

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; 
    } 
} 

어쩌면 확장 방법은 청소기 그것을 만들

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

을에 제어 장치.

+1

컨트롤러에서 기본 ViewResult를 생성해야하므로이 작업은 도움이되지 않습니다. –

2

나는 동일한 질문을했고 다르게 대답했다. 나는 이것을 위해 상속을 사용하고 싶지 않았기 때문에 대신 람다를 사용했습니다.나는이의 인스턴스를 만들고 해당하는 메소드에 매개 변수로 전달

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);를 호출 할 수 있습니다 : 결과를 반환합니다. 이것의 많은 변형이있을 수있다, 기본적인 생각은 콜백을 사용하는 것이다.

6

조치 필터에서 같은 문제가 발생 했으므로이 게시물을 읽으십시오. 내 솔루션 명시 적으로보기 작업을 만드는 것입니다. 이것은 MVC 소스별로 보호 된 View() 메소드를 기반으로하므로 필수 속성을 채워야합니다. 어쨌든, 문제없이 작동하는 것 같습니다.

public static NotFound(Controller controller){ 
    controller.HttpContext.Response.StatusCode = 404; 

    ViewResult result = new ViewResult { 
      ViewName = "NotFound", 
      ViewData = controller.ViewData, 
      TempData = controller.TempData 
     }; 
    return result; 
} 

다소 늦은 날이지만 나에게 도움이되었습니다.

관련 문제