2010-02-22 23 views
10

में नियंत्रकों के बाहर ViewResults बनाना मेरे नियंत्रक कार्यों में से कई विफलता-हैंडलिंग व्यवहार का एक मानक सेट है। सामान्य तौर पर, मैं चाहता हूँ करने के लिए:ASP.NET MVC

  • लोड एक वस्तु मार्ग डेटा (आईडी और की तरह)
    • के आधार पर मार्ग डेटा एक वैध वस्तु को इंगित नहीं करता है (उदा: के माध्यम से यूआरएल हैकिंग) तो समस्या के उपयोगकर्ता को सूचित और एक 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; 
} 

समस्या है कि यहाँ Controller.View() एक संरक्षित तरीका है और इसलिए एक सहायक से सुलभ नहीं है । मैंने स्पष्ट रूप से एक नया ViewResult उदाहरण बनाने पर देखा है, लेकिन यह निर्धारित करने के लिए पर्याप्त गुण हैं कि मैं पहले नुकसान के बिना ऐसा करने के बारे में सावधान हूं।

किसी विशेष नियंत्रक के बाहर से ViewResult बनाने का सबसे अच्छा तरीका क्या है?

उत्तर

4

जैसा कि मैं इसे लिख रहा था, मैंने एक तरह से सोचा।

एक सहायक में उपरोक्त कोड रखने की बजाय, मैं इसे नियंत्रक के उप-वर्ग में डाल सकता हूं और फिर अपने वास्तविक नियंत्रकों के लिए इस वर्ग को उप-वर्ग कर सकता हूं। यह मुझे संरक्षित दृश्य() विधि को कॉल करने की अनुमति देगा।

मुझे यह विशेष रूप से बहुत पसंद नहीं है क्योंकि यह requires inheritance to work है, लेकिन यह अभी भी एक विकल्प है।

+0

+1: इस तरह मैं इसे करूँगा। –

+0

जो चीज़ मुझे इस बारे में पसंद नहीं है वह यह है कि इसका मतलब है कि नियंत्रक के पास केवल साझा क्रिया व्यवहार का एक सेट हो सकता है: जिसे वह (अकेला) विरासत में मिलता है। इस विशेष उदाहरण के लिए यह कोई मुद्दा नहीं है, लेकिन प्रोजेक्ट बढ़ने के साथ ही मैं इसे और अधिक बेकार महसूस कर सकता हूं। –

+0

मुझे एहसास है कि आपका प्रश्न साल पुराना है, लेकिन मैंने सोचा कि मैं एक और संभावना का उल्लेख करूंगा। आप अपने बेस कंट्रोलर पर 'व्यू व्यू()' नामक 'व्यू()' के सार्वजनिक संस्करण का पर्दाफाश कर सकते हैं, फिर आप अपने सहायक को एक अलग वर्ग में रख सकते हैं। आपको अभी भी अपने नियंत्रक को अपने सहायक में पास करने की आवश्यकता होगी, जो थोड़ा अजीब है, लेकिन यह विरासत की बजाय संरचना की अनुमति देता है। – devuxer

0

एक और तरीका है सज्जाकार का उपयोग करेंगे:

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"); 

अपने नियंत्रक।

+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

बस इस पोस्ट को पढ़ें क्योंकि मुझे एक एक्शन फ़िल्टर से एक ही समस्या थी। मेरा समाधान स्पष्ट रूप से दृश्य कार्रवाई बना रहा था। यह एमवीसी स्रोत के अनुसार संरक्षित दृश्य() विधि पर आधारित है, इसलिए इसे आवश्यक गुणों को पॉप्युलेट करना चाहिए। वैसे भी, मुद्दों के बिना काम करने लगता है।

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

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

दिन में थोड़ा देर हो गई लेकिन यह मेरे लिए काम किया।