कैसे एक स्ट्रिंग के रूप में ASP.NET MVC दृश्य प्रस्तुत करना है?


485

मैं दो अलग-अलग विचारों (एक स्ट्रिंग के रूप में जिसे एक ईमेल के रूप में भेजा जाएगा), और दूसरा पृष्ठ उपयोगकर्ता को प्रदर्शित करना चाहता हूं।

क्या यह ASP.NET MVC बीटा में संभव है?

मैंने कई उदाहरण आज़माए हैं:

1. ASP.NET MVC बीटा में स्ट्रिंग के लिए RenderPartial

अगर मैं इस उदाहरण का उपयोग करता हूं, तो मुझे "HTTP हेडर भेजे जाने के बाद पुनर्निर्देशित नहीं किया जा सकता है"।

2. एमवीसी फ्रेमवर्क: एक दृश्य के आउटपुट को कैप्चर करना

यदि मैं इसका उपयोग करता हूं, तो मैं पुनर्निर्देशन करने में असमर्थ प्रतीत होता हूं, क्योंकि यह उस दृश्य को प्रस्तुत करने का प्रयास करता है जो मौजूद नहीं हो सकता है। यदि मैं दृश्य वापस करता हूं, तो यह पूरी तरह से गड़बड़ है और बिल्कुल भी सही नहीं लगता है।

क्या किसी के पास इन मुद्दों के लिए कोई विचार / समाधान है, या बेहतर लोगों के लिए कोई सुझाव है?

बहुत धन्यवाद!

नीचे एक उदाहरण है। मैं जो करने की कोशिश कर रहा हूं वह GetViewForEmail विधि है :

public ActionResult OrderResult(string ref)
{
    //Get the order
    Order order = OrderService.GetOrder(ref);

    //The email helper would do the meat and veg by getting the view as a string
    //Pass the control name (OrderResultEmail) and the model (order)
    string emailView = GetViewForEmail("OrderResultEmail", order);

    //Email the order out
    EmailHelper(order, emailView);
    return View("OrderResult", order);
}

टिम स्कॉट से स्वीकार किए गए उत्तर (मेरे द्वारा थोड़ा स्वरूपित और परिवर्तित):

public virtual string RenderViewToString(
    ControllerContext controllerContext,
    string viewPath,
    string masterPath,
    ViewDataDictionary viewData,
    TempDataDictionary tempData)
{
    Stream filter = null;
    ViewPage viewPage = new ViewPage();

    //Right, create our view
    viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);

    //Get the response context, flush it and get the response filter.
    var response = viewPage.ViewContext.HttpContext.Response;
    response.Flush();
    var oldFilter = response.Filter;

    try
    {
        //Put a new filter into the response
        filter = new MemoryStream();
        response.Filter = filter;

        //Now render the view into the memorystream and flush the response
        viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
        response.Flush();

        //Now read the rendered view.
        filter.Position = 0;
        var reader = new StreamReader(filter, response.ContentEncoding);
        return reader.ReadToEnd();
    }
    finally
    {
        //Clean up.
        if (filter != null)
        {
            filter.Dispose();
        }

        //Now replace the response filter
        response.Filter = oldFilter;
    }
}

उदाहरण उपयोग

आदेश पुष्टिकरण ईमेल प्राप्त करने के लिए नियंत्रक से कॉल को मानते हुए, Site.Master स्थान को पास करना।

string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);

2
आप इसका उपयोग कैसे कर सकते हैं, यह दृढ़ता से टाइप किया गया है। अर्थात। मैं किसी मॉडल को पेज कैसे खिला सकता हूं?
केजेनसेन

इसका उपयोग नहीं कर सकते हैं और बाद में JsonResult बना सकते हैं, क्योंकि हेडर भेजे जाने के बाद सामग्री प्रकार सेट नहीं किया जा सकता (क्योंकि फ्लश उन्हें भेजता है)।
अर्निस लैप्सा

