2010年8月24日 星期二

.NET 平台上 ORM 工具的趨勢

ORM 工具的趨勢比較,可由 Google trends 看到一些端倪

http://www.google.com.tw/trends?q=nhibernate%2C+entity+framework%2C+linq+to+sql&ctab=0&geo=all&date=all&sort=0

目前來說, NHibernate 的使用比率仍然相當高,但 Entity Framework 的逐漸看漲,未來應可凌駕 NHibernate 之上。

在目前資料庫存取技術,我建議開始使用 ADO.NET Entity Framework了,畢竟這是微軟主推的資料存取技術。而目前ADO.NET Entity Framework尚未有大廠推出 Oracle 的 Provider。Oracle預計明年推出。目前如果要存取Oracle,只能使用 NHibernate,目前只有它才能存取 Oracle,技術也相對成熟。

clip_image002

2010年8月21日 星期六

NHibernate 資源

前言

NHibernate 沿自 Java 的Hibernate,並在 .NET 平台中建立自己的勢力。在 ADO.NET Entity Framework 尚未出現前,在 .NET 平台中的 ORM 確實是第一把交椅。

許多客戶都在使用 Oracle,而在資料庫存取上, 到目前為止,ADO.NET Entity Framework 尚未有免費(或大廠)所推出的 provider for Oracle。Oracle 也有計畫要推出,見 Entity Framework Oracle Provider?,但時程至少落在2011年年初。我實在等不及了。只好回過頭來看看  Nhibernate 有沒有好的解決方案。

當然,我才 study 約5天左右,實在沒有實戰經驗。僅將找到的下載與學習資源集中在此,方便自己與大家學習。

官網資源

NHibernate 的官網當然是最多資源的地方。而 Download 區就有一堆實用的功能。我目前使用 2.1.2 版。

NHibernate Contrib

NHibernate Contrib 算是 NHibernate 的好兄弟,推出一些好用的工具,可在這裡下載。

其中極力推薦 NHibernate Linq,將 LINQ 的語法帶到了 NHibernate 中。因此不必再使用 Criteria 或 Query By Example 等不自然的方式來查詢,而且功能有限。HQL 雖然強大,可是不支援 Compile time 的除錯,當然也沒辦法 Intellisence。改用  LINQ 語法容易維護多了。

其他資源

PS:
   其他資源找到了會陸續補上。

2010年8月20日 星期五

Visual Studio Scrum 1.0 安裝

安裝過程,可見

http://visualstudiomagazine.com/Articles/2010/07/27/Installing-Scrum-Process-Template.aspx?Page=1

安裝

這裡 下載並安裝程式

上載Process Template

執行 Visual Studio 2010的功能表「Team/Team Project Collection Settings/Process Template Manager」

image

點擊「Upload」鍵,選擇目錄「C:\Program Files (x86)\Microsoft\Microsoft Visual Studio Scrum 1.0\Process Template」完成上傳.

Web Portal

小組網站必須顯示統計報表,而每種 Process Template 都可能有自己的顯示方式。Scrum 就是一例。

請將C:\Program Files (x86)\Microsoft\Microsoft Visual Studio Scrum 1.0\Project Portal\Microsoft.TeamFoundation.SharePoint.Scrum.wsp 複製到 moss 網站伺服器下的一個子目錄中,例如 c:\temp\。

再來,以管理員身份執行 cmd

image

逐一執行下列指令

SET STSADM="%CommonProgramFiles%\Microsoft Shared\web server extensions\12\Bin\stsadm.exe"
%STSADM% -o addsolution -filename Microsoft.TeamFoundation.SharePoint.Scrum.wsp
%STSADM% -o deploysolution -name Microsoft.teamfoundation.sharepoint.scrum.wsp -immediate -allowGacDeployment
%STSADM% -o execadmsvcjobs
%STSADM% -o enumsolution

記得注意一下是否有錯誤的訊息哦!我在執行%STSADM% -o execadmsvcjobs花了相當長的時間(1小時多),原來是在進行掃毒,你的環境可能沒有這回事。

結果

天啊!Dashboard 竟然出現了下面的錯誤訊息。但其它地方到還是正常的。而 Dashboard 也大約在半小時後自動正常了,也不曉得是什麼原因。

image

 

20110119 註記

這次安裝了另一台 TFS,這是安裝的是中文版的 TFS。使用上述方法後 並建立一個新的 Team Project 後,發生了下面的錯誤

TF249033: 沒有可供此地區設定識別項 (LCID) 使用的網站範本。網站範本名稱是: TFS2010 Agile Dashboard。LCID 是: 1033

