【问题标题】:Render MVC PartialView into SignalR response将 MVC PartialView 渲染到 SignalR 响应中
【发布时间】:2012-07-23 11:26:04
【问题描述】:

我想将 PartialView 呈现为 HTML 字符串,以便将其返回给 SignalR ajax 请求。

类似:

SignalR 集线器 (mySignalHub.cs)

public class mySignalRHub: Hub
{
    public string getTableHTML()
    {
        return PartialView("_MyTablePartialView", GetDataItems()) // *How is it possible to do this*
    }
}

Razor PartialView (_MyTablePartialView.cshtml)

@model IEnumerable<DataItem>

<table>
    <tbody>
        @foreach (var dataItem in Model)
        {
        <tr>
            <td>@dataItem.Value1</td>
            <td>@dataItem.Value2</td>
        </tr>
        }
    </tbody>
</table>

HTML (MySignalRWebPage.html)

<Script>
    ...      
    //Get HTML from SignalR function call
    var tableHtml = $.connection.mySignalRHub.getTableHTML();

    //Inject into div
    $('#tableContainer).html(tableHtml);
</Script>

<div id="tableContainer"></div>

我的问题是我似乎无法在 Controller 之外呈现 PartialView。甚至可以在 Controller 之外渲染 PartialView 吗?如果仍然能够利用 Razor 附带的出色的 HTML 生成功能,那就太好了。

这一切都错了吗?还有其他方法吗?

【问题讨论】:

  • 也有兴趣... 想法?你可以在控制器之外渲染局部吗?
  • 这不是一种方便的方法。最好只返回 kson 数据,然后建立客户端模板,该模板已经在页面中。 tempate,反过来可以用部分视图渲染

标签: c# asp.net-mvc asp.net-mvc-3 partial-views signalr


【解决方案1】:

这里,这是我在 ajax 控制器中使用的,我对其进行了一些修改,以便可以从方法而不是控制器调用它,方法 returnView 呈现您的视图并返回 HTML 字符串,因此您可以使用 JS/ 插入它当您在客户端接收它时,将 jQuery 放入您的页面:

  public static string RenderPartialToString(string view, object model, ControllerContext Context)
        {
            if (string.IsNullOrEmpty(view))
            {
                view = Context.RouteData.GetRequiredString("action");
            }

            ViewDataDictionary ViewData = new ViewDataDictionary();

            TempDataDictionary TempData = new TempDataDictionary();

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(Context, view);

                ViewContext viewContext = new ViewContext(Context, viewResult.View, ViewData, TempData, sw);

                viewResult.View.Render(viewContext, sw);

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

        //"Error" should be name of the partial view, I was just testing with partial error view
        //You can put whichever controller you want instead of HomeController it will be the same
        //You can pass model instead of null
        private string returnView()
        {
            var controller = new HomeController();
            controller.ControllerContext = new ControllerContext(HttpContext,new System.Web.Routing.RouteData(), controller);
            return RenderPartialToString("Error", null, new ControllerContext(controller.Request.RequestContext, controller));
        }

我没有在集线器上测试它,但它应该可以工作。

【讨论】:

  • 我使用类似的技术将各种视图呈现为字符串,以便将它们作为电子邮件发送,并且到目前为止已被证明是有效的。唯一的问题是,由于参数中的 ControllerContext,从控制器外部调用它可能会变得很棘手。
  • @Forty-Two 我认为这应该很好,因为我在调用此方法之前初始化了控制器的实例。您可以看到从头开始制作的 ControllerContext 实例。如果有人测试它只是为了让我知道,那就太好了,因为我正在度假,没有地方可以测试它。
  • 嗯。这最初看起来可以解决问题,但是当我完全测试时,我一直遇到问题:没有可用的路由数据(因为请求不是通过 MVC 路由路由的)。添加了虚假路由以解决此问题。现在在尝试查找部分视图时出现空引用异常......它仍然感觉这种方法正在逆流而上。我将研究其他一些选项(例如 Razor 模板引擎),看看这对我有什么帮助。当我发现更多信息时,我会更新这篇文章。
  • @James 只要您的局部视图在共享文件夹中,控制器就可以是任何控制器,如果不是,那么您必须使用局部视图所属的控制器实例,这是否解决了空引用?
  • @James 你能分享一下这条路线的样子吗?
【解决方案2】:

可能最好的选择是使用RazorEngine,正如Wim 所建议的那样。

public class mySignalRHub: Hub
{
    public string getTableHTML()
    {
        var viewModel = new[] { new DataItem { Value1 = "v1", Value2 = "v2" } };

        var template = File.ReadAllText(Path.Combine(
            AppDomain.CurrentDomain.BaseDirectory,
            @"Views\PathToTablePartialView\_MyTablePartialView.cshtml"));

        return Engine.Razor.RunCompile(template, "templateKey", null, viewModel);
    }
}

【讨论】:

  • 看起来很有趣。但是,这个库存在并发使用的问题,在 web 环境中不能很好地工作。有关详细信息,请参阅此线程:stackoverflow.com/questions/6444277/…。该引擎的作者正在重写以解决这些问题,但该项目似乎有一段时间没有任何动静 - 现在可能是一个死项目:github.com/Antaris/RazorEngine
  • @James RazorEngine v3(当前的NuGet package)在多线程场景中应该可以正常工作。你只需要实例化一个TemplateService,而不是调用静态方法Razor.Parse。查看this post了解更多详情。
【解决方案3】:

除了上面@user1010609 提供的答案之外,我也很努力地解决了这个问题,并最终得到了一个函数,该函数返回给定控制器名称、视图和模型路径的呈现的 PartialView。

考虑到您没有控制器这一事实,因此通常状态都不是来自 SignalR 事件。

public static string RenderPartialView(string controllerName, string partialView, object model)
{
    var context = new HttpContextWrapper(System.Web.HttpContext.Current) as HttpContextBase;

    var routes = new System.Web.Routing.RouteData();
    routes.Values.Add("controller", controllerName);

    var requestContext = new RequestContext(context, routes);

    string requiredString = requestContext.RouteData.GetRequiredString("controller");
    var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
    var controller = controllerFactory.CreateController(requestContext, requiredString) as ControllerBase;

    controller.ControllerContext = new ControllerContext(context, routes, controller);      

    var ViewData = new ViewDataDictionary();

    var TempData = new TempDataDictionary();

    ViewData.Model = model;

    using (var sw = new StringWriter())
    {
        var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, partialView);
        var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, ViewData, TempData, sw);

        viewResult.View.Render(viewContext, sw);
        return sw.GetStringBuilder().ToString();
    }
}

