2011年9月23日 星期五

ASP.NET MVC自訂登入權限

在ASP.NET MVC中
有些Action的執行,必須先判斷使用者是否經過登入,或是有沒有相關權限
所以我們在controller的action名稱前,可加入[Authorize]這個Attribute
若使用者沒有登入,則將他導向Web.config中定義的登入頁
controller的部份

2011年9月9日 星期五

Html attributes for EditorFor() in ASP.NET MVC 3(use Razor)

最近剛使用ASP.NET的新的view engine:Razor
專案中想讓view的某個欄位是disable的
但是原本用Visual Studio幫你產生出來時,view中的code對於欄位會產生如下:

@Html.EditorFor(model => model.EmployeeNo)


想要讓該欄位disable,後來找了一下資料,試成這樣:

PetaPOCO with stored procedure

在試PetaPoco執行stored procedure時
主要是參考下面這篇文章
PetaPoco with parameterised stored procedure and Asp.Net MVC

自己試了之後,有幾項要點先memo下來

2011年9月8日 星期四

PetaPOCO使用JOIN回傳Muti-POCOs

新的案子由於一些考量,不使用Entity Framework
所以找了一個替代方案-PetaPOCO
它是一個輕量級的ORM
這裡這先不介紹它那麼多了
先memo下來我在使用SQL join多table時,要對應到相對的POCO時所發生的問題

使用Fetch時,無法回傳對應的POCO
例:

var sql = PetaPoco.Sql.Builder
                .Append("SELECT Test_Basic.*, Test_Detail.*")
                .Append(" From Test_Basic ")
                .Append(" JOIN Test_Detail ON Test_Basic.MID = Test_Detail.TID Where Test_Basic.Account = 'test' ");
 var test = databaseContext.Fetch<TestBasic, TestDetail>(sql);

後來才發現是TestBasic那個POCO裡面
少了一個TestDetail的關聯,補上如下:

[ResultColumn]
 public TestDetail TestDetailObject { get; set; }

這樣就抓的到了
另外欄位也記得加上PetaPOCO的annotation

[PetaPoco.Column]
 public string Account { get; set; }


或者是拿掉[ExplicitColumns]

2011年9月2日 星期五

MySQL : SELECT ... FOR UPDATE

之前公司有一個功能是負責商品搶購
也就是在某一段時間內,給會員用優惠的價格買東西
這個案例在電子商務的世界裡很常見
對於商品的可購買數量,若是在交易過程中,計算錯了
那可是會有一大堆客訴

那時該系統是使用MySQL
而商品的table是用InnoDB
我們必須在會員購買前,先確認商品的庫存數量
庫存>0的時候,我能才能賣
如果SQL是這樣寫
SELECT quantity FROM product WHERE id="商品編號";

再判斷quantity >0為true的話,就再更新賣掉後的數量
UPDATE products SET quantity = 5 WHERE id="商品編號";
 要是這樣寫的話,就挫起來了
我們必須在這段程式裡包一個交易(transaction)
並且將SELECT的後面再上 FOR UPDATE
才能避免產生race condition
修改如下:
SELECT quantity FROM product WHERE id="商品編號" FOR UPDATE; 
UPDATE products SET quantity = 5 WHERE id="商品編號";

2011年9月1日 星期四

為ELMAH custom error page

ELMAH真是個記錄網站error的好工具
從NuGet下載安裝後
幾乎web.config都設定好了
不過我不想網站發生錯誤時,都跳出詳細的錯誤資訊給別人看
所以需要設定自訂錯誤頁

這時候,把web.config打開來
確認<configSections>有下面的資料(從NuGet安裝會自動幫你加)
<configSections>
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"  />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />     
    </sectionGroup>  
  </configSections>
再來是<httpModules>加上
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
 然後<httpHandlers>加上
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
以上是從NuGet安裝ELMAH後,會自動加上去的
再來就自己在<system.web> 區塊內加入
<customErrors mode="On" />
這裡可以指定你的錯誤頁,但是我目前預設是用View/Shared/Error.cshtml

還有在<configuration> section為你的xml log檔選個地方存檔
<elmah>
    <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="D:/WebLog" />
  </elmah>
最後,確認一下Gobal.asax檔的RegisterRoutes method有沒有加上:
routes.IgnoreRoute( "elmah.axd" );  

按照上面的部份,照理說就可以work了
不過,我自己看官方文件的時候做完之後,是會導到自訂錯誤頁沒錯
可是看elmah.axd檔時,卻沒有任何error被log下來
後來發現我的web.conf檔有多了一個section
<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <handlers>
      <add name="Elmah" path="elmah.axd" verb="POST,GET,HEAD" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
    </handlers>
  </system.webServer>
把它拿掉之後,就可以了
目前還沒研究這一段有何功用
等改天研究好再PO出來