2010年12月29日 星期三

Windows Server 2008 常常 BSOD (藍色死機)

最近公司的一台伺服器,連續兩天建立 Hyper-V 的 Virtul Machine時,就會發生 Blue Screen Of Dead 的經典畫面。畫面中,出現了

IRQL_NOT_LESS_OR_EQUAL, 及

STOP: 0x0000000A (parameter1parameter2parameter3parameter4)


最後是找到了這個 KB979444,套上了 hotfix 才解決了問題。

2010年12月20日 星期一

WCF RIA Service 部署的問題

原故

今天將寫了幾天的 Silverlight 部署到測試機時,一直發生錯誤。404 resource not found.

使用 Fiddler 來查詢,是在呼叫 RIA Service 時發生錯誤。  http://servername/virtul directory/ClientBin/My-Ria-Service.svc.svc/binary/MyMethod 404。

明明在我的機器可以執行啊!

原故

爬了一下文,知道了原因。RIA Service 實在做的太好了,以致於在開發階段,幾乎不必手動增加必要的參考。而在 http://www.silverlight.net/getstarted/riaservices/ 下載的安裝檔,又直接幫我們註冊到 GAC 中,以致於一些部署需要的 dll 就被遺忘了, 這些設定通常在 Web.config 中會出現。

部署時,主要有兩種做法。一是 bin 另一種是 GAC。

bin: 即 XCopy 做法

在部署ASP.NET 專案中,加以下的參考,並且在Property 中標Copy Local 為 True。

  • System.ServiceModel.dll
  • System.ServiceModel.DomainServices.Hosting.dll
  • System.ServiceModel.DomainServices.Server.dll
  • System.ComponentModel.DataAnnotations.dll

image

GAC

第二種做法,是直接將 Ria Services 註冊到伺服器上。指令如下
msiexec /i RiaServices.msi SERVER=TRUE

可惜,這樣不會將 System.ServiceModel.dll , System.ComponentModel.DataAnnotations.dll 標示為 Copy Local = true。還是要手動將這兩個dll設定一下。

換SSL 憑證後,客戶得到未信任的憑證

原由

這次,由於網站的 SSL 憑證到期了,更新了SSL 憑證。更換後,有一家公司抱怨瀏覽網站時,會出現「未信任的憑證」問題。

原因

只有這一位客戶哦!請客戶幫我們看一下憑證的問題,會出現「信任憑證授權單位無法確認這個憑證」的錯誤訊息。如下圖

image

檢視憑證路徑時,也少了一層根憑證。

客戶的電腦
image

正常的狀況
SNAGHTMLc8c1dc

因此,我判斷 Baltimore CyberTrust Root 這個憑證並未在「 信任的根憑證」中。

Debug 步驟

為什麼別的客戶ok,單獨這位客戶有這樣的議題呢?我找到一某一台相同問題的電腦,特別先看了在「 信任的根憑證」中,也相同地沒有這張憑證。

接著,我瀏覽了該網頁,並以 Fiddler 錄下的 Request ,如下圖。

image

答案揭曉。原來當我們瀏覽一個https網頁時,windows 會幫我們檢查SSL 憑證。而SSL 憑證的 CA 尚未匯入時,且是公開常見的CA時,windows update 會自動匯入 CA 任證。

該客戶由於控管嚴格,連 windows update 的 IP 都使用防火牆封鎖了,造成憑證路徑不正確的問題。

結論

雖然只能檢視 https 網站這樣常見的動作,其後隱含了多少工作原理啊。這一次又學到新東西。

2010年12月14日 星期二

全球千大企業的應用伺服器使用的網頁技術

舊聞了,但今天才知道的訊息。根據Port80 Surveys the Top 1000 Corporations' Application Servers and Scripting Platforms (July 2007),ASP.NET 在2007 年時被採用的比例為 51.5%,遠超過第二名的Java platform 12.7%

image

而在這篇中Port80's 2010 - Top 1000 Corporation Web Servers,54.5%的伺服器是使用 IIS,但其中絕大部份仍使用 IIS 6.0。