क्योंकि एक भी सही उत्तर नहीं है, मुझे लगता है। :) मैंने एक प्रश्न बनाया जो मेरे लिए विशिष्ट था, लेकिन मुझे पता था कि यह एक व्यापक रूप से पूछा जाएगा।
डेन एटकिन्सन

2
सुझाए गए समाधान MVC 3 में काम नहीं करता है
कैस्पर होल्डम

1
@Qua: सुझाए गए समाधान दो साल से अधिक पुराने हैं। मैं इसे MVC 3 के लिए भी काम करने की उम्मीद नहीं करूँगा! इसके अलावा, अब ऐसा करने के बेहतर तरीके हैं।
डान एटकिंसन

जवाबों:


572

यहाँ मैं क्या लेकर आया हूँ, और यह मेरे लिए काम कर रहा है। मैंने अपने कंट्रोलर बेस क्लास में निम्न विधि जोड़ी। (आप हमेशा इन स्थिर तरीकों को कहीं और बना सकते हैं जो नियंत्रक को एक पैरामीटर के रूप में स्वीकार करते हैं जो मुझे लगता है)

MVC2 .ascx शैली

protected string RenderViewToString<T>(string viewPath, T model) {
  ViewData.Model = model;
  using (var writer = new StringWriter()) {
    var view = new WebFormView(ControllerContext, viewPath);
    var vdd = new ViewDataDictionary<T>(model);
    var viewCxt = new ViewContext(ControllerContext, view, vdd,
                                new TempDataDictionary(), writer);
    viewCxt.View.Render(viewCxt, writer);
    return writer.ToString();
  }
}

रेज़र .cshtml स्टाइल

