2013年6月14日 星期五

在Web Form專案中使用Rzaor上Azure WebSites的問題

先不談問何需要在WebForm當中使用Razor WebPages,這一篇主要還是討論到的問題和解決的方法。 首先要在WebForm中使用Razor不是太大的問題,建立一個HTML Page把副檔名直接改cshtml即可:

接著我們就可以撰寫Razor語法了(我找一天完整一點介紹Razor以及他的意義,但還沒寫之前,gelis的這一篇不錯,如果你喜歡讀英文,可以看這篇)。

OK,撰寫一段簡單的程式碼如下,結果一執行,馬上發生錯誤:

我們很乖的依照指示,到web.config中改成:
<configuration>
 <appSettings>
   <add key="webPages:Version" value="2.0"/>
 </appSettings>
<system.web>
  <compilation debug="true" targetFramework="4.0" />
</system.web>
</configuration>

OK,可以work囉。


但悲劇發生在上Azure WebSites時:

本來以為是Azure websites看不懂cshtml,還我改了一陣子MIME設定,後來想想不對,如果看不懂就應該不能run MVC 的razor才對,所以又轉往另一個方向嘗試,折騰了半天,原來Azure websites尚未支援2.0。 立馬到Azure WebSites設定畫面調整看看:

設定完成之後,搞定囉。 cshtml的razor頁面可以混在WebForm中上Azure囉...

先寫到這邊(其實還有一個在cshtml page中存取資料的問題...改天繼續)

==================================
沒事幹嘛在ASP.NET WebForm中混入Razor呢?

其實我也有點掙扎。 這一陣子有個案子是以MVC來設計,開發的同仁跟我說,選用MVC其中一個原因是他討厭WebForm中的WebControl,總是沒有辦法隨心所欲的調整UI,不管套入CSS或是選用哪一套JavaScript Framework,實在都不容易整合。

某種程度上我是接受的,因為WebControls自己reder出來的HTML,想要調整很難不寫後端C#(VB) code,來微調WebControl的HTML輸出。但如此一來,前端又有寫死在.aspx中的JavaScript,後端又有透過C#(VB)動態產生的JavaScript,整個頁面的呈現就算能夠達成我們要的效果,但已經讓後續維護越來越困難。

這是很多人選用MVC的動機之一...但,如果這只是唯一原因...對專案來說背後的代價也不算低。

因為寫慣了WebForm(或Windows Form)的開發人員轉往MVC會有一段掙扎的時間(我發現反而原本從沒寫過WebForm或WindowsForm的開發人員卻比較容易進入),而且MVC要寫的漂亮,且維持MVC的精神,其實對於物件(OO)操作的觀念需要比WebForm對於OO的觀念來的更精實才行。而在採用MVC來開發之後,處理UI時想要用比較短(比WebForm或Silverlight還快)的時間來達成相同的效果,大概非得用上一兩套JS Framework不可,這些都增加了入門的門檻和學習(開發)的成本。 而URL Routing和Controller的觀念也是必須的,導致我在專案中想讓ASP.NET WebForm開發人員立刻接手MVC開發工作,常常會發生一些衍生的成本。

為了兼顧網頁UI呈現的自由度,又不想用MVC這麼大一套架構,因此我們最近開始採用Razor Page在WebForm專案中,搭配自己的code generator(關鍵其實在這裡 :) ),並依照專案的不同選用JS Framework。這會迫使開發人員必須放棄WebControls來設計UI,而直接用HTML/JS來處理,搭配Razor Page以提高開發的效率。

(那為何不用inline ASPX? 可參考上面gelis那一篇中的解釋)

這是一個嘗試(也就是說我也不確定這樣一定是好的,如果有想法非常歡迎一起討論)。在.NET Web開發的領域中,已經累積了相當多不同的技術,傳統的WebForm有WebForm的好處,MVC有MVC的優點,Silverlight有Silverlight的價值,Razor有Razor的便利...也因此,在熟悉每一種技術之後,看看怎麼讓開發成本最低,後續的維護便利、程式碼的重用性最高...是我們在開發專案的目標。

2013年6月9日 星期日

ASP.NET Reporting - 如何讓SSRS中TextBox的Go To URL Action中跳新視窗

SSRS對於ASP.NET開發人員來說實在是一個很好的工具,畢竟,對很多MIS/IT所服事的大老闆來說,資訊系統
唯一的價值,其實就是那一份份的報表。

如果你有用SSRS,一定會發現文字方塊是可以設定成超連結的,關鍵在於TextBox的Action屬性,只需要設定成Go To URL,然後在Select URL那邊放入網址即可: 但你找了半天,居然沒有可以設定點選該URL的Target設定位置,那...如果要開新視窗怎麼辦呢??? 好問題!!! 其實,這個Go To URL有一個更有趣的設定,可以解決這些問題,你可以直接在Select URL中,輸入底下內容:
沒想到,居然可以輸入JavaScript,如此一來,在報表中點選該連結,就可以開新視窗囉。