image

2010年12月10日 星期五

Corss domain access

Silverlight 預設只能存取同一個網站的服務。例如  http://server/ 下的 silverlight 就不能存取 http://server.domain.com/service.svc ,即使其實這兩者是同一台伺服器。此時,必須在Web伺服器的根目錄下放 clientaccesspolicy.xml,內容如下

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>      
      <allow-from http-request-headers="*">
        <domain uri="*"/>"
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

詳細使用方式見 讓服務可跨網域界限使用

2010年12月9日 星期四

Silverlight TreeView 的 DataBinding (2)

簡介

WPF TreeView 的 DataBinding (2) 相同的問題,仍然發生在 Silverlight 上。那 Silverlight 可以使用與 WPF 相同的解法嗎?不行,原因出在Silverlight 並設計出 DataTemplateSelector 這樣的概念。

但是,相同的問題該怎麼解決呢?

自己做一個 DataTemplateSelector

沒有?就自己打造一個。

using System.Windows;
using System.Windows.Controls;

namespace SilverlightTreeView1
{
    public abstract class DataTemplateSelector : ContentControl
    {
        public virtual DataTemplate SelectTemplate(
                object item, DependencyObject container)
        {
            return null;
        }

        protected override void OnContentChanged(
                object oldContent, object newContent)
        {
            base.OnContentChanged(oldContent, newContent);

            ContentTemplate = SelectTemplate(newContent, this);
        }
    }
    
    public class MyDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate FileTemplate { get; set; }
        public HierarchicalDataTemplate FolderTemplate { get; set; }
        public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
        {
            if (item is MyFolder)
                return FolderTemplate;
            else
                return FileTemplate;
        }
    }
}

xaml

<UserControl x:Class="SilverlightTreeView1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:SilverlightTreeView1="clr-namespace:SilverlightTreeView1">
    <UserControl.Resources>
        <SilverlightTreeView1:FolderHelper x:Key="helper" />
        <sdk:HierarchicalDataTemplate x:Key="folder" ItemsSource="{Binding Items}">
            <StackPanel Orientation="Horizontal">
                <Image Source="/SilverlightTreeView1;component/Images/folder.png" />
                <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </sdk:HierarchicalDataTemplate>
        <sdk:HierarchicalDataTemplate x:Key="file">
            <StackPanel Orientation="Horizontal">
                <Image Source="/SilverlightTreeView1;component/Images/doc.png" />
                <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </sdk:HierarchicalDataTemplate>
    </UserControl.Resources>
        <Grid x:Name="LayoutRoot" Background="White">
        <sdk:TreeView Name="treeView1" ItemsSource="{Binding Source={StaticResource helper}, Path=Items}">
            <sdk:TreeView.ItemTemplate>
                <sdk:HierarchicalDataTemplate ItemsSource="{Binding Items}">
                    <SilverlightTreeView1:MyDataTemplateSelector Content="{Binding}"
                        FolderTemplate="{StaticResource folder}" FileTemplate="{StaticResource file}" />
                </sdk:HierarchicalDataTemplate>
            </sdk:TreeView.ItemTemplate>
        </sdk:TreeView>
    </Grid>
</UserControl>

程式運行結果

image

程式碼下載

Generics Variance

一個有趣的問題。以下的程式可以編譯嗎?

using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            List<A> listA = new List<A>();
            List<B> listB = new List<B>();
            listA.AddRange(listB.AsEnumerable());
        }
    }

    internal class A{} 
    class B : A{}
}
答案很好玩,.NET Framwork 4可以,.NET 2.0 不可以。
.NET Framwork 2 的錯誤訊息是

cannot convert from 'System.Collections.Generic.IEnumerable<B>' to 'System.Collections.Generic.IEnumerable<A>'   

這是為什麼呢?B 是 A 的子代,把 B 當成A 加到 listA 這個集合中,看起來沒有什麼不對。

