Treating a module's controller action as a content managed page

Topics: Writing modules
Nov 16, 2012 at 8:51 PM

How would I treat an action in my module's controller as any other orchard page?  That is, expose the zones in the layout and allow the content to be managed in the dashboard?

Do I return a ShapeResult?

 

Coordinator
Nov 16, 2012 at 9:17 PM

Yes. :)

Nov 16, 2012 at 9:18 PM

I'm not sure what you mean here. For the output of anything to be managed by orchard through the dashboard it should be a contentType. You can fairly easily use the IContentManager to access any ContentItem that you want to display using code something like the below adapted to the content item you want to retrieve

        public dynamic GetManagedContentBlock(string id) {
    		var contentItems = _contentManager.Query().ForType(new[] {"ManagedContentBlock"}).Where<IdentifierPartRecord>(x => x.Identifier == id).List();
    		var managedContentBlock = _contentItemFilteringService.GetBestMatchContentItem(contentItems.ToList());
            dynamic itemShape = null;
            if (managedContentBlock != null)
            {
                itemShape = _contentManager.BuildDisplay(managedContentBlock);
            }
            return itemShape;
        }

This code returns a dynamic that you can attach to a view model and inside your view call @Display on it.

As far as having the zones and widgets active around the Content coming from your controller you just need to use the [Themed] attribute either on the action or on the controller as a whole.

Coordinator
Nov 16, 2012 at 9:21 PM

No, for something to be managed in Orchard, you do not need it to be a content type. You can create your own controllers that manage anything you want.

Now if an action is [Themed] and returns a ShapeResult, it will be themed and will be a possible target for widgets to appear on.

Nov 16, 2012 at 9:40 PM

I'm a bit new, how exactly do I return the ShapeResult correctly?  The commented out line is what I thought I might need to do.

 

		public ActionResult Help()
		{
			return View(); 
			//return new ShapeResult(this,_services.New.Content());//View();
		}

Nov 16, 2012 at 9:45 PM
Edited Nov 16, 2012 at 9:46 PM

I was trying to infer how from this tutorial: 

http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-part-6

Coordinator
Nov 16, 2012 at 9:48 PM

What happens if you try that? You should have a themed empty page, as you created an empty Content shape.

Nov 16, 2012 at 10:00 PM
bertrandleroy wrote:

What happens if you try that? You should have a themed empty page, as you created an empty Content shape.

I get an error logged in App_Data\Logs\

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'ClaySharp.Clay' does not contain a definition for 'Add'
   at lambda_method(Closure )
   at ClaySharp.ClayBehavior.InvokeMemberMissing(Func`1 proceed, Object self, String name, INamedEnumerable`1 args) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehavior.cs:line 16
   at ClaySharp.ClayBehaviorCollection.<>c__DisplayClass32.<>c__DisplayClass34.<InvokeMemberMissing>b__31() in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 49
   at ClaySharp.ClayBehavior.InvokeMemberMissing(Func`1 proceed, Object self, String name, INamedEnumerable`1 args) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehavior.cs:line 16
   at ClaySharp.ClayBehaviorCollection.<>c__DisplayClass32.<>c__DisplayClass34.<InvokeMemberMissing>b__31() in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 49
   at ClaySharp.ClayBehaviorCollection.Execute(Func`1 proceed, Func`3 linker) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 13
   at lambda_method(Closure )
   at ClaySharp.Behaviors.NilBehavior.InvokeMember(Func`1 proceed, Object self, String name, INamedEnumerable`1 args) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\Behaviors\NilBehavior.cs:line 19
   at ClaySharp.ClayBehaviorCollection.<>c__DisplayClass14.<>c__DisplayClass16.<InvokeMember>b__13() in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 29
   at ClaySharp.ClayBehavior.InvokeMember(Func`1 proceed, Object self, String name, INamedEnumerable`1 args) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehavior.cs:line 7
   at ClaySharp.ClayBehaviorCollection.<>c__DisplayClass14.<>c__DisplayClass16.<InvokeMember>b__13() in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 29
   at ClaySharp.ClayBehaviorCollection.Execute(Func`1 proceed, Func`3 linker) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 13
   at CallSite.Target(Closure , CallSite , Object , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
   at Orchard.DisplayManagement.Implementation.DefaultShapeFactory.Create(String shapeType, INamedEnumerable`1 parameters, IEnumerable`1 behaviors) in c:\Users\sebros\My Projects\Orchard\src\Orchard\DisplayManagement\Implementation\DefaultShapeFactory.cs:line 106
   at Orchard.DisplayManagement.Implementation.DefaultShapeFactory.ShapeFactoryBehavior.InvokeMember(Func`1 proceed, Object target, String name, INamedEnumerable`1 args) in c:\Users\sebros\My Projects\Orchard\src\Orchard\DisplayManagement\Implementation\DefaultShapeFactory.cs:line 24
   at ClaySharp.ClayBehaviorCollection.<>c__DisplayClass14.<>c__DisplayClass16.<InvokeMember>b__13() in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 29
   at ClaySharp.ClayBehaviorCollection.Execute(Func`1 proceed, Func`3 linker) in C:\Users\sebros\My Projects\Clay\src\ClaySharp\ClayBehaviorCollection.cs:line 13
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)

 

 

