Using ContentManager within Shape Template/Driver

Topics: Customizing Orchard, General
Sep 8, 2011 at 1:52 AM
Edited Sep 8, 2011 at 2:21 AM

I've got a few questions around the ContentManager. I know how to use this within a controller, by passing it into the constructor of a controller in a custom module. See below:

 

public HomeController(IContentManager contentManager)
        {
            _contentManager = contentManager;
        }

public JsonResult Index()
        {
            List<WhatsAroundItem> items = new List<WhatsAroundItem>();

            // Load the WhatsAround content items
            IEnumerable<ContentItem> whatsAroundContentItems = _contentManager.Query().ForType("WhatsAround").List();

            foreach (ContentItem contentItem in whatsAroundContentItems)
            {
                ContentItemRecord contentItemRecord = contentItem.Record;
                if (contentItem == null)
                    continue;           

                WhatsAroundItem item = new WhatsAroundItem(contentItemRecord.Data);
                items.Add(item);
            }

            // Allow JSON GET as this is insecure data
            return base.Json(items, JsonRequestBehavior.AllowGet);
        }

 

My question is how can use this elsewhere, i.e. use it within any code or even within a code block within a shape template?

Is there any code I can use to instantiate or get a reference to the IContentManager elsewhere?

If anyone can point me to some other good examples where the IContentManager is used that would be great.

Sep 8, 2011 at 2:45 AM
Edited Sep 8, 2011 at 2:50 AM

An update on this, I've seen this article and can see that the Driver can be configured with a constructor that takes the IContentManager in it.

http://www.deepcode.co.uk/2011/06/real-world-orchard-cmspart-7finding.html

private readonly IContentManager _cms; 

public RelatedContentWidgetDriver(IContentManager cms)
{
_cms = cms;
}

Still wondering if I can access the content manager within a PartialView in the code block without having to create a widget?

Sep 8, 2011 at 12:55 PM

As you already discovered you can inject the IContentManager into any class in your module - a driver is really no different than a controller in that regard. In fact, anything which is an IDependency can be injected this way. Orchard automatically takes care of the dependency injection - just add anything which inherits from IDependency to your constructor and Orchard (using AutoFac) will inject it for you.

And yes, you can also get access to it in your view template by using WorkContext. The WorkContext class is available in all views, and it includes a Resolve<T> method for gaining access to the items registered in the IOC container. That means you can do something like this:

@using Orchard.ContentManagement
@{
    var contentManager = WorkContext.Resove<IContentManager>();
    var items = contentManager.Query("WhatsAround");
    // You now have an IContentQuery and can do whatever you want with it, like call .List(), etc. just like in your controller
}
I would caution however, that just because you CAN do this doesn't always mean you should. I would be careful about getting too carried away with this sort of thing. Separation of Concerns/Single Responsibility applies in Orchard as it does anywhere else. It's probably not a good idea to put too much logic directly in your view templates.

Sep 8, 2011 at 10:44 PM

Hi Kevin,

Yes I know about good architecture and it's best to place code/data access in your modules as best practice. I just wanted to know if it was possible, which you've shown me, so we have more options just in case. The more options to solve the problem the better.

Thanks again for the great advice.

Kev

Sep 8, 2011 at 10:44 PM

Hi Kevin,

Yes I know about good architecture and it's best to place code/data access in your modules as best practice. I just wanted to know if it was possible, which you've shown me, so we have more options just in case. The more options to solve the problem the better.

Thanks again for the great advice.

Kev

Developer
Jan 3, 2012 at 1:44 PM
Edited Jan 3, 2012 at 1:45 PM

Is it also possible to get a service instance inside a ViewModel which is instantiated by the model binder?
For example, I have a view model class that implements IValidatableObject. Inside the Validate method, I need an instance of IMembershipService so I can see if the specified Username and Password (which are properties on the view model class) are a valid combination.

I could of course do this validation from within my action method, but I would like to keep the validation as part of the view model in this case.

Jan 3, 2012 at 2:34 PM

I thought there was a static class/method that you could call to resolve something from the container, but I can't seem to find it right now. If I find how to do it I'll post the answer.

Developer
Jan 3, 2012 at 3:12 PM

Hi kevink,

I did find this on Google:

 http://code.google.com/p/orchardcms/source/browse/src/Orchard/Environment/ServiceLocator.cs?r=cbd752639d154c0e06c0772b002ea4a9bc24e20a

However I did not find the ServiceLocator class in the Orchard sourcecode.
I hope you can find it.

Thanks.