TempData 仅显示在子局部视图中,而不显示在父局部视图中

Posted

技术标签:

【中文标题】TempData 仅显示在子局部视图中,而不显示在父局部视图中【英文标题】:TempData only displaying in child partial view, not parent partial view 【发布时间】:2015-03-11 17:11:07 【问题描述】:

我正在 Umbraco 网页中创建一个 MVC 迷你应用程序。我在 Umbraco 用户论坛中提出了问题,但到目前为止还没有得到解决方案。

我的 Umbraco 6.1.6 网站有一个 webForms MasterPage(s)。在我的内容页面上是一个富文本编辑器,我在其中放置了一个宏。该宏加载一个宏局部视图,如下所示:

<p><span style="color: red;">@TempData["CustomMessage"]</span></p>

@html.Partial("~/Views/MacroPartials/Admin/Ethics/_Opinions.cshtml")
<br />
<input type="button" value="Add a New Opinion" class="btn btn-default" onclick="OpenCreatePopup()" />

<div id="opinionEditForm"></div>

@Html.Partial 加载一个 jQuery 记录网格。每个都有一个触发以下 javascript 函数的编辑按钮:

function editOpinion(id) 
    var formDiv = $("#opinionEditForm");
    formDiv.html();
    formDiv.load("/umbraco/surface/OpinionsSurface/editOpinion/" + id, function () 
        $("form").removeData("validator");
        $("form").removeData("unobtrusiveValidation");
        $.validator.unobtrusive.parse("form");
        bootstrapValidatorFix();
        formDiv.dialog(
            modal: true,
            width: 830,
            height: 800,
            title: "Edit Ethics Opinion",
            resizable: false
        );
    );

该函数命中一个 SurfaceController:

    // GET: OpinionsSusrface/editOpinion/5
    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    public ActionResult editOpinion(int id)
    
        Table<Opinion> opinions = db.GetTable<Opinion>();

        var opinion = (from o in opinions
                      where o.opinionID == id
                      select new  opinionID = o.opinionID, opinionNumber = o.opinionNumber, title = o.title, opinionDate = o.opinionDate, summary = o.summary, bodyText = o.bodyText ).FirstOrDefault();

        OpinionViewModel ovm = new OpinionViewModel();
        ovm.opinionID = opinion.opinionID;
        ovm.opinionNumber = opinion.opinionNumber;
        ovm.title = opinion.title;
        ovm.opinionDate = opinion.opinionDate.ToString("MM/yyyy");
        ovm.summary = opinion.summary;
        ovm.bodyText = opinion.bodyText;

        ViewBag.Action = "Edit";
        return PartialView("/Views/MacroPartials/Admin/Ethics/_OpinionEdit.cshtml", ovm);
    

它创建了一个编辑表单,之前的 javascript 将该表单注入到上述 div 中,并将该 div 显示为模式对话框。我可以对表单进行更改,点击保存,表单回传到以下控制器:

    // POST: OpinionsSurface/Edit/5
    [HttpPost]
    [NotChildAction]
    [ValidateAntiForgeryToken]
    [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
    public ActionResult editOpinion(OpinionViewModel model)
    
        if (!ModelState.IsValid)
        
            return CurrentUmbracoPage();
        

        Table<Opinion> opinions = db.GetTable<Opinion>();

        Opinion opinion = opinions.Where(u => u.opinionID == model.opinionID).SingleOrDefault();

            opinion.opinionNumber = model.opinionNumber;
            opinion.title = model.title;
            opinion.summary = HttpUtility.HtmlDecode(model.summary);
            opinion.bodyText = HttpUtility.HtmlDecode(model.bodyText);
            opinion.opinionDate = DateTime.Parse(model.opinionDate);
            opinion.link = model.opinionNumber + ".pdf";

        try
        
        db.SubmitChanges();
        
        catch (Exception ex)
        
        
        TempData["CustomMessage"] = "Your form was successfully submitted at " + DateTime.Now;
        return RedirectToUmbracoPage(2097);
    

记录被更新,页面刷新,我的 jQuery 网格显示更新的值。

永远不会发生的是成功消息,传递到 TempData 永远不会显示在第一个局部视图上。

如果我说的话,这似乎是一个奇怪的副作用

<p><span style="color: red;">@TempData["CustomMessage"]</span></p>

在表单所在的部分视图中,下次单击编辑记录时会显示 TempData!这向我证明了TempData还有我的价值,等待使用。那么为什么它只会显示在我的主要部分视图的子部分视图上?为什么它不会显示在最低嵌套部分视图之外的任何位置?

【问题讨论】:

【参考方案1】:

我最近遇到了一个类似的问题,我使用部分视图宏将表单插入富文本编辑器。在提交表单时,我发现我无法在部分视图中访问TempData,并且服务器端验证错误无法正常工作。但是,我可以在页面的 Index 操作方法和父视图中访问此信息,因此看起来宏部分位于不同的控制器上下文中。

为了解决这个问题,我添加了一对操作过滤器属性,用于在会话中存储 ModelStateTempData

public class ExportModelStateToSessionAttribute : ActionFilterAttribute

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        
            HttpContext.Current.Session["ModelState"] = filterContext.Controller.ViewData.ModelState;
        

        HttpContext.Current.Session["TempData"] = filterContext.Controller.TempData;
        base.OnActionExecuted(filterContext);
    

另一个检索数据以在宏部分中使用:

public class ImportModelStateFromSessionAttribute : ActionFilterAttribute

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    
        var modelState = HttpContext.Current.Session["ModelState"] as ModelStateDictionary;
        var tempData = HttpContext.Current.Session["TempData"] as TempDataDictionary;

        HttpContext.Current.Session.Remove("ModelState");
        HttpContext.Current.Session.Remove("TempData");
        if (modelState != null)
        
            filterContext.Controller.ViewData.ModelState.Merge(modelState);
        

        if (tempData != null)
        
            foreach (var item in tempData)
            
                filterContext.Controller.TempData[item.Key] = item.Value;
            
        

        base.OnActionExecuted(filterContext);
    

在您的情况下,您需要将 [ImportModelStateFromSession] 属性添加到您的 GET 方法,并将 [ExportModelStateToSession] 属性添加到您的 POST 方法。

理想情况下,您不必将这些信息存储在会话中,但这是迄今为止我遇到的唯一可行的解​​决方案。

【讨论】:

以上是关于TempData 仅显示在子局部视图中,而不显示在父局部视图中的主要内容,如果未能解决你的问题,请参考以下文章

UIBarButtonItem 未显示在子视图中

在子视图中显示视图控制器

显示另一个控制器的局部视图[重复]

如何在Objective C的表视图中仅显示具有内容的表行

如何在子视图中使用 QLPreviewController 显示页面洗涤器

Cordova 应用程序仅在分屏视图/多个应用程序视图中显示