Search code examples
dependency-injectionorchardcmsopenrasta

Orchard CMS : Creating module for OpenRasta, problems with dependency injection


I'm trying to create an Orchard CMS module that enables a RESTful web service using OpenRasta for a given route (/openrasta/* for example).

I need to get to the Orchard ContentManager to get the content for the service to return, so my OpenRasta handler (ContentHandler) uses a ContentService, which implements IContentService, which inherits IDependency. Normally this would work because Orchard will inject a ContentManager into the constructor:

public class ContentService : IContentService {
    public IContentManager content;

    public ContentService(IContentManager content) {
        this.content = content;
    }

    public IEnumerable<string> GetContentTypeDefinitionNames() {
        return content.GetContentTypeDefinitions().Select(d => d.Name);
    }
}

But when I run it I get an error because OpenRasta doesn't know anything about the Orchard dependencies and it's trying to create ContentService, not Orchard, which is fair enough:

OpenRasta.DI.DependencyResolutionException: Could not resolve type ContentService because its dependencies couldn't be fullfilled Constructor: Orchard.ContentManagement.IContentManager

Is there a way to achieve this, can I go to an Orchard class somewhere and say "give me an instance of the ContentManager"?

Update: See my comments on @rfcdejong's answer for updates on my progress.


Solution

  • Are u using a ServiceRoute, added in a class implementing IRouteProvider Look at the ServiceRoute summary, it says "Enables the creation of service routes over HTTP in support of REST scenarios."

    public class Routes : IRouteProvider
    {
        public void GetRoutes(ICollection<RouteDescriptor> routes)
        {
            foreach (var routeDescriptor in GetRoutes())
                routes.Add(routeDescriptor);
        }
    
        private static ServiceRoute _rastaService = new ServiceRoute(
            "openrasta",
            new MyServiceHostFactory<IOpenRastaService>(), 
            typeof(IOpenRastaService));
    
        public IEnumerable<RouteDescriptor> GetRoutes()
        {
            return new[] 
            {
                new RouteDescriptor
                {
                    Priority = -1,
                    Route = _rastaService
                }
            };
        }
    }
    

    And want to resolve ContentService? U might have to resolve the interface.

    i guess u want the following to work:

    var contentService = LifetimeScope.ResolveNew<IContentService>();
    

    I have used HostContainer.Resolve directly and had issues as well. I will describe the solution i'm using at the moment in my own ServiceHostFactory

    Do u have a own ServiceHostFactory deriven from OrchardServiceHostFactory? In that case u can implement the following code to help u resolve instances

        private ILifetimeScope _lifetimeScope = null;
        private ILifetimeScope LifetimeScope
        {
            get
            {
                if (_lifetimeScope == null)
                {
                    IHttpContextAccessor accessor = HostContainer.Resolve<IHttpContextAccessor>();
                    IRunningShellTable runningShellTable = HostContainer.Resolve<IRunningShellTable>();
                    ShellSettings shellSettings = runningShellTable.Match(accessor.Current());
                    IOrchardHost orchardHost = HostContainer.Resolve<IOrchardHost>();
                    ShellContext shellContext = orchardHost.GetShellContext(shellSettings);
                    _lifetimeScope = shellContext.LifetimeScope;
                }
                return _lifetimeScope;
            }
        }
    

    I also created LifetimeScopeExtensions that has the following code

    public static class LifetimeScopeExtensions
    {
        public static T ResolveNew<T>(this ILifetimeScope scope)
        {
            IWorkContextAccessor workContextAccessor = scope.Resolve<IWorkContextAccessor>();
            WorkContext workContext = workContextAccessor.GetContext();
            if (workContext == null)
            {
                using (IWorkContextScope workContextScope = workContextAccessor.CreateWorkContextScope())
                {
                    ILifetimeScope lifetimeScope = workContextScope.Resolve<ILifetimeScope>();
                    return lifetimeScope.Resolve<T>();
                }
            }
            else
            {
                ILifetimeScope lifetimeScope = workContext.Resolve<ILifetimeScope>();
                return lifetimeScope.Resolve<T>();
            }
        }
    
        public static object ResolveNew(this ILifetimeScope scope, Type type)
        {
            IWorkContextAccessor workContextAccessor = scope.Resolve<IWorkContextAccessor>();
            WorkContext workContext = workContextAccessor.GetContext();
            if (workContext == null)
            {
                using (IWorkContextScope workContextScope = workContextAccessor.CreateWorkContextScope())
                {
                    ILifetimeScope lifetimeScope = workContextScope.Resolve<ILifetimeScope>();
                    return lifetimeScope.Resolve(type);
                }
            }
            else
            {
                ILifetimeScope lifetimeScope = workContext.Resolve<ILifetimeScope>();
                return lifetimeScope.Resolve(type);
            }
        }
    }
    
    
            var settingsService = LifetimeScope.ResolveNew<ITokenServiceSettingsService>();