public string RenderRazorViewToString(string viewName, object model)
{
  ViewData.Model = model;
  using (var sw = new StringWriter())
  {
    var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
                                                             viewName);
    var viewContext = new ViewContext(ControllerContext, viewResult.View,
                                 ViewData, TempData, sw);
    viewResult.View.Render(viewContext, sw);
    viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

संपादित करें: रेजर कोड जोड़ा गया।


31
एक स्ट्रिंग को एक दृश्य प्रदान करना हमेशा "पूरे रूटिंग अवधारणा के साथ असंगत" होता है, क्योंकि इसका रूटिंग से कोई लेना-देना नहीं है। मुझे यकीन नहीं है कि एक जवाब जो काम करता है उसे डाउन वोट मिला।
बेन लेश

4
मुझे लगता है कि आपको रेजर संस्करण की विधि घोषणा से "स्थिर" को हटाने की आवश्यकता हो सकती है, अन्यथा यह नियंत्रककंटेक्ट एट अल नहीं पा सकता है।
माइक

3
आपको उन शानदार व्हाट्सएपों को हटाने के अपने तरीके को लागू करने की आवश्यकता होगी। सबसे अच्छा तरीका है कि मैं अपने सिर के ऊपर से सोच सकता हूं कि स्ट्रिंग को एक XmlDocument में लोड करना है, फिर इसे एक XmlWriter के साथ एक स्ट्रिंग पर वापस लिखें, लिंक के अनुसार मैंने अपनी पिछली टिप्पणी में छोड़ दिया था। मैं वास्तव में आशा करता हूं कि मदद करता है।
बेन लेश

3
हम्म मुझे एक वेबएपी नियंत्रक का उपयोग कैसे करना चाहिए, किसी भी सुझाव की सराहना की जाएगी
अलेक्जेंडर

3
हाय, सभी नियंत्रकों के लिए "स्टेटिक" कीवर्ड के साथ इसका उपयोग करने के लिए इसे सामान्य बनाने के लिए आपको स्थिर वर्ग बनाना होगा और इसके अंदर आपको इस विधि को "नियंत्रक" के रूप में "नियंत्रककान्टेक्स्ट" के साथ रखना होगा। आप इसे यहां stackoverflow.com/a/18978036/2318354 देख सकते हैं ।
Dilip0165

68

यह जवाब मेरे रास्ते में नहीं है। यह मूल रूप से https://stackoverflow.com/a/2759898/2318354 से है, लेकिन यहां मैंने इसे सभी नियंत्रकों के लिए सामान्य बनाने के लिए "स्टेटिक" कीवर्ड के साथ इसका उपयोग करने का तरीका दिखाया है।

उसके लिए आपको staticक्लास इन क्लास फाइल बनानी होगी। (मान लीजिए कि आपका वर्ग फ़ाइल नाम Utils.cs है)

यह उदाहरण रेजर के लिए है।

Utils.cs

public static class RazorViewToString
{
    public static string RenderRazorViewToString(this Controller controller, string viewName, object model)
    {
        controller.ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
            var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }
}

अब आप नियंत्रक के पैरामीटर के रूप में "यह" पास करके निम्न तरीके से अपने नियंत्रक फ़ाइल में नामस्थान जोड़कर अपने नियंत्रक से इस वर्ग को कॉल कर सकते हैं।

string result = RazorViewToString.RenderRazorViewToString(this ,"ViewName", model);

@Sergey द्वारा दिए गए सुझाव के रूप में यह विस्तार विधि नीचे दिए गए अनुसार cotroller से भी कॉल कर सकती है

string result = this.RenderRazorViewToString("ViewName", model);

मुझे आशा है कि यह आपके लिए कोड को साफ और स्वच्छ बनाने के लिए उपयोगी होगा।


1
अच्छा समाधान! एक बात, RenderRazorViewToString वास्तव में एक्सटेंशन मेथड है (क्योंकि आप इस कीवर्ड के साथ कंट्रोलर पैरामीटर पास करते हैं), इसलिए इस एक्सटेंशन मेथड को इस तरह कहा जा सकता है: यह। RenderRazorViewToString ("ViewName", मॉडल);
सेर्गी

@ शेर्ज़ी हम्म ... मुझे इस तरह से जांचने दें, अगर यह मेरे जवाब को अपडेट कर देगा तो ठीक है। वैसे भी आपके सुझाव के लिए धन्यवाद।
Dilip0165

Dilip0165, मुझे var viewResult = ViewEngines.Engines.FindPartialView (कंट्रोलर.कंट्रोलरकोटेक्स्ट, viewName); क्या तुम्हारे पास कोई विचार है?
CB4

@ CB4 मुझे लगता है कि यह "viewName" का मुद्दा हो सकता है जिसे आप फंक्शन में देख रहे हैं। आपको अपने फ़ोल्डर संरचना के अनुसार पूरे मार्ग के साथ "viewName" पास करना होगा। तो इस बात की जाँच करें।
Dilip0165

1
@ मेरे सुझाव के लिए धन्यवाद, मैंने आपके सुझाव के अनुसार अपना उत्तर अपडेट कर दिया है जो पूरी तरह से सही है
दिलीप ०१६५

32

यह मेरे लिए काम करता है:

public virtual string RenderView(ViewContext viewContext)
{
    var response = viewContext.HttpContext.Response;
    response.Flush();
    var oldFilter = response.Filter;
    Stream filter = null;
    try
    {
        filter = new MemoryStream();
        response.Filter = filter;
        viewContext.View.Render(viewContext, viewContext.HttpContext.Response.Output);
        response.Flush();
        filter.Position = 0;
        var reader = new StreamReader(filter, response.ContentEncoding);
        return reader.ReadToEnd();
    }
    finally
    {
        if (filter != null)
        {
            filter.Dispose();
        }
        response.Filter = oldFilter;
    }
}

आपकी टिप्पणी के लिए धन्यवाद, लेकिन यह एक दृश्य के अंदर प्रतिपादन के लिए प्रयोग नहीं किया जाता है? मैंने जिस प्रश्न के साथ अद्यतन किया है, उस संदर्भ में मैं इसका उपयोग कैसे कर सकता हूं?
डैन एटकिंसन

क्षमा करें, अभी भी पिछले साल सिल्वरलाइट के बारे में सोच रहा था जिसका पहला आरसी 0. था। :) मैं आज यह शॉट दे रहा हूं। (जैसे ही मैं दृश्य पथ के सही प्रारूप पर काम करता हूं)
निकोलाईडेंट

