如何将ASP.NET MVC视图呈现为字符串?


485

我想输出两种不同的视图(一种作为将作为电子邮件发送的字符串),另一种显示给用户。

在ASP.NET MVC beta中可能吗?

我尝试了多个示例:

1. 在ASP.NET MVC Beta中将RenderPartial转换为字符串

如果使用此示例,则会收到“发送HTTP标头后无法重定向”。

2. MVC框架:捕获视图的输出

如果使用此方法,则似乎无法执行redirectToAction,因为它尝试呈现可能不存在的视图。如果我确实返回视图,则它完全被弄乱了,看起来根本不正确。

是否有人对我遇到的这些问题有任何想法/解决方案,或者对更好的问题有任何建议?

非常感谢!

下面是一个例子。我想做的是创建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);
}

蒂姆·斯科特(Tim Scott)接受的答案(由我更改并格式化):

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
如何将其与强类型视图一起使用?就是 如何将模型输入页面?
2009年

无法使用它并在以后创建JsonResult,因为发送标头后无法设置内容类型(因为Flush发送它们)。
阿尼斯·拉普萨09年

我想因为没有一个正确的答案。:)我创建了一个特定于我的问题,但我知道这也是一个普遍问到的问题。
丹·阿特金森

2
建议的解决方案不MVC 3工作
卡斯帕Holdum

1
@Qua:建议的解决方案已使用两年以上。我也不希望它也适用于MVC 3!此外,现在有更好的方法可以做到这一点。
丹·阿特金森

Answers:


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
将视图呈现给字符串始终“与整个路由概念不一致”,因为它与路由无关。我不确定为什么有效的答案会被否决。
Ben Lesh 2010年

4
我认为您可能需要从Razor版本的方法声明中删除“静态”,否则找不到ControllerContext等。
Mike

3
您需要为这些多余的空白实现自己的删除方法。我可以想到的最好的方法是将字符串加载到XmlDocument中,然后按照我在上一条注释中留下的链接,用XmlWriter将其写回到字符串中。我真的希望有帮助。
Ben Lesh 2012年

3
嗯,我该如何使用WebApi控制器执行此操作,任何建议将不胜感激
亚历山大

3
大家好,要对所有控制器使用“ Static”关键字来使其通用,就必须使它成为静态类,而在其中必须将带有“ this”作为参数的方法放在“ ControllerContext”中。您可以在此处查看stackoverflow.com/a/18978036/2318354 it。
Dilip0165

68

这个答案不在我身边。这最初来自https://stackoverflow.com/a/2759898/2318354, 但在这里,我展示了将其与“静态”关键字一起使用以使其对所有Controller通用的方法。

为此,您必须static在类文件中创建类。(假设您的类文件名是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();
        }
    }
}

现在,您可以通过将“ this”作为参数传递给Controller,通过以下方式在控制器文件中添加NameSpace来从控制器中调用此类。

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

根据@Sergey的建议,此扩展方法也可以从cotroller调用,如下所示

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

我希望这对您使代码整洁有帮助。


1
不错的解决方案!一件事,RenderRazorViewToString实际上是扩展方法(因为您使用此关键字传递了控制器参数),因此可以通过这种方式调用此扩展方法:this.RenderRazorViewToString(“ ViewName”,model);
谢尔盖

@Sergey Hmmm ...让我以这种方式检查一下,如果可以的话,我将更新我的答案。无论如何,谢谢您的建议。
Dilip0165 '16

Dilip0165,我在var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext,viewName);上收到空引用错误。你有什么主意吗?
CB4

@ CB4我认为这可能是您传递给函数的“ viewName”问题。您必须按照文件夹结构传递带有完整路径的“ viewName”。所以看看这个东西。
Dilip0165 '16

1
@Sergey感谢您的建议,我已根据您的建议更新了答案,这是完全正确的
Dilip0165 '18

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

感谢您的评论,但是它不是用于视图内部的渲染吗?我在更新问题的背景下如何使用它?
Dan Atkinson

抱歉,去年还在思考Silverlight的第一个rc是0。:)今天我要试一下。(一旦我确定了视图路径的正确格式)
NikolaiDante

这仍然会中断RC1中的重定向

打败:不,不是。如果是这样,则说明您做错了事。
丹·阿特金森

将其与stackoverflow.com/questions/520863/…合并,增加了对ViewEnginesCollection的了解,尝试弹出partialview并获得了stackoverflow.com/questions/520863/…。:E
Arnis Lapsa,

31

我找到了一个新的解决方案,该视图可以将视图呈现为字符串,而不必弄乱当前HttpContext的Response流(不允许您更改响应的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);
MartinF,2009年

1
在ASP.NET MVC 1.0版中,有几种RenderPartial扩展方法。我特别使用的是System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(此HtmlHelper,字符串,对象)。我不知道该方法是否已在MVC的最新版本中添加,而在较早的版本中不存在。
2009年

谢谢。只需要将System.Web.Mvc.Html命名空间添加到using声明(否则将无法访问其他html.RenderPartial(..):))
MartinF,2009年

有谁可以与MVC2的RC一起使用吗?他们向ViewContext添加了一个额外的Textwriter参数。我尝试仅添加一个新的StringWriter(),但没有成功。
beckelmw 2010年

1
@beckelmw:我更新了回复。您必须传递StringWriter用于写入的原始文档StringBuilder,而不要传递新实例,否则视图的输出将丢失。
LorenzCK 2010年

11

本文介绍如何在不同情况下将视图呈现为字符串:

  1. MVC控制器调用其自己的另一个ActionMethods
  2. MVC控制器调用另一个MVC控制器的ActionMethod
  3. WebAPI控制器调用MVC控制器的ActionMethod

解决方案/代码作为称为ViewRenderer的类提供。它是GitHub上 Rick Stahl的WestwindToolkit的一部分。

用法(3-WebAPI示例):

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

3
也作为NuGet包West Wind Web MVC Utilities(nuget.org/packages/Westwind.Web.Mvc)。另外,视图渲染器不仅可以渲染部分视图,还可以渲染包括布局在内的整个视图。博客文章,代码:weblog.west-wind.com/posts/2012/May/30/…–
Jeroen K,

如果将它分成较小的包装,那就太好了。Nuget软件包对您的web.config进行了大量更改,并将js文件添加到您的项目中,然后在您将其卸载时不会清除它们:/
Josh 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);

它在这里使用了很棒的开源Razor Engine:https//github.com/Antaris/RazorEngine


真好!您是否知道WebForms语法是否有类似的解析引擎?我仍然有一些旧的WebForms视图,现在还不能移到Razor。
Dan Atkinson

嗨,我的razorengine有很多问题,错误报告不是很好。我不认为网址助手支持
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

ASP NET CORE的其他提示:

接口:

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

我正在使用MVC 1.0 RTM,但以上解决方案均不适用于我。但这确实做到了:

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和Razor的实现,对我有用:

    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渲染的更多信息-MVC3视图渲染为字符串


是的,这实际上或多或少是已接受答案的副本。:)
丹·阿特金森

2

为了在服务层中呈现字符串视图而不必传递ControllerContext,这里有一篇很好的Rick Strahl文章,网址为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;
}

然后在Service类中呈现View:

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为此目的编写的一个类。我使用它,因此可以使用Razor生成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

当上述方法出现错误时,我发现了一种更好的呈现剃刀视图页面的方法,该方法适用于Web表单环境和MVC环境。无需控制器。

这是代码示例,在此示例中,我使用异步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());
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.