【问题标题】:Exception Rendering a partial view as string that contains another partial view异常将局部视图呈现为包含另一个局部视图的字符串
【发布时间】:2018-08-20 16:10:11
【问题描述】:

我正在尝试将部分视图呈现为字符串以在 JSON 对象中返回。我有这个代码:

/// <summary>
/// Render razor view to a string.
/// </summary>
/// <param name="model">Model sent to view.</param>
/// <param name="filePath">Path to the view location in project hierarchy.</param>
/// <returns>String with the html code of returned view.</returns>
public static string Func_GetRazorViewAsString(object model, string filePath)
{
    var st = new StringWriter();
    var context = new HttpContextWrapper(HttpContext.Current);
    var routeData = new RouteData();
    var controllerContext = new ControllerContext(new RequestContext(context, routeData), new FakeController());
    var razor = new RazorView(controllerContext, filePath, null, false, null);
    razor.Render(new ViewContext(controllerContext, razor, new ViewDataDictionary(model), new TempDataDictionary(), st), st);
    return st.ToString();
}

当 View 不包含 PartialView 时效果很好,但是当要渲染的 View 调用另一个 Partial View 时它会抛出异常。例如:

@using Anpr_Web_Manager.App_GlobalResources
@model IEnumerable<Anpr_Web_Manager.Models.DetectionCardViewModel>

@{
    int iCountElementsRow = 0;
    int iNumberElements = Model.Count();
    int iNumNavigationPages = (int)Math.Ceiling(iNumberElements / (double)3);
}
    <div class="col-12 bootstrap-carousel">
        <div id="carouselDetections" class="carousel slide" data-ride="carousel" data-interval="false">
            @if (iNumberElements != 0)
            {
                @:<ol class="carousel-indicators">
                    <li data-target="#carouselDetections" data-slide-to="0" class="active"></li>
                    for (int i = 1; i < iNumNavigationPages; i++)
                {
                    <li data-target="#carouselDetections" data-slide-to="@i"></li>
                    }
                @:</ol>
            }
            <div class="container carousel-inner">
                <div class="row row-equal row-slider carousel-item active">
                    @foreach (var item in Model)
                    {
                        if (iCountElementsRow != 0 && iCountElementsRow % 3 == 0)
                        {
                            //Insert new row
                            @:</div>
                            @:<div class="row row-equal row-slider carousel-item">
                        }
                        //TODO: RENDER ELEMENT
                        @Html.Partial("~/Views/Capturas/_DetectionElement.cshtml", item);
                        iCountElementsRow++;
                    }
                </div>
            </div>
        </div>
    </div>

异常信息是:

"RouteData 必须包含一个名为 'controller' 且具有非空字符串值的项目。"

请问,我该如何解决?我知道我可以复制和粘贴第二个局部视图的代码,但这不是我最好的解决方案,因为我在其他地方使用此局部视图,我不想重复相同的代码。

非常感谢。最好的问候,

【问题讨论】:

  • 其他部分视图中似乎存在问题。您应该更正您的方法并避免在服务器端代码中呈现视图。如果您可以解释为什么要这样做,则可以提供更好的方法来处理用例。

标签: c# asp.net-mvc razor


【解决方案1】:

使用此方法将 View 渲染为字符串:

public static string RenderViewToString(ControllerContext context, string viewPath, object viewModel = null, bool partial = false)
{
    // get 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 = viewModel;

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

如果你打电话可以工作:

@foreach (var item in Model.SomeIEnumerableModel)
{
    @Html.Partial("~/Views/SomePath/SomeViewTwo.cshtml", item);
}

在“父局部视图”中。

可以使用这个在Controller中调用它(假设你从一个ajax请求返回json,并且RenderViewToString方法位于调用Controller中):

public ActionResult TestViewToString()
{
    var viewModel = new TestViewModel();
    // Populate ViewModel here ...

    string data = RenderViewToString(ControllerContext, "~/Views/SomePath/SomeViewOne.cshtml", viewModel, true);
    return Json(data, JsonRequestBehavior.AllowGet);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 2015-05-31
    相关资源
    最近更新 更多