ASP.NET MVC görünümü dize olarak nasıl oluşturulur?


485

İki farklı görünüm (bir e-posta olarak gönderilecek bir dize olarak) ve diğer sayfa bir kullanıcıya görüntülenen çıktı istiyorum.

Bu ASP.NET MVC beta ile mümkün mü?

Birden fazla örnek denedim:

1. ASP.NET MVC Beta Dizeye RenderPartial

Bu örneği kullanırsam, "HTTP üstbilgileri gönderildikten sonra yeniden yönlendirilemiyor."

2. MVC Çerçevesi: Bir görünümün çıktısını yakalama

Bunu kullanırsam, var olmayan bir görünüm oluşturmaya çalışırken, redirectToAction'ı yapamıyorum. Görünümü geri verirseniz, tamamen berbat ve hiç doğru görünmüyor.

Bu sorunlara ilişkin herhangi bir fikrim / çözümüm var mı veya daha iyisi için herhangi bir öneriniz var mı?

Çok teşekkürler!

Aşağıda bir örnek verilmiştir. Ne yapmaya çalışıyorum GetViewForEmail yöntemi oluşturmaktır :

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

Tim Scott'tan kabul edilen cevap (benim tarafımdan biraz değiştirildi ve biçimlendirildi):

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

Örnek kullanım

Sipariş onay e-postasını almak için denetleyiciden bir çağrı kabul ederek Site.Master konumunu iletin.

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

2
Bunu güçlü bir şekilde yazılmış bir görünümle nasıl kullanabilirsiniz? Yani. bir modeli sayfaya nasıl besleyebilirim?
Kjensen

Üstbilgiler gönderildikten sonra içerik türü ayarlanamadığı için (Flush bunları gönderdiği için) bu kullanılamaz ve daha sonra JsonResult oluşturulamaz.
Arnis Lapsa

Çünkü tek bir doğru cevap yok, sanırım. :) Bana özel bir soru yarattım, ama bunun da çok sorulan bir soru olacağını biliyordum.
Dan Atkinson

2
Önerilen çözüm MVC 3'te çalışmaz.
Kasper Holdum

1
@Qua: Önerilen çözüm iki yaşın üzerindedir. Ben de MVC 3 için çalışmak beklemem! Ayrıca, bunu şimdi yapmanın daha iyi yolları var.
Dan Atkinson

Yanıtlar:


572

İşte benimle geldim ve bu benim için çalışıyor. Denetleyici temel sınıfıma aşağıdaki yöntemleri ekledim. (Bu statik yöntemleri her zaman bir denetleyiciyi sanırım parametre olarak kabul eden başka bir yerde yapabilirsiniz)

MVC2 .ascx stili

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

Jilet .cshtml stili

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

Düzenleme: Jilet kodu eklendi.


31
Bir dizeye görünüm oluşturmak her zaman "tüm yönlendirme kavramıyla tutarsız" dır, çünkü yönlendirme ile ilgisi yoktur. İşe yarayan bir cevabın neden aşağı oy aldığından emin değilim.
Ben Lesh

4
Razor sürümünün yöntem bildirimi "statik" kaldırmanız gerekebilir düşünüyorum, aksi takdirde ControllerContext et al.
Mike

3
Bu gereksiz boşluklar için kendi kaldırma yönteminizi uygulamanız gerekir. Başımın üstünden düşünebileceğim en iyi yol, dizeyi bir XmlDocument'e yüklemek, ardından son yorumumda bıraktığım bağlantıya göre bir XmlWriter ile bir dizeye geri yazmaktır. Umarım bu yardımcı olur.
Ben Lesh

3
Hmm bir WebApi Denetleyicisi kullanarak bunu nasıl yapmalıyım, herhangi bir öneri mutluluk duyacağız
Alexander

3
Herkese merhaba, tüm denetleyicilerin ortak olmasını sağlamak için "Statik" anahtar sözcüğü ile kullanmak için statik sınıf yapmak zorundasınız ve içinde bu yöntemi "ControllerContext" parametresi olarak "this" ile koymak zorundasınız. Burada stackoverflow.com/a/18978036/2318354 adresinde görebilirsiniz .
Dilip0165

68

Bu cevap benim yolumda değil. Bu aslında https://stackoverflow.com/a/2759898/2318354 adresinden geliyor, ancak burada tüm Denetleyiciler için ortak hale getirmek için "Statik" Anahtar Kelime ile kullanmanın yolunu gösterdim.

Bunun için staticsınıf dosyasında sınıf yapmak zorundasınız . (Sınıf Dosya Adınızın Utils.cs olduğunu varsayalım)

