2015-03-11 2 views
2

Je crée une mini-application MVC dans une page Web Umbraco. J'ai posé des questions sur les forums d'utilisateurs d'Umbraco mais je n'ai pas encore trouvé de solution.TempData ne s'affiche que dans une vue partielle enfant, pas dans une vue partielle parentale

Mon site Umbraco 6.1.6 comporte une ou plusieurs pages WebForms. Sur ma page de contenu est un éditeur de texte riche dans lequel je place une macro. Cette macro charge une macro Voir partielle qui ressemble à ceci:

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

Le @ Html.Partial charge une grille jQuery d'enregistrements. Chacun a un bouton d'édition qui déclenche la fonction javascript suivante:

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

Cette fonction frappe un 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); 
    } 

qui crée une forme d'édition et les précédentes injectent javascript qui forment dans la div mentionnés ci-dessus et affiche ce div comme un dialogue modal. Je peux apporter des modifications à la forme, cliquez sur Enregistrer, les messages de formulaire au contrôleur suivant:

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

et l'enregistrement est mis à jour, la page est actualisée et ma grille jQuery montre les valeurs mises à jour.

Ce qui n'arrive jamais, c'est que le message de réussite, passé dans TempData, n'est jamais affiché sur la première vue partielle.

Ce qui semble être un effet secondaire étrange, si je mets

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

sur la vue partielle de la forme est, je reçois le TempData affiché la prochaine fois que je clique pour modifier un record! Cela me prouve que TempData a toujours ma valeur, attendant d'être utilisé. Alors, pourquoi ne s'affichera-t-il que sur la vue partielle qui est un enfant de ma vue partielle principale? Pourquoi ne s'affichera-t-il pas à l'extérieur de la vue partielle imbriquée la plus basse?

Répondre

1

J'ai récemment eu un problème similaire avec une macro de vue partielle que j'utilisais pour insérer un formulaire dans un éditeur de texte enrichi. Lors de la soumission du formulaire, j'ai constaté que je ne pouvais pas accéder à TempData dans ma vue partielle et les erreurs de validation côté serveur ne fonctionnaient pas correctement. Toutefois, je pouvais accéder à ces informations dans la méthode d'action Index pour la page et dans la vue parente, de sorte qu'il semble que la macro partielle se trouve dans un contexte de contrôleur différent.

Pour contourner le problème, j'ai ajouté une paire d'attributs de filtre d'action, un pour stocker l'ModelState et TempData à la session:

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

et un autre pour récupérer les données à utiliser dans la partie macro:

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

Dans votre cas, vous auriez besoin d'ajouter ensuite l'attribut [ImportModelStateFromSession] à votre méthode GET et l'attribut [ExportModelStateToSession] à votre méthode POST.

Idéalement, vous ne devriez pas stocker cette information dans la session, mais c'est la seule solution de travail que j'ai rencontrée jusqu'à présent.