顯示具有 Asp.Net MVC 標籤的文章。 顯示所有文章
顯示具有 Asp.Net MVC 標籤的文章。 顯示所有文章

2014年12月12日 星期五

不要在 ASP.NET MVC 5 中,在 ActionFilterAttribute 上使用 Task.Factory.StartNew

今天在調整校能的時候,想到可以使用非同步的方式來增加網站的校能。

就拿 Log 來試試身手好了。

MVC 5 的ActionFilterAttribute 尚不支援非同步

真的是這樣,見 ActionFilterAttribute, 果然沒有像 WebAPI 上的 ActionFilterAttributeOnActionExecutedAsync 方法。

怎麼辦呢?

異相天開地找了一段如下的程式 (https://aspnetwebstack.codeplex.com/discussions/478983),既然被標為解答,大概就可以運作了吧!

Task.Factory.StartNew(() => Logger.WriteLogAsync(log),
				TaskCreationOptions.LongRunning);

想法是:自己使用多執行緒的方式寫 log.

結果還不錯,而且單頁測試時,效能還快了將近10%呢?

上線前效能測試

想說單頁沒問題,應該就沒問題了呢?於是就送出去測試來。

這個效能測試是正式的首頁,測個10分鐘,效能變差也就算了,竟然還會出現 502 Bad GetWays?然後網站就掛了。

結論

ASP.NET MVC 5 的ActionFilterAttribute 不支援 async/await,看來是有道理的。

印象中,ASP.NET 有這個規定:不要在頁面中自己產生新的執行緒。我不信邪,就只能撞撞牆,練練經驗了。

不要自己找麻煩。

2013年10月18日 星期五

ASP.NET MVC 5 預設會設定 X-Frame-Options 為 SAMEORIGIN

如標題。

X-Frame-Options 是一個新的瀏覽器特色。請參考http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-10

MVC 5 在 final 時,看來加上了這個預設選項。因此使用 F12 開發工具時,可以看到 MVC 5的網頁會多出 X-Frame-Options: 的 Header

image

VS2013 RC 時澴沒有這個事情呢。

而且,目前(2013-10-18) 網路上可參考的 ASP.NET MVC 5 文件並沒有說到這個事情。

偏偏,我就有這個需求,要讓我的網頁鑲在別人的網頁中。不得已,只好在 Global.axsx.cs 內加上這一段,解決這個困擾。

private void Application_EndRequest()
{
    Response.Headers.Remove("X-Frame-Options");
    Response.Headers["X-Frame-Options"] = "ALLOW-FROM http://aaa.test.domain/Main/";
}

其中,aaa.test.domain 就是我的另一個開發機器啦。

2014-02-06 Update:

後來找到更簡單的方法:

AntiForgeryConfig.SuppressXFrameOptionsHeader = true;

2012年10月15日 星期一

ASP.NET MVC unobtrusive Cheat Sheet

需要一個 client side 的 JavaScript validation library. 而使用 ASP.NET MVC 當然最好使用 jQuery.validate.unobtrusive.js,雖然還是有一點不好用啦!
然而每次都要到 google 找資料也是很累,不如自己做一個清單好了。

    說明
  data-val true, false 是否要驗證
長度限制 data-val-length 字串 字串長度不符合時的錯誤訊息
  data-val-length-max 整數 字串最大長度
  data-val-length-min 整數 字串最小長度
必填 data-val-required 字串 未填入時的錯誤訊息
RegEx data-val-regex 字串 錯誤訊息
  data-val-regex-pattern 字串 regex
數字 data-val-digits 字串 錯誤訊息。只接受數字字元。
  data-val-number 字串 錯誤訊息。只接受數字(正負)
日期 data-val-date 日期 錯誤訊息。只接受日期。
Email data-val-email 字串 錯誤訊息
Url data-val-url 字串 錯誤訊息
範圍 data-val-range 字串 錯誤訊息
  data-val-range-min 整數  
  data-val-range-max 整數  
比較 data-val-equalto 字串 錯誤訊息
  data-val-equalto-other 驗證項目的name  
驗證訊息 data-valmsg-for 驗證項目的name 驗證訊息
附檔名限制 data-val-accept 字串 錯誤訊息
  data-val-accept-exts 字串 Ex: “jpg|gif|png”

範例見黑大的 使用jQuery.validate.unobtrusive.js

動態驗證的 JavaScript

self.save = function() {
        var form = $('#editForm');
        form.removeData("validator");
        $.validator.unobtrusive.parse(form); 
        form.validate();
        if (form.valid()) {
          var url = form.attr('action');
          var postData = form.serialize()
            + "&field1=" + self.field1();
          $.post(url, postData, function(data) {
            if (data.IsOk) {
              alert("已儲存");
            } else {
              alert(data.Message);
            }
          });
        }
      };

2012年9月11日 星期二

@Scripts.Render("~/bundles/jqueryval") 引用次數要剛剛好一次

在執行 ASP.NET MVC ajax 新增資料時,發生了重覆 insert的事情。

為什麼呢?原來是重複引用了 @Scripts.Render("~/bundles/jqueryval"). (在 View 中用了一次,在 layout page 中又一次 )

產生的 html code 如下

<script src="/App/Scripts/jquery.unobtrusive-ajax.js" type="text/javascript"></script>
<script src="/App/Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="/App/Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>

兩次會有什麼效果呢?就是執行一次Request,結果會出現2次的 Request. 如下圖所示。

SNAGHTML4eedc9

如果該引用這些 js 而忘了引用呢?不會發生 javascript error, 反而像是沒有 client side validation 一般,只出現 server side 的 validation。

這種現象好奇怪,在開發時很難想到是js 引用次數的問題。

2010年5月18日 星期二

MVC 1.0 專案升級為 2.0

MVC 2.0 已經在 2010/3/12 號出來了。可是我之前寫的 MVC 1.0 的專案該怎麼辦呢?當然是升級。

要升級前,必須確認是否讓 Visual Studio 安裝了 MVC 2.0 的專案樣版。如果是 Visual Studio 2010,就不必安裝了,因為已經內建。如果是 Visual Studio 2008,請到這裡下載。

接下來是升級專案。

  1. 記得先備份方案。
  2. 先將整個方案 Check Out。唯讀屬性會造成升級失敗。Check OUt 後關閉 Visual Studio 2008。
  3. 請到這裡下載轉換器(MvcAppConverter)。
  4. 執行轉換器,並按”Convert”
  5. 再打開 Visual Studio 2008,Build方案。
  6. 完成

是不是很簡單呢?雖然很簡單,但內部作的動作卻很繁複,包含了改參考 MVC2.dll,修改 configuration,修改 csproj等。

參考

2010年5月16日 星期日

MVC 的快速鍵

在開發程式的過程中,最好不要經常使用滑鼠。想想一下,打不到幾個字就要挪一下滑鼠,再打幾個字,是非常沒效率的事。

MVC 的開發中,最常見的是 Add Controller, Add View,或者在 Controller 與 View之間切換。快速鍵如下

Action ShortCut Key
Add Controller Ctrl + M, Ctrl + C
Add View Ctrl + M, Ctrl + V
Controller, View 的切換 Ctrl + M, Ctrl + G

2010年5月14日 星期五

MVC 2.0 的建置與 TFS 2010

雖然與過往的 WebForm 差異甚大,但在使用 MVC 2.0 來建立網站仍是一個美好的經驗。

更佳者,是內建了 MvcBuildViews 的功能。

MvcBuildViews

以往在建置Asp.net WebForm 網站時,Web Application 的編譯並不包含 aspx的部份。換句話說,WebApplication可在 Visual Studio 編譯成功,但在 aspx 上的語法如果有錯誤的話,只有該網頁在執行時期才會發現錯誤。

asp.net 有個 PreCompile 的機制,可以提早發現這類的錯誤。但並沒有整合到開發環境中,總是要等到上線時才被客戶踩到地雷後,才怪微軟怎麼 compile 會過。

因此,在 asp.net MVC 中,增加了 MvcBuildViews 的機制。也就是在編譯時期提早編譯 View 的部份。

這個選項預設是 false。必須以 xml 的方式打開 .csproj,找到 MvcBuildViews,將其值改為 true,才會編譯 View。

<Project ...> 
  ... 
  <MvcBuildViews>true</MvcBuildViews> 

其實這裡的作業方式仍然是作 asp.net 的 precompile。見 .csproj 最下方有個 build target,引導 MSBuild 在 Compile 完畢後接著再執行 aspnet_compile。

<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)" />
</Target>

