Asp.net MVC2 使用經驗,性能優化建議

作者: Otis's Technology Space  來源: 博客園  發布時間: 2010-03-23 13:48  閱讀: 7402 次  推薦: 0   原文鏈接   [收藏]  

這個月一直在用 asp.net MVC2 做http://www.86e0.com/t 這個網站,用的時候是 aps.net MVC2 RC2,然后現在Asp.net MVC2正式版已經是發布了。 在MVC的使用上,有一些心得。下面作一下總結,希望對大家有用,也歡迎大家討論。

1.關于緩存

緩存上,數據層上的緩存是必須的,這點不必多說了。

另一個很重要的是:視圖片段緩存。

我參考了老趙的寫的三篇關于片段緩存的文章:

本想用老趙的了,但是我發現Asp.net MVC2 的有一個新功能:Html.Partial可以返回生成的HTML,返回的類型是:MvcHtmlString. 雖然要利用PartialView才能生成Html片段,但是我想這個已經夠我用的了,所以我做了一個這樣一個Helper,主要是將生成的HTML片段緩存到Memcached里。代碼如下:

 
public static class MvcHtmlHelper
{

public static MvcHtmlString MemcacheHtmlPartial(this HtmlHelper htmlHelper,int duration, string partialViewName, object model, ViewDataDictionary viewData)
{

object obaear = htmlHelper.ViewContext.RouteData.DataTokens["area"];
string area=string.Empty;
if (obaear != null) area = obaear.ToString();
string key = string.Format("MemcacheHtmlPartial_{0}{1}", area, partialViewName);
object ob = DistCache.Get(key);
if (ob == null)
{
MvcHtmlString mstr
= htmlHelper.Partial(partialViewName, model, viewData);
DistCache.Add(key, mstr.ToString(), TimeSpan.FromSeconds(duration));

return mstr;
}

else
{
return MvcHtmlString.Create((string)ob);
}
}
}

  然后,我覺得,這樣,在每次請求時,還是要在Controller 里把數據取出來,然后再傳到 Partial View里。 既然已經緩存了,就應該不用每次請求都要在Controller里把數據取出來才對!雖然數據層會有緩存。

  所以我,能不能再省下去Controller取數據的消耗,于是又有了以下代碼,其功能是:緩存Action生成的HTML到Memcached里。

 
public static MvcHtmlString MemcacheHtmlRenderAction(this HtmlHelper htmlHelper, int duration, string actionName,string controllerName, RouteValueDictionary routeValues)
{

object obaear = htmlHelper.ViewContext.RouteData.DataTokens["area"];
string area = string.Empty;
if (obaear != null) area = obaear.ToString();
string key = string.Format("MemcacheHtmlRenderAction_{0}{1}{2}", area, controllerName,actionName);
object ob = DistCache.Get(key);
if (ob == null)
{


// htmlHelper.RenderAction(actionName, controllerName, routeValues);
StringWriter writer = new StringWriter(CultureInfo.CurrentCulture);
ActionHelper(htmlHelper, actionName, controllerName, routeValues, writer);

string wStr = writer.ToString();
DistCache.Add(key, wStr,TimeSpan.FromSeconds(duration));
MvcHtmlString mstr
= MvcHtmlString.Create(wStr);

return mstr;
}

else { return MvcHtmlString.Create((string)ob); }
}

  說明一下,Actionhelper的方法是在MVC原代碼里提取出來的。 因為MVC2里的 Html.RenderAction方法并沒有返回 MvcHtmlString的重載版。那位有更好的方法?

  其實,MVC里的Action有輸出緩存,所以直接在View里用 Html.RenderAction都可以解決很多問題了。這個主要是可以用程序管理緩存。

2.關于靜態內容的放置

習慣上,靜態內容會放在 mvc程序所在的目錄下,比如說js,css,上傳的圖片等。但是這樣的話,所有的靜態請求都要經過 aspnet_isapi 處理,這樣是非常不合算的。所以靜態內容一般都會放在另外的子域上。http://www.86e0.com/t 是放在 cdn.86e0.com上。

