Inside Silverlight 4 OOB Mode

從Silverlight 3開始,Silverlight Team即提供了Out Of Browser,簡稱為OOB的模式,在這個模式中,Silverlight應用程式可以完全脫離瀏覽器來執行,
此舉揭開了Client端應用程式的另一新頁。
在Silverlight 4中,Silverlight Team更加入了許多新功能,除了顯而易見的列印、音訊及視訊的支援外,在OOB模式中更加入了Elevated Trust支援,
在這個模式下的OOB,不僅可以脫離瀏覽器執行,更可在有限程度下取用原生系統資源

 

Inside Silverlight 4 OOB Mode
 
文/黃忠成
 
 
 
Silverlight 4 OOB Mode
 
    從Silverlight 3開始,Silverlight Team即提供了Out Of Browser,簡稱為OOB的模式,在這個模式中,Silverlight應用程式可以完全脫離瀏覽器來執行,
此舉揭開了Client端應用程式的另一新頁。
    在Silverlight 4中,Silverlight Team更加入了許多新功能,除了顯而易見的列印、音訊及視訊的支援外,在OOB模式中更加入了Elevated Trust支援,
在這個模式下的OOB,不僅可以脫離瀏覽器執行,更可在有限程度下取用原生系統資源,這使得Silverlight OOB應用程式的應用範圍瞬時擴展。
    在OOB加上Elevated Trust模式下,Silverlight應用程式可以直接連接網路,不受Cross-Domain的限制,也可以直接存取客戶端的個人資料夾,例如
My Documents、My Pictures等等,甚至還能使用COM。
    由於Silverlight只需要一個小型的CLR,所以相當適合用於Thin-Client的架構下,在持續進化的情況下,無形中Silverlight已經悄悄的從網頁應用程式
橫跨到Native Client了,這符合了Microsoft所提出的RIA(Rich Interactive Application),而不僅僅是RIA(Rich Internet Application)。
 
 
Enable OOB Mode
 
 開啟OOB Mode的方法很簡單,只要於Silverlight Project上按右鍵打開應用程式屬性窗,即可見到圖1的設定。
圖1
將【Enable running application out of the browser】打勾,即代表此應用程式可以被使用者安裝於電腦中,當使用者瀏覽此網站時,便可按右鍵來安裝此應用程式。
圖2
3
點選確定後,此應用程式會脫離瀏覽器執行,也會出現一個捷徑於開始功能表中。
4
5
日後使用者只需點選此捷徑,即可開啟此應用程式。
 
 
Install OOB Application via Programming
 
 當然,應用程式自己也能提供一個安裝機制供使用者點選,請於Silverlight Page中放入一個Button,然後鍵入以下程式碼。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
 
namespace SilverlightApplication10
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            App.Current.Install();
        }
    }
}
接著啟用OOB模式,這樣一來,當使用者點選此按紐時,便會開啟Install至客戶端的對話盒。
圖6
 
 
 
 
 
 
Silent install OOB Application
 
    除了以上兩種安裝OOB應用程式的方式外,你也可以選擇【Silent Install】,也就是以命令列模式安裝,這種安裝方式不會顯示
任何視窗於使用者電腦上。
C:\temp1>"c:\Program Files (x86)\Microsoft Silverlight\sllauncher.exe" /install:
SilverlightApplication10.xap /origin:http://localhost:29162/ClientBin/Silverligh
tApplication10.xap /shortcut:startmenu /overwrite
將此命令放至批次檔(.bat)中,然後與.xap一併封裝給使用者,那麼使用者就能執行.bat來安裝你的OOB應用程式了。
更多的silent install參數請參考:
 
 
 
 
 
Entering into elevated trust mode
 
    在Silverlight 4之前,Silverlight應用程式一直都執行在sandbox(沙箱)中,無法存取本地端的資源,在網路存取部份也受到
Cross-Domain Policy的限制,即使是在OOB模式下也不例外,這使得Silverlight的應用受到了很大的限制。
    Silverlight 4中添加了elevated trust模式,在這個模式下,OOB應用程式可以在有限程度下存取本地資源,例如存取
