最近公司的一台伺服器,連續兩天建立 Hyper-V 的 Virtul Machine時,就會發生 Blue Screen Of Dead 的經典畫面。畫面中,出現了
IRQL_NOT_LESS_OR_EQUAL, 及
STOP: 0x0000000A (parameter1、 parameter2、 parameter3、 parameter4)
最後是找到了這個 KB979444,套上了 hotfix 才解決了問題。
最近公司的一台伺服器,連續兩天建立 Hyper-V 的 Virtul Machine時,就會發生 Blue Screen Of Dead 的經典畫面。畫面中,出現了
IRQL_NOT_LESS_OR_EQUAL, 及
STOP: 0x0000000A (parameter1、 parameter2、 parameter3、 parameter4)
最後是找到了這個 KB979444,套上了 hotfix 才解決了問題。
今天將寫了幾天的 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。
在部署ASP.NET 專案中,加以下的參考,並且在Property 中標Copy Local 為 True。
第二種做法,是直接將 Ria Services 註冊到伺服器上。指令如下
msiexec /i RiaServices.msi SERVER=TRUE
可惜,這樣不會將 System.ServiceModel.dll , System.ComponentModel.DataAnnotations.dll 標示為 Copy Local = true。還是要手動將這兩個dll設定一下。
這次,由於網站的 SSL 憑證到期了,更新了SSL 憑證。更換後,有一家公司抱怨瀏覽網站時,會出現「未信任的憑證」問題。
只有這一位客戶哦!請客戶幫我們看一下憑證的問題,會出現「信任憑證授權單位無法確認這個憑證」的錯誤訊息。如下圖
檢視憑證路徑時,也少了一層根憑證。
因此,我判斷 Baltimore CyberTrust Root 這個憑證並未在「 信任的根憑證」中。
為什麼別的客戶ok,單獨這位客戶有這樣的議題呢?我找到一某一台相同問題的電腦,特別先看了在「 信任的根憑證」中,也相同地沒有這張憑證。
接著,我瀏覽了該網頁,並以 Fiddler 錄下的 Request ,如下圖。
答案揭曉。原來當我們瀏覽一個https網頁時,windows 會幫我們檢查SSL 憑證。而SSL 憑證的 CA 尚未匯入時,且是公開常見的CA時,windows update 會自動匯入 CA 任證。
該客戶由於控管嚴格,連 windows update 的 IP 都使用防火牆封鎖了,造成憑證路徑不正確的問題。
雖然只能檢視 https 網站這樣常見的動作,其後隱含了多少工作原理啊。這一次又學到新東西。
舊聞了,但今天才知道的訊息。根據Port80 Surveys the Top 1000 Corporations' Application Servers and Scripting Platforms (July 2007),ASP.NET 在2007 年時被採用的比例為 51.5%,遠超過第二名的Java platform 12.7%
而在這篇中Port80's 2010 - Top 1000 Corporation Web Servers,54.5%的伺服器是使用 IIS,但其中絕大部份仍使用 IIS 6.0。
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>
詳細使用方式見 讓服務可跨網域界限使用
與WPF TreeView 的 DataBinding (2) 相同的問題,仍然發生在 Silverlight 上。那 Silverlight 可以使用與 WPF 相同的解法嗎?不行,原因出在Silverlight 並設計出 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>
程式運行結果
程式碼下載
一個有趣的問題。以下的程式可以編譯嗎?
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 (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。程式運作結如果附圖
上面運作的結果是正確的,但風格還是無法讓使用者接受。原因在於無法分辨何者為目錄,何者為檔案。
但怎麼改呢?HierarchicalDataTemplate 只有一個,如何才能分開顯示目錄及檔案呢?
答案是實作一個 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>程式運行結果如下
WPF 已經幫我們想到非常多的問題與解決方式。在解決問題的時候,千萬不要一味的自己發明輪子,最後又難以維護。
程式碼下載
一樣的問題,在 Silverlight 的版本如何在 WPF 上實作呢?其實作法是一致的。
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(); } } }執行結果如下圖:
在 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(); } } }
當然,程式運作的結果是一致的。
程式碼下載
這一天研究了 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; } } }
在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(); } } }
運行程式後,結果如下圖
運作的結果只出現了最上層的兩個目錄,而且並沒有顯示我想要的目錄名稱。
要顯示目錄名稱,其實很簡單,就是要在 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)。結果如下圖。
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>
結果如下圖
程式碼下載
微軟出了很多的 Best Practices Analyzer(BPA),幫助我們檢視電腦、資料庫、伺服器的設定。目前介紹的就是 TFS 的 BPA
掃描完畢後,看一下報告。Oh! 好像有不少的問題。
再按一下 「Tell me more about this issue and how to resolve it」連結,就會顯示相關的訊息。