3.關于強類型ViewModel

  我基本上看了老趙的Asp.net MVC最佳實踐。其中有一點,就是強烈推薦使用強類型的ViewModel.我試了一些頁面,發現用強類型的ViewModel,現階段并不適用于我。因為我是用NbearLite,從數據庫抓出來的大多是DataTable.我是覺得DataTable+NbearLite蠻方便的,雖然沒有動態語言的數據訪問來得方便,但是比用Entity,ViewModel,DTO,等等來說,還是可以省下很多代碼。然后,最重要的是,由于我這種站經常會修改,所以數據庫改變,加字段,減字段是很經常性的事。但是,用NbearLite + DataSet,DataTable,卻非常方便。

  所以我覺得,做Asp.net MVC,如果你不是用DDD,DDT的話,用DataTable還是可以的。因為DDD,DDT學習起來還是要點成本的。

4.關于URL生成

URL生成, 老趙寫了一系列文章:

  請大家注意生成的 URL, 是用 ?參數=頁碼 的方式。代碼如下:

 
/// <summary>
/// 分頁Pager顯示
/// </summary>
/// <param name="html"></param>
/// <param name="currentPageStr">標識當前頁碼的QueryStringKey</param>
/// <param name="pageSize">每頁顯示</param>
/// <param name="totalCount">總數據量</param>
/// <returns></returns>
public static string Pager(this HtmlHelper html, string currentPageStr, int pageSize, int totalCount)
{
var queryString
= html.ViewContext.HttpContext.Request.QueryString;
int currentPage = 1; //當前頁
if(!int.TryParse(queryString[currentPageStr], out currentPage)) currentPage = 1; //與相應的QueryString綁定
var totalPages = Math.Max((totalCount + pageSize - 1) / pageSize, 1); //總頁數
var dict = new RouteValueDictionary(html.ViewContext.RouteData.Values);

 

var output

= new StringBuilder();

 

 

foreach (string key in queryString.Keys)
if (queryString[key] != null && !string.IsNullOrEmpty(key))
dict[key]
= queryString[key];
if (totalPages > 1)
{

if (currentPage != 1)
{
//處理首頁連接
dict[currentPageStr] = 1;
output.AppendFormat(
"<span class=\"p_home\">{0}</span>", html.RouteLink("首頁", dict));
}

if (currentPage > 1)
{
//處理上一頁的連接
dict[currentPageStr] = currentPage - 1;
output.AppendFormat(
"<span class=\"p_up\">{0}</span>", html.RouteLink("上一頁", dict));
}

else
{
output.AppendFormat(
"<span class=\"p_disable\">{0}</span>","上一頁");
}

int currint = 5;
for (int i = 0; i <= 10; i++)
{
//一共最多顯示10個頁碼,前面5個,后面5個
if ((currentPage + i - currint) >= 1 && (currentPage + i - currint) <= totalPages)
if (currint == i)
{
//當前頁處理
output.Append(string.Format("<span class=\"p_current\">{0}</span>", currentPage));
}

else
{//一般頁處理
dict[currentPageStr] = currentPage + i - currint;
output.AppendFormat(
"<span class=\"p_num\">{0}</span>",html.RouteLink((currentPage + i - currint).ToString(), dict));
}
}

if (currentPage < totalPages)
{
//處理下一頁的鏈接
dict[currentPageStr] = currentPage + 1;
output.AppendFormat(
"<span class=\"p_down\">{0}</span>", html.RouteLink("下一頁", dict));
}

else
{
output.AppendFormat(
"<span class=\"p_disable\">{0}</span>", "下一頁");
}

if (currentPage != totalPages)
{
dict[currentPageStr]
= totalPages;
output.AppendFormat(
"<span class=\"p_last\">{0}</span>",html.RouteLink("末頁", dict));
}
}
output.AppendFormat(
"<span class=\"p_count\">第{0}頁/共{1}頁</span>", currentPage, totalPages);//這個統計加不加都行
return output.ToString();
}

 

 

另: http://www.86e0.com/t 是做淘寶客類應用的。園子里還有誰在做淘寶客類網站么? 有的話多交流。^_^

0
0
 
標簽:MVC ASP.NET
 
 

文章列表

全站熱搜
創作者介紹
創作者 大師兄 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣()