【问题标题】:MVC RenderAction from View Error after model error模型错误后视图错误中的 MVC RenderAction
【发布时间】:2013-05-24 21:19:55
【问题描述】:

我在使用 RenderAction 时遇到了一个奇怪的问题。由于我的视图模型非常复杂,我将尝试简化流程,如下所示:

  1. 浏览器请求控制器操作。
  2. 动作填充复杂的视图模型并传递给视图
  3. View 包含一个 renderAction 来构建子/部分视图。 (一世 此时使用 renderAction 而不是 partialView 由于模型的复杂性,部分视图需要。)
  4. 这会根据需要继续进行,并且视图会在浏览器中正确显示。
  5. 如果我在回发一些不良数据后创建模型错误,然后将同一模型返回到同一视图,则在调用 renderAction 时会引发错误。调试时,会访问控制器,但会跳过该操作,应用直接进入控制器底部的 disposing。

似乎唯一的区别是填充大视图模型的主控制器操作(不是部分)首先通过 get 到达,然后在通过 post 到达时失败。我用这个模型玩了几个小时——甚至从头开始重新创建模型——所以它与模型无关。

这是堆栈跟踪:

    at System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride)
   at System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage)
   at System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
   at System.Web.HttpServerUtilityWrapper.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
   at System.Web.Mvc.Html.ChildActionExtensions.ActionHelper(HtmlHelper htmlHelper, String actionName, String controllerName, RouteValueDictionary routeValues, TextWriter textWriter)
   at System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper htmlHelper, String actionName, Object routeValues)
   at ASP._Page_Views_Pricelist__drawProductPricelistProductRow_cshtml.Execute() in c:\Users\Administrator\Documents\ProofPix_TFS\ProofPix\ProofPixAdmin\Views\Pricelist\_drawProductPricelistProductRow.cshtml:line 35
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection)
   at System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper htmlHelper, String partialViewName, Object model)
   at ASP._Page_Views_Pricelist_edit_cshtml.Execute() in c:\Users\Administrator\Documents\ProofPix_TFS\ProofPix\ProofPixAdmin\Views\Pricelist\Edit.cshtml:line 121
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.StartPage.RunPage()
   at System.Web.WebPages.StartPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)

这里是渲染动作:

Html.RenderAction("_pricelistProductOptions", new { id = Model.Product.ProductId, ShowHtml = false });

非常感谢您的帮助。顺便说一句(有点新)!