查了保哥的 TFS2010 安裝 Microsoft Visual Studio Scrum 1.0 流程範本 ,才知道需要安裝 WSS 3.0 的 language pack

但最後,還是失敗了。用改 WSSTasks.xml 中的 language=1028 才能成功。

2010年8月19日 星期四

Method Chaining

原本在開發程式的時候,一個物件的 instant 如果需要連續地執行某些動作時,程式會類似下面範例程式。

using System;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyClass();
            c.Do1();
            c.Do2();
            c.Do3();
        }
    }

    internal class MyClass
    {
        public void Do1()
        {
            Console.WriteLine("Do1");
        }

        public void Do2()
        {
            Console.WriteLine("Do2");
        }

        public void Do3()
        {
            Console.WriteLine("Do3");
        }
    }
}

instance c 必須呼叫 Do1, Do2, Do3, instance c 必須寫三次 c., c., c.

Method Chaining 則是另一種物件行為的設計方式。將上述 MyClass 的 void Method 改回傳物件本身,就可以達到另一種呼叫方式。

using System;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            var c = new MyClass();
            c.Do1().Do2().Do3();
        }
    }

    internal class MyClass
    {
        public MyClass Do1()
        {
            Console.WriteLine("Do1");
            return this;
        }

        public MyClass Do2()
        {
            Console.WriteLine("Do2");
            return this;
        }

        public MyClass Do3()
        {
            Console.WriteLine("Do3");
            return this;
        }
    }
}

看到了嗎?可以改成 c1.Do1().Do2().Do3() 的方式來呼叫,是不是很簡潔呢?

使用 Method chaining 的 API,是源自 small talk 語言的習慣,近來的 jQuery 大量地使用這樣的設計,方便程式開發人員使用。

這樣也有個缺點,會造成程式可讀性較差。總地來說,還是優點較大呢。

2010年8月12日 星期四

使用 Ajax 方式取得 UserControl 的內容

同事問到,如何以 Ajax 的方式取得 UserControl 的內容。

問題

由於 UserControl 是無法單獨被客戶端所呼叫(Request),因此我們必須想個辦法將 UserControl 加到一個 Page內。

解決步驟

1 Web Service 回傳 UserControl 的內容

使用 Visual Studio (我使用 2010) 建立一個 Web Application,並加入一個 WebService。程式碼如下

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
    [WebMethod(EnableSession = true)]
    public string GetUserControlHtml(string location)
    {
        var webServiceString = string.Format("Thread Id={0}, Time={1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HHmmss fffffff"));
        var page = new Page();
        var userControl = (UserControl)page.LoadControl(location);
        userControl.EnableViewState = false;
        var form = new HtmlForm();
        form.Controls.Add(userControl);
        page.Controls.Add(form);
        var writer = new StringWriter();
        HttpContext.Current.Server.Execute(page, writer, false);

        return webServiceString + "<br /> " + RemoveFormTagFromHtml(writer.ToString());
    }


    /// <summary>
    /// 移掉 Form Tag
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    private static string RemoveFormTagFromHtml(string html)
    {
        return Regex.Replace(html, @"<[/]?(form)[^>]*?>", "", RegexOptions.IgnoreCase);
    }
}

過程大略是:手動建立一個 Page,Page 內加入一個 Form,Form 動態載入指定的 UserControl。使用 Server.Execute 取得 html 內容後,將 <form tag 移除,避免避免原 asp.net 網頁失敗。

2 寫 UserControl

今天的配角是 UserControl。UserControl並不難實作。我簡單的寫了兩個 UserControl,分別 Thread.Sleep 了2秒,3秒。

3 於呼叫網頁使用 Ajax 方式呼叫 ASP.NET Web Service

我再入成兩種方式來呼叫。一個是 ASP.NET AJAX,一個則是 jQuery。

3.1 使用 ASP.NET AJAX 呼叫 Web Service