Bu örnek Razor içindir.

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

Şimdi bu sınıfı Kontrolör Dosyanıza NameSpace ekleyerek "this" parametresini Controller'a parametre olarak geçirerek aşağıdaki sınıfı kontrol cihazınızdan çağırabilirsiniz.

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

@Sergey tarafından verilen öneri olarak bu genişletme yöntemi, aşağıda belirtildiği gibi denetleyiciden de çağrılabilir

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

Bu kod temiz ve derli toplu yapmak için yararlı olacağını umuyoruz.


1
Güzel çözüm! Bir şey, RenderRazorViewToString aslında uzatma yöntemidir (çünkü bu anahtar kelimeyle denetleyici parametresini ilettiğiniz için), bu uzantı yöntemi şu şekilde çağrılabilir: this.RenderRazorViewToString ("ViewName", model);
Sergey

@Sergey Hmmm ... Bu şekilde kontrol edeyim, eğer cevabımı güncelleyeceğimden daha iyiyse. Neyse Öneriniz için teşekkürler.
Dilip0165

Dilip0165, var viewResult = ViewEngines.Engines.FindPartialView (controller.ControllerContext, viewName); Herhangi bir fikrin var mı?
CB4

@ CB4 Bence bu fonksiyona geçtiğiniz "viewName" sorunu olabilir. Klasör yapınıza göre "viewName" ifadesini tam yol ile geçirmeniz gerekir. Bu şeye bir göz atın.
Dilip0165

1
@Sergey Öneriniz için teşekkürler, cevabımı tamamen doğru olan önerinize göre güncelledim
Dilip0165

32

Bu benim için çalışıyor:

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

Yorumunuz için teşekkürler, ancak bu bir görünüm içinde renderleme için kullanılmıyor mu? Soruyu güncellediğim bağlamda nasıl kullanabilirim?
Dan Atkinson

Üzgünüm, geçen yıl ilk rc'si 0 olan Silverlight'ı düşünüyoruz. Bugün bunu deniyorum. (Görünüm yolunun doğru biçimini
öğrenir öğrenmez

Bu durum RC1'deki yönlendirmeleri hala bozuyor
yenildi

mağlup: Hayır, değil. Eğer öyleyse, yanlış bir şey yapıyorsunuz.
Dan Atkinson

Bunu stackoverflow.com/questions/520863/… ile birleştirdi , ViewEnginesCollection hakkında farkındalık ekledi, kısmi görüntüleme yapmaya çalıştı ve bu stackoverflow.com/questions/520863/… . : E
Arnis Lapsa

31

Geçerli HttpContext (bu yanıtın ContentType veya diğer üstbilgileri değiştirmenize izin vermez) Yanıt akışı ile uğraşmak zorunda kalmadan dizeye bir görünüm oluşturan yeni bir çözüm buldum.

Temel olarak, yaptığınız tek şey görünümün kendisini göstermesi için sahte bir HttpContext oluşturmaktır:

/// <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 vb. İle birlikte çalışır (orijinal HttpResponse'deki Üstbilgilerin değiştirilmesi " HTTP üstbilgileri gönderildikten sonra sunucu içerik türünü ayarlayamaz " özel durumu oluşturmaz).

Güncelleme: ASP.NET MVC 2.0 RC'de, görünümü biraz StringWriteryazmak için kullanılan kodu geçirmemiz gerektiğinden kod biraz değişir 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 nesnesinde RenderPartial yöntemi yoktur. Bu mümkün değildir - html.RenderPartial (viewName, viewData);
MartinF

1
ASP.NET MVC sürüm 1.0 RenderPartial uzantısı yöntemleri bir çift vardır. Özellikle kullandığım System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial (bu HtmlHelper, dize, nesne). Yöntemin en son MVC revizyonlarına eklenip eklenmediğinin ve daha öncekilerinde bulunup bulunmadığının farkında değilim.
LorenzCK

Teşekkürler. Sadece System.Web.Mvc.Html ad alanını kullanarak bildirime eklemeniz gerekiyor (başka html.RenderPartial (..) elbette erişilebilir olmayacak :))
MartinF

Herkes bu MVC2 RC ile çalışma var mı? ViewContext'e ek bir Textwriter parametresi eklediler. Sadece yeni bir StringWriter () eklemeyi denedim, ama işe yaramadı.
beckelmw

1
@beckelmw: Yanıtı güncelledim. Yeni bir örneğe değil, StringWriteryazmak için kullandığınız orijinali iletmeniz gerekir StringBuilder; aksi takdirde görünümün çıktısı kaybolur.
LorenzCK