原因是 .NET Framwork 2 的泛型(Generics)尚不支援這樣的場景。這樣的狀況稱 Generics Variance。以前的處理方式請參考Variance in Generic Types

當然,這樣的問題已經在 .NET Framework 4 中得到了解決。

 

WPF TreeView 的 DataBinding (2)

上一回的 WPF TreeView 的 DataBinding (1),TreeView繫結的是單一型別物件的樹狀結構。這一次要挑戰的是同時繫結到兩種型別。

資料

和上次不同的,這一次目錄 (MyFolder)這個容器(container)中,可同時持有MyFolder 與 MyFile。為此,我們修改程式如下

public static List<MyFolder> GetAllFolder()
{
    var folders = new List<MyFolder>()
                      {
                          new MyFolder("A")
                              {
                                                Files = new List<MyFile>() { new MyFile("d_1")},
                                                SubFolders = new List<MyFolder>(){
                                  new MyFolder("A1")
                                      {
                                                        Files = new List<MyFile>() { new MyFile("d1_1"), new MyFile("d1_2")},
                                                        SubFolders = new List<MyFolder>()
                                                                         {
                                                                             new MyFolder("A11"),
                                                                                        new MyFolder("A12"),
                                                                                        new MyFolder("A13"),
                                                                                        new MyFolder("A14"),
                                                                         }
                                      },
                                                new MyFolder("A2"),
                                                new MyFolder("A3")
                                                }
                              },
                                            new MyFolder("B")
                                                {
                                                    Files = new List<MyFile>() { new MyFile("db_1"), new MyFile("db_2")},
                                                    SubFolders = new List<MyFolder>(){
                                  new MyFolder("B1"),
                                                new MyFolder("B2"),
                                                new MyFolder("B3"),
                                                new MyFolder("B4"),
                                                }
                                            }
                      };
    return folders;
}

繫結

.NET Framework 的元件(control)在進行繫結時,只能繫結到單一物件或同一類別的集合。因此,TreeView 要同時顯示 MyFolder 或 MyFile 時,ItemsSource 給什麼值呢?是 SubFolders 嗎?還是 Files 嗎?都只能顯示一部份。為了讓 ItemsSource 在繫結時可以繫結到所有的children,我們必須製作一個新的屬性 Items,可讀取到所有的children,包含MyFolder 及 MyFiles。故程式碼修改如下

public abstract class MyItem
{
    public string Name { get; set; }
}
public class MyFolder : MyItem
{
    public MyFolder(string name)
    {
        Name = name;
    }

    public List<MyFolder> SubFolders { get; set; }
    public List<MyFile> Files { get; set; }

    public List<MyItem> Items
    {
        get
        {
            var items = new List<MyItem>();
            items.AddRange(SubFolders.AsEnumerable());
            items.AddRange(Files.AsEnumerable());
            return items;
        }
    }
}

xaml 修改如下

<Window x:Class="WpfTreeView1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfTreeView1="clr-namespace:WpfTreeView1" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <WpfTreeView1:FolderHelper x:Key="helper" />
    </Window.Resources>
    <Grid>
        <TreeView Name="treeView1" ItemsSource="{Binding Source={StaticResource ResourceKey=helper}, Path=Items}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                    <TextBlock TextWrapping="Wrap" Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

注意到我們ItemsSource改繫結到 Items。程式運作結如果附圖image

圖示

上面運作的結果是正確的,但風格還是無法讓使用者接受。原因在於無法分辨何者為目錄,何者為檔案。

但怎麼改呢?HierarchicalDataTemplate 只有一個,如何才能分開顯示目錄及檔案呢?

image

答案是實作一個 DataTemplateSelector。

DataTemplateSelector 的想法是這樣:資料繫結的過程中,當遇到某類型的物件時,套用指定的樣版。而這樣的邏輯是完全客製化的,因此必須自己實作。在 WPF 中,就是繼承DataTemplateSelector, 實作自己的 SelectTemplate。程式如下

using System.Windows;
using System.Windows.Controls;

