Silverlight Application是客户端程序,没有也无法访问服务端的web.config,它自己也不允许添加.config文件,加上Silverilght 3.0之后,原来ASP.NET 2.0中的Silveright控件也被去掉了,要读取web.config就又更困难了一些。
不过如果仔细分析一下的话,可以发现Silverlight App是由一个Web Application来host的,而那个Web Application是可以方便地配置的,于是,可以考虑由网站来把配置传给Silverlight,宿主Silverlight的Page文件中会有这样一段代码:
<param name="source" value="ClientBin/GetWebConfig.xap"/> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50826.0" /> <param name="autoUpgrade" value="true" />
可以看到这里有很多关于Silverlight的参数,我们可以从这段代码下手,在这里为其添加一个新的参数:
<param name="InitParams" value="127.0.0.1" />
可以看到其中有一个param标签的name为InitParams,其值可以在App.xaml.cs中的Application_Startup事件处理方法中,使用传入StartupEventArgs参数的InitParams属性取得,类型为IDictionary<string, string>。下面来看一下具体的方法:
1. 首先,我们需要在Page文件中加入一个Literal控件,以便能够动态地将<param name="InitParams" value="" />赋到Page中,但是在Visual Studio 2010里,默认为我们创建的ASPX页面没有.cs文件,需要我们创建一个新的ASPX页面,把原先<HTML></HTML>当中的内容Copy过来,并加上Literal控件,如下方代码所示:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="HostPage.aspx.cs" Inherits="GetWebConfig.Web.HostPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>GetWebConfig</title> <style type="text/css"> html, body { height: 100%; overflow: auto; } body { padding: 0; margin: 0; } #silverlightControlHost { height: 100%; text-align:center; } </style> <script type="text/javascript" src="Silverlight.js"></script> <script type="text/javascript"> function onSilverlightError(sender, args) { var appSource = ""; if (sender != null && sender != 0) { appSource = sender.getHost().Source; } var errorType = args.ErrorType; var iErrorCode = args.ErrorCode; if (errorType == "ImageError" || errorType == "MediaError") { return; } var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n"; errMsg += "Code: " + iErrorCode + " \n"; errMsg += "Category: " + errorType + " \n"; errMsg += "Message: " + args.ErrorMessage + " \n"; if (errorType == "ParserError") { errMsg += "File: " + args.xamlFile + " \n"; errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } else if (errorType == "RuntimeError") { if (args.lineNumber != 0) { errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } errMsg += "MethodName: " + args.methodName + " \n"; } throw new Error(errMsg); } </script> </head> <body> <form id="form1" runat="server"> <div id="silverlightControlHost"> <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="ClientBin/GetWebConfig.xap"/> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50826.0" /> <param name="autoUpgrade" value="true" /> <asp:Literal ID="litInitParams" runat="server" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration:none"> <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/> </a> </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div> </form> </body> </html>
2. 接下来,我们要在这个页面的后台.cs文件中读取web.config的内容,并且把它赋给Literal控件:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Collections.Specialized; using System.Web.Configuration; using System.Text; namespace SL_ReadConfigFile.Web { public partial class SL_ReadConfigFile : System.Web.UI.Page { private string _seperator = ","; protected void Page_Load( object sender , EventArgs e ) { Response.Cache.SetCacheability( HttpCacheability.NoCache ); WriteInitParams(); } private void WriteInitParams() { NameValueCollection appSettings = WebConfigurationManager.AppSettings; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append( "<param name=\"InitParams\" value=\"" ); string paramContent = string.Empty; for( int i = 0 ; i < appSettings.Count ; i++ ) { if( paramContent.Length > 0 ) { paramContent += _seperator; } paramContent += string.Format( "{0}={1}" , appSettings.GetKey( i ) , appSettings[ i ] ); } stringBuilder.Append(paramContent ); stringBuilder.Append( "\" />" ); this.litInitParams.Text = stringBuilder.ToString(); } } }
3. 在App.xaml.cs中的Application_Startup事件处理方法中,使用传入StartupEventArgs参数的InitParams属性取得,类型为IDictionary<string, string>:
using System; using System.Collections.Generic; using System.Windows; namespace SL_ReadConfigFile { public partial class App : Application { private IDictionary<string , string> _configurations; public IDictionary<string , string> Configurations { get { return _configurations; } } public App() { this.Startup += this.Application_Startup; this.Exit += this.Application_Exit; this.UnhandledException += this.Application_UnhandledException; InitializeComponent(); } private void Application_Startup( object sender , StartupEventArgs e ) { _configurations = e.InitParams; this.RootVisual = new MainPage(); } private void Application_Exit( object sender , EventArgs e ) { } private void Application_UnhandledException( object sender , ApplicationUnhandledExceptionEventArgs e ) { if( !System.Diagnostics.Debugger.IsAttached ) { e.Handled = true; Deployment.Current.Dispatcher.BeginInvoke( delegate { ReportErrorToDOM( e ); } ); } } private void ReportErrorToDOM( ApplicationUnhandledExceptionEventArgs e ) { try { string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; errorMsg = errorMsg.Replace( '"' , '\'' ).Replace( "\r\n" , @"\n" ); System.Windows.Browser.HtmlPage.Window.Eval( "throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");" ); } catch( Exception ) { } } } }
4. 最后就是在Silverlight页面当中获取InitParams的值并显示到页面上:
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SL_ReadConfigFile.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:DesignWidth="800" d:DesignHeight="600" Width="Auto" Height="Auto" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="50"></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition Height="30"></RowDefinition> </Grid.RowDefinitions> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24">Silverlight Reads web.config Demo</TextBlock> <sdk:DataGrid Grid.Row="1" Name="dgdConfigurations"> </sdk:DataGrid> <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Center"> <Button Name="btnShowEntry" Width="200" Margin="10,0" Click="btnShowEntry_Click"> <StackPanel Orientation="Horizontal"> <TextBlock VerticalAlignment="Center">Read number</TextBlock> <toolkit:NumericUpDown Name="numericUpDown" Margin="5,0" DecimalPlaces="0"/> <TextBlock VerticalAlignment="Center">entry</TextBlock></StackPanel> </Button> <Button Name="btnBindConfig" Width="200" Margin="10,0" Click="btnBindConfig_Click">Binding Configurations</Button> </StackPanel> </Grid> </UserControl>
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 SL_ReadConfigFile { public partial class MainPage : UserControl { private IDictionary<string , string> _configurations; public MainPage() { InitializeComponent(); _configurations = ( Application.Current as App ).Configurations; if( _configurations.Count > 0 ) { numericUpDown.Minimum = 1; numericUpDown.Maximum = _configurations.Count; } } private void btnBindConfig_Click( object sender , RoutedEventArgs e ) { this.dgdConfigurations.ItemsSource = _configurations; } private void btnShowEntry_Click( object sender , RoutedEventArgs e ) { string entryContent = string.Format( "{0} = {1}" , _configurations.ElementAt( ( int ) numericUpDown.Value - 1 ).Key , _configurations.ElementAt( ( int ) numericUpDown.Value - 1 ).Value ); MessageBox.Show( entryContent ); } } }
5. 我们已经可以读取到web.config里面的值了,但是,要注意的是,在ASPX页面当中InitParams会以明文显示在Source Code当中,如果是数据库连接串或是其他需要加密的信息,请自己开发加密算法来解决这一问题,下一篇我会介绍如何加密InitParams中的值。