यह अभी भी RC1 में रीडायरेक्ट को तोड़ता है
हराया

पराजित: नहीं, यह नहीं है। अगर ऐसा होता है, तो आप कुछ गलत कर रहे हैं।
डेन एटकिन्सन

इसे stackoverflow.com/questions/520863/… के साथ मर्ज किया गया, ViewEnginesCollection की जागरूकता को जोड़ा गया, आंशिक रूप से पॉप करने की कोशिश की और इस stackoverflow.com/questions/520863/… को प्राप्त किया । : ई
अर्निस लैप्सा

31

मुझे एक नया समाधान मिला, जो मौजूदा HttpContext के रिस्पॉन्स स्ट्रीम (जो आपको प्रतिक्रिया के ContentType या अन्य हेडर को बदलने की अनुमति नहीं देता है) के साथ गड़बड़ किए बिना स्ट्रिंग को देखने के लिए प्रदान करता है।

मूल रूप से, आप जो कुछ भी करते हैं वह स्वयं को प्रस्तुत करने के लिए एक नकली HttpContext बनाता है:

/// <summary>Renders a view to string.</summary>
public static string RenderViewToString(this Controller controller,
                                        string viewName, object viewData) {
    //Create memory writer
    var sb = new StringBuilder();
    var memWriter = new StringWriter(sb);

    //Create fake http context to render the view
    var fakeResponse = new HttpResponse(memWriter);
    var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
    var fakeControllerContext = new ControllerContext(
        new HttpContextWrapper(fakeContext),
        controller.ControllerContext.RouteData,
        controller.ControllerContext.Controller);

    var oldContext = HttpContext.Current;
    HttpContext.Current = fakeContext;

    //Use HtmlHelper to render partial view to fake context
    var html = new HtmlHelper(new ViewContext(fakeControllerContext,
        new FakeView(), new ViewDataDictionary(), new TempDataDictionary()),
        new ViewPage());
    html.RenderPartial(viewName, viewData);

    //Restore context
    HttpContext.Current = oldContext;    

    //Flush memory and return output
    memWriter.Flush();
    return sb.ToString();
}

/// <summary>Fake IView implementation used to instantiate an HtmlHelper.</summary>
public class FakeView : IView {
    #region IView Members

    public void Render(ViewContext viewContext, System.IO.TextWriter writer) {
        throw new NotImplementedException();
    }

    #endregion
}

यह ASP.NET MVC 1.0 पर काम करता है, साथ में ContentResult, JsonResult, आदि (मूल HttpResponse पर हेडर बदलते हुए " HTTP हेडर भेजे जाने के बाद सर्वर हेडर टाइप नहीं कर सकता "

अपडेट: ASP.NET MVC 2.0 RC में, कोड थोड़ा बदल जाता है क्योंकि हमें StringWriterदृश्य में लिखने के लिए उपयोग में पास करना होगा ViewContext:

//...

//Use HtmlHelper to render partial view to fake context
var html = new HtmlHelper(
    new ViewContext(fakeControllerContext, new FakeView(),
        new ViewDataDictionary(), new TempDataDictionary(), memWriter),
    new ViewPage());
html.RenderPartial(viewName, viewData);

//...

HtmlHelper ऑब्जेक्ट पर कोई RenderPartial विधि नहीं है। यह संभव नहीं है - html.RenderPartial (viewName, viewData);
मार्टिन एफएफ

1
ASP.NET MVC रिलीज़ 1.0 में RenderPartial एक्सटेंशन विधियों के एक जोड़े हैं। जो मैं विशेष रूप से उपयोग कर रहा हूं वह System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial (यह HtmlHelper, string, object) है। मैं इस बात से अनजान हूँ कि MVC के नवीनतम संशोधनों में इस विधि को जोड़ा गया है या नहीं।
लॉरेंजकॉक

धन्यवाद। बस System.Web.Mvc.Html नेमस्पेस को घोषणा में जोड़ने की आवश्यकता है (अन्यथा html.RenderPartial (..) बेशक अभ्यस्त हो :))
मार्टिन