加入一個 ScriptManager,並加入一個 ScriptReference 參考到剛剛建立的 WebService。利用動態產生的 javascript file (可使用 http://…/WebService1.asmx/jsdebug 取得內容)協助呼叫 ASP.NET Web Service

3.2 使用jQuery 的 .ajax 呼叫 Web Service

使用jQuery 大概是近來 Web 技術的顯學吧。為了方便未來的 ASP.NET MVC的使用,還是乖乖的學一下吧。

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication3._Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var datestring = getNow();
            $("#div1").html("at client, " + datestring + "<br/>");
            getData("WebUserControl1.ascx", $("#div1"));

            datestring = getNow();
            $("#div2").html("at client, " + datestring + "<br/>");
            getDataByJquery("WebUserControl2.ascx", $("#div2"));
        });

        function getNow() {
            var today = new Date();
            return today.format("HHmmss ffffff");
        }
        function getData(controlLocation, container) {
            WebApplication3.WebService1.GetUserControlHtml(controlLocation,
                function (result) {
                    $(container).append(result);
                },
                function () { alert(error.get_message()); }
            );
        }

        function getDataByJquery(controlLocation, container) {
            var datestring = getNow();
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "WebService1.asmx/GetUserControlHtml",
                data: "{'location': '" + controlLocation + "'}",
                dataType: "json",
                success: function (result) {
                    $(container).append(result.d);
                },
                error: function (error) { alert(error.responseText); }
            });
        }
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Services>
            <asp:ServiceReference Path="~/WebService1.asmx" />
        </Services>
    </asp:ScriptManager>
    <h2>
        Welcome to ASP.NET!
    </h2>
    <div style="border: 2px solid red">
        <h1>
            User Controll 1</h1>
        <div id="div1">
        </div>
    </div>
    <div style="border: 2px solid red">
        <h1>
            User Controll 2</h1>
        <div id="div2">
        </div>
    </div>
    <div id="result">
    </div>
</asp:Content>

4 測試

測試時發現狀況還不錯。雖然同時發出 Request, 約2秒後得到UserControl1 的內容,但 UserControl2卻在約略在 5.5 秒後才得到內容,而非3秒。為什麼?

image

5 Session 造成 lock,因而 Delay

原來是步驟1中,[WebMethod(EnableSession = true)] 這個 true 所造成的。改成 EnableSessioin = false後,網頁測試結果如下

image
這樣就符合我們的期待了。

沒事最好還是不要用 Session。

範例下載

2010年8月10日 星期二

WPF 學習:透明應用程式

有些程式有獨特的風格,例如透明應用程式就是一例。那要如何寫出這類風格的程式呢?

Xaml

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" AllowsTransparency="True" WindowStyle="None"
        Background="Transparent" MouseLeftButtonDown="Window_MouseLeftButtonDown">
    <Grid>
    <Ellipse Opacity="0.5" Fill="Green">
      <Ellipse.BitmapEffect>
        <DropShadowBitmapEffect />
      </Ellipse.BitmapEffect>
    </Ellipse>
  </Grid>
</Window>

重點
  1. Window 的 AllowsTransparency 必須設為 True,否則無法呈現透明。
  2. Window 的 WindowStyle 必須設為 None。否則會出現例外。
  3. Window 的 Background 必須設為 Transparent,以顯示透明效果。
經過這三個設定後,程式一跑,就看不到任何的程式內容了。所以我們必須加上內容。如上面範例所示,我增加了一個 半透明的Ellipse,並且以 DropShadowBitmapEffect 產生些微的陰影效果。 再來,為了讓應用程式的 Window 可以移動,我加了MouseLeftButtonDown 的事件處理器。
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
  this.DragMove();
}
這樣,我們就可以拖動視窗了。範例執行畫面如下。

image

2010年8月9日 星期一

AppFabric Cache Exception.

問題

我在寫入一個大量資料的Cache時,發生如下的錯誤

Microsoft.ApplicationServer.Caching.DataCacheException: ErrorCode<ERRCA0016>:SubStatus<ES0001>:The connection was terminated, possibly due to server or network problems or serialized Object size is greater than MaxBufferSize on server. Result of the request is unknown.

由錯誤訊息得知可以透過 MaxBufferSize 來解決問題。

解法步驟

解決方法,必須同時在 Server 端及 Client 端增加 MaxBufferSize 的設定。

首先是 Server Side

Server Side

Export Cluster Config


Export-CacheClusterConfig -File c:\temp\cluster.config

將Cluster 的設定匯出到一個 xml config 檔。此處我命名為 cluster.config

增加 transportProperties 的設定

依照 Application Configuration Settings 的建議,在上一步驟的cluster.config 增加下面的設定

匯入並套用設定

在匯入設定前,必須先停止 Cluster。匯入設定後,記得再啟動 Cluster。
Stop-CacheCluster
Import-CacheClusterConfig -File c:\temp\cluster.config
Start-CacheCluster

再來是 Client Side

Client Side

在 Client config 加入 transportProperties 設定

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="dataCacheClient"
                    type="Microsoft.ApplicationServer.Caching.DataCacheClientSection,
                        Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0, 
                        Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                     allowLocation="true"
                     allowDefinition="Everywhere"/>
    </configSections>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
    <dataCacheClient>
        <hosts>
            <host name="localhost" cachePort="22233"/>
        </hosts>
        <transportProperties maxBufferPoolSize="268435456" maxBufferSize="83886080" />
    </dataCacheClient>
</configuration>

Share with Facebook