2008年7月24日 星期四

使用 Enterprise Library Configuration 設定 DAAB

新增 connection string

clip_image002

修改剛剛新增的 connection string 的設定

clip_image004

修改 connection string 的值

clip_image006

點選 “Data Access Application Block”

clip_image008

設定預設的資料庫

clip_image010

Response.Flush() 在 Windows 2000 + IIS 5 上有效能的問題

一模一樣的程式(Asp.Net 2.0),在 Windows 2003 上跑就很好,而 Windows 2000 就奇慢無比,差了40倍。

clip_image002

程式碼如下

            string strRes = DateTime.Now.ToString("MMMM dd, yyyy HH:mm:ss", DateTimeFormatInfo.InvariantInfo);
            Response.Clear();           
            Response.Write(strRes);
            Response.Flush();
            Response.End();

查了好久。查過修改 Global.asax.cs,IIS 的權限設定,帳號等。最後,竟然是 Response.Flush(); 這一行的問題。將這一行刪除後,就正常了。

image

2008年7月22日 星期二

網頁權限不正常的部署

網頁權限不正常的部署

部署網頁程式時,必須使用Copy & Paste,不能 Cut & Paste。一旦使用Cut & Paste,非常容易造成權限的問題。

主要是「網際網路的Guest 帳號」的權限不見了。如下圖。

clip_image002

處理

首先,在出事的目錄上,按右鍵,點擊「內容」

clip_image004

再來,按下方的進階

clip_image008

再來,勾選「以顯示於此套用到子物件的項目,取代所有子項物件上的權限項目」

clip_image011

按「套用」鍵後,會出現下面視窗,請按「是」。

clip_image013

Linq to SQL 的 bug?

看來,我發現了一個 Linq to SQL 的 bug。
要還原現場,當然要 database 。

CREATE TABLE [dbo].[A](
	[AId] [int] NOT NULL,
	[AName] [char](10) NOT NULL,
 CONSTRAINT [PK_A] PRIMARY KEY CLUSTERED 
(
	[AName] ASC
),
 CONSTRAINT [IX_A] UNIQUE NONCLUSTERED 
(
	[AId] ASC
)
)
GO
INSERT [dbo].[A] ([AId], [AName]) VALUES (1, N'Charles   ')
go
CREATE TABLE [dbo].[A2](
	[AId] [int] NOT NULL,
	[AValue] [varchar](50) NOT NULL,
 CONSTRAINT [PK_A2] PRIMARY KEY CLUSTERED 
(
	[AId] ASC
)
)

GO
ALTER TABLE [dbo].[A2]  WITH CHECK ADD  CONSTRAINT [FK_A2_A] FOREIGN KEY([AId])
REFERENCES [dbo].[A] ([AId])
GO
ALTER TABLE [dbo].[A2] CHECK CONSTRAINT [FK_A2_A]
GO

注意到,A2.AId 是 reference 到 A.AId。而A.AId 是 unique key,而非 primary key。A 的 primary key 是 AName

再來,就開始拉 dbml ,如下圖

image

再 create 一個 Console Application,如下

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      TestDataContext ctx = new TestDataContext();
      A2 a2 = new A2 { AId = 1, AValue = "xxx" };
      ctx.A2s.InsertOnSubmit(a2);
      ctx.SubmitChanges();
    }
  }
}
程式錯誤訊息如下:

Type : System.InvalidCastException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Message : Unable to cast object of type 'System.Int32' to type 'System.String'. Source : System.Data.Linq Help link : Data : System.Collections.ListDictionaryInternal TargetSite : Boolean TryCreateKeyFromValues(System.Object[], V ByRef) Stack Trace :    at System.Data.Linq.IdentityManager.StandardIdentityManager.SingleKeyManager`2.TryCreateKeyFromValues(Object[] values, V& v)    at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache`2.Find(Object[] keyValues)    at System.Data.Linq.IdentityManager.StandardIdentityManager.Find(MetaType type, Object[] keyValues)    at System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues)    at System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance)    at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()    at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)    at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)    at System.Data.Linq.DataContext.SubmitChanges()

image

這個錯誤訊息,真是是令人不敢領教。


