U4-1327 - Umbraco MVC in v4 & v6: ability to change MVC template/view with events in controller

Created by Arnold Visser 17 Dec 2012, 13:24:07 Updated by Sebastiaan Janssen 17 Apr 2013, 09:34:26

Add the ability to change the MVC template/view in the umbraco controller using events.

Pull request done for both v4 and v6

Comments

Sebastiaan Janssen 17 Dec 2012, 13:35:48

Pull request: http://umbraco.codeplex.com/SourceControl/network/forks/mnwsmit/MvcTemplateSwapEvent/contribution/3810


Arnold Visser 17 Dec 2012, 13:36:55

4.0: http://umbraco.codeplex.com/SourceControl/network/forks/mnwsmit/MvcTemplateSwapEvent/contribution/3810


Arnold Visser 17 Dec 2012, 13:37:57

6.0: http://umbraco.codeplex.com/SourceControl/network/forks/mnwsmit/MvcTemplateSwapEvent/contribution/3809


Sebastiaan Janssen 17 Dec 2012, 13:38:06

That's what she said.. ;-)


Randy McCluer 18 Dec 2012, 16:45:17

Very cool. This would be great for swapping out desktop/mobile masters.


Asbjørn Riis-Knudsen 15 Jan 2013, 13:29:29

@Randy: That is actually unnecessary in v6. MVC4 provides native, customizable desktop/mobile switching. But this ability could certainly still have its uses, no doubt about that.


Jeroen Breuer 15 Jan 2013, 14:07:38

I'm currently creating a website with MVC that uses uWebshop 2 and this is used there. Currently running on a custom version of 4.11 that has the code from the fork, but I extended it a bit more. The event to change the template is not enough because if you suddenly return a different view (template) it could also need a new model. So in the attachment is a version which has an extra event. If the template is changed you can also change the model.


Jeroen Breuer 15 Jan 2013, 14:09:04

Hmm does the attachment work? Getting a 404 when trying to download.


Sebastiaan Janssen 15 Jan 2013, 14:11:41

@Jeroen: doesn't work for me. I realize I didn;t update the issue, but we rejected the pull request because it was fixing this in the wrong way. So while your update might work, it's not the way we want to handle this in the core. See the pull request for the full explanation.


Jeroen Breuer 15 Jan 2013, 14:16:57

Removed it if it's not going to be used anyway :-). I'll keep using my custom version of 4.11 so I can use uWebshop with MVC. Doing it with some custom routing is probably a better solution.


Stephan 15 Jan 2013, 14:23:02

For what it's worth there's work-in-progress on that subject at the moment, which unfortunately can't be published because parts of the request pipeline aren't public yet. Working hard to make it all public soon.

@Jeroen: point taken re. being able to change the template ''and'' the model.


Shannon Deminick 17 Jan 2013, 22:38:11

In the meantime guys (@Arnold not sure if you got my email about this) but a workaround that should work and be quite easy is create an MVC global filter. You'd be able to add your global filter to the global filters collection on startup (either in your global.asax or using an IApplicationEventHandler). Then in your filter:

  • Run the filter before an action is executed (assigned)
  • Check that the current controller instance is of type RenderMvcController
  • Change the 'action' value in the route values to whatever template you'd like

I think that'd work without any mods to the core and should be really easy.


Stephan 01 Feb 2013, 16:37:57

Just FYI. The inbound pipeline prepares a PublishedContentRequest which represents what Umbraco must do: the domain, culture, published content, template, rendering engine... and then transfers that request to the appropriate handler (WebForms, MVC...). In the future there will be a PublishedContentRequest.Prepared event that will trigger once the request is prepared and before anything else takes place. There, you will be able to see which content is to be rendered, and to change the template, and replace it with another WebForms ''or'' Mvc template. Now about changing the "template" much later, ie in the controller, well, it's not so much changing the "template" (because eg you won't be able to pick a WebForms template) but changing the "view". An Shannon knows much more than I do about this?


Jeroen Breuer 27 Feb 2013, 08:47:27

Will the PublishedContentRequest.Prepared event be part of 6.1? Is it already somewhere in the source code?


Stephan 27 Feb 2013, 09:48:13

Not fully in the source code, still cleaning up stuff. Hope to push this week or the week after. Yes, should be in 6.1.


Stephan 15 Mar 2013, 17:40:59

@Shannon: if I understand correctly that would be for changing the template from within the MVC controller? And changing only to another MVC template? What would be the relationship between this and PublishedContentRequest.Prepared event, which is precisely intended to let ppl change the template for another one, be it WebForms or MVC?


Shannon Deminick 15 Mar 2013, 17:47:52

@Stephan I'm aware of the PublishedContentRequest.Prepared which is precisely what is required to complete this task. I just updated it because I know that you were creating this event in hopes that you could close this issue :)


Stephan 15 Mar 2013, 18:26:58

Oh OK. Well, it's getting closer and closer... hopefully next week...


Stephan 22 Mar 2013, 16:18:06

The public pipeline has landed in branch 6.1.0-public for review by HQ, should merge into 6.1.0 eventually.


Sebastiaan Janssen 04 Apr 2013, 13:58:42

It's now merged into 6.1.0.


Sebastiaan Janssen 04 Apr 2013, 16:18:00

My bad, this has not yet been merged in, sorry! Scheduled for the final 6.1.0 release though.


Patrick Scott 09 Apr 2013, 15:06:01

The PublishedContentRequest.Prepared event sounds like it might solve a particuarly tricky issue I am working on right now. Can you change the content (NodeID) being rendered in this event also?


Stephan 09 Apr 2013, 15:37:32

Technically, yes. Practically, you might want to question whether it makes sense to do it in the .Prepared event, or via a ContentFinder (formerly known as NotFoundHandler). Content finders run before .Prepared, and are meant to find content based upon the url. So if your idea is to use a special url scheme to pick some content, then a ContentFinder would be more appropriate?


Patrick Scott 09 Apr 2013, 15:45:11

I did a quick search for ContentFinder and can't find any info. The url I want to redirect would also be a valid UMBRACO url, so a NotFoundHandler would not fire. Are ContentFinders different to NotFoundHandlers or has the name just changed? Basically I am looking for a NotFoundHandler which would fire for all page requests.


Stephan 09 Apr 2013, 15:55:23

Umbraco.Web.Routing.IContentFinder -- should be public in 6.1 and is not yet because I'm late.

They are different to NotFoundHandler in that NotFoundHandlers ran once everything else had failed (and in theory, were meant to display a 404 page of some sort, although people started to use them for other things), whereas ContentFinders run way before. In fact, Umbraco implements some important ContentFinder, such as ContentFinderByNiceUrl which tries to find a content based upon the request url.

You can remove, insert, reorder the content finders, so yours could run first, last, whatever. In you case if you want to catch a valid Umbraco url before Umbraco finds the corresponding document, you'd insert your content finder before the built-in finders.

Oh and obviously, I also plan to document all this or at least post some sample code on Our.


Patrick Scott 09 Apr 2013, 16:00:40

Excellent news, sounds like just what I need.


Shannon Deminick 16 Apr 2013, 21:30:08

@Stephan, can we close this now ?


Stephan 17 Apr 2013, 06:41:37

Definitively.


Priority: Minor

Type: Feature (request)

State: Fixed

Assignee: Shannon Deminick

Difficulty: Normal

Category: Architecture

Backwards Compatible: False

Fix Submitted: Pull request

Affected versions: 4.10.0, 4.11.0, 6.0.0, 4.11.1, 4.11.2, 4.11.3, 4.11.4

Due in version: 6.1.0

Sprint:

Story Points:

Cycle: