創建Silverlight 5瀏覽器內受信應用


    在Silverlight 4中受信應用已經被支持,受信應用簡單的說就是可以訪問一些本地受限資源的Silverlight應用。在Silverlight 4中受信應用必須是OOB類型,即必須先安裝在本地,同時受信應用能訪問的資源也有限,例如只能訪問我的文檔、我的圖片等位置的文件。而在Silverlight 5中受信應用的功能做了很大的改進和增強:

  • 受信應用可以運行於瀏覽器之內
  • 可以無限制的訪問本地文件系統
  • 訪問強安全性方法時,不會再引發MethodAccessException異常
  • 當運行於桌面模式時,可以創建多個窗口
  • 在Windows平台可以直接調用非托管函數

    可以看到,在Silverlight 5中受信應用的權限幾乎獲得了與桌面應用相當的權限,在這里,我將為大家介紹如何創建瀏覽器內的受信應用。以下示例將通過Silverlight來監視本地的網絡流量。

  1. 受信應用的創建與常規Silverlight應用沒有差異,直接通過新建項目來創建:
    1
  2. 要使應用受信任,必須修改項目的屬性,必須勾選“允許在瀏覽器外允許程序”,以及“在瀏覽器內運行時需要提升的權限”:
    2
  3. 單擊瀏覽器外設置按鈕,進入以下設置界面,勾選“在瀏覽器之外運行時需要提升的信任”,由於我們的應用只允許在瀏覽器內運行,所以可將“顯示安裝菜單”的復選框去掉。這里說明一下,由於受信應用在Silverlight之前版本是和瀏覽器外運行綁定的,所以這里我們可以看到,雖然現在不使用瀏覽器外運行方式,但也需要對OOB進行設置,以此來獲取受信模式。
    3
  4. 實現功能。我們將調用非托管的Win32 API來實現本地網絡流量的監視,在Silverlight 5中,調用本地非托管函數的方式與.NET下完全一致。具體請參照本文源碼,代碼片段:
     
        public static class WIN32API
        {
            [DllImport("kernel32.dll")]
            public static extern bool GetComputerName(StringBuilder computerName, out Int32 nameLength);
    
            [DllImport("Iphlpapi.dll")]
            private static extern Int32 GetIfTable(Byte[] pIfTable, out long pdwSize, bool bOrder);
    
            [DllImport("kernel32.dll")]
            private static extern  int MultiByteToWideChar(uint CodePage,Int32 dwFlags,byte[] lpMultiByteStr,Int32 cbMultiByte,byte[] lpWideCharStr, int cchWideChar);
    
            public static MIB_IFTABLE GetIfTable()
            {
                MIB_IFTABLE table = new MIB_IFTABLE();
                long size = 0;
                GetIfTable(null, out size, false);
                if (size != 0)
                {
                    Byte[] data = new Byte[size];
                    long ret = GetIfTable(data, out size, false);
                    if (ret == 0)
                    {
                        MemoryStream ms = new MemoryStream(data);
                        ms.Position = 0;
                        BinaryReader br = new BinaryReader(ms, Encoding.Unicode);
    
                        table.dwNumEntries = br.ReadInt32();
                        table.table = new MIB_IFROW[table.dwNumEntries];
                        for (int i = 0; i < table.dwNumEntries; i++)
                        {
                            table.table[i] = new MIB_IFROW();
                            MIB_IFROW curRow = table.table[i];
                            FieldInfo[] fis = typeof(MIB_IFROW).GetFields();
                            foreach (FieldInfo fi in fis)
                            {
                                if (!fi.IsStatic)
                                {
                                    MarshalAsAttribute[] attrs = fi.GetCustomAttributes(typeof(MarshalAsAttribute), true) as MarshalAsAttribute[];
                                    if (attrs != null && attrs.Length > 0 && attrs[0].SizeConst != 0)
                                    {
    
                                        if (fi.FieldType == typeof(String))
                                        {
                                            Byte[] tmpChars = br.ReadBytes(attrs[0].SizeConst*2);
                                            fi.SetValue(curRow, Encoding.Unicode.GetString(tmpChars, 0, tmpChars.Length).TrimEnd('\0'));
                                        }
                                        else if (fi.FieldType == typeof(Byte[]))
                                        {
                                            fi.SetValue(curRow, br.ReadBytes(attrs[0].SizeConst));
                                        }
                                    }
                                    else
                                    {
                                        if (fi.FieldType == typeof(Int32))
                                        {
                                            Int32 tmpValue = br.ReadInt32();
                                            fi.SetValue(curRow, tmpValue);
                                        }
                                    }
    
                                }
                            }
                        }
                    }
                }
    
                return table;
            }
    
            public static String AsciiToUTF8(Byte[] asciiBytes)
            {
                int mustBytes = MultiByteToWideChar(WIN32CONST.CP_ACP, WIN32CONST.MB_PRECOMPOSED, asciiBytes, -1, null, 0);
                if (mustBytes > 0)
                {
                    Byte[] tmpBytes = new Byte[mustBytes*2];
                    if (MultiByteToWideChar(WIN32CONST.CP_ACP, WIN32CONST.MB_PRECOMPOSED, asciiBytes, -1, tmpBytes, mustBytes) != 0)
                    {
                       return Encoding.Unicode.GetString(tmpBytes, 0, tmpBytes.Length);
                    }
                }
                return "";
            }
        }
    

     

      

     

  5. 測試,當在本地測試時,即訪問地址為localhost或127.0.0.1時,受信應用無需做任何設置即可運行,本示例運行結果如下:
    4
  6. 接下來我們將說明如何部署受信應用,首先,要使受信應用在遠程客戶機上被訪問,必須對xap進行簽名。
  7. 進入TrustedApp項目屬性,轉到簽名頁,勾選“為Xap文件簽名”,這里我們將創建一個新的測試證書,以此進行演示,實際項目中可以向證書頒發機構申請信任證書,當然這是需要$的。單擊創建新測試證書按鈕,在彈出對話框中輸入密碼,這里設置為test,確定后,Visual Studio將創建一個證書文件,默認保存在項目根目錄下。
    5
  8. 接下來單擊“從存儲區選擇”按鈕,在彈出窗口中選擇剛才創建的證書
    6
  9. 在簽名頁面,單擊“更多詳細信息”按鈕,將會顯示證書的詳細信息,選擇詳細信息標簽,然后單擊“復制到文件”按鈕,進入證書導出向導:
    7


    進入以下頁面后,選擇不要導出私鑰:
    8
    此步驟導出的證書供客戶端使用!
  10. 完成后重新生成解決方案
  11. 將受信應用部署到IIS,部署與傳統ASP.NET應用一樣,無需做其他設置。
  12. 以上基本完成了服務端的設置,接下來對於客戶端需要做一些設置,才能在瀏覽器內運行受信應用
  13. 首先需要啟用瀏覽器內受信應用權限,這可直接通過修改注冊表來完成:
    注冊表路徑:HKEY_LOCAL_MACHINE\Software\Microsoft\Silverlight\
    值名稱:AllowElevatedTrustAppsInBrowser
    值類型:DWORD
    可用值:不可在瀏覽器內運行受信應用,設置為0,如果啟用設置為1
  14. 在客戶端安裝第9步驟導出的證書,在證書文件上單擊右鍵,選擇安裝,進入證書安裝向導,選擇存儲區時,將證書導入到“受信任的發布者”位置:
    9
  15. 重復第14步驟,選擇存儲區時,將證書導入到“受信任的根證書頒發機構”位置。
  16. 到此,我們即可在此客戶端上運行受信應用了(注意下圖中的地址已經是非本機地址):
    10
  17. 但是,必須注意此時的Silverlight是沒辦法自動更新的,也就是說服務端xap更新后,客戶端重新訪問時不會去自動下載xap,這顯然不符合需求,那該怎么做呢?我們需要在每次生成xap的時候,自動對xap進行時間戳簽名。
  18. 進入到TrustedApp項目屬性,選擇生成事件:
    11
    在后期生成事件命令行中輸入以下命令,進行xap的時間戳簽名:
    "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\signtool.exe" sign /v /f "$(ProjectDir)TrustedApp_1_TemporaryKey.pfx" /p test /t http://timestamp.comodoca.com/authenticode $(TargetName).xap
    前面為signtool的全路徑,它通常位於所安裝的Windows SDK目錄下, /f 后面跟隨證書的全路徑,以上示例表示當前項目下的TrustedApp_1_TemporaryKey.pfx證書文件,/p 后面表示證書的密碼,/t 后面跟隨一個CA Authenticode Timestamping Service的URL地址,命令最后部分為需要簽名的xap文件。
    進行此步操作后,每次生成xap文件后,Visual Studio將自動調用次命令進行xap的時間戳簽名。這樣,客戶端重新訪問網頁時,即可自動下載更新xap。

源代碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM