Enterprise configuration management

Almost every application requires some form of configuration information. This information can be as simple as a database connection string or as complex as multipart and hierarchical user preference information. How and where to store an application’s configuration data are questions you often face as a developer.

Any large enterprise application has many moving blocks. They all need to be configured for a proper working of the application. As the application size increases or for scalability the same configuration has to be repeated in different applications. For most applications once the configuration has been changed the application needs to be restarted.

Sample Code (create a blank console project, add json.net nuget)

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;

namespace CM
{
    // configuration management API, 
    //1. allow clients specify typesafe models for configuations
    //2. Store flat data on server (table) which is easy to edit
    //3. can be extended to have inheritance of values (overrides)
    //4. can be extended to lock / unlock certain property by admins etc.
    
    class Program
    {
        //Sample configuration model
        internal class SampleConfigModal
        {
            public SampleConfigModal()
            {
                Address = new Address();
            }
            public string Name { get; set; }
            public Address Address { get; set; }
            public int Age { get; set; }


        }
        public class Address
        {
            public string Street { get; set; }

        }

        // this is how client api will look like
        static void Main(string[] args)
        {
            // sample client code
            var data = new SampleConfigModal() { Name = "Rajnish", Age = 18, Address = new Address() { Street = "Oxley" } };

            // save Configuration
            SaveConfiguration("app", "section", data);

            //get Configuration
            var data2 = GetConfiguration("app", "section");
        }

        // Client side framework api -> call to rest end point
        private static T GetConfiguration(string appName, string SectionName) where T : new()
        {
            var defaultValue = new T();
            var samplePayload = JsonConvert.SerializeObject(defaultValue);
            var payload = GetConfiguration(appName, SectionName, samplePayload);
            return JsonConvert.DeserializeObject(payload);
        }

        // Client side framework api -> call to rest end point
        private static void SaveConfiguration(string appName, string SectionName, T data)
        {
            var payload = Newtonsoft.Json.JsonConvert.SerializeObject(data);
            SaveConfigurationa(appName, SectionName, payload);
        }


        //---------------------------------------- Server Code -------------------------- 
        //-------------- server has no knowledge of configuration structure or model

        private static Dictionary<string, string> storage;

        private static void SaveConfigurationa(string appName, string SectionName, string payload, string enumForHierarchyLevel = null)
        {
            // transformer
            var section = string.Format("{0}.{1}", appName, SectionName);
            var data = (JObject)JsonConvert.DeserializeObject(payload);
            var keyValueData = Flatten(data, section);

            // check if user has permission for level overrides
            // store with proper overides

            // store the flat list in sql or data 
            //| KEY |           |Value|            |OverrideType| - default,sysadmin,appadmin,groups,user etc
            //app.section.Name, Rajnish
            //app.section.Address.Street, Oxley
            //app.section.Age, 18

            storage = keyValueData;
        }

        private static string GetConfiguration(string appName, string SectionName, string samplePayload)
        {
            var section = string.Format("{0}.{1}", appName, SectionName);
            var data = (JObject)JsonConvert.DeserializeObject(samplePayload);
            var keyValueSample = Flatten(data, section);
            // update data from sql or data store
            // apply property override rules and get value from overrides if exists
            var keyValueData = keyValueSample.Select(x => new KeyValuePair<string, string>(x.Key, storage[x.Key]));

            //read these
            //app.section.Name, Rajnish
            //app.section.Address.Street, Oxley
            //app.section.Age, 18

            UnFlatten(data, section, keyValueData);

            var formatedData = JsonConvert.SerializeObject(data);
            /*
             * {
                  "Name": "Rajnish",
                  "Address": {
                    "Street": "Oxley"
                  },
                  "Age": "18"
                }
             * */
            return formatedData;

        }
        
        // Server side json helper