=============================================================
既然可以開新視窗,那可不可以更進一步的???

答案也是可以的,SSRS真是個好物。

2013年6月6日 星期四

ASP.NET WebForm Forms驗證整合Google oAuth驗證

ASP.NET從4.x開始,支援不少重要的機制,也不知道是因為用的人變少了,還是因為大家都沒空,所以ASP.NET WebForms相關的中文post比起其他技術相形之下少的可憐。

最近開發團隊中有夥伴需要透過ASP.NET WebForm來整合Google/Faccbook/MS的身分驗證,當然,我們都知道現在大家都支援oAuthOpenID了,最理想的狀況是讓我們家的網站跟MS自己的網站一樣,User只需要登入一次,就可以跨網站跑來跑去不需要重新登入,同時,我們的網站也不需要負責維護用戶的帳號密碼,而是透過Google/Faccbook/MS幫我們做身分驗證。
(有空我會畫張圖,上面這張是出自oauth.net)

簡單的說,就是我們的網站的用戶只需要有Google/Faccbook/Microsoft Account等帳號,即可登入我們的網站,而我們的網站也不需要傷腦筋身分驗證的事情,畢竟,驗證是一個可能導致風險的機制,也是駭客進入你的網站的第一道防線,如果隨意設計可能後患無窮,與其自己辛苦,不如透過oAuth機制幫你驗證用戶身分。

前面說過,在ASP.NET要實現這樣的功能,從4.0之後的版本,大幅簡化了工作流程,甚至,你現在只需要透過DotNetOpenAuth.AspNet套件即可完成。 我們以底下這個ASP.NET WebForm 4.0與Google帳號整合的驗證機制來示範,我們建立一個新的WebForm網站:

我刻意用ASP.NET Empty Web Application,因為這個範本比較乾淨,甚至連app_start都沒有,這樣比較容易說明。 接著,請進入到我們的ASP.NET專案,在VS2012中開啟Package Manager Console(主選單--> Tools --> Library Package Manager --> Package Manager Console),並依序輸入:

Install-Package Microsoft.AspNet.Membership.OpenAuth
  和
Install-Package DotNetOpenAuth.AspNet

輸入後,VS2012會執行一些動作...


你會發現Visual Studio在你的專案中加入了一堆有的沒的.dll,完成後大致如下:

主要是頭底上那幾個Microsoft.AspNet.Membership.OpenAuth... 接著,請在專案中加入Global.asax:

並且在Application_Start中加上這一行:(以整合Google驗證為例)
protected void Application_Start(object sender, EventArgs e)
 {
      OpenAuth.AuthenticationClients.AddGoogle();
 }

然後我們要建立幾個頁面,分別是default.aspx, login.aspx, GoogleCallBack.aspx
  1. default.aspx 是我們的首頁,在首頁中會顯示登入用戶的資訊,如果發現使用者沒登入,則導入到login.aspx。
  2. login.aspx登入頁面,過去我們是在這個頁面中放入login控制項,而現在我們則在這個頁面中,把用戶帶到google去做登入驗證
  3. GoogleCallBack.aspx則是google幫我們驗證完之後,要將用戶帶去的那個頁面
在default.aspx中,我們的程式碼是:
protected void Page_Load(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(User.Identity.Name))
        this.Label1.Text = User.Identity.Name;
    else
        Response.Redirect("login.aspx");
}

在Login.aspx中,我們的程式碼是:
protected void Page_Load(object sender, EventArgs e)
{
    OpenAuth.RequestAuthentication("google", "~/GoogleCallBack.aspx");
}

最後,是重要的GoogleCallBack.aspx
protected void Page_Load(object sender, EventArgs e)
{
    var returnUrl = Request.QueryString["sid"];
    var authResult = OpenAuth.VerifyAuthentication(returnUrl);
    if (authResult.IsSuccessful)
    {
        System.Web.Security.FormsAuthentication.SetAuthCookie(authResult.UserName, false);
        Response.Redirect("default.aspx");
    }
}

別忘了Web.Config中必須要設為Forms驗證:
<system.web>
<authentication mode="Forms"></authentication>
   ...
   ...

接著,就可以試試看囉....你會發現當進入default.aspx頁面,如果用戶尚未登入,系統會導入google驗證畫面:

當用戶登入後,則會出現此要求授權畫面:

這個畫面只會出現一次,當用戶接受之後,未來登入時就不會出現,接著,系統自動將程式導入到我們先前設計的GoogleCallBack.aspx,在該頁面當中,我們透過API取得用戶帳號,並且透過SetAuthCookie保留用戶身分,再導回首頁,如此就完成google與ASP.NET WebForm Forms 驗證的整合囉。



Source Code:
https://github.com/isdaviddong/aspnet4WebFormsAuthAndGoogleoAuth