namespace WpfTreeView1
{
    public class MyDataTemplateSelector : DataTemplateSelector
    {
        public HierarchicalDataTemplate FileTemplate { get; set; }
        public HierarchicalDataTemplate FolderTemplate { get; set; }
        public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
        {
            if (item is MyFolder)
                return FolderTemplate;
            else
                return FileTemplate;
        }
    }
}

xaml

<Window x:Class="WpfTreeView1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfTreeView1="clr-namespace:WpfTreeView1" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <WpfTreeView1:FolderHelper x:Key="helper" />
        <HierarchicalDataTemplate x:Key="folder" ItemsSource="{Binding Items}">
            <StackPanel Orientation="Horizontal">
                <Image Source="/WpfTreeView1;component/Images/folder.png" />
                <TextBlock TextWrapping="Wrap" Text="{Binding Name}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="file">
            <StackPanel Orientation="Horizontal">
                <Image Source="/WpfTreeView1;component/Images/doc.png" />
                <TextBlock TextWrapping="Wrap" Text="{Binding Name}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
        <WpfTreeView1:MyDataTemplateSelector x:Key="selector" FolderTemplate="{StaticResource ResourceKey=folder}" FileTemplate="{StaticResource ResourceKey=file}" />
    </Window.Resources>
    <Grid>
        <TreeView Name="treeView1" ItemsSource="{Binding Source={StaticResource ResourceKey=helper}, Path=Items}"
                            ItemTemplateSelector="{StaticResource ResourceKey=selector}">
        </TreeView>
    </Grid>
</Window>
程式運行結果如下

image

結論

WPF 已經幫我們想到非常多的問題與解決方式。在解決問題的時候,千萬不要一味的自己發明輪子,最後又難以維護。

程式碼下載

WPF TreeView 的 DataBinding (1)

一樣的問題,在 Silverlight 的版本如何在 WPF 上實作呢?其實作法是一致的。

實作1

xaml

<Window x:Class="WpfTreeView1.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">
    <Grid>
        <TreeView Name="treeView1">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding SubFolders}">
                    <TextBlock TextWrapping="Wrap" Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>
cs
using System.Windows;

namespace WpfTreeView1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            treeView1.ItemsSource = FolderHelper.GetAllFolder();
        }
    }
}
執行結果如下圖: image

實作2: 改用 Resource 讀取 Folder

在 cs 中,只有一行的程式 treeView1.ItemsSource = FolderHelper.GetAllFolder(); 實在不美觀。這裡使用在介紹的static binding小技巧,將這一行消除掉。

xaml

<Window x:Class="WpfTreeView1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfTreeView1="clr-namespace:WpfTreeView1" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <WpfTreeView1:FolderHelper x:Key="helper" />
    </Window.Resources>
    <Grid>
        <TreeView Name="treeView1" ItemsSource="{Binding Source={StaticResource ResourceKey=helper}, Path=AllFolders}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding SubFolders}">
                    <TextBlock TextWrapping="Wrap" Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

cs

using System.Windows;

namespace WpfTreeView1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

當然,程式運作的結果是一致的。

程式碼下載

2010年12月8日 星期三

Silverlight TreeView 的 DataBinding (1)

這一天研究了 Silverlight TreeView 的 DataBinding. 這裡作一下簡單的記錄,以便自己回憶。

首先,使用 Silverlight Application 建立一個  SilverlightApplication1 吧。

資料

由於 TreeView 是樹狀結構的顯示元件,要顯示 TreeView 的 DataBinding,當然需要一個樹狀結構的資料。以下是目錄的結構程式。

using System.Collections.Generic;

namespace SilverlightTreeView1
{
    public class MyFolder
    {
        public MyFolder(string name)
        {
            Name = name;
        }
        public string Name { get; set; }