My Documents、My Pictures等目錄下的檔案,或是不受限於Cross-Domain Policy來存取網路。
    啟用elevated trust mode的步驟很簡單,只要Silverlight Project的Application設定頁中開啟Out-Of-Browser Settings,
即可勾選此模式。
圖7
當使用者安裝此OOB應用程式時,會被提醒此應用程式將以elevated trust模式安裝。
8
 
 
 
Accessing Local Files
 
    在OOB+elevated trust模式下,Silverlight應用程式將可存取部份的本地端資源,如下列程式碼所示:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{     
         using(FileStream fs =
                 new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) +
                    "\\調皮貓.jpg",FileMode.Open,FileAccess.Read))
                {
                    BitmapImage bmp = new BitmapImage();
                    bmp.SetSource(fs);
                    image1.Source = bmp;
                }
}
如果不在OOB+elevated trust模式下,此程式將拋出圖9的錯誤。
圖9
你可以透過App.Current.IsRunningOutOfBrowser屬性來判斷目前程式是否處於OOB模式下:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
            if (App.Current.IsRunningOutOfBrowser)
            {
                using(FileStream fs =
                 new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) +
                "\\調皮貓.jpg",FileMode.Open,FileAccess.Read))
                {
                    BitmapImage bmp = new BitmapImage();
                    bmp.SetSource(fs);
                    image1.Source = bmp;
                }
            }
}
 
 
 
Network Accessing
 
   同樣的,在elevated trust + OOB模式下,你也可以不受Cross-Domain Policy限制來存取網路,如下列程式碼所示:
private void button1_Click(object sender, RoutedEventArgs e)
{
            WebRequest wr = WebRequest.Create("http://www.hinet.net");
            wr.BeginGetResponse((IAsyncResult state)=>           
            {
                WebResponse rep = wr.EndGetResponse(state);
                Dispatcher.BeginInvoke(() =>
                    {
                        MessageBox.Show(rep.ContentLength.ToString());
                    });
            }
            ,wr);
}
 
 
Debugging OOB Application
 
 當開發OOB + elevated trust應用程式時,由於程式可以存取許多本地端資源,因此原本的網頁式除錯就不再適用了(因為當存取本地資源時,
網頁模式會拋出例外),Visual Studio 2010添加了一個OOB專用的除錯模式,請將Silverlight Project設為Startup Project。
圖10
然後於Silverlight Project Application設定中,將Debug頁中的Start Action改為Out-Of-Browser application。
圖11
接著按下F5執行程式,此時便進入了OOB專屬的除錯模式。
 
 
Accessing Local Files without limit
 
     雖然OOB + elevated trust可以存取本地檔案,但是依然受限於My Documents、My Pictures等目錄,如果想要存取這
之外的目錄,都會以例外收場。
    不過解法也不是沒有,由於OOB + elevated trust可以直接存取COM,只要透過ADODB.Stream或是FileSystemObject等COM物件,
OOB + elevated trust應用程式也是可以越過這道牆的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Runtime.InteropServices.Automation;
 
............
 
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
        LoadFromTemp();
}
 
private void LoadFromTemp()
{
        dynamic binStream = AutomationFactory.CreateObject("ADODB.Stream");
        binStream.Type = 1;
        binStream.Open();
        binStream.LoadFromFile("C:\\temp1\\調ODOs.jpg");
        dynamic bytes = binStream.Read();
        MemoryStream ms = new MemoryStream(bytes);
        BitmapImage bmp = new BitmapImage();
        bmp.SetSource(ms);
        image1.Source = bmp;
}
當然,這只能在Windows 下執行就是了(別忘了,Silverlight是跨平台的)。
 
 
Executing Local Application
 
     那如果想於Silverlight OOB+elevated trust程式中執行外部程式呢?答案一樣是透過COM,有個Windows Script物件
可以達到需求。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Runtime.InteropServices.Automation;
 
