代码之家  ›  专栏  ›  技术社区  ›  JoakDA

将部分视图呈现为包含其他部分视图的字符串时出现异常

  •  0
  • JoakDA  · 技术社区  · 7 年前

    我正试图将局部视图呈现为一个字符串,以便在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();
    }
    

    当视图不包含partialView时,它工作得很好,但当要呈现的视图调用另一个分部视图时,它抛出异常。例如:

    @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“且字符串值非空的项。”

    拜托,我怎么解决?我知道我可以复制和粘贴第二个局部视图的代码,但这不是我的最佳解决方案,因为我在其他地方使用了这个局部视图,我不想复制相同的代码。

    非常感谢你。最好的问候,

    1 回复  |  直到 7 年前
        1
  •  1
  •   RickL    7 年前

    使用此方法将视图呈现为字符串:

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

    在“父部分视图”中。

    可以使用这个在控制器中调用它(假设您从Ajax请求返回JSON,并且 RenderViewToString 方法位于调用控制器中):

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