Convert MVC app to support alternates on Partial Views

Topics: Customizing Orchard, Writing modules
Jun 14, 2012 at 7:51 AM
Edited Jun 14, 2012 at 7:54 AM

We have build a custom Orchard Module to implement a application that works with external data. We want to use the power of Orchard to support theming and alternates, but for the latter what is the best way to make (partial) views available for Shape Alternates.

I've seen the discussions on 'Widget partial view from custom controller' and 'Widget without a record or part? 

Do I need to create the AlterTypeDefinition for every page and partial views in order to make them changeable from a Theme (alternates)?

And change the controllers to return a ShapeResult and not the View or Partial View?

What is the best approach for this?

For example you have a Index.cshtml with 3 Html.Partial(). Now for a specific theme we want to override the Index or one or more of the partial views through alternates.

Coordinator
Jun 15, 2012 at 4:42 AM

I'm not sure I understand the question but yes, your actions should return a shape result. The controller action can also set-up alternates.

Jun 16, 2012 at 7:25 AM
Edited Jun 18, 2012 at 8:47 AM

Ok, I made a small POC to test these things, I created a controller

 

    [Themed]
    public class HomeController : Controller
    {
        private readonly IOrchardServices _orchardServices;

        public HomeController(IOrchardServices orchardServices) {
            _orchardServices = orchardServices;
        }

        public ActionResult Index() {
            return new ShapeResult(this, _orchardServices.New.Index());
        }
    }

 

And created a Index.cshtml in Module\Views\Home\ with some static html, after running project I got the error message that the shape could not be found.
So I moved the file to Module\Views and it started to work ---> GREAT! --> is it possible to render a view from a subfolder? (I tried with _orchardServices.New.Home_Index() but didn't work.

Then I enabled ShapeTracing to look if I get the alternates to override in a theme --> YES

One thing I try to solve is: how to create widgets from these Controller/Views without creating extra drivers and parts. 
Is there a simple approach to get this job done? 

Also something we try todo is the following: In previous code we return a ShapeResult for index view, and now I added a @Display(New.SearchWidget()) --> a partial view SearchWidget.cshtml without driver or part. 
I thought it was possible this way to use alternates for this SearchWidget in a theme folder for a specific customer. But when I look in the ShapeDesigner I can only create an alternate for the Index.cshtml. What do I need todo to get an alternate for SearchWidget.cshtml?

What we are trying to do with Orchard is to build a platform that we build a base application and use theming to override (alternates) views and partial views for specific customers. I'm getting the feeling that we need to convert all our partials into widgets and drivers+parts. Or can a MVC app be converted in an easier way without drivers and parts. Because it feels to me like double work if you already have the controllers and views + partial. Or you maybe suggest to move the code from controllers to drivers and extend our models to inherit ContentPart? And use the pages in Orchard to add the widgets?

Can you help me to find an easy way to implement this behavior into Orchard. (It's for a webapp with millions of requests per day, so it could be a good reference of what orchard is able to do :-))


** EDIT 

I just found this post as well on the orchard discussion boards: http://orchard.codeplex.com/discussions/353404

I created a folder structure \Views\Module\ControllerName\(Partial)View.cshtml and override the content. Even the model binding kept working. --> Great

Coordinator
Jun 19, 2012 at 1:33 AM

I'll answer some of the questions. From a controller action, you probably won't really want to create full widgets but it is super easy to create more than just the shape result and inject that into arbitrary zones. For instance, you can inject a IWorkContextAccessor and then do _workContextAccessor.GetContext().Layout.SomeZoneYouWantToInjectInto.Add(someShapeYouNewedUp). That shape itself can have alternates that you create on the shape object: someShapeYouNewedUp.Metadata.Alternates.Add("alternate_shape_name") IIRC.

Also know that a good shortcut in views to create new shapes and display them is @Display.SomeNewShape(SomeProperty: SomeValue, SomeOtherProperty: SomeOtherValue) but any alternates you want on those shapes that you create on the fly you have to add yourself through the Metadata.Alternates property.

But in the end, widgets are probably not the metaphor you're after. What most closely corresponds to a partial view is a shape. A widget is a different abstraction, it's really a full content item.