其實,這個錯誤,只需要修改 A 的 primary key 為 AId 即可。但實務上,卻非常有可能如上例的資料庫設計。
以發票的例子為例,常常會以發票號碼作為 primary key,而另設一個 ObjectId (int) 作為別的 table 的 reference key,因為 int 的size 較小。

Sql Script 可這裡下載, 而程式碼可這裡下載

目前我已向微軟提出這樣的 bug。這是算是我的第一次呢!

[註] 2008/08/19 MS Linq to SQL team 已經證實這個 issue ,而且會在下一次 release 修正。

IIS 7 的網站管理 with managed code

以往,要在 IIS 6 新增網站,增加 application 或 application pool ,都必須靠人工由 inetmgr 操作,或寫 script 操作 activeX 元件。
不是非常方便。

學了 .net 後,這些工作並沒有得到改善。原因是 IIS 6 仍然是 unmanaged code。

終於, IIS 7 算是改寫了。因此,可以用下面的程式來新增一個 "MyDemoSite" 網站,port 是 8080。該網站的根目錄是 c:\demoSite。
並建立一個 applicatioin pool 為 "demoPool",且是 intergrated。並將該網站的 application pool 設為 "demoPool"。
(ps: 上一段的文字描述,反而不如程式碼來的清楚)

首先,必須 add reference。必須瀏覽到 C:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll

然後再寫下面這一段

      ServerManager serverManager = new ServerManager();
      serverManager.Sites.Add("MyDemoSite", @"c:\demoSite", 8080);
      ApplicationPool pool = serverManager.ApplicationPools.Add("demoPool");
      pool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
      serverManager.Sites["MyDemoSite"].Applications["/"].ApplicationPoolName = "demoPool";

      serverManager.CommitChanges();
這一段程式,必須由具有權限的人來執行。否則會發生例外。

2008年7月21日 星期一

Cannot implicitly convert type IEnumerable to System.Data.Linq.EntitySet. An explicit conversion exists (are you missing a cast?)

Cannot implicitly convert type IEnumerable<A> to System.Data.Linq.EntitySet. An explicit conversion exists (are you missing a cast?)

這是我開發時發生的問題。
大概是這樣的。

var q = from storeEl in buyerEl.Elements("store")
                      select new Store
              {
                StoreId = storeEl.Element("id").Value,
                TaxNo = buyerEl.Value,
                StoreName = storeEl.Element("cname").Value,
                Emails = from sub in storeEl.Elements("mails")
                                   select new StoreEmail
                                   {
                                     StoreId = storeEl.Attribute("id").Value,
                                     Email = sub.Attribute("email").Value
                                   },
              };
問題出現在 from sub in 那一段。Emails 是一個 EntitySet<Email>,而非 IEnumerable<Email>,於是發生了錯誤。
goole 了一下,找到了一個看來不是很好的方法。
  public static class LinqExtension
  {
    public static EntitySet ToEntitySet(this IEnumerable source) where T : class
    {
      var es = new EntitySet();
      es.AddRange(source);
      return es;
    }
  }

然後,將程式改為

var q = from storeEl in buyerEl.Elements("store")
                      select new Store
        {
                StoreId = storeEl.Element("id").Value,
                TaxNo = buyerEl.Value,
                StoreName = storeEl.Element("cname").Value,
                Emails = (from sub in storeEl.Elements("mails")
                                   select new StoreEmail
                                   {
                                     StoreId = storeEl.Attribute("id").Value,
                                     Email = sub.Attribute("email").Value
                                   }).ToEntitySet(),
        };

Lutz Roeder's .NET Reflector

當要研究 Compiler 的特性時,有時需要一些工具來看產生的 assembly 結果。
例如,C# 3.0 的 auto implement property

namespace ClassLibrary1
{
  class Employee
  {
    public int Id { get; private set; }
    public string Name { get; set; }
  }
}
會產生什麼樣的結果呢?
當然可以使用 .net  內建的 ildasm。但是只能看到 IL 的語法,十分不容易懂。

Lutz Roeder's .NET Reflector 這個工具可以讓我們的生活更輕鬆一些。

image

Share with Facebook