Prism/WCF - single configuration file for ASP.NET, Silverlight and WCF

For a functional demo, with the following principals applied, see our http://www.CodePlex.com/SDMS project.

In a recent blog I noted issues with Prism/Silverlight, WCF and configuration files.  I have since resolved this issue and respond to a programmers question below.

Hi,

I've read your post about problems with wcf service reference and have a question about your solution.

What if i have different wcf services and have more than one ServiceReference.ClientConfig. It would be impossible to add them all as link to shell project.

See Related WEBCAST

I resolved my issues with configuration files by programmatically setting the Binding and Address – I now have “one” configuration file (Web.Config) that services my ASP.NET, Silverlight and WCF Service(s).    The following is my DoctorServiceDAL (Presentation Tier’s Data Layer); after I do an “Add Web Reference” or “Update Web Reference” I delete the configuration file (not required). 

        public DoctorServiceDAL(IUnityContainer container)
        {
            try
            {
                // Set container reference for class use
                Container = container; 

                IServerConfiguration config = container.Resolve<IServerConfiguration>(); 

                // Use basic HttpBinding on both Silverlight and Desktop
                BasicHttpBinding binding =
                    new BasicHttpBinding(BasicHttpSecurityMode.None); 

               binding.Name = "bndDoctorService"; 

                // Get the WebServiceURI from the unity container
                Uri baseAddress = new Uri(config.WebServiceURI); 

                EndpointAddress address = new EndpointAddress(baseAddress); 

                // Instantiate our service using configured data
                client = new wcf.DoctorServiceClient(binding, address); 

                // Subscribe to the Completed events.  The DSEAxxxxx classes that
                // will actually handle setting up the event argument (which will be
                // raised below) are in the Data project (for service references).
                client.GetProviderListCompleted += AsyncCompleted;
                client.GetConfigurationCompleted += AsyncCompleted; 

                // Note: be sure to update applicable modules, i.e., PatientModule.cs
                //       after updating the above to ensure DSEAxxxx can be resolved!
            }
            catch (Exception ex)
            {
                Error = ex;
            }
        }

        /// <summary>
        /// Requests the doctor list.  When list is available it will
        /// be directed to the AsyncCompleted event (subscribed to in
        /// the Constructor)
        /// </summary>
        /// <param name="doctorID">The doctor ID.</param>
        public void RequestProviderData(int doctorID)
        {
            client.GetProviderListAsync(doctorID);
        }

       
        /// <summary>
        /// Request the system configuration parameter string
        /// </summary>
        public void RequestConfigurationString()
        {
            client.GetConfigurationAsync();
        }

        /// <summary>
        /// Executes when async calls are completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e"></param>
        /// instance containing the event data.</param>
        void AsyncCompleted(object sender, AsyncCompletedEventArgs e)
        {
            // All Async callbacks will end up here
            // prepare global event argument
            IDoctorServiceEventArgs args = new DoctorServiceEventArgs();

            // Retrieve the name of the process that just completed
            // and strip off the CompletedEventArgs
            string name = e.GetType().Name.Replace("CompletedEventArgs", "");

            try // Use Unity Container as a factory
            {
                // Resolve it - it must be configured in the Module(s) that
                // use this data layer (reference PatientModule.cs)
                args = Container.Resolve<IDoctorServiceEventArgs>(name);

                // Set the properties to the result
                args.SetArgProperties(e);
            }
            catch (Exception ex)
            {
                Error = new Exception(string.Format("{0} was not configured in {1} \r\n{2}{3}",
                    name, GetType().FullName, ex.Message, ex.StackTrace));
               
            }

            // If anyone is subscribing to the event (which they should be)
            // then raise the event with the data returned
            if (OnDoctorServiceEvent != null)
                OnDoctorServiceEvent(this, (DoctorServiceEventArgs) args);

        }
    }
 

My Default.aspx.cs, code-behind file, has the following which provides information I will need.   Note that I pass it into Xaml1 for Silverlight (read BLOG) and to my WCF Service DoctorServiceClient which is injected into the WCF unity container for successive use (related BLOG). 

    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Retrieve Connection String
            string connectionString =
                ConfigurationManager.ConnectionStrings["PRMS"].ConnectionString;

            // Retrieve Web Service URIs
            string webServiceURI_Dev =
                ConfigurationManager.AppSettings["WebServiceURI-DEV"];
            string webServiceURI_IIS =
                ConfigurationManager.AppSettings["WebServiceURI-IIS"]; 

            // Retrieve Web Service Path
            string webServicePath =
                Request.ApplicationPath == "/" ? webServiceURI_Dev : webServiceURI_IIS; 

            // Set InitParameters for Silverlight use
            Xaml1.InitParameters = string.Format(
                "InitParameters=" +
                "ServerURL=http://{0};" +
                "ServerPath={1};" +
                "ConnString={2};" +
                "WebServiceURI={3}",
                    Request.Url.Authority,
                    Server.MapPath("~"),
                    connectionString,
                    webServicePath); 

            // Send parameters to WCF Service for its use
            new DoctorServiceClient().SetConfiguration(Xaml1.InitParameters);
        }
    }


After the above code runs I can obtain my configuration information from anywhere in the application (ASP.NET, Silverlight or WCF) by resolving the IServerConfiguration. 

 IServerConfiguration config = container.Resolve<IServerConfiguration>();

Below is the class that implements IServerConfiguration and does the heaviy lifting, note that I provide a mechanism to strongly type the values stored in InitParam:

using Microsoft.Practices.Unity;
using System.Collections;
using System.Collections.Generic;
using System;
namespace Library.Interface.Configuration
{
    public class ServerConfiguration : AppBase, IServerConfiguration
    {
        private IDictionary<string, string> constructorParam;
        public IDictionary<string, string> InitParam { get; set; } 

        public ServerConfiguration(IUnityContainer container) : base(container)
        {
            try
            {
                InitParam = new Dictionary<string, string>();
                constructorParam = container.Resolve<IDictionary<string, string>>("InitParameters");
                string paraString = constructorParam["InitParameters"];
                string[] paraList = paraString.Split(';');
                foreach (string para in paraList)
                {
                    string[] keyValue = para.Split('=');
                    InitParam.Add(new
                        KeyValuePair<string, string>(keyValue[0], keyValue[1]));
                }
            }
            catch (Exception ex)
            {
                Error = ex;
            }
        } 

        public string WebServerURL
        {
            get { return InitParam["ServerURL"]; }
        }
        public string WebServerPath
        {
            get { return InitParam["ServerPath"]; }
        }
        public string WebServiceURI
        {
            get { return InitParam["WebServiceURI"]; }
        } 
    }
}

 

 


Tags: , , ,
Categories: CompositeWPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know