在任务中将Razor视图渲染为字符串

时间:2019-03-05 19:32:12

标签: asp.net-mvc

以下代码可以很好地将Razor View呈现为字符串:

/// 
/// url: /api/createHtml
///
public ActionResult CreateHtml()
{
    // Heavy calculations
    MyModel myModel = new MyModel();
    myModel.Feature1 = ...;
    myModel.Feature2 = ...;
    myModel.Feature3 = ...;

    ViewData.Model = myModel;

    using (var stringWriter = new StringWriter())
    {
        var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, "MyView");
        var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, stringWriter);
        viewResult.View.Render(viewContext, stringWriter);
        viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);

        string html = stringWriter.GetStringBuilder().ToString();

        byte[] htmlBytes = Encoding.ASCII.GetBytes(html);

        System.IO.File.WriteAllBytes(Server.MapPath("~/temp/foo.html"), htmlBytes);
    }

    return JSON(new 
    {
         error = false,
         message = "Your view is available at temp/foo.html"
    });
}

以上代码同步运行,这意味着对/api/createHtml/的AJAX请求将以创建的temp/foo.html文件结束。

我想异步执行此操作:这意味着AJAX请求会通过以下消息快速返回给用户:“ 您的视图可以在temp / foo.html 获得>”。然后用户必须去检查文件是否准备好(通过简单地轮询到temp目录[或使用其他方法,在这个问题上不重要])

因此,当我在Task中尝试相同的代码时,它不起作用:

/// 
/// url: /api/createHtml
///
public ActionResult CreateHtml()
{
    new Task(() =>
    {
        // Heavy calculations
        MyModel myModel = new MyModel();
        myModel.Feature1 = ...;
        myModel.Feature2 = ...;
        myModel.Feature3 = ...;

        ViewData.Model = myModel;

        using (var stringWriter = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, "MyView");
            var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, stringWriter);
            viewResult.View.Render(viewContext, stringWriter); // <--- Problem
            viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);

            string html = stringWriter.GetStringBuilder().ToString();

            byte[] htmlBytes = Encoding.ASCII.GetBytes(html);

            System.IO.File.WriteAllBytes(Server.MapPath("~/temp/foo.html"), htmlBytes);
        }

    }).Start();

    return JSON(new 
    {
         error = false,
         message = "Your view _WILL BE_ available at temp/foo.html"
    });
}

它不起作用,因为它在viewResult.View.Render(...)处引发了异常

  

值不在预期范围内。

传递给viewContext的{​​{1}}在新线程中似乎不再有效,如下所示:ASP.NET MVC: Exception rendering view in new thread

是否存在一种在viewResult.View.Render(...)中呈现视图的解决方法?

我知道我可以使用“ RazorEngine”,这是一个免费的库,可以呈现剃刀视图,而无需所有控制器混合框,但是我更喜欢使用本机代码来重新利用代码。

后期编辑:

一些答案​​认为我想使用“等待异步”。 我不知道。我不想等待任务完成。

2 个答案:

答案 0 :(得分:1)

好吧,您的任务可能正在做应做的事情,但是主要的威胁不是在等他。

尝试使用:

var myTask=new Task(() =>
{
    // all of your code

}).Start();

myTask.Wait();

检查更多info

最好的方法是使用async and await,因为应该将Tasks用于异步操作,祝您好运。

答案 1 :(得分:0)

异步操作方法仅在Web服务器内部异步工作。异步方法的优点是,当它们不需要时(而不是阻塞它),它们会将宝贵的线程释放回线程池中。但是 HttpRequest仍然是同步的。 。您的浏览器将同步等待异步操作方法的响应

您需要的是产生一个新的线程或任务来执行您的长时间运行的任务,然后从action方法中返回。

看看:Long Running Background Tasks in Asp.Net MVC3

这个问题可能也有帮助:Do asynchronous operations in ASP.NET MVC use a thread from ThreadPool on .NET 4