自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

分享Web應(yīng)用運(yùn)行的細(xì)節(jié)問題

開發(fā) 前端
在這個(gè)文章里,我將分享一下在iOpenWorks.com這個(gè)網(wǎng)站試運(yùn)行中碰到的若干問題和解決方案,這些問題包含了:(1)如果通過ASP.NET MVC預(yù)編譯提高性能;(2)如果知道網(wǎng)站在運(yùn)行中,用戶響應(yīng)速度、網(wǎng)站異常信息、用戶操作習(xí)慣;(3)解決與DiscuzToolkit集成的線程同步問題。

在這個(gè)文章里,我將分享一下在iOpenWorks.com這個(gè)網(wǎng)站試運(yùn)行中碰到的若干問題和解決方案,這些問題包含了:(1)如果通過ASP.NET MVC預(yù)編譯提高性能;(2)如果知道網(wǎng)站在運(yùn)行中,用戶響應(yīng)速度、網(wǎng)站異常信息、用戶操作習(xí)慣;(3)解決與DiscuzToolkit集成的線程同步問題。

1 ASP.NET MVC 3預(yù)編譯支持

提高網(wǎng)站性能,除了我們常見的壓縮、CDN、緩存之外,還有一個(gè)就是使用預(yù)編譯。不管是ASP.NET WebForm,或者是ASP.NET MVC,這些頁面在網(wǎng)站運(yùn)行過程中,都是要先經(jīng)過編譯處理的。因此,如果能在網(wǎng)站運(yùn)行前對(duì)其進(jìn)行編譯,那無疑能更好的提高網(wǎng)站的響應(yīng)速度。因此,我們選擇了一個(gè)RazorGenerator來對(duì)所有的ASP.NET MVC 3的視圖進(jìn)行編譯,這樣,在部署時(shí)僅需要將dll文件拷貝過去,而不再需要cshtml文件了。下面介紹如何使用它來實(shí)現(xiàn)預(yù)編譯。

1.1 下載安裝RazorGenerator

你可以在http://razorgenerator.codeplex.com/下載到RazorGenerator,這是一個(gè)VS 2010的擴(kuò)展。下載完成后,就可以直接安裝了。接著你還需要下載源代碼,然后編譯一下,獲取編譯的RazorGenerator.Mvc.dll程序集。

1.2 改變視圖文件的生成方式

將所有的視圖的BuildAction改成None,并且將CustomTool改成RazorGenerator,這時(shí)候,你可以看到一個(gè)關(guān)聯(lián)的.generated.cs文件,這個(gè)文件就是預(yù)編譯的源碼文件了。

image

1.3 處理Helper

對(duì)于Helpr文件,處理方式有所不同。Helper文件一般放在App_Code文件夾里面。首先,你需要在Helper文件的第一行添加 @* Generator: MvcHelper *@ 來聲明一下,接著將BuildAction改成None,并且將CustomTool改成RazorGenerator

image

下面,還需要額外一個(gè)步驟,這個(gè)非常重要,否則編譯無法通過,那就是需要將.generated.cs文件的BuildAction由Content改為Compile。

image

1.4 注冊(cè)PrecompiledMvcEngine

下面我們?cè)贏SP.NET MVC 3項(xiàng)目中引用RazorGenerator.Mvc.dll這個(gè)程序集,然后定義一個(gè)PreApplicationStartCode,并在AssemblyInfo.cs文件中注冊(cè)這個(gè)PreApplicationStartCode。這樣,我們就注冊(cè)了PrecompiledMvcEngine了。

(1)在AssemblyInfo.cs注冊(cè)

  1. [assembly: PreApplicationStartMethod(   
  2.     typeof(UIShell.iOpenWorks.PreApplicationStartCode), "PreStart")] 

(2)PreApplicationStartCode定義

  1. namespace UIShell.iOpenWorks   
  2. {   
  3.     public class PreApplicationStartCode   
  4.     {   
  5.         private static bool _isStarting;  
  6.         public static void PreStart()   
  7.         {   
  8.             if (!_isStarting)   
  9.             {   
  10.                 _isStarting = true;  
  11.                 var engine = new PrecompiledMvcEngine(   
  12.                     typeof(PreApplicationStartCode).Assembly);  
  13.                 ViewEngines.Engines.Add(engine);  
  14.                 VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);   
  15.             }   
  16.         }   
  17.     }   

1.5 部署