namespace ExecuteExeInOOB
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            dynamic wshell = AutomationFactory.CreateObject("WScript.Shell");
            wshell.Run(@"C:\Windows\Notepad.exe", 1, false);
        }
    }
}
 
 
Executing OOB Application via .NET Application
 
      那Silverlight OOB應用程式是裝在那呢 ?如果我想用程式去喚起某個OOB應用程式,又該如何做呢? OOB應用程式其實只是個.xap檔,
透過sllauncher.exe執行,因此當你查看OOB應用程式的捷徑內容時,會發現其命令列是sllauncher.exe加上一串數字。
圖12
事實上,OOB應用程式是存放於" Local Settings\Application Data\Microsoft\Silverlight\OutOfBrowser"目錄下,裡面有個
index目錄中包含了這些數字與實際xap的對應,透過解析裡面的檔案,可以達到以外部應用程式喚起OOB應用程式的目的。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
 
namespace ExecuteOOBApp
{
    public partial class Form1 : Form
    {
        private List<XapInfo> _xapInfos = new List<XapInfo>();
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex != -1)
            {
                XapInfo xi = _xapInfos[listBox1.SelectedIndex];
                Process.Start(@"C:\Program Files (x86)\Microsoft Silverlight\sllauncher.exe", xi.XapID + "." + xi.Uri.Host);
            }
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            string localAppPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
           
            foreach (string file in Directory.GetFiles(localAppPath+"\\Microsoft\\Silverlight\\OutOfBrowser\\index\\", "*.*"))
            {
                using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
                {
                    if (fs.Length == 0) continue;
                    using (StreamReader sr = new StreamReader(fs, Encoding.Unicode))
                    {
                        while (!sr.EndOfStream)
                        {
                            string dm = sr.ReadLine();
                            string[] infos = dm.Split('\t');
                            Uri uri = new Uri(infos[1], UriKind.Absolute);
                            _xapInfos.Add(new XapInfo() { Uri = uri, XapID = infos[0], XapName = uri.AbsoluteUri });
                        }
                    }
                }
            }
 
            listBox1.DisplayMember = "XapName";
            listBox1.DataSource = _xapInfos;
        }
    }
 
    public class XapInfo
    {
        public Uri Uri { get; set; }
        public string XapID { get; set; }
        public string XapName { get; set; }
    }
}
13
你也可以透過sllanucher.exe來以url執行某個已安裝的OOB應用程式。
C:\temp1>"c:\Program Files (x86)\Microsoft Silverlight\sllauncher.exe" /emulate:
SilverlightApplication10.xap /origin:http://localhost:29162/ClientBin/Silverligh
tApplication10.xap /overwrite
 
 
Auto Update in OOB
 
    先天上,Silverlight OOB 應用程式擁有自動更新的機制,這也是你為何要在sllauncher.exe後加上origin參數的原因,
不過這個機制預設是關閉的,需要透過程式來啟用。
public partial class App : Application
    {
 
        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;
 
            InitializeComponent();
 
            if (Application.Current.IsRunningOutOfBrowser)
            {
                App.Current.CheckAndDownloadUpdateCompleted +=
                 new CheckAndDownloadUpdateCompletedEventHandler(
                    Current_CheckAndDownloadUpdateCompleted);
                App.Current.CheckAndDownloadUpdateAsync();
            }
 
        }
 
        void Current_CheckAndDownloadUpdateCompleted(object sender,
                  CheckAndDownloadUpdateCompletedEventArgs e)
        {
            if (e.Error == null && e.UpdateAvailable)
            {
                MessageBox.Show("Application updated, please restart to apply changes.");
            }
        }
.............
一旦啟用自動更新機制後,當使用者執行電腦上的OOB應用程式時,假如有連上網路及遠端的.xap有更新時,便會出現提示更新的訊息。
圖14
按下確定後,此OOB程式便會自動下載新的.xap,關閉後再啟動此應用程式,便是最新版本。
 
PS: 當 OOB + Elevated Trust時,自動更新的機制需要簽署XAP方能正常運作,如果沒有憑證,可於Silverlight Project Page中建立一個測試用憑證來測試.
 圖15