我们正在从类似内部部署的应用程序转变为多租户云应用程序。
对于我的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);
或者我可以重新启动路径编译/缓存吗? (现在已足够,该服务可以在租户范围内到达)
答案 0 :(得分:1)
ServiceStack中的所有配置都应包含在AppHost.Configure()
中,之后保持不变。在运行时修改ServiceStack的静态配置不是ThreadSafe,比如尝试修改注册路由或需要在IPreInitPlugin
的StartUp注册一次的服务元数据。
看起来您需要重新构建解决方案,以便所有路由都在Startup上注册。如果有帮助Plugins可以实现IPostInitPlugin
和appHost.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 ServiceStack.Funq为我们提供了解决方案。 Funq允许制作儿童容器,您可以在其中注册您的ioc。解析子容器时,如果无法解析接口,请让其父容器解析它。
Container.CreateChildContainer()