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文件中会有 这样一段代码:


  1. <param name="source" value="ClientBin/GetWebConfig.xap"/>
  2. <param name="onError" value="onSilverlightError" />
  3. <param name="background" value="white" />
  4. <param name="minRuntimeVersion" value="4.0.50826.0" />
  5. <param name="autoUpgrade" value="true" />


可以看到这里有很多关于Silverlight的参数,我们可以从这段代码下手,在这里为其添加一个新的参数:


  1. <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控件,如下方代码所示:


  1. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="HostPage.aspx.cs" Inherits="GetWebConfig.Web.HostPage" %>

  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4. <head runat="server">
  5. <title>GetWebConfig</title>
  6. <style type="text/css">
  7. html, body {
  8. height: 100%;
  9. overflow: auto;
  10. }
  11. body {
  12. padding: 0;
  13. margin: 0;
  14. }
  15. #silverlightControlHost {
  16. height: 100%;
  17. text-align:center;
  18. }
  19. </style>
  20. <script type="text/javascript" src="Silverlight.js"></script>
  21. <script type="text/javascript">
  22. function onSilverlightError(sender, args) {
  23. var appSource = "";
  24. if (sender != null && sender != 0) {
  25. appSource = sender.getHost().Source;
  26. }

  27. var errorType = args.ErrorType;
  28. var iErrorCode = args.ErrorCode;

  29. if (errorType == "ImageError" || errorType == "MediaError") {
  30. return;
  31. }

  32. var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n";

  33. errMsg += "Code: " + iErrorCode + " \n";
  34. errMsg += "Category: " + errorType + " \n";
  35. errMsg += "Message: " + args.ErrorMessage + " \n";

  36. if (errorType == "ParserError") {
  37. errMsg += "File: " + args.xamlFile + " \n";
  38. errMsg += "Line: " + args.lineNumber + " \n";
  39. errMsg += "Position: " + args.charPosition + " \n";
  40. }
  41. else if (errorType == "RuntimeError") {
  42. if (args.lineNumber != 0) {
  43. errMsg += "Line: " + args.lineNumber + " \n";
  44. errMsg += "Position: " + args.charPosition + " \n";
  45. }
  46. errMsg += "MethodName: " + args.methodName + " \n";
  47. }

  48. throw new Error(errMsg);
  49. }
  50. </script>
  51. </head>
  52. <body>
  53. <form id="form1" runat="server">
  54. <div id="silverlightControlHost">
  55. <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
  56. <param name="source" value="ClientBin/GetWebConfig.xap"/>
  57. <param name="onError" value="onSilverlightError" />
  58. <param name="background" value="white" />
  59. <param name="minRuntimeVersion" value="4.0.50826.0" />
  60. <param name="autoUpgrade" value="true" />
  61. <asp:Literal ID="litInitParams" runat="server" />
  62. <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0" style="text-decoration:none">
  63. <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
  64. </a>
  65. </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
  66. </form>
  67. </body>
  68. </html>


2. 接下来,我们要在这个页面的后台.cs文件中读取web.config的内容,并且把它赋给Literal控件:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6. using System.Web.UI.WebControls;
  7. using System.Collections.Specialized;
  8. using System.Web.Configuration;
  9. using System.Text;

  10. namespace SL_ReadConfigFile.Web
  11. {
  12. public partial class SL_ReadConfigFile : System.Web.UI.Page
  13. {
  14. private string _seperator = ",";

  15. protected void Page_Load( object sender , EventArgs e )
  16. {
  17. Response.Cache.SetCacheability( HttpCacheability.NoCache );
  18. WriteInitParams();
  19. }

  20. private void WriteInitParams()
  21. {
  22. NameValueCollection appSettings = WebConfigurationManager.AppSettings;
  23. StringBuilder stringBuilder = new StringBuilder();
  24. stringBuilder.Append( "<param name=\"InitParams\" value=\"" );
  25. string paramContent = string.Empty;
  26. for( int i = 0 ; i < appSettings.Count ; i++ )
  27. {
  28. if( paramContent.Length > 0 )
  29. {
  30. paramContent += _seperator;
  31. }
  32. paramContent += string.Format( "{0}={1}" , appSettings.GetKey( i ) , appSettings[ i ] );
  33. }
  34. stringBuilder.Append(paramContent );
  35. stringBuilder.Append( "\" />" );
  36. this.litInitParams.Text = stringBuilder.ToString();
  37. }
  38. }
  39. }