Nov 16, 2012 at 10:29 PM
sarudak wrote:

I'm not sure what you mean here. For the output of anything to be managed by orchard through the dashboard it should be a contentType. You can fairly easily use the IContentManager to access any ContentItem that you want to display using code something like the below adapted to the content item you want to retrieve

        public dynamic GetManagedContentBlock(string id) {
    		var contentItems = _contentManager.Query().ForType(new[] {"ManagedContentBlock"}).Where<IdentifierPartRecord>(x => x.Identifier == id).List();
    		var managedContentBlock = _contentItemFilteringService.GetBestMatchContentItem(contentItems.ToList());
            dynamic itemShape = null;
            if (managedContentBlock != null)
            {
                itemShape = _contentManager.BuildDisplay(managedContentBlock);
            }
            return itemShape;
        }

This code returns a dynamic that you can attach to a view model and inside your view call @Display on it.

As far as having the zones and widgets active around the Content coming from your controller you just need to use the [Themed] attribute either on the action or on the controller as a whole.

 

Perhaps a better way to pose the question - How do I pull the content from the ContentManager for the view? I don't need to specify the content in the controller.  It looks like I will need to create a page if it doesn't exist and then return that content?  

Developer
Nov 16, 2012 at 11:14 PM

What you need to do is Build a Display for the content item that you want to render. Given a content item, you can pass it into ContentManager.BuildDisplay.

// Build a display shape
var contentShape = _contentManager.BuildDisplay(contentItem);

// Return the shape
return new ShapeResult(this, contentShape);

 

Nov 17, 2012 at 3:14 PM
sfmskywalker wrote:

What you need to do is Build a Display for the content item that you want to render. Given a content item, you can pass it into ContentManager.BuildDisplay.

// Build a display shape
var contentShape = _contentManager.BuildDisplay(contentItem);

// Return the shape
return new ShapeResult(this, contentShape);

 

Thank you sfmskywalker, so the last step in the puzzle is obtaining the contentItem for the page/zones?  Could you point me to a doc that could help in pulling/creating the content item?

Coordinator
Nov 18, 2012 at 8:34 AM

Your action can Get on content manager to obtain an item by id, or it can use Query to get items from any custom criteria you need. But I'm not sure what exactly you're asking.

Nov 18, 2012 at 10:09 PM
bertrandleroy wrote:

Your action can Get on content manager to obtain an item by id, or it can use Query to get items from any custom criteria you need. But I'm not sure what exactly you're asking.

That's probably because I'm doing something the wrong way... I think I have a good idea on what to do now though, thank you.  I was just trying to require a content page to exist in my module.  In particular I want to be able to include the Help page within the module and let the content be administrated through the Dashboard.