Servicestack Multitenancy动态插件

时间:2016-10-12 14:47:00

标签: servicestack

我们正在从类似内部部署的应用程序转变为多租户云应用程序。

对于我的Web应用程序,我们基于IPlugin创建了一个非常简单的界面,以创建一个插件架构。 (客户可以拥有/安装不同的插件)

public interface IWebPlugin : IPlugin
{
    string ContentBaseUrl { set; get; }
}

我们有一些通常在启动时加载的插件。现在我正在迁移代码以在请求开始时加载(在请求启动时调用Register函数),并将此请求中的所有内容作为范围。 它并不理想,但它现在对插件系统的影响最小。

我可以通过制作一个坚持请求的AppHost子容器来确定容器的范围:

    Container IHasContainer.Container
    {
        get
        {
            if (HasStarted)
                return ChildContainer;
            return base.Container;

        } 
    }
    public Container ChildContainer
    {
        get { return HttpContext.Current.Items.GetOrAdd<Container>("ChildContainer", c => Container.CreateChildContainer()); }
    }

问题案例

现在我试图让插件工作,实际上添加API服务。

   appHost.Routes.Add<GetTranslations>("/Localizations/translations", ApplyTo.Get);

但此服务无法访问(在元数据中不可见)。我如何让它可以到达?

我看到你在ServiceController AfterInit中执行以下命令。重新执行此操作仍然无法使其正常工作。

    //Copied from servicestack repo
    public void AfterInit()
    {
        //Register any routes configured on Metadata.Routes
        foreach (var restPath in appHost.RestPaths)
        {
            RegisterRestPath(restPath);

            //Auto add Route Attributes so they're available in T.ToUrl() extension methods
            restPath.RequestType
                .AddAttributes(new RouteAttribute(restPath.Path, restPath.AllowedVerbs)
                {
                    Priority = restPath.Priority,
                    Summary = restPath.Summary,
                    Notes = restPath.Notes,
                });
        }

        //Sync the RestPaths collections
        appHost.RestPaths.Clear();
        appHost.RestPaths.AddRange(RestPathMap.Values.SelectMany(x => x));

        appHost.Metadata.AfterInit();
    }

解决方案

有没有办法可以覆盖路线查找?比如延长RestHandler.FindMatchingRestPath(httpMethod, pathInfo, out contentType);

或者我可以重新启动路径编译/缓存吗? (现在已足够,该服务可以在租户范围内到达)

2 个答案:

答案 0 :(得分:1)

ServiceStack中的所有配置都应包含在AppHost.Configure()中,之后保持不变。在运行时修改ServiceStack的静态配置不是ThreadSafe,比如尝试修改注册路由或需要在IPreInitPlugin的StartUp注册一次的服务元数据。

看起来您需要重新构建解决方案,以便所有路由都在Startup上注册。如果有帮助Plugins可以实现IPostInitPluginappHost.AfterInitCallbacks接口,以便在注册插件之前和之后执行自定义逻辑。在ServiceStack的AppHost初始化之后,他们还可以注册appHost.RawHttpHandlers.Add(httpReq => MyShouldHandleThisRoute(httpReq.PathInfo) ? new CustomActionHandler((req, res) => { //Handle Route }); : null); 来注册自定义逻辑。

不确定它是否适用但在运行时您可以通过注册RawHttpHandler or a PreRequestFilter在ServiceStack中“hi-jack Requests”,例如:

{{1}}

答案 1 :(得分:0)

简单的答案似乎是,不。该框架并非构建为运行时可插入系统。

您必须在ServiceStack之上自己构建此架构。

路由解决方案

要使其路由到这些运行时加载的服务/路由,需要进行自己的实现。

ServiceStack.HttpHandlerFactory检查是否存在路由(在init上注册的路由)。所以这是你必须开始扩展的地方。方法GetHandlerForPathInfo检查它是否可以找到(服务)路由,否则返回NotFoundHandler或StaticFileHandler。

我的解决方案包含以下代码:

 string contentType;
 var restPath = RestHandler.FindMatchingRestPath(httpMethod, pathInfo, out contentType);
 //Added part
 if (restPath == null)
     restPath = AppHost.Instance.FindPluginServiceForRoute(httpMethod, pathInfo);
//End added part
 if (restPath != null)
     return new RestHandler { RestPath = restPath, RequestName = restPath.RequestType.GetOperationName(), ResponseContentType = contentType };
从技术上讲,IAppHost.IServiceRoutes应该是进行路由的人。可能在未来,这将是可扩展的。

解决服务

第二个问题是解决服务问题。找到路由后,解析了正确的Message / Dto Type。 IAppHost.ServiceController将尝试找到正确的服务并使其执行消息。

此类还具有init函数,这些函数在启动时调用以反映servicestack中的所有服务。我还没有找到合适的工作,但是通过努力使其在未来几周的ServiceStack中成为可能。

nuget上的当前版本无法使其正常工作。我在servicestack中添加了一些可扩展性,使其成为可能。

开箱即用的Ioc解决方案

对于ioc ServiceStack.Funq为我们提供了解决方案。 Funq允许制作儿童容器,您可以在其中注册您的ioc。解析子容器时,如果无法解析接口,请让其父容器解析它。

Container.CreateChildContainer()