        private static void UnFlatten(JObject jsonObject, string prefix, IEnumerable<KeyValuePair<string, string>> data)
        {
            foreach (var item in data)
            {
                var keyName = item.Key.Substring(prefix.Length + 1);
                var storageValue = item.Value;
                if (keyName.Contains("."))
                {
                    var keys = keyName.Split('.');
                    var jtoken = (JToken)jsonObject;
                    foreach (var k in keys)
                    {
                        jtoken = jtoken.SelectToken(k);
                    }
                    ((JValue)jtoken).Value = storageValue;
                }
                else
                {
                    jsonObject[keyName] = storageValue;
                }
            }
        }

        private static Dictionary<string, string> Flatten(JObject jsonObject, string prefix)
        {

            IEnumerable jTokens = jsonObject.Descendants().Where(p => p.Count() == 0);
            Dictionary<string, string> results = jTokens.Aggregate(new Dictionary<string, string>(), (properties, jToken) =>
            {
                properties.Add(string.Format("{0}.{1}", prefix, jToken.Path), jToken.ToString());
                return properties;
            });
            return results;
        }
    }
}

Silverlight WebSockets – Duplex Communication

A duplex communication system is a system composed of two connected parties or devices that can communicate with one another in both directions. Duplex communication is required when you need to send some data in the reverse direction i.e. from Server to client. For scenario purpose assume that something happens on server (some event is received from source) and message from server should be sent to connected clients. Off-course the solution should be highly scalable with low latency client and server.

Let’s talk about silverlight client in our scenario

 There could be couple of options with silverlight client demonstrated by Gill Cleeren In series of article “The duplex story: looking at duplex communication in Silverlight 4

Silverlight 4.0 now supports 3 different types of duplex communications

  • HTTP Polling Duplex: Duplex requires that the server can itself initiate communication, which is not supported by HTTP, HTTP Polling duplex (HTTP long polling, or Comet-style) protocol allows us to do bi-directional communication over HTTP. What happens behind the scenes is the following:
    • The Silverlight client initiates the communication by sending an initial request to the service.
    • After the client is registered with the service, it continuously starts polling the service for updates.
    • Whenever the service has new messages to send to the client, they are queued up until a new poll arrives from the client.

The HTTP Polling Duplex is therefore not real duplexing: it creates an illusion of duplex communication by polling (at network layer) so frequently that it looks as if the messages are pushed from the service to the client. If you still want to use this method here is the link for you to tune performance of http polling duplex.

  • Sockets: Socket is implemented through the use of a TcpListener, Being pure TCP endpoints, sockets are fast and true duplex communicators. However sockets in Silverlight can only work over ports between 4502 and 4534 making it unsuitable for duplex communication over the internet. Secondly you need to build policy server to provide clientaccesspolicy.xml for sockets.Note that Silverlight 4 also allows that the policy calls are made over HTTP.
  • net.tcp binding: this entirely new binding, added in Silverlight 4, also supports duplex communication. net.tcp combines advantages of both polling duplex and sockets. Its programming model is, just like polling duplex, based on WCF. That means that we can take advantage of automatic proxy generation inside Visual Studio.
  • Poll based communication: Not scalable, out of scope.

So what’s next?

 HTML 5 – WebSockets

Web socket protocol or WebSockets are “TCP for the Web,” a next-generation bidirectional communication technology for web applications being standardized in part of Web Applications 1.0.

The Web Sockets API enables web applications to handle bidirectional communications with server-side process in a straightforward way. Once you get a Web Socket connection, you can send data from browser to server by calling a send() method, and receive data from server to browser by an onmessage event handler. The protocol is not raw TCP because it needs to provide the browser’s “same-origin” security model. It’s also not HTTP because web socket traffic differers from HTTP’s request-response model. you do need a new server implementation to communicate with web sockets .

web socket prototype is out now at http://html5labs.interoperabilitybridges.com/prototypes/available-for-download/websockets/html5protos_Download or websocket msi from here

 for more information see : http://tomasz.janczuk.org/2010/12/websockets-wcf-service-silverlight-and.html

Please also find the published websocket transport binding (Incomplete project)  here which i was trying to build using custom duplex WCF channel.

Custom Domain Service Factory

Parameterized constructors are not allowed in WCF RIA domain service, however your object model may requires to have constructor with arguments. For example EmployeeService (in this example) is WCF RIA Domain Service which requires Authentication and have constructor with authenticated User instance as parameter. The activate the service in such scenario you need to provide your own custom domain factory calls and plug the factory in Application_Start event of Global.aspx.