किसी को भी यह एमवीसी 2 के आरसी के साथ काम करता है? उन्होंने ViewContext में एक अतिरिक्त टेक्स्ट राइटर पैरामीटर जोड़ा। मैंने एक नया स्ट्रिंगराइटर जोड़ने की कोशिश की (), लेकिन यह काम नहीं किया।
beckelmw

1
@beckelmw: मैंने प्रतिक्रिया को अपडेट किया। आपको उस मूल में पास होना चाहिए जिसे StringWriterआप लिखने के लिए उपयोग कर रहे हैं StringBuilder, न कि एक नया उदाहरण या दृश्य का आउटपुट खो जाएगा।
लॉरेंजकके

11

यह आलेख वर्णन करता है कि किसी दृश्य को विभिन्न परिदृश्यों में स्ट्रिंग में कैसे रेंडर किया जाए:

  1. एमवीसी नियंत्रक अपने खुद के एक्शनमेथोड्स को कॉल करता है
  2. एमवीसी नियंत्रक एक और एमवीसी नियंत्रक के एक्शनमेथोड को बुलाता है
  3. WebAPI नियंत्रक एक MVC नियंत्रक के एक ActionMethod बुला रहा है

समाधान / कोड ViewRenderer नामक एक वर्ग के रूप में प्रदान किया गया है । यह GitHub में रिक स्टाल के वेस्टविंडटूलकिट का हिस्सा है

उपयोग (3. - WebAPI उदाहरण):

string html = ViewRenderer.RenderView("~/Areas/ReportDetail/Views/ReportDetail/Index.cshtml", ReportVM.Create(id));

3
इसके अलावा NuGet पैकेज वेस्ट विंड वेब MVC यूटिलिटीज ( nuget.org/packages/Westwind.Web.Mvc ) के रूप में। एक बोनस के रूप में, दृश्य रेंडरर न केवल आंशिक विचारों को प्रस्तुत कर सकता है, बल्कि लेआउट सहित पूरे दृश्य को भी प्रस्तुत कर सकता है। कोड के साथ ब्लॉग लेख: weblog.west-wind.com/posts/2012/May/30/…
Jeroen K

यह बहुत अच्छा होगा अगर इसे छोटे पैकेज में तोड़ दिया जाए। Nuget पैकेज आपके web.config में परिवर्तनों का एक गुच्छा बनाता है और आपकी परियोजना में js फाइलें जोड़ता है, जो तब साफ नहीं किए जाते हैं जब आप इसे अनइंस्टॉल करते हैं: /
जोश Noe

8

यदि आप MVC को पूरी तरह से त्यागना चाहते हैं, जिससे सभी HttpContext मेस से बचना है ...

using RazorEngine;
using RazorEngine.Templating; // For extension methods.

string razorText = System.IO.File.ReadAllText(razorTemplateFileLocation);
string emailBody = Engine.Razor.RunCompile(razorText, "templateKey", typeof(Model), model);

यह यहाँ भयानक ओपन सोर्स रेजर इंजन का उपयोग करता है: https://github.com/Antaris/RazorEngine


अच्छा! क्या आपको पता है कि WebForms सिंटैक्स के लिए एक समान पार्सिंग इंजन है? मेरे पास अभी भी कुछ पुराने WebForms विचार हैं जिन्हें अभी तक रेजर में स्थानांतरित नहीं किया जा सकता है।
दान एटकिन्सन

