2014-10-07 74 views
3

我一直在閱讀Wooncherk,Twisted WhispererAlex Wolf的一些很好的帖子。他們的文章分別是(Wooncherk),(Twisted Whisperer)(Alex Wolf)已經非常翔實,但可惜我只是不如SO社區的其他人聰明,不能完全湊齊我失蹤的東西。非常接近但不能完全覆蓋核心視圖nopcommerce

我重寫了管理區域中的核心視圖...特別是順序編輯視圖。我看到的行爲是它不是命中我的插件中的控制器,但它DOES顯示我的自定義視圖。問題是自定義視圖在Admin項目中,這真讓我困惑。我如何擁有一個獨立的插件,但必須將我的自定義視圖安裝到核心管理區域?

我想,也許不正確,會發生什麼是我的控制器會因爲我的更高定義的優先級搜索路徑時被首先命中。

所以按照這裏的指示是我的代碼。

CustomViewEngine:


private readonly string[] _emptyLocations = null; 

    public CustomViewEngine() 
    { 
     PartialViewLocationFormats = new[] 
     { 
      "~/Administration/MyExtension/Views/{1}/{0}.cshtml", 
      "~/Administration/MyExtension/Views/Shared/{0}.cshtml" 
     }; 

     ViewLocationFormats = new[] 
     { 
      "~/Administration/MyExtension/Views/{1}/{0}.cshtml", 
      "~/Administration/MyExtension/Views/Shared/{0}.cshtml" 
     }; 
    } 


    protected override string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string theme, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) 
    { 
     searchedLocations = _emptyLocations; 
     if (string.IsNullOrEmpty(name)) 
     { 
      return string.Empty; 
     } 

     string areaName = GetAreaName(controllerContext.RouteData); 

     //little hack to get nop's admin area to be in /Administration/ instead of /Nop/Admin/ or Areas/Admin/ 
     if (!string.IsNullOrEmpty(areaName) && areaName.Equals("admin", StringComparison.InvariantCultureIgnoreCase)) 
     { 
      var newLocations = areaLocations.ToList(); 
      newLocations.Insert(0, "~/Administration/Views/{1}/{0}.cshtml"); 
      newLocations.Insert(0, "~/Administration/Views/Shared/{0}.cshtml"); 

      //Insert your custom View locations to the top of the list to be given a higher precedence 
      newLocations.Insert(0, "~/Administration/MyExtension/Views/{1}/{0}.cshtml"); 
      newLocations.Insert(0, "~/Administration/MyExtension/Views/Shared/{0}.cshtml"); 

      areaLocations = newLocations.ToArray(); 
     } 

     bool flag = !string.IsNullOrEmpty(areaName); 
     List<ViewLocation> viewLocations = GetViewLocations(locations, flag ? areaLocations : null); 

     if (viewLocations.Count == 0) 
     { 
      throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Properties cannot be null or empty.", new object[] { locationsPropertyName })); 
     } 

     bool flag2 = IsSpecificPath(name); 
     string key = CreateCacheKey(cacheKeyPrefix, name, flag2 ? string.Empty : controllerName, areaName, theme); 

     if (useCache) 
     { 
      var cached = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key); 
      if (cached != null) 
      { 
       return cached; 
      } 
     } 

     if (!flag2) 
     { 
      return GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, theme, key, ref searchedLocations); 
     } 

    return GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations); 
} 

路由供應看評論 試圖覆蓋核心URL〜/管理/訂單/編輯/ 1


public void RegisterRoutes(RouteCollection routes) 
    { 
     ViewEngines.Engines.Insert(0, new CustomViewEngine()); 

//the articles above did NOT mention adding a path but it seemed like I needed to in order for my override path to be included??? 
     routes.MapRoute("Plugin...OrderDetailsOverride", "Order/Edit/{id}", 
      new { controller = "MyOrder", action = "Edit" }, 
      new { id = @"\d+" }, 
      new[] { "MyPlugin.Controllers" } 
     );    

    } 

    public int Priority 
    { 
     get 
     { 
      return 1; 
     } 
    } 

我得到一個404錯誤,仔細的閱讀扭曲語他(我假設他)說:

例如,如果你是overrding Nop.Admin /瀏覽/分類/ Tree.cshtml,將您的自定義樹.cshtml在Nop.Admin/CustomExtension /瀏覽/分類/ Tree.cshtml

好吧,如果我解釋,從字面上我將在CORE ADMIN項目做到這一點:

enter image description here

我明顯這樣做,它的工作... sorta。

因此,在總結我的問題/問題是:

  1. 在插件我的訂單覆蓋控制器是打不到....(不使用ActionFilters感興趣,因爲他們不給我什麼,我需要......我不認爲)。

  2. 我的插件中的視圖沒有命中,但添加到管理項目中的視圖命中?

  3. 與2有些相關。如果兩個是正確的,那麼這個可行的插件解決方案如何?對於產品推送,更新等,我可能不得不觸及NopCommerce核心項目....那麼爲什麼還要插入一個插件呢?

現在NOP傢伙以及SO社區都比我更聰明,所以我相信我只是不明白。

+0

你是否看到我的文章的意見部分?我的讀者有幾個更新,可以解決您的問題? :) – wooncherk 2014-10-08 08:39:26

