我正在使用ASP.NET MVC创建CMS,并且在设计上,我已经确定每个插件(附加组件)应该在传入的HTTP请求中有一个密钥。因此,我在主机应用程序中使用了这条通用路线:
{pluginKey}/{controller}/{action}/{id}
我创建了一个实现IControllerFactory
的自定义控制器工厂,当然,它有一个基于ReqeustContext
和控制器名称创建控制器的方法。但是,我想创建一个人工HttpContext(以及所有其他相关对象,如HttpRequest,RequestContext,RouteData等),以便插件的控制器不会错误地误解这些URL段。换句话说,我想剪切传入URL的第一部分,并让插件认为他们正在处理这个URL:
{controller}/{action}/{id}
我怎样才能做到这一点?
答案 0 :(得分:3)
虽然您可以创建所有上下文类的新实现,但看起来有点矫枉过正。为什么不在返回HttpHandler之前使用应用过滤功能的派生路由处理程序?这是一个例子:
// To avoid conflicts with similarly named controllers, I find it to be good practice
// to create a route constraint with the set of all plugin names. If you don't have
// this function already, you should be able to access it with reflection (one time
// per app lifecycle) or you hard-code them. The point is to have a regex which ensures
// only valid plugins will get selected
string[] pluginNames = GetPluginNames();
string pluginNameRegex = string.Join("|",pluginNames);
Route pluginRoute = new Route (
url: "{pluginKey}/{controller}/{action}/{id}",
defaults: null,
constraints: new RouteValueDictionary(new { pluginKey = pluginNameRegex }),
routeHandler: new PluginRouteHandler()
});
// The custom route handler can modify your route data after receiving the RequestContext
// and then send it to the appropriate location. Here's an example (markdown code/untested)
// Note: You don't have to inherit from MvcRouteHandler (you could just implement IRouteHandler
// but I'm assuming you want Mvc functionality as the fallback)
public class PluginRouteHandler : MvcRouteHandler
{
public PluginRouteHandler(IControllerFactory controllerFactory)
: base(controllerFactory)
{}
protected override IHttpHandler GetHttpHandler(RequestContext requestContext){
if(ValidatePluginRoute(requestContext))
{
// we are going to remove the pluginKey from the RequestContext, It's probably wise
// to go ahead and add it to HttpContext.Items, in case you need the data later
requestContext.HttpContext.Items["pluginKey"] = requestContext.RouteData.Values["pluginKey"];
// now let's get ride of it, so your controller factory will process the
// requestContext as you have described.
requestContext.Values.Remove("pluginKey");
// the route will now be interpreted as described so let the flow go to the MvcRouteHandler's method
}
return base.GetHttpHandler(requestContext);
}
static bool ValidatePluginRoute(RequestContext requestContext){
return requestContext.RouteData.ContainsKey("pluginKey");
}
}