1

我正在使用 ASP.NET MVC 创建一个 CMS,根据设计,我决定每个插件(附加组件)在传入的 HTTP 请求中都应该有一个键。因此,我的主机应用程序中有这条一般路线:

{pluginKey}/{controller}/{action}/{id}

我创建了一个自定义控制器工厂,它实现IControllerFactory了,当然,它有一个基于ReqeustContext控制器名称创建控制器的方法。但是,我想创建一个人工 HttpContext(以及所有其他相关对象,如 HttpRequest、RequestContext、RouteData 等),以便插件的控制器不会错误地误解这些 URL 段。换句话说,我想剪掉传入 URL 的第一部分,让插件认为他们正在处理这个 URL:

{controller}/{action}/{id}

我怎样才能做到这一点?

4

1 回答 1

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");
    }
}
于 2012-06-06T08:22:47.763 回答