你可以用类似的东西来称呼它:

RenderPartialView("MyController", "~/Views/MyController/_partialView.cshtml", model);

【讨论】:

  • Response is not available in this context. 我在var viewResult=ViewEngines.Engines.FindView(controller.ControllerContext,viewName,masterName) 上遇到了这个异常。有什么帮助吗?
【解决方案4】:

您是否考虑过使用像 http://razorengine.codeplex.com/ 这样的剃须刀模板引擎? 你不能用它来解析局部视图,但你可以用它来解析剃刀模板,这几乎类似于局部视图。

【讨论】:

  • 很有趣,谢谢。请参阅下面对 Paolo 帖子的评论。我可能会进一步测试,但该项目似乎存在一些潜在问题。
【解决方案5】:

如何使用RazorEngineHostRazorTemplateEngine。我发现这个nice article 可能就是你要找的东西。这是关于在 ASP.NET (MVC) 之外托管 Razor。

【讨论】:

    【解决方案6】:

    根据下面提供给类似问题的答案,我建议使用

    Html.Partial(partialViewName)

    它返回一个 MvcHtmlString,您应该可以将其用作 SignalR 响应的内容。但是,我没有对此进行测试。

    堆栈溢出问题:Is it possible to render a view outside a controller?

    【讨论】:

    • “HTML”对象的类型是“HTMLHelper”。要实例化它,您需要一个 ViewContext。要实例化一个 ViewContext 你需要一个 ControllerContext... 回到同样的问题。没有控制器。感谢您的关注!
    猜你喜欢
    • 2013-12-06
    • 1970-01-01
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多