Sample Employee Service class

[EnableClientAccess()]
[RequiresAuthentication()]
public class EmployeeService : DomainService
{
        
    public EmployeeService(User user)
    {
            
    }
    //......
        
}

Custom Domain service factory

internal sealed class DomainServiceFactory : IDomainServiceFactory
{
    private IDomainServiceFactory _defaultFactory;


    public DomainServiceFactory(IDomainServiceFactory defaultFactory)
    {
        _defaultFactory = defaultFactory;
    }

    public static void Setup()
    {
        if (!(DomainService.Factory is DomainServiceFactory))
        {
            DomainService.Factory = new DomainServiceFactory(DomainService.Factory);
        }
    }

    public DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context)
    {
        if (domainServiceType == typeof(EmployeeService))
        {
            DomainServiceContext authServiceContext =
                new DomainServiceContext(context, DomainOperationType.Query);
            AuthenticationService authService =
                (AuthenticationService)_defaultFactory.CreateDomainService(typeof(AuthenticationService), authServiceContext);
            User user = authService.GetUser();

            DomainService domainService = (DomainService)Activator.CreateInstance(domainServiceType, user);
            domainService.Initialize(context);
            return domainService;
        }
        else
        {
            return _defaultFactory.CreateDomainService(domainServiceType, context);
        }
    }

    public void ReleaseDomainService(DomainService domainService)
    {
        if (domainService is EmployeeService)
        {
            domainService.Dispose();
        }
        else
        {
            _defaultFactory.ReleaseDomainService(domainService);
        }
    }
}

Setup Domain service factory

protected void Application_Start(object sender, EventArgs e)
{
    DomainServiceFactory.Setup();

}

Silverlight 4.0 with WCF Ria (2008)

Visual studio 2010 comes with nice Silverlight designer, But for LOB applications you always need data which can be pumped only via WCF RIA service (assuming you want to finish the project ASAP). Lot of programmers have still issues with WCF RIA 1.0 (for Vs2010) in terms of publishing the application on shared hosting domain. Actually this problem is because of not having correct version of .net framework on shared hosting domains. Example – my hosting provider has .net version 4.0.2xxx installed on web server. With 4.0.2 i got error saying Unrecognized attribute ‘multipleSiteBindingsEnabled’ where as on local machine i am having 4.0.3, and hosting provider will not install .net version on shared hosting domain until it get stable and they get some confidence ..So till than are we going to use Silverlight 3 ??

Well in my previous post i have tried to fix issues with WCF RIA on shared hosting domain which is working fine. Note that this fix is for WCF RIA Beta 1 which is compiled for Vs 2008. There is no fix available which could be applied to WCF RIA 1.0 (for 2010) in similar way. What we are going to do here is use best out of what we have i.e SL 4.0 + Vs2010 and WCF RIA + Vs2008.

Jumping directly to the point : How to work with Silverlight 4.0 (VS 2010) and WCF RIA (VS 2008)..

What you required:

  1. Vs 2008 with WCF RIA Beta
  2. Vs 2010 with Silverlight 4.0

How to build:

  1. Create WCF RIA Service Library using Visual Studio 2008. –
    1. Above step will create two libraries -one for silverlight project (client) and another for web server project.
  2. Create another Silverlight business app using Visual Studio 2008
    1. Add above assemblies to both projects (Sl+Web).- test it.
    2. Now delete the SL project created in step 2. we will only need wcf-web project from step 2.
  3. Now Open Vs 2010 and open the web project (existing) created in step 2 above.This will migrate you project from VS 2008 to 2010.
  4. Add new silverlight project to above solution.
  5. Go to properties of web project and link it with silverlight project in the group.

And that it !

For silverlight application you will use VS 2010 (framework 3.5) and for Ria service you need to launch Vs 2008 (project in step 1).

While you try to publish app on shared hosting domain,the fix which is provided in my previous articles can be applied. The WCF RIA libraries generated in step 1 could be migrated to WCF RIA 1.0 if in future issues with WCF got resolved and you need not to change you silverlight app.