回答

6

如果我讀你的問題正確,要創建一個插件,並試圖做這個插件的所有plumbings,而完全不觸及核心管理文件。然後,你必須把你的插件項目中的所有這些文件,而不是在Nop.Admin

從外觀上來看,你將覆蓋兩個控制器查看後端的(管理區)。您引用的SO post,其中我的答案只是針對覆蓋的管理員查看,而不是控制器。覆蓋控制器在管理區域是不同於覆蓋查看,甚至更重要的是,如果你覆寫控制器的前端(假設涉及SEO友好的URL)。

覆蓋控制器本質上是要求ASP.NET MVC使用您的自定義控制器來提供請求,而不是原始控制器。請求通過路由指向控制器。因此,重寫控制器只是簡單地操縱路由來將請求定向到您的自定義控制器。

ASP.NET MVC保留一個包含路由的通用查找表,名爲RouteTable.Routes。一個路由包含的

  1. 的URL模式
  2. 控制器數據傳入請求轉發到

每天有傳入的請求時,ASP.NET MVC將搜索RouteTable.Routes從上到下查找URL模式與請求的URL匹配的路由。第一條匹配路線將用於將請求引導至匹配路線的控制器。表中可能有幾條匹配路線,但只有第一條將被使用。因此,我們可以說表格頂部的路線具有最高優先級。因此,覆蓋現有控制器的關鍵是要確保路由指向您的自定義控制器早於路由指向註冊到原控制器

在nopCommerce,您不需要直接操縱RouteTable.Routes查找表。通常,您只需將自定義控制器路由註冊到實施IRouteProvider接口的RegisterRoutes接口中,並且優先級高於原始Controller路由(不適用於SEO友好URL區域路由)。 優先級越高,路由越早註冊,因此它將位於查找表中的位置越高。 但是,nopCommerce的後端實際上是一個名爲Admin的ASP.NET MVC區域。這個事實使得通常的方式覆蓋路線變得非常棘手。這是因爲,在Global.asax的

//global.asax 
protected void Application_Start() { 
    //.... Omitted for brevity 

    //Registering some regular mvc stuff 
    //The two lines below populate the RouteTable.Routes 
    AreaRegistration.RegisterAllAreas(); //add Area routes into the lookup table first such as the "Admin" area 
    RegisterRoutes(RouteTable.Routes); //followed by adding routes of classes implementing **IRouteProvider** 

    //.... Omitted for brevity 
} 

正如你可以在上面看到,區域內路由總是先註冊,因此具有最高的優先級。因此,在IRouteProvider中,無論您設置優先級有多高,它仍然會低於區域路線。因此,您將不得不直接操縱RouteTable.Routes。在您的IRouteProvider

public void RegisterRoutes(RouteCollection routes) 
{ 
    ViewEngines.Engines.Insert(0, new CustomViewEngine()); 

    var route = routes.MapRoute("Plugin...OrderDetailsOverride", 
     "Admin/Order/Edit/{id}", 
     new { controller = "MyOrder", action = "Edit" area = "Admin" }, //notice 'area="Admin"' is added 
     new { id = @"\d+" }, 
     new[] { "MyPlugin.Controllers" } 
    ); 
    routes.remove(route); //remove your route from the RouteTable.Routes 
    routes.insert(0, route); //only to add it back again to the top of RouteTable.Routes, above all the routes that have been registered earlier 
} 

public int Priority 
{ 
    get 
    { 
     return 1; 
    } 
} 

這是重寫控制器。現在覆蓋查看。稍作調整的CustomViewEngine(請確保您的CustomViewEngine是在你的插件,而不是在Nop.Admin)

//Insert your custom View locations to the top of the list to be given a higher precedence 
newLocations.Insert(0, "~/Plugins/MyPlugin/Views/Admin/{1}/{0}.cshtml"); 
newLocations.Insert(0, "~/Plugins/MyPlugin/Views/Admin/Shared/{0}.cshtml"); 

實際上,你可以刪除CustomViewEngine的構造。如果您在GetPath方法中具有上述兩行,則構造函數不是必需的。

+0

扭曲的Whisperer ...一如既往非常有幫助和詳細...讓它理順了。謝謝。 – GPGVM 2014-10-08 23:37:57

+0

很高興我能幫到你。 – 2014-10-09 05:43:15

2

最重要的是讓控制器命中,其他的事情需要一些調整。

  1. 路由不正確覆蓋,請參閱http://www.nopcommerce.com/boards/t/27039/plugin-override-admin-route.aspx

  2. 在管理項目中的視圖使用,由於設置爲自定義視圖位置的路徑:〜/行政/ MyExtension /瀏覽次數。 NopCommerce不知道哪些視圖嵌入到插件中。

  3. 對於基於插件的解決方案確保CustomViewEngineRouteProvider和意見是在插件。確保視圖被複制到輸出目錄。將插件中視圖的輸出文件夾註冊爲自定義視圖位置,例如〜/ Plugins/MyPlugin/Views/Admin

+0

謝謝!我想知道這是否可能是這種情況,但是我自己也懷疑過,並沒有嘗試過......這在後視中是愚蠢的......所以VS引發了一個特例。應該給它一個鏡頭。 – GPGVM 2014-10-08 23:23:41