3. 在App.xaml.cs中的Application_Startup事件处理方法中,使用传入StartupEventArgs参数的InitParams属性取得,类型为IDictionary<string, string>:


  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows;

  4. namespace SL_ReadConfigFile
  5. {
  6. public partial class App : Application
  7. {
  8. private IDictionary<string , string> _configurations;
  9. public IDictionary<string , string> Configurations
  10. {
  11. get
  12. {
  13. return _configurations;
  14. }
  15. }

  16. public App()
  17. {
  18. this.Startup += this.Application_Startup;
  19. this.Exit += this.Application_Exit;
  20. this.UnhandledException += this.Application_UnhandledException;
  21. InitializeComponent();
  22. }

  23. private void Application_Startup( object sender , StartupEventArgs e )
  24. {
  25. _configurations = e.InitParams;
  26. this.RootVisual = new MainPage();
  27. }

  28. private void Application_Exit( object sender , EventArgs e )
  29. {

  30. }

  31. private void Application_UnhandledException( object sender , ApplicationUnhandledExceptionEventArgs e )
  32. {
  33. if( !System.Diagnostics.Debugger.IsAttached )
  34. {
  35. e.Handled = true;
  36. Deployment.Current.Dispatcher.BeginInvoke( delegate { ReportErrorToDOM( e ); } );
  37. }
  38. }

  39. private void ReportErrorToDOM( ApplicationUnhandledExceptionEventArgs e )
  40. {
  41. try
  42. {
  43. string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
  44. errorMsg = errorMsg.Replace( '"' , '\'' ).Replace( "\r\n" , @"\n" );
  45. System.Windows.Browser.HtmlPage.Window.Eval( "throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");" );
  46. }
  47. catch( Exception )
  48. {
  49. }
  50. }
  51. }
  52. }


4. 最后就是在Silverlight页面当中获取InitParams的值并显示到页面上:


  1. <UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SL_ReadConfigFile.MainPage"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. mc:Ignorable="d"
  7. d:DesignWidth="800" d:DesignHeight="600"
  8. Width="Auto" Height="Auto" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">

  9. <Grid x:Name="LayoutRoot" Background="Transparent">
  10. <Grid.RowDefinitions>
  11. <RowDefinition Height="50"></RowDefinition>
  12. <RowDefinition></RowDefinition>
  13. <RowDefinition Height="30"></RowDefinition>
  14. </Grid.RowDefinitions>
  15. <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24">Silverlight Reads web.config Demo</TextBlock>
  16. <sdk:DataGrid Grid.Row="1" Name="dgdConfigurations">
  17. </sdk:DataGrid>
  18. <StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Center">
  19. <Button Name="btnShowEntry" Width="200" Margin="10,0" Click="btnShowEntry_Click">
  20. <StackPanel Orientation="Horizontal">
  21. <TextBlock VerticalAlignment="Center">Read number</TextBlock>
  22. <toolkit:NumericUpDown Name="numericUpDown" Margin="5,0" DecimalPlaces="0"/>
  23. <TextBlock VerticalAlignment="Center">entry</TextBlock></StackPanel>
  24. </Button>
  25. <Button Name="btnBindConfig" Width="200" Margin="10,0" Click="btnBindConfig_Click">Binding Configurations</Button>
  26. </StackPanel>
  27. </Grid>
  28. </UserControl>


  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Documents;
  8. using System.Windows.Input;
  9. using System.Windows.Media;
  10. using System.Windows.Media.Animation;
  11. using System.Windows.Shapes;

  12. namespace SL_ReadConfigFile
  13. {
  14. public partial class MainPage : UserControl
  15. {
  16. private IDictionary<string , string> _configurations;
  17. public MainPage()
  18. {
  19. InitializeComponent();

  20. _configurations = ( Application.Current as App ).Configurations;

  21. if( _configurations.Count > 0 )
  22. {
  23. numericUpDown.Minimum = 1;
  24. numericUpDown.Maximum = _configurations.Count;
  25. }

  26. }

  27. private void btnBindConfig_Click( object sender , RoutedEventArgs e )
  28. {
  29. this.dgdConfigurations.ItemsSource = _configurations;
  30. }

  31. private void btnShowEntry_Click( object sender , RoutedEventArgs e )
  32. {
  33. string entryContent = string.Format( "{0} = {1}" , _configurations.ElementAt( ( int ) numericUpDown.Value - 1 ).Key , _configurations.ElementAt( ( int ) numericUpDown.Value - 1 ).Value );
  34. MessageBox.Show( entryContent );
  35. }
  36. }
  37. }



5. 我们已经可以读取到web.config里面的值了,但是,要注意的是,在ASPX页面当中InitParams会以明文显示在Source Code当中,如果是数据库连接串或是其他需要加密的信息,请自己开发加密算法来解决这一问题,下一篇我会介绍如何加密InitParams中的值。