TFS 2010

導入 TFS 2010後,上述的 MvcBuildViews 的選項會導致 Build Machine 編譯失敗。失敗的錯誤訊息如下

/temp/global.asax (1): Could not load type 'XXX.MvcApplication'.

原因呢?我認為MVC 的MvcBuildViews的設計僅就開發人員在 Desktop 上能進行編譯即可,故把 Project 的路徑等同於Build的路徑。而TFS在編譯時,並非將專案的路徑當成編譯的輸出路徑,故$(ProjectDir) 的值並非完整編譯後的可執行環境。

因此,我們必須針對該 .csproj 進行修改。修改 csproj 時必須顧慮到開發人員及 TFS 的 Build machine 同時可以編譯的需求,我作了下面的改變。

<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
  <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
也就是改變 $(ProjectDir) 為 $(WebProjectOutputDir)。

MVCContrib

在使用了 MVCContrib 的元件後,上述的 Team Build 又失敗了。錯誤訊息如下

c:\Builds\1\…\PublishedWebsites\xxx\Web.config (114): The type or namespace name 'MvcContrib' could not be found (are you missing a using directive or an assembly reference?)

我在MVC 網站所參考的 MVCContrib.dll 竟不見了。不知為何?原來,我忘了將MVCContrib.dll加入Source Control 中了。到了 Build Server 找不到該dll.