這時(shí)候,部署網(wǎng)站就不再需要將視圖文件部署過去了,只需要拷貝dll文件和網(wǎng)站資源。注意,在Views下面已經(jīng)沒有.cshtml文件了,也沒有App_Code文件,因?yàn)樗鼈兌急活A(yù)編譯到了UIShell.iOpenWorks.dll這個(gè)程序集了。接下來,你就可以測(cè)試一下網(wǎng)站,享受一下預(yù)編譯帶來的性能提升了。

imageimage

2 跟蹤網(wǎng)站運(yùn)行情況

網(wǎng)站在內(nèi)測(cè)期間,會(huì)碰到較多的問題。但是,這時(shí)候,用戶已經(jīng)進(jìn)來測(cè)試,你怎么能夠及時(shí)發(fā)現(xiàn)用戶響應(yīng)速度、用戶訪問過程中網(wǎng)站異常信息以及用戶是如何來使用你的網(wǎng)站。這里,我們使用了log4net這個(gè)日志組件,它用于記錄:(1)用戶訪問了哪些頁面;(2)用戶在訪問頁面過程中,碰到了哪些異常;(3)每一個(gè)頁面的響應(yīng)速度。下面,我來介紹如何記錄這些信息的。

2.1 在Global中,跟蹤每個(gè)用戶訪問的頁面,并且要記錄用戶響應(yīng)的速度

  1. [ThreadStatic]   
  2. private static Stopwatch _stopwatch;  
  3. protected void Application_BeginRequest()   
  4. {   
  5.     _stopwatch = Stopwatch.StartNew();  // 計(jì)時(shí)開始   
  6.     if (DiscuzHelper.IsLoggedIn()) // 記錄當(dāng)前用戶   
  7.     {   
  8.         try   
  9.         {   
  10.             var user = DiscuzHelper.LoggedUser();   
  11.             if(user != null)   
  12.             {   
  13.                 ThreadContext.Properties["user"] = user.UserName;   
  14.                 return;   
  15.             }   
  16.         }   
  17.         catch (Exception ex)   
  18.         {   
  19.             _logger.Error("Failed to get the user name though the user is logged in.", ex);   
  20.         }   
  21.     }   
  22.               
  23.     ThreadContext.Properties["user"] = string.Empty;  
  24.     if (Request != null) // 記錄當(dāng)前用戶的IP   
  25.     {   
  26.         ThreadContext.Properties["ipaddress"] = Request.ServerVariables["REMOTE_ADDR"];   
  27.     }   
  28.     else   
  29.     {   
  30.         ThreadContext.Properties["ipaddress"] = string.Empty;   
  31.     }   
  32. }  
  33. protected void Application_EndRequest()   
  34. {   
  35.     if (Request != null && _stopwatch != null && _logger != null)  // 計(jì)時(shí)結(jié)束,就用戶響應(yīng)時(shí)間和訪問頁面   
  36.     {   
  37.         _stopwatch.Stop();   
  38.         _logger.Debug(string.Format("Accessed page 'Response time: {0} ms, Url: {1}'.", _stopwatch.ElapsedMilliseconds, Request.Url));   
  39.     }   

2.2 在Global中,記錄系統(tǒng)的異常

  1. void Application_Error(Object sender, EventArgs ea)   
  2. {   
  3.     if (Server != null)   
  4.     {   
  5.         Exception e;   
  6.         for (e = Server.GetLastError(); e != null; e = e.InnerException)   
  7.         {   
  8.             _logger.Error("Unhandled server exception thrown.", e);   
  9.         }   
  10.     }   

2.3 處理關(guān)鍵方法

下面,我還在關(guān)鍵方法記錄了用戶的操作異常信息、響應(yīng)速度。比如我必須記錄了:(1)用戶注冊(cè)時(shí)響應(yīng)速度、注冊(cè)時(shí)發(fā)生的異常、用戶登錄時(shí)響應(yīng)速度、用戶登錄時(shí)發(fā)生的異常;(2)用戶在什么情況下嘗試下載iOpenWorksSDK這個(gè)免費(fèi)插件框架;(3)嘗試下載時(shí),會(huì)轉(zhuǎn)到注冊(cè)頁面,這時(shí)候用戶是否繼續(xù)注冊(cè)并下載,還是放棄。

對(duì)這些關(guān)鍵方法的記錄,有助于提高應(yīng)用系統(tǒng)的易用性。通過日志,我們修復(fù)了與Discuz集成的很多問題,并且提高了用戶響應(yīng)速度。

2.4 日志分析

下面,我們需要來看一下日志分析,這里我們?cè)谝粋€(gè)開源的LogViewer自定義了一下。通過對(duì)日志的分析,你就可以知道系統(tǒng)發(fā)生了什么異常、系統(tǒng)性能如何、用戶操作習(xí)慣、關(guān)鍵方法的信息。當(dāng)然,你也可以打開日志文件直接查看,只是,那樣比較費(fèi)勁。對(duì)了,在這里我們絕不記錄用戶的密碼,這太不職業(yè)道德了,此外,所有密碼都是加密的,避免“CSDN”!

(1)查看異常信息

image

(2)查看關(guān)鍵方法信息:用戶訪問習(xí)慣、響應(yīng)性能等

image

3 解決DiscuzToolkit線程同步

網(wǎng)站的社區(qū)是與Discuz集成的,我們就用了DiscuzToolkit來集成。這是官方發(fā)布的類庫,但是依然問題一堆。最嚴(yán)重的2個(gè)問題就是線程同步引起的,可見Discuz這幫人都ASP.NET多線程模型壓根沒有當(dāng)一回事,或者連線程安全都沒有注意到。下面就說一下碰到的2個(gè)線程安全問題。

(1)在注冊(cè)用戶時(shí),碰到以下異常:當(dāng)前會(huì)話所提交的call_id沒有大于前一次的call_id

Failed to get the user name though the user is logged in.
Discuz.Toolkit.DiscuzException: Code: 103, Message: 當(dāng)前會(huì)話所提交的call_id沒有大于前一次的call_id
at Discuz.Toolkit.Util.GetResponse[T](String method_name, DiscuzParam[] parameters) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\DiscuzToolkit\Util.cs:line 97
at Discuz.Toolkit.DiscuzSession.GetUserInfo(Int64[] uids, String[] fields) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\DiscuzToolkit\DiscuzSession.cs:line 224
at Discuz.Toolkit.DiscuzSession.GetUserInfo(Int64 uid) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\DiscuzToolkit\DiscuzSession.cs:line 255

這個(gè)問題是由Discuz.Toolkit.Util的Sign方法引起的,在這里,它為每一個(gè)API請(qǐng)求生成一個(gè)call_id。

  1. list.Add(DiscuzParam.Create("call_id", DateTime.Now.Ticks)); 

如果你在當(dāng)前線程API調(diào)用太勤快的話,DateTime.Now.Ticks會(huì)生成一樣的值,從而引發(fā)異常。因此,官方提議可以Sleep一下。因此,我們就需要改成如下:

  1. list.Add(DiscuzParam.Create("call_id", DateTime.Now.Ticks));   
  2. // Avoid to generate same 'call_id' and throws an exception on '當(dāng)前會(huì)話所提交的call_id沒有大于前一次的call_id'.   
  3. Thread.Sleep(50); 

但是這樣,依然是不過的,這個(gè)異常只是變得更加詭異了,讓你碰到機(jī)會(huì)少一點(diǎn)而已。你別忘了ASP.NET應(yīng)用程序是多線程的,當(dāng)兩個(gè)線程同時(shí)訪問時(shí),依然可能獲得同一個(gè)call_id,于是,在碰到若干次這個(gè)問題后,我用以下方法來修復(fù)。

  1. lock (_syncRoot)   
  2. {   
  3.     list.Add(DiscuzParam.Create("call_id", DateTime.Now.Ticks));   
  4.     // Avoid to generate same 'call_id' and throws an exception on '當(dāng)前會(huì)話所提交的call_id沒有大于前一次的call_id'.   
  5.     Thread.Sleep(50);   

(2)注冊(cè)用戶時(shí),碰到以下異常:An item with the same key has already been added.

[2012-04-07 17:11:30,818] [7] [ERROR] [AccountController] [49.72.46.135] []: System.ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at Discuz.Toolkit.Util.GetSerializer(Type t) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\DiscuzToolkit\Util.cs:line 157
at Discuz.Toolkit.Util.GetResponse[T](String method_name, DiscuzParam[] parameters) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\DiscuzToolkit\Util.cs:line 88
at Discuz.Toolkit.DiscuzSession.GetUserID(String username) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\DiscuzToolkit\DiscuzSession.cs:line 243
at UIShell.iOpenWorks.Controllers.AccountController.Register(DiscuzNewUser newUser, String returnUrl) in E:\Work\Design\Core\milestore 1\osgi\m10\uishell.iopenworks\UIShell.iOpenWorks\Controllers\AccountController.cs:line 53

你想想,要是用戶注冊(cè)時(shí),動(dòng)不動(dòng)碰到注冊(cè)不成功,是多么窩火?。∷?,我根據(jù)日志再次調(diào)查發(fā)現(xiàn),DiscuzToolkit在使用靜態(tài)變量保存數(shù)據(jù)時(shí),竟然不加鎖,太不拿Thread-Safe當(dāng)回事了。這會(huì)異常也發(fā)生在Util類里,代碼如下,其中serializer_dict是靜態(tài)全局變量。

  1. serializer_dict.Add(type_hash, new XmlSerializer(t)); 

于是,我修改如下。這樣,徹底解決了和Discuz的集成了。

  1. private static Dictionary<int, XmlSerializer> serializer_dict = new Dictionary<int, XmlSerializer>();   
  2. private static ReaderWriterLock _lock = new ReaderWriterLock();   
  3. public static XmlSerializer GetSerializer(Type t)   
  4. {   
  5.     int type_hash = t.GetHashCode();   
  6.     const int timeout = 5000;  
  7.     try   
  8.     {   
  9.         _lock.AcquireReaderLock(timeout);   
  10.         if (!serializer_dict.ContainsKey(type_hash))   
  11.         {   
  12.             _lock.UpgradeToWriterLock(timeout);   
  13.             if (!serializer_dict.ContainsKey(type_hash))   
  14.             {   
  15.                 serializer_dict.Add(type_hash, new XmlSerializer(t));   
  16.             }   
  17.         }  
  18.         return serializer_dict[type_hash];   
  19.     }   
  20.     catch (ApplicationException ex)   
  21.     {   
  22.         throw new Exception("Accquire lock failed.", ex);   
  23.     }   
  24.     finally   
  25.     {   
  26.         if (_lock.IsReaderLockHeld)   
  27.         {   
  28.             _lock.ReleaseReaderLock();   
  29.         }   
  30.         else if (_lock.IsWriterLockHeld)   
  31.         {   
  32.             _lock.ReleaseWriterLock();   
  33.         }   
  34.     }   

OK,關(guān)于網(wǎng)站試運(yùn)行中,最重要的幾點(diǎn)分享描述完了。順道介紹一下什么是iOpenWorks.com。iOpenWorks.com是一個(gè)免費(fèi)工廠的開放倉庫,旨在向開發(fā)人員提供完全免費(fèi)的標(biāo)準(zhǔn)化的OSGi.NET面向服務(wù)插件框架以及共享的插件倉庫,這樣,你既可以從插件倉庫使用別人插件,也可以共享自己的插件,互利共贏!

你也可以加入iOpenWorks交流群:121369588,Thanks。

原文鏈接:http://www.cnblogs.com/baihmpgy/archive/2012/04/09/2438720.html

【編輯推薦】

  1.  10個(gè)基于Web的HTML5音樂播放器
  2. 淺談Web自動(dòng)化測(cè)試原理
  3. 分享21個(gè)最新的超酷web設(shè)計(jì)特效
  4. 開發(fā)者應(yīng)該關(guān)注的五項(xiàng)Web新興技術(shù)
  5. 手機(jī)WEBKIT引擎HTML元素定位和事例
責(zé)任編輯:林師授 來源: 陳貞寶的博客
相關(guān)推薦

2011-03-28 10:05:20

細(xì)節(jié)PlayBookAndroid

2009-12-29 16:08:41

Silverlight

2009-10-22 11:03:20

OSGi Web應(yīng)用程

2014-05-26 09:13:46

DockerPython

2020-11-04 13:18:34

WebAPIWeb Share A

2010-04-28 17:01:30

Apusic負(fù)載均衡器

2023-01-03 10:30:00

Java工具

2010-05-28 10:23:59

JavaScriptWeb

2011-03-25 11:06:46

2009-01-15 09:43:51

Web架構(gòu)設(shè)計(jì)緩存

2011-05-27 17:28:27

nofollowSEO

2010-06-23 08:56:58

ASP.NET MVC

2015-10-14 10:03:28

Web應(yīng)用云服務(wù)PaaS

2023-11-20 08:02:49

2011-10-28 13:34:10

iPhone應(yīng)用設(shè)計(jì)

2014-08-26 10:29:31

2010-07-26 08:46:21

PHP負(fù)載均衡

2012-03-24 20:40:16

Windows 8

2022-08-09 09:55:23

Web方案

2011-01-19 13:11:25

Zimbra白名單證書
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)