Oxite移植到ASP.NET MVC2 BETA 笔记(关于Html.RenderPartialFromSkin)
????? 在將Oxite移植到asp.net mvc2 beta平臺后,經過一系列有關“方法調用”變更的修正后,終于能夠通過編譯運行起來了!(移植后的源碼參見:http://ecubecms.codeplex.com/)但經過測試,發現存在一個問題:
????? 在site.master中的<%Html.RenderPartialFromSkin("HeadCustomContents"); %>無法加載到"~/skins/admin/Views/…”下的*.ascx了("~/Views/”下的可以),換句話說Oxite中的Htmlhelper擴展方法RenderPartialFromSkin方法無法加載指定皮膚的視圖了。下面對該問題的根源和如何解決做一分析。
一、Oxite 皮膚機制的簡單分析。
1、Oxite首先實現了自己的ViewEngine,即Oxite.Skinning.OxiteWebFormViewEngine。
OxiteWebFormViewEngine繼承自System.Web.MVC.WebFormViewEngine并實現了IOxiteViewEngine接口。它的主要職責是通過設置RootPath來封裝請求的文件路徑。
2、Oxite自動注冊了一個實現IResultFilter接口的類Oxite.Filters.ViewEnginesResultFilter。ViewEnginesResultFilter的OnResultExecuting方法中根據指定的皮膚來實例化幾個OxiteWebFormViewEngine(一個皮膚實例化一個,由SkinResolverRegistry.GenerateViewEngines方法來完成的。)并存儲到ResultExecutingContext.Result.ViewEngineCollection和ViewData["OxiteViewEngines"]。
檢索皮膚的優先順序:
????? request.QueryString["skin"]
????? request.Cookies["skin"]
????? request.Url.PathAndQuery.StartsWith("/Admin")
????? ViewData["Skin"]??
????? Site.Skin
3、Controller.View和PartialView方法通過ResultExecutingContext.Result.ViewEngineCollection檢索到View(.aspx,.ascx)。而Html.RednerPartial方法則是直接通過ViewEngines.Engines集合來檢索View,結果是檢索不到有皮膚的View的。所以Oxite定制了RenderPartialFromSkin的Htmlhelper擴展方法,它不通過ViewEngines.Engines而通過ViewData["OxiteViewEngines"](別忘了上面提到過它是由ViewEnginesResultFilter.OnResultExecuting方法存進去的)以檢索到View。
二、為什么加載不到有皮膚的ascx(aspx)文件了?
????? 通過上面的分析,RenderPartialFromSkin方法加載View的原理很清楚了,在ASP.NET MVC1.0中運行的也非常好。但為什么移植到ASP.NET MVC2 BETA就不行了呢?
先看一下Oxite中的RenderPartialFromSkin方法加載到ViewEngines后都干了些什么?
foreach (IViewEngine viewEngine in (IEnumerable<IOxiteViewEngine>)newViewData[viewEngineCollectionName])
{
????????? ViewEngineResult result = viewEngine.FindPartialView(htmlHelper.ViewContext, partialViewName, true);
…
}
上面這段代碼的意思是,從newViewData[viewEngineCollectionName](注:ViewData["OxiteViewEngines”])中檢索每個IViewEngine,并調用它們的FindPartialView方法。也就是:此處調用的FindPartialView方法在asp.net mvc2 beta下并沒有找到由該方法的參數partialViewName指定的View。
三、如何初步解決問題。
????? 先來看一下IViewEngine.FindPartialView方法的定義:
ViewEngineResult IViewEngine.FindPartialView(ControllerContext controllerContext,string partialViewName,bool useCache)
注意一下第三個參數:useCache。RenderPartialFromSkin方法調用時傳的是true值(意思是使用緩存),那不使用緩存是不是能找到View呢,就把ture改為false。即這樣調用:ViewEngineResult result = viewEngine.FindPartialView(htmlHelper.ViewContext, partialViewName,false);// true);
竟然成功了!至此,問題已初步解決。但“不使用緩存”,心里總有些遺憾。
四、深入分析問題的根源并完全解決問題。
????? 如何解決上面提到的“遺憾”呢?首先的思路是在OxiteWebFormViewEngine中重載FindPartialView方法,這樣我不但要寫大量代碼,而且要考慮緩存等各種情況,會深陷細節的泥沼。那只有換另一個思路了,能不能不直接調用FindPartialView方法。通過反射htmlhelper的RenderPartial方法,發現它最終是通過調用ViewEngineCollection.FindPartialView(ControllerContext controllerContext,string partialViewName),這個方法沒有useCache參數,終于見到了解決問題的一絲曙光。
馬上修改Oxite的有關RenderPartialFromSkin方法源碼。
1、Oxite的ViewEnginesResultFilter中放入ViewData["OxiteViewEngines"]中的是IEnumerable<IOxiteViewEngine>,我把它改為ViewEngineCollection放進去。
IEnumerable<IOxiteViewEngine> viewEngines = skinResolvers.GenerateViewEngines(new SkinResolverContext(requestContext, skin), skin);ViewEngineCollection vec =?new ViewEngineCollection(viewEngines.Cast<IViewEngine>().ToList());
viewData["OxiteViewEngines"] = vec;
注:此處修改的是Oxite.Filters.ViewEnginesResultFilter.setupSkinViewEngines()方法,位于Oxite(項目)/Filters/ViewEnginesResultFilter.cs中。
2、在renderPartialFromSkin方法中改成這樣調用:
ViewContext vc =?new ViewContext(htmlHelper.ViewContext, htmlHelper.ViewContext.View, newViewData,htmlHelper.ViewContext.TempData);ViewEngineCollection vec = newViewData[viewEngineCollectionName] as ViewEngineCollection;
ViewEngineResult result = vec.FindPartialView(vc, partialViewName);
注:此處修改的是Oxite.Extensions.HtmlHelperExtensions.renderPartialFromSkin()方法,位于Oxite(項目)/Extensions/HtmlHelperExtensions.cs中。
至此,問題終于較完美的解決。
源碼可參考我的ECubeCMS項目:http://ecubecms.codeplex.com/。
轉載于:https://www.cnblogs.com/erpcrm/archive/2009/11/26/1611133.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Oxite移植到ASP.NET MVC2 BETA 笔记(关于Html.RenderPartialFromSkin)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javascript DOM基础(一)
- 下一篇: asp.net ajax控件工具集 Au