參考

2010年5月5日 星期三

開發 asp.net webform 與 asp.net mvc 不同處

開發流程

asp.net web form 開發功能時,是以網頁(Page)為重心。舉例來說,實作「新增訂單」功能時,

  1. 會想在 web application 下新增一個 Order 目錄
  2. 在Order 目錄下新增一個 AddOrder.aspx 網頁。
  3. 在 designer 上拉 UI Control,例如 GridView
  4. 將 GridView 連接到 datasource,例如設定到 datasource control。

而 asp.net mvc 在開發相同功能時,卻走下面的流程

  1. 思考Url 如何配置:例如 /Order/Create。
  2. 對應到哪一個 Controller:與上一步相關,此時會對應到 OrderController
  3. 在 OrderController 實作 Create 的 Action
  4. 在該 Action 中,取得適當的 Model (即顯示的資料)
  5. 在Action 挑選一個適當的 View,並傳遞Model(資料)到View
  6. 實作該 View

重心

由上述流程觀之,兩者開發的重心大大不同。asp.net web form 重點在網頁,而 asp.net mvc 則在 Controller。asp.net web form 會讓開發人員急著開發功能,而在designer 上設定視覺控件並連接上資料元件。asp.net mvc 開發流程卻會讓開發人員一步步地思考責任分工,最後才實作 View。

由設計流程上, asp.net mvc 的確較優,這也是為何微軟在2008到現在,花了較多的心思在 mvc 上。而asp.net web form 我認為該設計已到了一個顛峰,也就更難突破了。

asp.net web form 為了讓網頁的開發更像 VB Winform 的開發流程,特意地設計了 ViewState 的東西,讓 Web form 有了事件的概念。接著為了讓 Control 能順利地執行與開發,設計了 Page Life cycle。由 page life cycle 與 event 交織出來的複雜度,實在很難讓開發人員深入地了解。如下圖。

ASP.NET Page Life Cycle Diagram

而 asp.net mvc 返璞歸真地去除了這此 page life cycle、event 的困擾,以簡單的責任分工方式來開發設計,相對地容易。

結論