नमस्ते, मैं razorengine के साथ मुद्दों की एक बहुत कुछ था, और त्रुटि रिपोर्टिंग बहुत अच्छा नहीं है। मुझे नहीं लगता कि Url हेल्पर का समर्थन किया जाता है
Layinka

@Layinka यकीन नहीं है कि अगर यह मदद करता है, लेकिन त्रुटि की जानकारी के अधिकांश CompilerErrorsअपवाद की संपत्ति में है।
जोश नू

5

आपको इस तरह से उपयोग करके स्ट्रिंग में दृश्य मिलेंगे

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

    if (model != null)
        ViewData.Model = model;

    using (StringWriter sw = new StringWriter())
    {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}

इस विधि को हम दो तरह से कहते हैं

string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", null)

या

var model = new Person()
string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", model)

4

एएसपी नेट कोर के लिए अतिरिक्त टिप:

इंटरफेस:

public interface IViewRenderer
{
  Task<string> RenderAsync<TModel>(Controller controller, string name, TModel model);
}

कार्यान्वयन:

public class ViewRenderer : IViewRenderer
{
  private readonly IRazorViewEngine viewEngine;

  public ViewRenderer(IRazorViewEngine viewEngine) => this.viewEngine = viewEngine;

  public async Task<string> RenderAsync<TModel>(Controller controller, string name, TModel model)
  {
    ViewEngineResult viewEngineResult = this.viewEngine.FindView(controller.ControllerContext, name, false);

    if (!viewEngineResult.Success)
    {
      throw new InvalidOperationException(string.Format("Could not find view: {0}", name));
    }

    IView view = viewEngineResult.View;
    controller.ViewData.Model = model;

    await using var writer = new StringWriter();
    var viewContext = new ViewContext(
       controller.ControllerContext,
       view,
       controller.ViewData,
       controller.TempData,
       writer,
       new HtmlHelperOptions());

       await view.RenderAsync(viewContext);

       return writer.ToString();
  }
}

में पंजीकरण Startup.cs

...
 services.AddSingleton<IViewRenderer, ViewRenderer>();
...

और नियंत्रक में उपयोग:

public MyController: Controller
{
  private readonly IViewRenderer renderer;
  public MyController(IViewRendere renderer) => this.renderer = renderer;
  public async Task<IActionResult> MyViewTest
  {
    var view = await this.renderer.RenderAsync(this, "MyView", model);
    return new OkObjectResult(view);
  }
}

3

मैं एमवीसी 1.0 आरटीएम का उपयोग कर रहा हूं और उपरोक्त किसी भी समाधान ने मेरे लिए काम नहीं किया है। लेकिन इस एक ने किया:

Public Function RenderView(ByVal viewContext As ViewContext) As String

    Dim html As String = ""

    Dim response As HttpResponse = HttpContext.Current.Response

    Using tempWriter As New System.IO.StringWriter()

        Dim privateMethod As MethodInfo = response.GetType().GetMethod("SwitchWriter", BindingFlags.NonPublic Or BindingFlags.Instance)

        Dim currentWriter As Object = privateMethod.Invoke(response, BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, New Object() {tempWriter}, Nothing)

        Try
            viewContext.View.Render(viewContext, Nothing)
            html = tempWriter.ToString()
        Finally
            privateMethod.Invoke(response, BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, New Object() {currentWriter}, Nothing)
        End Try

    End Using

    Return html

End Function

2