编辑(添加操作)

        // POST: /Pricelist/Edit/5

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(adminEditPricelistVM adminEditPricelistVM)
    {

        if (ModelState.IsValid)
        {
            //Code removed for simplicity

            return RedirectToAction("Edit", new { id = pricelist.PricelistId });
        }

        int vendorId = (int)adminEditPricelistVM.VendorId;
        Vendor vendor = (from b in db.Vendors where b.VendorId == vendorId select b).SingleOrDefault();

        adminEditPricelistVM.ProductCategories = (from a in db.ProductCategories
                                                  from b in db.VendorProductCategory
                                                  where b.VendorId == vendorId && a.ProductCategoryId == b.ProductCategoryId
                                                  select a).OrderBy(o => o.SortOrder).ToList();

        List<Product> products = (from a in db.Products where a.DiscontinuedDate == null && a.VendorId == 1 select a).OrderBy(o => o.SortOrder).ToList();

        //repopulate ProductCategory and Vendor nav properties in the Formula items as these are no longer populated after post
        foreach(PricingFormula pf in adminEditPricelistVM.PricingFormulas){
            pf.ProductCategory = (from a in adminEditPricelistVM.ProductCategories where a.ProductCategoryId == pf.ProductCategoryId select a).SingleOrDefault();
            pf.Vendor = vendor;
        }


        adminEditPricelistVM.Pricelist.PricingFormulas = new List<PricingFormula>();
        adminEditPricelistVM.Pricelist.PricingFormulas.AddRange(adminEditPricelistVM.PricingFormulas);

        List<PricelistProduct> thisFilteredPP = (from a in adminEditPricelistVM.Pricelist.PricelistProducts where a.ProductId > 0 select a).ToList();
        List<PricelistProductOption> thisOptionsToDelete = new List<PricelistProductOption>();
        List<PricelistProductOptionsDetail> thisOptionDetailsToDelete = new List<PricelistProductOptionsDetail>();

        //filter pricelistProducts so only selected options remain in list
        foreach (PricelistProduct pp in thisFilteredPP)
        {
            pp.PricelistId = adminEditPricelistVM.Pricelist.PricelistId;
            var x = pp.ProductId;


            foreach (PricelistProductOption ppo in pp.PricelistProductOptions)
            {
                //repopulate PricelistProduct object
                ppo.PricelistProduct = pp;
                ppo.PricelistProductId = pp.PricelistProductId;

                int numPODs = (from a in ppo.PricelistProductOptionsDetails where a.ProductOptionsDetailId > 0 select a).Count();

                if (numPODs == 0)
                {
                    thisOptionsToDelete.Add(ppo);

                }
                else
                {

                    foreach (PricelistProductOptionsDetail ppod in ppo.PricelistProductOptionsDetails)
                    {
                        //repopulate  PricelistProductOption object
                        ppod.PricelistProductOption = ppo;
                        ppod.PricelistProductOptionsId = ppo.PricelistProductOptionId;

                        if (ppod.ProductOptionsDetailId == 0)
                        {
                            thisOptionDetailsToDelete.Add(ppod);
                        }
                        else //POD is selected but if it is the default option and it is the only option and it is priced at 0.00, then we will remove it to as it is the default setting.
                        {

                            if (ppod.Price == 0 && numPODs == 1)
                            {
                                ProductOptionsDetail prodOpDet = (from c in db.ProductOptionsDetails where c.ProductOptionsDetailId == ppod.ProductOptionsDetailId select c).SingleOrDefault();
                                if (prodOpDet.IsDefault == true)
                                {
                                    thisOptionsToDelete.Add(ppo);
                                }
                            }
                        }
                    }

                    foreach (PricelistProductOptionsDetail dppod in thisOptionDetailsToDelete)
                    {
                        ppo.PricelistProductOptionsDetails.Remove(dppod);
                    }
                    thisOptionDetailsToDelete.Clear();
                }
            }

            foreach (PricelistProductOption dppo in thisOptionsToDelete)
            {
                pp.PricelistProductOptions.Remove(dppo);
            }
            thisOptionsToDelete.Clear();
        }

        adminEditPricelistVM.Pricelist.PricelistProducts = new List<PricelistProduct>();
        adminEditPricelistVM.Pricelist.PricelistProducts.AddRange(thisFilteredPP);

        adminEditPricelistVM.PPPVMs =
               (from product in products
                join pricelistProduct in adminEditPricelistVM.Pricelist.PricelistProducts on product.ProductId equals pricelistProduct.ProductId into gj
                from subpricelistProduct in gj.DefaultIfEmpty()
                select new adminEditProductsPricelistProductsVM()
                {
                    CategoryId = (int)product.ProductCategoryId,
                    Product = product,
                    PricelistProduct = subpricelistProduct
                }).ToList();

        //repopulate PricelistProducts.Product and PricelistProducts.ProductCategory in Pricelist
        foreach (PricelistProduct pp in adminEditPricelistVM.Pricelist.PricelistProducts)
        {
            pp.Product = (from p in products where p.ProductId == pp.ProductId select p).SingleOrDefault();
            pp.ProductCategory = (from a in adminEditPricelistVM.ProductCategories where a.ProductCategoryId == pp.ProductCategoryId select a).SingleOrDefault();
            pp.Pricelist = adminEditPricelistVM.Pricelist;
        }

        ViewBag.PricingFormulaRoundingTypes = (from c in db.PricingFormulaRoundingTypes select c).ToList();

        var errors = ModelState.Select(x => x.Value.Errors).ToList();
        return View(adminEditPricelistVM);

    }

【问题讨论】:

  • 至少向我们展示操作方法如何,尤其是签名?
  • 感谢 JTMon。我加了。
  • 抛出的错误是什么? Model.Product 是否为空?它的 id 是空的吗?您需要提供更多代码,因为我不知道第一次运行时调用了什么操作方法(在第 1 点中)。您不需要提供方法,只需提供签名和任何重定向、返回等以及视图的重要部分。

标签: asp.net-mvc-4 renderaction


【解决方案1】:

这个答案只是一个巨大的问题,因为实际的错误没有显示,只是堆栈跟踪。

//repopulate PricelistProducts.Product and PricelistProducts.ProductCategory in Pricelist
foreach (PricelistProduct pp in adminEditPricelistVM.Pricelist.PricelistProducts)
{
    pp.Product = (from p in products where p.ProductId == pp.ProductId select p).SingleOrDefault();

您的PricelistProducts 中可能有更多产品,其中ProductId 与您的products 列表中的任何产品都不匹配,导致pp.Product 被设置为空。

当为Model.PricelistProducts 中的每个对象渲染你的动作时

html.RenderAction("_pricelistProductOptions", new { id = Model.Product.ProductId, ShowHtml = false });

它会(可能)抛出一个System.NullReferenceException: Object reference not set to an instance of an object.,因为你不能调用Model.Product.ProductId,因为Model.Product 是空的。

【讨论】:

  • 谢谢,但事实并非如此。正如我所提到的,我从头开始填充模型,但它仍然失败。换句话说,我传递了使用 get 方法时成功运行的相同模型。
  • 那么问题来了,视图_drawProductPricelistProductRow.cshtml中的第35行是什么
【解决方案2】:

您在那里使用 Razor 引擎(*.cshtml 文件)?在这种情况下,您必须使用:

@Html.Action("actionName", "controllerName", new { id="myId" })

而且,您似乎将视图名称放在“_pricelistProductOptions”中,而不是操作。我怀疑你有:public ActionResult _pricelistProductOptions(....) 对吗?

【讨论】:

  • 谢谢。是的,它是 C# 剃须刀。这是动作和视图的名称。当从 get 请求中传递模型时,这一切都可以完美运行。
  • 那么,您很可能会在视图中操纵您的 ID 并搞砸绑定。我们能看到准确的模型和视图渲染吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多