11

Bu makalede , farklı senaryolarda bir dizeye bir görünümün nasıl oluşturulacağı açıklanır:

  1. MVC Kontrol Birimi kendi ActionMethods'ından başka birini çağırıyor
  2. Başka bir MVC Denetleyicisinin ActionMethod'unu çağıran MVC Denetleyici
  3. MVAP Denetleyicisinin ActionMethod'unu çağıran WebAPI Denetleyicisi

Çözüm / kod ViewRenderer adlı bir sınıf olarak sağlanır . GitHub'daki Rick Stahl'un WestwindToolkit'inin bir parçası .

Kullanım (3. - WebAPI örneği):

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

3
Ayrıca NuGet paketi olarak West Wind Web MVC Utilities ( nuget.org/packages/Westwind.Web.Mvc ). Bonus olarak, görünüm oluşturucu yalnızca kısmi görünümleri oluşturmakla kalmaz, aynı zamanda Mizanpaj dahil tüm görünümü de oluşturabilir. Kodlu
Jeroen K

Bunun daha küçük paketlere ayrılması harika olurdu. Nuget paketi, web.config dosyasında bir sürü değişiklik yapar ve projenize js dosyaları ekler; bu dosyaları kaldırdığınızda temizlenmez: /
Josh Noe

8

MVC'yi tamamen bırakmak istiyorsanız, tüm HttpContext karmaşasından kaçınmak istiyorsanız ...

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

Burada müthiş açık kaynaklı Razor Engine kullanılıyor: https://github.com/Antaris/RazorEngine


Güzel! WebForms sözdizimi için benzer bir ayrıştırma motoru olup olmadığını biliyor musunuz? Hala henüz Razor'a taşınamayan bazı eski WebForms görünümlerim var.
Dan Atkinson

Merhaba, jilet ile ilgili bir sürü sorun vardı ve hata raporlama çok hoş değil. Url yardımcısının desteklendiğini düşünmüyorum
Layinka

@Layinka Bunun yardımcı olup olmadığından emin değilim, ancak hata bilgilerinin çoğu CompilerErrorsistisnanın özelliğinde.
Josh Noe

5

görünümü bu yolla dizede alırsınız

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

Bu yöntemi iki şekilde adlandırıyoruz

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

VEYA

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

4

ASP NET CORE için ek ipucu:

Arayüz:

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

Uygulama:

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

Kayıt Startup.cs

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

Ve kontrolörde kullanım:

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

Ben MVC 1.0 RTM kullanıyorum ve yukarıdaki çözümlerin hiçbiri benim için çalıştı. Ama bunu yaptı:

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

MVC 3 ve Razor için başka bir web sitesinden bir uygulama gördüm, benim için çalıştı:

    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;

        }

    }

Razor render- MVC3 hakkında daha fazla bilgi Dize Oluştur


Evet, bu aslında kabul edilen cevabın bir kopyası. :)
Dan Atkinson

2

ControllerContext'i iletmek zorunda kalmadan Servis Katmanı'ndaki bir dizeye bir görünüm oluşturmak için, burada genel bir denetleyici oluşturan http://www.codemag.com/Article/1312081 numaralı iyi bir Rick Strahl makalesi bulunmaktadır . Aşağıdaki kod özeti:

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

Sonra View hizmet sınıfında oluşturmak için:

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

1

Hızlı ipucu

Güçlü yazılan bir model için RenderViewToString'e geçmeden önce onu ViewData.Model özelliğine ekleyin. Örneğin

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

0

Daha bilinmeyen bir sorudan tekrarlamak için MvcIntegrationTestFramework adresine bir göz atın .

Sonuç yayınlamak için kendi yardımcılarınızı yazmanızı sağlar ve yeterince iyi çalıştığı kanıtlanmıştır. Bunun bir test projesinde olacağını ve bu kurulumu yaptıktan sonra bonus olarak diğer test yeteneklerine sahip olacağını varsayıyorum. Ana rahatsızlık muhtemelen bağımlılık zincirini sıralamak olacaktır.

 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 için bunu yapmak için yazdığım bir sınıf. Razor kullanarak html e-posta oluşturabilmem için kullanıyorum.

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

Hem web form ortamı hem de mvc ortamı için bu çözüm yukarıdaki yöntemlerle hata aldığımda jilet görünümü sayfası oluşturmak için daha iyi bir yol buldum. Denetleyici gerekmez.

İşte kod örneği, bu örnekte ben bir async http işleyicisi ile bir mvc eylem simüle:

    /// <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());
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.