I still need to test the solution mentioned above (althought i had quick test before writting this article) to ensure that we are not lossing any thing..

Let me know if template project is required for this, i will be glad to help..

So what you are thinking now go-ahead….

 You may need to refer fix2 to catch exceptions from server..

Implementing Silverlight Faults in SL 3.0 with RIA Domain Services – Fix 2

Last month i have post article on how to host Silverlight (With RIA Domain services) project on shared domain. In that article (Link is Here ) some web.config settings are recommended to configure RIA end points. While working tonight i have noticed that Silverlight clients are not able to catch exceptions raised by DomainService ! and that’s because we have replaced the RIA default end point configurations via web.config settings. Silverlight version 3 enables support for the Windows Communication Foundation (WCF) SOAP fault programming model, which allows the service to communicate error conditions to the client. We need to perform following steps to enable error catch to Silverlight client. To send faults to a Silverlight client that are accessible to it, an WCF service must modify the way it sends its fault messages. The key change needed is for WCF to return fault messages with a HTTP 200 response code instead of the HTTP 500 response code. This change enables Silverlight to read the body of the message and also enables WCF clients of the same service to continue working using their normal fault-handling procedures.
The modification on the server can be made by defining a WCF endpoint behavior for Silverlight faults. The following code sample shows how to do this.
Create Project Paris.Silverlight and add class SilverlightFaultBehavior
Copy the code as mentioned below (This has been taken from assembly System.Web.Ria 2.0.0.0) or follow link

1.

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace Paris.Silverlight
{
    public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public SilverlightFaultBehavior()
        {

        }
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector();
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public override System.Type BehaviorType
        {
            get { return typeof(SilverlightFaultBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new SilverlightFaultBehavior();
        }
    }

    public class SilverlightFaultMessageInspector : IDispatchMessageInspector
    {
        object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            // Do nothing to the incoming message
            return null;
        }

        void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            if (reply.IsFault)
            {
                HttpResponseMessageProperty property = new HttpResponseMessageProperty();
                property.StatusCode = System.Net.HttpStatusCode.OK; // 200

                reply.Properties[HttpResponseMessageProperty.Name] = property;
            }
        }

    }
}


Compile the project and add reference of above assembly to your RIA web service project.

Now we need to register the custom behaviorExtension element in web.config before doing that i would recommend to find full Qualified name of your assembly holding above class.

Type code mentioned below to your start up aspx page

string name = typeof(Paris.Silverlight.SilverlightFaultBehavior).AssemblyQualifiedName;

copy the value of name , in my case thay are
Paris.Silverlight.SilverlightFaultBehavior, SilverlightFaultBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Note that you need to copy the same to web .config. Service may not work if you may put extra space or new line character in web .config.

When registering a custom behaviorExtension element in your app.config to set up a custom endpoint behavior
for a WCF service, WCF seems to require that the type attribute of the behaviorExtension matches *exactly* the assembly qualified name of the BehaviorExtensionElement class at a string level.

2. Add RIASilverlightFaultBehavior to your web.config and also add behaviorConfiguration=”RIASilverlightFaultBehavior” to each endpoint of RIA service where address=”/binary”

<service name="SparkExams.Web.UserRegistrationService" behaviorConfiguration="RIAServiceBehavior">
  <endpoint address="" binding="wsHttpBinding" contract="SparkExams.Web.UserRegistrationService" />
  <endpoint address="/soap" binding="basicHttpBinding" contract="SparkExams.Web.UserRegistrationService"/>
  <endpoint address="/binary" binding="customBinding"  bindingConfiguration="BinaryHttpBinding"
  contract="SparkExams.Web.UserRegistrationService"  behaviorConfiguration="RIASilverlightFaultBehavior"/>
</service>

Don’t forget to deploy SilverlightFaultBehavior assembly to your web server.
Please also note that type attribute is space sensitive, use typeof(className).AssemblyQualifiedName to find type .
Code and article has been tested against Vs 2008, and RIA 2.0 Beta.

Click here for details on Fault Strategies in SL3