        public List<MyFolder> SubFolders { get; set; }
    }
    public class FolderHelper
    {
        public static List<MyFolder> GetAllFolder()
        {
            var folders = new List<MyFolder>()
                              {
                                  new MyFolder("A")
                                      {
                                                        SubFolders = new List<MyFolder>(){
                                          new MyFolder("A1")
                                              {
                                                                SubFolders = new List<MyFolder>()
                                                                                 {
                                                                                     new MyFolder("A11"),
                                                                                                new MyFolder("A12"),
                                                                                                new MyFolder("A13"),
                                                                                                new MyFolder("A14"),
                                                                                 }
                                              },
                                                        new MyFolder("A2"),
                                                        new MyFolder("A3")
                                                        }
                                      },
                                                    new MyFolder("B")
                                                        {
                                                            SubFolders = new List<MyFolder>(){
                                          new MyFolder("B1"),
                                                        new MyFolder("B2"),
                                                        new MyFolder("B3"),
                                                        new MyFolder("B4"),
                                                        }
                                                    }
                              };
            return folders;
        }
    }


}

使用 TreeView 元件

在MainPage.xaml 上拖入一個 TreeView 元件。

Xaml

<UserControl x:Class="SilverlightTreeView1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:SilverlightTreeView1="clr-namespace:SilverlightTreeView1">
        <Grid x:Name="LayoutRoot" Background="White">
        <sdk:TreeView Name="treeView1">
        </sdk:TreeView>
    </Grid>
</UserControl>

在 MainPage.xaml 中,建構子程式碼中設定 treeView1.ItemsSource

using System.Windows.Controls;

namespace SilverlightTreeView1
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            treeView1.ItemsSource = FolderHelper.GetAllFolder();
        }
    }
}

運行程式後,結果如下圖

image

運作的結果只出現了最上層的兩個目錄,而且並沒有顯示我想要的目錄名稱。

修改1: 顯示目錄名稱

要顯示目錄名稱,其實很簡單,就是要在 xaml 中作一些變化。

<sdk:TreeView Name="treeView1">
    <sdk:TreeView.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </sdk:TreeView.ItemTemplate>
</sdk:TreeView>
TreeView.ItemTemplate的內容是內容的樣版,並且使用DataTemplate 作為資料繫結樣版。這裡使用了一個 TextBlock,並且繫結到 MyFolder 物件的 Name 屬性(Property)。
結果如下圖。
image

修改2:改成樹狀顯示

DataTemplate 只能顯示繫結物件的資料,並無法顯示樹狀結構。為了顯示樹狀結構,我們必須將資料顯示的樣版,改用HierarchicalDataTemplate

<sdk:TreeView Name="treeView1">
    <sdk:TreeView.ItemTemplate>
        <sdk:HierarchicalDataTemplate ItemsSource="{Binding SubFolders}">
            <TextBlock Text="{Binding Name}" />
            </sdk:HierarchicalDataTemplate>
    </sdk:TreeView.ItemTemplate>
</sdk:TreeView>

結果如下圖

image

程式碼下載

2010年12月2日 星期四

使用 TFS Power Tool 的 Best Practices Analyzer

微軟出了很多的 Best Practices Analyzer(BPA),幫助我們檢視電腦、資料庫、伺服器的設定。目前介紹的就是 TFS 的 BPA

SNAGHTML1590726

掃描完畢後,看一下報告。Oh! 好像有不少的問題。

SNAGHTML184e2de

再按一下 「Tell me more about this issue and how to resolve it」連結,就會顯示相關的訊息。

Team Foundation Server Power Tools September 2010

直到最近才知道 TFS Power Tool 又在10月皆出新的版本

移除舊版本

如果之前已安裝過舊的版本,記得先移除舊版本。下圖是舊的版本。

image

安裝

安裝仍和之前版本相同。記得安裝前先將 Visual Studio 2010 關閉。安裝時使用 Typical 的選項即可。

也不知道為什麼,這個工具安裝時總是會花去5分鐘以上。明明該安裝檔 tfpt.msi 才 12.8 MB 啊!

使用

與之前的功能相同的就不說了。新功能可見這裡的說明。之後有機會再介紹吧!

Share with Facebook