Why are notifier items being cleared?

Topics: Writing modules
Sep 1, 2011 at 8:15 PM
Edited Sep 1, 2011 at 8:16 PM

I've got a part which renders a form on a content item via a content part. The form posts to a controller which deals with the form response and adds items to the notifier on error, or to say that the details have been submitted etc.

The controller action method ends with the following lines:

_orchard.Notifier.Add(NotifyTypes.Information, T("Saved"));
var meta = _orchard.ContentManager.GetItemMetadata(part.ContentItem);
return RedirectToRoute(meta.DisplayRouteValues);

However, I've noticed that on returning, nothing is displayed in the notifer section at the top of the page. Setting a breakpoint at the end of my action method lets me check _orchard.Notifier.List().Count() which is 1, however if I set a breakpoint on the Display method of my content part's driver, it is back to 0.

I get the same results if I use RedirectToAction as well:

return RedirectToAction((meta.DisplayRouteValues["Action"] ?? "").ToString()
(meta.DisplayRouteValues["Controller"] ?? "").ToString(),
new { Id = form.ContentItem.Id, Area = meta.DisplayRouteValues["Area"] });

This confused me at first, then I thought "Well, it's doing a redirect, which means a new request, so the notifier is being reset somehow." (to be honest I'm not particularly well-versed with the ins-and-outs of ASP MVC routing other than what I've encountered with Orchard, but that explanation wouldn't seem like 'odd' with Web Forms), but this doesn't match any behavior I see anywhere else with the notifier, for instance in Orchard.Users.Controllers.AccountController:

_orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link."));
return RedirectToAction("LogOn");

Similarly, I've got this working in another module (albeit posting from, and returning to an [Admin] controller):

_orchard.Notifier.Add(NotifyType.Information, T("{0} assigned", name));
return RedirectToAction("Edit", new { id = Service });

Clearly I'm missing something here or making a wildly incorrect assumption somewhere along the line - can anyone point me in the right direction? 

Coordinator
Sep 2, 2011 at 12:29 AM

I am not completely sure, because I have seen that sometimes notifications are not rendered on the fron end, and the request after when we are in admind they are there, but I also got some notifications working on the front end from some modules. I suspect notifications created from a front end controller are displayed on the front end, and same for admin controllers. But this is to be verified.

Willing to open a bug for that ?

Sep 2, 2011 at 7:20 AM
sebastienros wrote:

 I suspect notifications created from a front end controller are displayed on the front end, and same for admin controllers. But this is to be verified.

That is a very interesting point. If I decorate my controller with a [Themed] attribute, it starts to work! So to extend your point, notifications created from a controller marked with neither [Admin] or [Themed] apparently aren't displayed.

Inevitably, my question is now "Why?". The default implementation of INotifer is very simple and doesn't appear to keep track of the location from which the notification is set.

Feb 17, 2012 at 12:53 AM

Sorry for dragging up an old(ish) thread, but I was looking everywhere for a solution to why notifications don't show up on the Home Page and couldn't find one, so I looked into it myself.

Normally, the notifications are added to the active controller's TempData by the NotifyFilter's OnActionExecuted() method, and then pulled from the TempData in OnResultExecuting() and added to the Messages layout zone. Which works except whenever you access the home page...

Enter RoutableHomePageProvider and the HomePage module (in Orchard.Core). When the provider is asked to GetHomePage() by the Index action of the HomeController, it fetches the ContentItem for the home page and returns it in a brand new PartialViewResult for the "Routable.HomePage" view, which it passes back to the HomeController. The HomeController then sets up the Model and ViewData and returns the PartialViewResult to the MVC pipeline. Notice anything missing? That's right, because it's a new PartialViewResult the TempData is never assigned, so the notifications don't get rendered until the next page that isn't the home page is accessed. And by then, the messages are out-of-date and don't really make sense.

So the first step is to get the TempData back onto the result:

Open HomeController.cs in Orchard.Web/Core/HomePage/Controllers, add the bolded line with the comment at line 44:

    var result = provider.GetHomePage(item);
    if (result is ViewResultBase) {
        var resultBase = result as ViewResultBase;
        ViewData.Model = resultBase.ViewData.Model;
        resultBase.ViewData = ViewData;
        resultBase.TempData = TempData; // attach notifications for NotifyFilter
    }

If you test it at this point, you'll see notifications showing up on the home page! Hooray! But wait, they show up twice?! The reason is that the Routable.HomePage.cshtml view actually calls Html.RenderAction() to render out the ContentItem. This means another PartialViewResult, which also gets processed by the NotifyFilter.OnResultExecuting() method, and they are added twice. So we just need to stop it adding the messages when the Routable.HomePage view is rendered, and let the ContentItem do it.

Open NotifyFilter.cs in Orchard/UI/Notify, add the 5 bolded lines at line 63:

public void OnResultExecuting(ResultExecutingContext filterContext) {
    var viewResult = filterContext.Result as ViewResultBase;

    // if it's not a view result, a redirect for example
    if (viewResult == null)
        return;

    // if the View is Routable.HomePage in a PartialViewResult from the HomeController, 
    // don't process the messages yet (they will be added by the Content Item when it is 
    // rendered from the view)
    if (viewResult.ViewName == "Routable.HomePage")
        return;

    var messages = Convert.ToString(viewResult.TempData[TempDataMessages]);
    if (string.IsNullOrEmpty(messages))
        return;// nothing to do, really

 

And we're done! Hope this helps somebody.

How would I go about submitting this as a patch so it can be integrated into the main repository?

Coordinator
Feb 17, 2012 at 12:55 AM

http://docs.orchardproject.net/Documentation/Contributing-patches

Coordinator
Feb 17, 2012 at 1:37 AM

On 1.x branch it would be irrelevant as their is no more HomePAgeProvider. Can you check the issue is still effective on 1.x first ?

Feb 17, 2012 at 4:57 AM

Hi Sebastien,

I see you've recently merged Autoroute and Alias with 1.x (sorry I didn't see those before). I don't know how they work (yet), but you are right that my change is only relevant for users running Orchard <=1.3 and the default RoutableHomePageProvider/HomeController combo.

As they're now removed there is presumably no need for this patch. It is only because the new PartialViewResult is never being assigned any TempData that the notifications weren't showing up.

Looks like I need to go and find out how to use these new Autoroute and Alias modules, are how the removal of RoutePart is going to break my modules... ;)