我認為,asp.net mvc 將來會成為主流。然而 web form 的生產力較高,也容易產生第三方的元件,也不會因此而消失。

2010年4月27日 星期二

CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced

在開發 asp.net MVC 並使用 Entity Framework 4.0 時,在執行網頁發生這樣的一個錯誤。

Compiler Error Message: CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

我有參考 System.Data.Entity 啊!

原來,MVC2 為了相容.net framework 3.5,故無法在 web.config hard code 參考 System.Data.Entity。為了這個原因,我們必須在 web.config 上自行加入參考給 asp.net 使用。

  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>

2010年2月6日 星期六

MVC 2.0 RC2 又出來了

沒多久前,才出了 RC 版,現在又出了 RC2 了。

版本說明請見 haacked 的 blog

2009年9月5日 星期六

MVC (3): Controller

接收使用者的 Request ,經由 Url routing 後,第一關來到的是 Controller。
Controller 的責任可參考 MVC (1): Asp.NET MVC 概念說明

Controller 的責任是:處理資料 (Model) 並挑選一個 View 回應給 Client。由 Routing ,到 Controller 處理Model,最後到 View,一氣喝成。一個關節沒弄好,就會出錯。

舉例來說,預設的 routing table 如下:

routes.MapRoute( 
"Default",                                              // Route name 
"{controller}/{action}/{id}",                           // URL with parameters 
new { controller = "Home", action = "Index", id = "" }  // Parameter defaults 
); 
http://localhost/Home 則會找到 HomeController 的 Index Action。請參考下例
[HandleError]
    public class HomeController : Controller
    {
        //http://localhost:4041/Home/
        public ActionResult Index()
        {
            return View();
        }

        //http://localhost:4041/About/
        public ActionResult About()
        {
            return View();
        }

        //http://localhost:4041/About/3
        public ActionResult About(int id)
        {
            ViewData["id"] = id;
            return View();
        }
    }
如果執行 http://localhost:4041/Home的要求,但 HomeController 沒有 Index() 這個 Action的話,會出現什麼狀況呢?答案是 The resource cannot be found.

controller要如何「挑選」View 呢?答案是 View() 這個 Method
當我們使用 return View() 時,會使用同 Action 的 View。

舉例來說,
[HandleError]
    public class HomeController : Controller
    {
        //http://localhost:4041/Home/
        public ActionResult Index()
        {
            return View();
		//與 return View("Index") 相同
        }
    }
如果,硬要挑選其他名稱的 View,就要指定 View 的名稱。如下例

[HandleError]
    public class HomeController : Controller
    {
        //http://localhost:4041/Home/
        public ActionResult Index()
        {
            return View("List"); //雖然是 HomeController下的 Index Action,但指名挑選名為 List 的 View
        }
    }

2009年9月3日 星期四

The SessionStateTempDataProvider requires SessionState to be enabled

'/EPWeb' 應用程式中發生伺服器錯誤。
--------------------------------------------------------------------------------

The SessionStateTempDataProvider requires SessionState to be enabled.

面對這樣的錯誤時,實在不知如何下手。當然,Google 大神還是要招喚一下。

原來,asp.net mvc 是需要使用 session來作為暫存資料用。(oh! my god)
而我的應用程式的虛擬目錄,是建立在 moss 的網站下,會受到 moss 的 web.config 影響。

參考 http://www.flyvergrillen.dk/2009/03/26/being-trapped-in-iis/ 後,發現雖然我是使用 Windows 2003 ,但發現了我仍是缺少 SessionStateModule ,因此,加上 SessionStateModule,並啟用 SessionState 即可。

<httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="SessionStateModule" type="System.Web.SessionState.SessionStateModule" />
    </httpModules>
    <sessionState mode="InProc" />

MVC (2): Url Routing 的測試

以往,在 Web form 甚至在 asp 的久遠年代,網頁執行的 url 是與作業系統相關的。
舉例來說,http://localhost/app/Bulletin/Add.aspx 這個 url ,我們大概可以猜 add.aspx 是位於 web server 的 c:\wwwroot\inetpub\app\Bulletin\Add.aspx 下。雖然IIS 的網站主目錄會變動,但 Bulletin\Add.aspx 的目錄結構幾乎是定律了。

