2012-05-30 54 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