मैंने एमवीसी 3 और रेजर के लिए एक अन्य वेबसाइट से कार्यान्वयन देखा, इसने मेरे लिए काम किया:

    public static string RazorRender(Controller context, string DefaultAction)
    {
        string Cache = string.Empty;
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        System.IO.TextWriter tw = new System.IO.StringWriter(sb); 

        RazorView view_ = new RazorView(context.ControllerContext, DefaultAction, null, false, null);
        view_.Render(new ViewContext(context.ControllerContext, view_, new ViewDataDictionary(), new TempDataDictionary(), tw), tw);

        Cache = sb.ToString(); 

        return Cache;

    } 

    public static string RenderRazorViewToString(string viewName, object model)
    {

        ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            return sw.GetStringBuilder().ToString();
        }
    } 

    public static class HtmlHelperExtensions
    {
        public static string RenderPartialToString(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
        {
            ViewEngineResult result = ViewEngines.Engines.FindPartialView(context, partialViewName);

            if (result.View != null)
            {
                StringBuilder sb = new StringBuilder();
                using (StringWriter sw = new StringWriter(sb))
                {
                    using (HtmlTextWriter output = new HtmlTextWriter(sw))
                    {
                        ViewContext viewContext = new ViewContext(context, result.View, viewData, tempData, output);
                        result.View.Render(viewContext, output);
                    }
                }
                return sb.ToString();
            } 

            return String.Empty;

        }

    }

रेज़र रेंडर पर अधिक- MVC3 स्टेंडर को रेंडर देखें


हां, यह वास्तव में स्वीकृत उत्तर की एक कॉपी है। :)
डेन एटकिन्सन

2

कंट्रोलरकोनटेक्स्ट पास करने के बिना सर्विस लेयर में एक स्ट्रिंग को देखने के लिए, यहाँ एक अच्छा रिक स्ट्राल आर्टिकल है http://www.codemag.com/Article/1312081 जो एक सामान्य नियंत्रक बनाता है। नीचे कोड सारांश:

// Some Static Class
public static string RenderViewToString(ControllerContext context, string viewPath, object model = null, bool partial = false)
{
    // first find the ViewEngine for this view
    ViewEngineResult viewEngineResult = null;
    if (partial)
        viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
    else
        viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);

    if (viewEngineResult == null)
        throw new FileNotFoundException("View cannot be found.");

    // get the view and attach the model to view data
    var view = viewEngineResult.View;
    context.Controller.ViewData.Model = model;

    string result = null;

    using (var sw = new StringWriter())
    {
        var ctx = new ViewContext(context, view, context.Controller.ViewData, context.Controller.TempData, sw);
        view.Render(ctx, sw);
        result = sw.ToString();
    }

    return result;
}

// In the Service Class
public class GenericController : Controller
{ }

public static T CreateController<T>(RouteData routeData = null) where T : Controller, new()
{
    // create a disconnected controller instance
    T controller = new T();

    // get context wrapper from HttpContext if available
    HttpContextBase wrapper;
    if (System.Web.HttpContext.Current != null)
        wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
    else
        throw new InvalidOperationException("Cannot create Controller Context if no active HttpContext instance is available.");

    if (routeData == null)
        routeData = new RouteData();

    // add the controller routing if not existing
    if (!routeData.Values.ContainsKey("controller") &&
        !routeData.Values.ContainsKey("Controller"))
        routeData.Values.Add("controller", controller.GetType().Name.ToLower().Replace("controller", ""));

    controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
    return controller;
}

फिर सेवा वर्ग में दृश्य प्रस्तुत करने के लिए:

var stringView = RenderViewToString(CreateController<GenericController>().ControllerContext, "~/Path/To/View/Location/_viewName.cshtml", theViewModel, true);

1

जल्द सलाह

एक जोरदार टाइप किए गए मॉडल के लिए बस इसे देखने के लिए ViewData.Model में जोड़ें RenderViewToString में जाने से पहले। जैसे

this.ViewData.Model = new OrderResultEmailViewModel(order);
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);

0

अधिक अज्ञात प्रश्न को दोहराने के लिए, MvcIntegrationTestFramework पर एक नज़र डालें

