I found this example of using route hijacking pretty tempting, so I started trying to create my own. The only difference is that I'm using strongly-typed models (through the now-core ModelsBuilder), and I can't find a way to make my custom model inherit the properties of the "normal" model as Sebastian does with his own.
In the example, Sebastian is creating a model in the following way so that he can take advantage of the document type's existing properties, essentially adding his own custom properties on top:
public class BlogOverview : RenderModel
{
public BlogOverview(IPublishedContent content) : base(content)
{ }
public int Page { get; set; }
// More custom properties
}
My own model is called BlogListModel, while my strongly-typed class that I would use instead of a generic IPublishedContent is PageBlogList (essentially, the name of the underlying document type). So what I need is a BlogListModel that will extend PageBlogList with more custom properties.
So my own model starts with something like this:
public class BlogListModel : RenderModel<PageBlogList> {
public BlogListModel(PageBlogList content) : base(content) {
// Some code here ....
}
}
But, of course, this returns a model that is an IPublishedContent and has the additional properties defined, but not the strongly-typed properties of PageBlogList.
In addition, to even use this from my controller, I had to do something like this merry-go-round:
BlogListModel currPage = new BlogListModel ((PageBlogList)model.Content);
Regardless, the problem remains: My currPage is essentially an IPublishedContent, not a PageBlogList. So I can't use extensions built for this, or even its strongly-typed properties.
I don't know if I'm making any sense, but I believe I've totally missed something in the process. Could anybody enlighten me on how (and if) I can correctly use route hijacking with strongly-typed PublishedContentModels?
I'm already in the process of reading the articles, thanks.
My impression on Umbraco route hijacking was exactly that when I first heard about it: Custom routes. But I understood later that it actually had nothing to do with custom routes - it was just a way of intercepting Umbraco's default controller and adding code to make your views "dumber" (as they probably should be). So, as far as I can understand, what you're suggesting probably applies to a different context (e.g. true custom routes)?
Could you copy your controller's method too? Not all the details, just the signature I guess + how you use the models. And also, an example of how you would want to use the models?
public class PageBlogListController : Umbraco.Web.Mvc.RenderMvcController
{
public override ActionResult Index(RenderModel model)
{
BlogListModel currPage = new BlogListModel((PageBlogList)model.Content);
//Some other stuff here
return base.Index(model);
}
}
This is a sample of what I've tried to do. This controller is supposed to create a BlogListModel (essentially, a PageBlogList with some more properties). I know this is not exactly the same as Sebastian's example, since I'm not going for CurrentTemplate but I was just trying to see whether the whole thing would work with stongly-typed models (which it didn't).
I still believe that there's something I'm missing and it probably is silly, but can't figure out what.
public override ActionResult Index(PageBlogList model)
{
var viewModel = new BlogListModel(model);
// stuff...
return CurrentTemplate(viewModel);
}
Things to understand: if you use you own model you have to use CurrentTemplate, you cannot use base.Index(). Then, your custom model cannot add properties to PageBlogList, it just can encapsulate it.
Model (changed it to PageBlogListViewModel for more clarity):
public partial class PageBlogListViewModel : PageBlogList
{
//Due to exception "Type DotSee.Models.BlogListModel is missing a public constructor with one argument of type IPublishedContent."
public PageBlogListViewModel(IPublishedContent currPage) : base(currPage) { }
public PageBlogListViewModel(PageBlogList currPage) : base(currPage) { }
public int Page { get; set; }
public int TotalPages { get; set; }
public int TotalItems { get; set; }
// Some more properties
}
}
Controller:
public class PageBlogListController : Umbraco.Web.Mvc.RenderMvcController
{
public ActionResult PageBlogList(PageBlogList model)
{
PageBlogListViewModel currPage = new PageBlogListViewModel(model);
//more code here
return CurrentTemplate(currPage);
}
}
Route Hijacking and Models Builder - how?
My question is based on this post by Sebastian Jaansen, written in 2014: https://umbraco.com/follow-us/blog-archive/2014/1/27/a-practical-example-of-route-hijacking-in-umbraco/
I found this example of using route hijacking pretty tempting, so I started trying to create my own. The only difference is that I'm using strongly-typed models (through the now-core ModelsBuilder), and I can't find a way to make my custom model inherit the properties of the "normal" model as Sebastian does with his own.
In the example, Sebastian is creating a model in the following way so that he can take advantage of the document type's existing properties, essentially adding his own custom properties on top:
My own model is called BlogListModel, while my strongly-typed class that I would use instead of a generic IPublishedContent is PageBlogList (essentially, the name of the underlying document type). So what I need is a BlogListModel that will extend PageBlogList with more custom properties.
So my own model starts with something like this:
But, of course, this returns a model that is an IPublishedContent and has the additional properties defined, but not the strongly-typed properties of PageBlogList.
In addition, to even use this from my controller, I had to do something like this merry-go-round:
Regardless, the problem remains: My currPage is essentially an IPublishedContent, not a PageBlogList. So I can't use extensions built for this, or even its strongly-typed properties.
I don't know if I'm making any sense, but I believe I've totally missed something in the process. Could anybody enlighten me on how (and if) I can correctly use route hijacking with strongly-typed PublishedContentModels?
Hi Sotiris,
Although the approach is a bit different, it maybe worthwhile looking at the source code of the hybrid framework:
https://our.umbraco.org/projects/developer-tools/hybrid-framework-for-umbraco-v7
Although not really simple, the code related to MasterModel and SurfaceRenderMvcController might help you further.
These two articles should help. Basically you should add your stuff to a partial instead of deriving.
https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki/Understand-And-Extend
https://github.com/zpqrtbnk/Zbu.ModelsBuilder/wiki/Umbraco.ModelsBuilder
Use dll mode.
If you need custom routes, you might wanna go with a custom contentfinder and urlprovider.
Playing at a children's park atm. Soz for short reply. Hth.
I'm already in the process of reading the articles, thanks.
My impression on Umbraco route hijacking was exactly that when I first heard about it: Custom routes. But I understood later that it actually had nothing to do with custom routes - it was just a way of intercepting Umbraco's default controller and adding code to make your views "dumber" (as they probably should be). So, as far as I can understand, what you're suggesting probably applies to a different context (e.g. true custom routes)?
Could you copy your controller's method too? Not all the details, just the signature I guess + how you use the models. And also, an example of how you would want to use the models?
This is a sample of what I've tried to do. This controller is supposed to create a BlogListModel (essentially, a PageBlogList with some more properties). I know this is not exactly the same as Sebastian's example, since I'm not going for CurrentTemplate but I was just trying to see whether the whole thing would work with stongly-typed models (which it didn't).
I still believe that there's something I'm missing and it probably is silly, but can't figure out what.
IIRC in 7.4.3 you can do eg
Things to understand: if you use you own model you have to use
CurrentTemplate
, you cannot usebase.Index()
. Then, your custom model cannot add properties to PageBlogList, it just can encapsulate it.Making sense?
Sweet. Didn't notice the RendereModel-less overload yet. :)
Okay! It looks like that's what I was missing!
So code looks like this now:
Model (changed it to PageBlogListViewModel for more clarity):
Controller:
View:
And now my view "knows" the add on properties that PageBlogListViewModel added to PageBlogList!
It looks like it was a silly confusion after all. It's good to know that I can do hijacking on top of PublishedContentModels. Thanks for the help!
If you've enabled ModelsBuilder in DLL mode, you should have a class under App_Data/Models.
Make sure you include the models in your VS project. You can then type the RenderModel to that type.
There's no real need to adapt it to a BlogListModel if there's no new logic.
In your view, you can now inherit UmbracoTemplatePage
If you do want extra logic, you can add a PageBlogList.partial.cs beside the PageBlogList.generated.cs file, and add methods and properties there.
is working on a reply...