Thanks

Coordinator
Feb 17, 2012 at 6:00 PM

If you can give me a small repro to test if notifications work on the homepage, I can ensure it works. Also please post any issue you have while migrating to 1.x

Feb 19, 2012 at 10:19 PM

There are two main cases. The first is if you are on the home page and click the Edit link, update its contents from the dashboard and click Save, then it redirects you back to the item (the home page), and there should be a notification saying 'Item updated' or whatever the Driver for that part has implemented.

The other case is where some event happens like logging in ("Welcome back"), or something outputs an message to the notification queue, like an invalid parameter was passed to a controller or a service failed to do something, etc. and then a call to RedirectLocal("~/") for example, sends the user back to the home page.

In Orchard 1.3.xxx (it says 1.3.0.0 in dashboard but it's running on changeset 6059f573ee035c4ef8617c404f0b77ab5f928faf), with no modifications, the messages do not show up until a page other than the home page is accessed, for example browsing to a different Page content item (say, /about-us). Then the message shows up ("Item updated" or "Welcome back", etc.) which looks a bit weird.

I will attempt to update my solution today to the tip changeset and will post back how it goes. I fully expect that once I get the solution upgraded this problem will go away because there will be no more custom override of the View/Result pipeline, because the HomeController and RoutableHomePageProvider will be gone.

Feb 20, 2012 at 5:04 AM

Some things are still broken in my Module (some to do with RoutePart, others not), but I can confirm that if you update the content item for the home page, it sends you back there and the message shows up.

Thanks