[Silverlight][ASP.Net][C#] 讓Silverlight也能讀取web.config的小撇步

寫習慣ASP.Net的朋友們應該都很習慣使用web.config來存放系統設定值了,但是Silverlight沒有專屬的設定檔可以用,又不能直接讀取web.config檔,加上Silverilght 3.0之後,原來2.0中ASP.Net的Silveright控制項也被拔掉了,要存取web.config看起來就又更遠了一些。
不過,路是人走出來的,方法是人想出來的,Follow me!!

 

寫習慣ASP.Net的朋友們應該都很習慣使用web.config來存放系統設定值了,但是Silverlight沒有專屬的設定檔可以用,又不能直接讀取web.config檔,加上Silverilght 3.0之後,原來2.0中ASP.Net的Silveright控制項也被拔掉了,要存取web.config看起來就又更遠了一些。

不過,路是人走出來的,方法是人想出來的,Follow me!!

如果仔細看一下用來host Silverilght 的aspx檔的話,會發現裡面有一段我們可以利用的區段:


<param name="source" value="ClientBin/SL_ReadConfigFile.xap"/>
 
<param name="onError" value="onSilverlightError" />
 
<param name="background" value="white" />
 
<param name="minRuntimeVersion" value="4.0.50826.0" />
 
<param name="autoUpgrade" value="true" />

 

沒錯,就是這個參數區段,我們可以從這個區段下手,在裡面加上一段

<param name="InitParams" value="" />

 

搭配Silverlight專案中的App.xaml.cs裡面的

App.xaml.cs

private void Application_Startup( object sender , StartupEventArgs e )
{
    this.RootVisual = new MainPage();
}


來取得InitParams的值。

 

OK,講完了理論,那實際的作法呢?

第一步,我們必需在aspx檔中加入一個Literal控制項,以便動態的塞入<param name="InitParams" value="" />到aspx檔,但是VS2010預設建立的aspx並沒有跟它對應的cs檔,所以我們就來自己建立一個新的WebForm頁面吧!!

建立好新的aspx檔之後,把原來的aspx檔中<html>到</html>中所有的內容複製到新的aspx檔中,取代掉原來的內容,並且在原來的加上<param>區段之後加入一個Literal控制項,我實作的範例檔內容如下:

 

SL_ReadConfigFile.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SL_ReadConfigFile.aspx.cs" Inherits="SL_ReadConfigFile.Web.SL_ReadConfigFile" %>
 
<!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 id="Head1" runat="server">
    <title>SL_ReadConfigFile</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" style="height:100%">
    <div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
          <param name="source" value="ClientBin/SL_ReadConfigFile.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>

 

第二步,我們要在新的aspx.cs檔中讀取web.config的內容,並且把內容透過Literal Control動態的寫進aspx檔中,實作方式如下:

SL_ReadConfigFile.aspx.cs

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 )
        {
            //清除Cache,以避免讀取到Cache中的資料
            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();
        }
    }
}

到這邊,我們已經完成了一半!!

第三步,要讓Silverlight專案能讀得到InitParams,修改App.xaml.cs檔,加入一個Property供MainPage存取,並且透過e.InitParams來取得aspx裡面的InitParams,我的範例如下:

App.xaml.cs

using System;
using System.Collections.Generic;
using System.Windows;
 
namespace SL_ReadConfigFile
{
    public partial class App : Application
    {
        //加入一個Property供Silverlight專案中其他頁面存取
        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();
        }
 
        //在這邊加入取得InitParams的程式碼
        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 )
            {
            }
        }
    }
}

 

最後就是在MainPage.xaml和MainPage.xaml.cs中動手腳,把InitParams顯示出來;而這邊應該就相對的簡單了,請直接參考範例程式碼。

MainPage.xaml

<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>

 

MainPage.xaml.cs

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 );
        }
    }
}

 

都做完之後就可以很開心的透過web.config來存放一些要讓Silverlight專案使用的設定值啦!!

不過,要注意的是,在aspx檔中的InitParams會以明碼顯示,如果有安全性的顧慮的話,請自行加上加密編碼喔!!

 

來看看成品吧:

 

最後,不免俗的還是得附上專原始碼,請自行服用: