2012-05-30 82 views
1

我使用ASP.NET MVC创建了一个CMS,并且通过设计,我决定每个插件(附加组件)在传入的HTTP请求中都应该有一个键。因此,我在我的主机这个总路线应用:在ASP.NET MVC中创建自定义RequestContext

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

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

{controller}/{action}/{id} 

我怎样才能做到这一点?

+0

您是否考虑过使用区域来托管您的插件?通过这种方式,您将拥有如下所示的内容:{areaName}/{controller}/{action}/{id} –

+0

是的,但区域不是独立的。应该创建一个插件作为一个单独的项目。 –

+2

便携区应该解决这个问题:http://lostechies.com/erichexter/2009/11/01/asp-net-mvc-portable-areas-via-mvccontrib/ –

回答

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"); 
    } 
} 
+0

好建议@smartcaveman。谢谢 ;)。 –

+0

我遇到了另一个问题。插件使用'@ Url.Action'或类似的东西来生成URL。现在他们创建的URL就像'controller/action/id'。我应该如何将这些URL与插件键('pluginKey/controller/action/id')相加? –

+1

@SaeedNeamati,改为使用'@ Url.RouteUrl'。由于这将是一个常见问题,因此可能会节省您的时间来添加自定义帮助程序方法来包装它(例如'@ Url.PluginUrl(...)'),该方法会依次将参数传递给'@ Url.RouteUrl' – smartcaveman