Dependency injection Orchard CMS:为OpenRasta创建模块,依赖注入问题

Dependency injection Orchard CMS:为OpenRasta创建模块,依赖注入问题,dependency-injection,orchardcms,openrasta,Dependency Injection,Orchardcms,Openrasta,例如,我正在尝试创建一个Orchard CMS模块,该模块使用OpenRasta为给定的route/OpenRasta/*启用RESTful web服务 我需要访问Orchard ContentManager以获取服务返回的内容,因此我的OpenRasta处理程序ContentHandler使用ContentService,它实现IContentService,继承IDependency。通常这会起作用,因为Orchard将向构造函数中注入ContentManager: public class

例如,我正在尝试创建一个Orchard CMS模块,该模块使用OpenRasta为给定的route/OpenRasta/*启用RESTful web服务

我需要访问Orchard ContentManager以获取服务返回的内容,因此我的OpenRasta处理程序ContentHandler使用ContentService,它实现IContentService,继承IDependency。通常这会起作用,因为Orchard将向构造函数中注入ContentManager:

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);
    }
}
但当我运行它时,我得到了一个错误,因为OpenRasta对Orchard依赖项一无所知,它试图创建ContentService,而不是Orchard,这很公平:

OpenRasta.DI.DependencyResolutionException:无法解析类型 ContentService,因为无法填充其依赖项 构造函数:Orchard.ContentManagement.IContentManager

有没有办法做到这一点,我可以去某个地方的乌节课上说,给我一个ContentManager的实例吗


更新:有关我的进度更新,请参阅@rfcdejong回答中的我的评论。

您是否使用在实现IRouteProvider的类中添加的ServiceRoute 看看ServiceRoute摘要,它说支持通过HTTP创建服务路由以支持REST场景

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
            }
        };
    }
}
要解决ContentService问题吗?您可能必须解析接口

我想你希望以下几点起作用:

var contentService = LifetimeScope.ResolveNew<IContentService>();
我使用了HostContainer。直接解决问题,也有问题。我将在我自己的ServiceHostFactory中描述我目前正在使用的解决方案

你有自己的服务主机工厂吗?甚至来自果园服务主机工厂? 在这种情况下,您可以实现以下代码来帮助您解析实例

    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;
        }
    }
我还创建了LifetimeScopeExtensions,其中包含以下代码

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>();

因此,问题是您的CMS使用自己的IoC容器。默认情况下,OpenRasta也会这样做

这意味着Orchard中的服务对OpenRasta不可见

对于所有其他IoC容器,答案非常简单:您使用IoC适配层,它允许OpenRasta生活在您想要的任何IoC容器中。我们支持unity、structuremap、castle和ninject。也就是说,autofac不受支持,因为从来没有人构建过它


解决此问题以及将来可能遇到的任何其他问题的最干净方法是为openrasta构建自己的autofac ioc适配层。如果您需要帮助,您可以加入OpenVerything邮件列表,开发者会很乐意为您提供帮助。

PS:我不知道OpenRasta以及您正在使用它做什么。Orchard使用Autofac,所有独立接口都自动注册。嗨@rfcdejong!非常感谢你的回复。你那里的东西看起来很有用,但我有点困惑。我没有ServiceHostFactory,老实说,我不确定HostContainer是什么-我可以获取当前Orchard实例的HostContainer还是需要创建一个?另外,我实际上想要解析IContentManager:var contentManager=LifetimeScope.ResolveNew;-IContentService已经可以由OpenRasta解析,因为我已经直接向它注册了依赖项。这是我正在努力解决的IContentService和IContentManager之间的链接。嗯,我想我进展得很慢,但在这一行ShellSettings ShellSettings=runningShellTable.Matchaccessor.Current;它抛出NullReferenceException,因为当前HttpContext为null:Right,sorted。我继承了OrchardServiceHostFactory,实现了LifetimeScope属性和您提供的ResolveNew扩展。然后更改runningShellTable.Match方法,将重载用于主机名和路径,而不是HttpContext。工作得很漂亮。唯一奇怪的是,我在第一次运行时收到一个NHibernate异常,但是只有当模块刚刚被修改和编译,并且只有当它是在此之后对应用程序的第一个请求,并且只有当第一个请求是对OpenRasta服务时——非常奇怪@rfcdejong,谢谢你的帮助:谢谢你的帮助Seb,我可能会在某个时候这么做:格雷格。