(Or how to configure service reference addresses easily)
Most developers will tell you that the XAP file is actually a ZIP file and all you have to do is edit the ServiceReferences.clientconfig file inside that XAP. Some will even tell you that they have developed an application that does it for you.
But is it easy? Is it keeping it simple (-stupid)?
I don’t think so, but you tell me?
What is more simple edit your web application web.config or edit your XAP file?
The first installation is a bit complex but afterwards all you have to do is edit the web.config.
In the Web Application Project:
On the aspx that host the XAP file add an ASP control for the config values. For example:
- <div id="silverlightControlHost">
- <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
- <param name="source" value="ClientBin/SilverlightApplication.xap"/>
- <param name="onError" value="onSilverlightError" />
- <param name="background" value="white" />
- <param name="minRuntimeVersion" value="3.0.40624.0" />
- <param name="autoUpgrade" value="true" />
- <asp:Literal ID="ParamInitParams" runat= "server"></asp:Literal>
- <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration:none">
- <img src="http://go.microsoft.com/fwlink/?LinkId=108181" 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>
On the code behind add the code that puts the config values in the ASP control. For example:
- private void SaveSilverlightDeploymentSettings(Literal litSettings)
- {
- NameValueCollection appSettings = ConfigurationManager.AppSettings;
- var parameters = new StringBuilder();
- parameters.Append("<param name=\"InitParams\" value=\"");
- var settingCount = appSettings.Count;
- for (int index = 0; index < settingCount; index++)
- {
- parameters.Append(appSettings.GetKey(index));
- parameters.Append("=");
- parameters.Append(HttpUtility.UrlEncode(appSettings[index]));
- parameters.Append(",");
- }
- parameters.Remove(parameters.Length - 1, 1);
- parameters.Append("\" />");
- litSettings.Text = parameters.ToString();
- }
- protected void Page_Load(object sender, EventArgs e)
- {
- Response.Cache.SetCacheability(HttpCacheability.NoCache);
- SaveSilverlightDeploymentSettings(ParamInitParams);
- }
On the web.config add your config values as appSettings:
- <?xml version="1.0"?>
- <configuration>
- <appSettings>
- <add key="DataUrl" value="http://GIS_SERVER_NAME/ArcGIS/rest/services/Layers" />
- <add key="RefreshTimerIntervalInMiliSeconds" value="15000"/>
- </appSettings>
- </configuration>
As you can see you can even add Application wide settings here not just service URLs.
In the Silverlight application – app.xaml file:
- private void Application_Startup(object sender, StartupEventArgs e)
- {
- MapApplicationConfigWrapper.Initialize(e);
- }
MapApplicationConfigWrapper is in a Common project (something all of your projects under the Silverlight application can access):
- public class MapApplicationConfigWrapper
- {
- #region C'tor
- private readonly IDictionary<string, string> _config = new Dictionary<string, string>();
- private MapApplicationConfigWrapper(StartupEventArgs e)
- {
- foreach (string key in e.InitParams.Keys)
- {
- SetValue(key, HttpUtility.UrlDecode(e.InitParams[key]));
- }
- }
- private MapApplicationConfigWrapper()
- {
- }
- public static MapApplicationConfigWrapper Instance
- {
- get
- {
- if (!Application.Current.Resources.Contains(MapResources.WebConfig))
- {
- Application.Current.Resources.Add(MapResources.WebConfig, new MapApplicationConfigWrapper());
- }
- return (MapApplicationConfigWrapper) Application.Current.Resources[MapResources.WebConfig];
- }
- }
- public static void Initialize(StartupEventArgs e)
- {
- var wrapper = new MapApplicationConfigWrapper(e);
- Application.Current.Resources.Add(MapResources.WebConfig, wrapper);
- }
- #endregion C'tor
- #region Config Properties
- public string DataUrl
- {
- get { return GetValue("DataUrl"); }
- set { SetValue("DataUrl", value); }
- }
- public int RefreshTimerIntervalInMiliSeconds
- {
- get
- {
- int result;
- return (int.TryParse(GetValue("RefreshTimerIntervalInMiliSeconds"), out result)) ? result : 60000;
- }
- set { SetValue("RefreshTimerIntervalInMiliSeconds", value.ToString()); }
- }
- #endregion Config Properties
- #region Private Helper Methods
- private string GetValue(string key)
- {
- if (!_config.ContainsKey(key))
- return null;
- return _config[key];
- }
- private void SetValue(string key, string value)
- {
- _config[key] = value;
- }
- #endregion Private Helper Methods
- }
So what is done here?
Well StartupEventArgs contains InitParams that is a dictionary with the config values we already entered in the aspx. We go through all the values and put them in our own dictionary.
Next we create properties with the specific types we need for the URL a string and for the RefreshTimerIntervalInMiliSeconds an int.
The code inside Instance (the if) is for when we just want to use the default parameters and we didn’t go through app.xaml.
Now using it is simply
MapApplicationConfigWrapper.Instance.DataUrl
MapApplicationConfigWrapper.Instance.RefreshTimerIntervalInMiliSeconds
and you have the value at your hand!
For everyday use it is much more simple and readable. But maybe it is just me…
What do you think?
Resources:
Managing service references and endpoint configurations for Silverlight applications
ConfigSwitcher: ServiceReferences.ClientConfig Switcher Utility
Configure Silverlight 3 Applications using the Web.config File from ASP.NET
Keywords: Silverlight, Config, configuration, web.config, Service Reference, ServiceReferences