在ASP.NET MVC中创建自定义RequestContext

时间:2012-05-30 10:48:08

标签: asp.net-mvc-3 httpcontext

我正在使用ASP.NET MVC创建CMS,并且在设计上,我已经确定每个插件(附加组件)应该在传入的HTTP请求中有一个密钥。因此,我在主机应用程序中使用了这条通用路线:

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

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

{controller}/{action}/{id}

我怎样才能做到这一点?

1 个答案:

答案 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");
    }
}