Skip to main content

Service-Oriented Architecture and Exposing Services

A core design premise of the ELEFLEX® platform is to expose all service commands for all system processing events and to provide a completely service-based user interface so that multiple platforms can be targeted as technologies evolve. The design also includes the ability to support each service hosted on a shared or independent hosted processes using request dispatchers.

The Eleflex.Services.WCF.IWCFCommand interface provides the core means to exposing a service method within the platform. The command interface uses a simple Request/Response paradigm for sending and receiving information, allowing for other communication method abstractions as needed. This method signature utilizes the ServiceKnownType() attribute that allows us to dynamically get a list of service commands exposed in the system for integrating all modules. Module service commands will be automatically registered with the WCFCommandRegistry object and then dynamically accessed depending on the request object sent to the system.


[ServiceContract]
public partial interface IWCFCommand
{
        [OperationContract]
        [ServiceKnownType("GetKnownTypes", typeof(WCFCommandRegistry))]
        Response ExecuteServiceCommand(Request request);
}


Exposing a service in the platform requires the following objects:

Calling a service requires a service endpoint to be defined. By default, all service calls in a module are made through a request dispatcher that is configured to the “EleflexDefault” endpoint in the application’s config file. This allows all modules to expose service commands on the same endpoint as other modules. Client Service objects in each of the modules call their respective request dispatcher to get the configuration to send the request out on. Integrators can then change the endpoint for a particular service to point to a new server address or using a different security configuration. This is done by changing the object location configuration for each service. For the logging service, it is ILoggingRequestDispatcher for security it is ISecurityRequestDispatcher and so on.

The following example displays the classes needed to expose a service command in the system. By using the [WCFCommandRegistration()] class attribute, the system will automatically register the command, request and response objects dynamically on system startup with an internal startup task. For client-calling applications not in the main hosted process, a separate configuration class is generated in the Messages assembly to register request and response objects on the client side for service communication.

    
//REQUEST OBJECT
public partial class ExampleRequest : Request
{
public string Input { get; set; }
}
//RESPONSE OBJECT
public partial class ExampleResponse : Response
{
public string Output { get; set; }
}
//SERVICE INTERFACE OBJECT
public partial interface IExampleService
{
      ExampleResponse ExampleMethod (ExampleRequest request);
}
//CLIENT SERVICE OBJECT
public partial class ExampleService : IExampleService
{
        
        public ExampleResponse ExampleMethod (ExampleRequest request)
        {
            using (IExampleRequestDispatcher dispatcher = ObjectLocator.Current.GetInstance<IExampleRequestDispatcher>())
            {
                return dispatcher.ExecuteServiceCommand<ExampleResponse>(request); //SERVICE CALL
            }
        }
}
//REQUEST DISPATCHER OBJECT
public partial interface IExampleRequestDispatcher : IWCFCommandRequestDispatcher
{
}
public class ExampleRequestDispatcher : WCFCommandRequestDispatcher, IExampleRequestDispatcher
{
        public ExampleRequestDispatcher()
            : base(WCFConstants.SERVICE_ENDPOINT_NAME_DEFAULT)
        { }
        public ExampleRequestDispatcher(string endpoint)
            : base(endpoint)
        { }
}
//SERVICE COMMAND OBJECT
[WCFCommandRegistration(typeof(ExampleRequest), typeof(ExampleResponse))]
public partial class ExampleCommand : WCFCommand<ExampleRequest, ExampleResponse>
{
        public override void Execute(ExampleRequest request, ExampleResponse response)
        {            
            response.Output = “Hello ” + request.Input;
        }
}

Securing service command methods can be done with the [PrincipalPermission()] class attribute or with a custom implementation. The next example shows adding the [PrincipalPermission()] attribute on the Execute() method to require only user’s that have the “Admin” role are allowed to call the method.


[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
public override void Execute(ExampleRequest request, ExampleResponse response)
{            
response.Output = “Hello ” + request.Input;
}


By default, OWIN is configured in the WCF pipeline with the current requestor’s user principal information for all requests. There may come times when an anonymous user or user without sufficient privileges is making a request, however the system needs to make a call that requires elevated privileges. In these cases, you can impersonate a specific user or the system admin account with the following objects:

Impersonation is handled by the system through a server WCF behavior, Eleflex.Services.WCF.OWIN.CookieSecurityServerBehaviorExtension that is responsible for receiving and processing the request and from the client using the ELEFLEX.Services.WCF.OWIN.CookieSecurityClientBehaviorExension As the name implies, the OWIN cookie is passed from client to server allowing authentication and authorization with OWIN since it has been injected into the WCP pipeline during a service call.

The next example shows how to make a service call impersonating the system account. In this case, we request the ISecurityUserServiceRepository interface that will allow us to make a service call to get users in the platform, which requires the requesting user to have “Admin” access. By making service calls while the ImpersonateSystem() object is alive, the request will resolve to the system admin account, rather than the user the call originated from and the call will succeed.

    
var service = ObjectLocator.Current.GetInstance<ISecurityUserServiceRepository>();
using (var adminAccess = new ImpersonateSystem())
{
var resp = service.Get(new RequestItem<Guid>() { Item = userKey });   
}