यह आपको परिणाम प्राप्त करने के लिए अपने स्वयं के सहायकों को लिखने से बचाता है और पर्याप्त रूप से काम करने के लिए सिद्ध होता है। मुझे लगता है कि यह एक परीक्षण परियोजना में होगा और एक बोनस के रूप में आपके पास यह सेटअप होने के बाद अन्य परीक्षण क्षमताएं होंगी। मुख्य चिंता शायद निर्भरता श्रृंखला को छांटना होगा।

 private static readonly string mvcAppPath = 
     Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory 
     + "\\..\\..\\..\\MyMvcApplication");
 private readonly AppHost appHost = new AppHost(mvcAppPath);

    [Test]
    public void Root_Url_Renders_Index_View()
    {
        appHost.SimulateBrowsingSession(browsingSession => {
            RequestResult result = browsingSession.ProcessRequest("");
            Assert.IsTrue(result.ResponseText.Contains("<!DOCTYPE html"));
        });
}

0

यहाँ एक वर्ग है जो मैंने ASP.NETCore RC2 के लिए ऐसा करने के लिए लिखा था। मैं इसका उपयोग करता हूं इसलिए मैं रेजर का उपयोग करके html ईमेल उत्पन्न कर सकता हूं।

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using System.IO;
using System.Threading.Tasks;

namespace cloudscribe.Web.Common.Razor
{
    /// <summary>
    /// the goal of this class is to provide an easy way to produce an html string using 
    /// Razor templates and models, for use in generating html email.
    /// </summary>
    public class ViewRenderer
    {
        public ViewRenderer(
            ICompositeViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IHttpContextAccessor contextAccesor)
        {
            this.viewEngine = viewEngine;
            this.tempDataProvider = tempDataProvider;
            this.contextAccesor = contextAccesor;
        }

        private ICompositeViewEngine viewEngine;
        private ITempDataProvider tempDataProvider;
        private IHttpContextAccessor contextAccesor;

        public async Task<string> RenderViewAsString<TModel>(string viewName, TModel model)
        {

            var viewData = new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
            {
                Model = model
            };

            var actionContext = new ActionContext(contextAccesor.HttpContext, new RouteData(), new ActionDescriptor());
            var tempData = new TempDataDictionary(contextAccesor.HttpContext, tempDataProvider);

            using (StringWriter output = new StringWriter())
            {

                ViewEngineResult viewResult = viewEngine.FindView(actionContext, viewName, true);

                ViewContext viewContext = new ViewContext(
                    actionContext,
                    viewResult.View,
                    viewData,
                    tempData,
                    output,
                    new HtmlHelperOptions()
                );

                await viewResult.View.RenderAsync(viewContext);

                return output.GetStringBuilder().ToString();
            }
        }
    }
}

0

रेजर व्यू पेज को रेंडर करने के लिए मुझे एक बेहतर तरीका मिला जब मुझे ऊपर दिए गए तरीकों से त्रुटि हुई, यह समाधान वेब फॉर्म पर्यावरण और एमवायवी पर्यावरण दोनों के लिए है। किसी कंट्रोलर की जरूरत नहीं है।

यहाँ कोड उदाहरण है, इस उदाहरण में मैंने एक async http हैंडलर के साथ एक mvc क्रिया का अनुकरण किया है:

    /// <summary>
    /// Enables processing of HTTP Web requests asynchronously by a custom HttpHandler that implements the IHttpHandler interface.
    /// </summary>
    /// <param name="context">An HttpContext object that provides references to the intrinsic server objects.</param>
    /// <returns>The task to complete the http request.</returns>
    protected override async Task ProcessRequestAsync(HttpContext context)
    {
        if (this._view == null)
        {
            this.OnError(context, new FileNotFoundException("Can not find the mvc view file.".Localize()));
            return;
        }
        object model = await this.LoadModelAsync(context);
        WebPageBase page = WebPageBase.CreateInstanceFromVirtualPath(this._view.VirtualPath);
        using (StringWriter sw = new StringWriter())
        {
            page.ExecutePageHierarchy(new WebPageContext(new HttpContextWrapper(context), page, model), sw);
            await context.Response.Output.WriteAsync(sw.GetStringBuilder().ToString());
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.