但,誰說這是一成不變的?在 asp.net 上,也有 HttpContext.Current.RewritePath 方法可以改變執行的網頁。因此上述的定律開始被打破。

到了 MVC 的世界,Url 與執行的網頁是不對應的。Request 必須經由解析後,找到對應的 Controller來處理。由 Request 找到對應 Controller 的過程,就是 url routing。

Url routing 如何配置呢?目前 asp.net mvc 1.0 的做法是在 global.asax.cs 上以 coding 的方法處理。這一點相當不彈性,應該可以在 config file 上設定即可。目前我尚未研究是否有 config file 的方法。

程式如下:

public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      routes.MapRoute(
          "Default",                                              // Route name
          "{controller}/{action}/{id}",                           // URL with parameters
          new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
      );
    }

以上是預設的,也就是 asp.net mcv project template 一開始就建好的範本。

我們也可以寫兩個以上的 routing rule。當 request 進入時,就會由上而下開始對應,直到第一個配對成功。

public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      routes.MapRoute(
    "R1",                                              // Route name
    "Order/{action}/{date}",                           // URL with parameters
    new { controller = "Order", action = "Index", date = "" }  // Parameter defaults
        );

      routes.MapRoute(
          "Default",                                              // Route name
          "{controller}/{action}/{id}",                           // URL with parameters
          new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
      );
    }

此時,http://localhost/app/Order 會match 到 R1 的規則,而其他如 http://localhost/app 的則會被 Default 的規則所補獲。

以上是人工的預測。但這個 routing table 是有些複雜的。到底 match 到哪一個 route卻是相當重要的。有沒有一個工具可以幫我們測試 routing 呢?有的。請參考 http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx  的說明

image

2009年6月27日 星期六

MVC (1): Asp.NET MVC 概念說明

MVC

MVC是一個 UI Presentation Pattern。與三層式架構並無直接關聯。但因為我們也常三層式架構,不可避免的,要如何將 MVC 與三層式架構一起使用呢?首先就必須了解什麼是 MVC.

MVC 是一種展現層(Presentation Layer)的架構。

Model 即資料
View 根據Model的數據,進行內容展示的組件
Controller 接受並處理客戶端的指命(即操作Model),選擇一個View並輸出內容

Asp.net MVC

Asp.net MVC 當然是將 MVC Pattern 使用於  asp.net  上。因此,會多了一些特定的特色。

Model 即資料
View 根據Model的數據,進行內容展示的組件。以 asp.net MVC 來說,就是輸出成HTML。
Controller 接受並處理客戶端的指命(即操作Model),選擇一個View並輸出內容。以asp.net MVC來說,就是負責Page flow or Page logic

Asp.net MVC + 3-layer Application

若加上三層式架構概念後,又加上了下表的粗體字。

Model 即資料。取得資料時,需呼叫業務邏輯層,再呼叫資料邏輯層以存取資料。因此,Model 與業務邏輯層相關性高。
View 根據Model的數據,進行內容展示的組件。以 asp.net MVC 來說,就是輸出成HTML。展示層
Controller 接受並處理客戶端的指命(即操作Model),選擇一個View並輸出內容。以asp.net MVC來說,就是負責Page flow or Page logic,(中文可翻成UI呈現邏輯)。展示層

 

image

相依性

有個非常重要的地方,是 MVC 的相依性,即下圖箭頭的方向。例如,View 相依於 Model,意即 View 組件有參考到  Model 組件。相反地,Model 並不知道 View 的存在。

這樣帶來了一些好處。首先,是同樣的數據(Model)可以使用不同的View來展示出不同的呈現方式。再者,我們可針對有邏輯的部份(Model的商業邏輯,Controller 的UI呈現邏輯)做測試。最難的部份View,即包含網頁的部份,才進行人工測試,如美工編排是否正確等。

image

Share with Facebook