Dynamic endpoint resolution using the Managed Services Engine
On my previous post I've listed some of the reasons because of which I believe Microsoft's Managed Services Engine (MSE) can be really useful in Enterprise SOA applications. The existing documentation of MSE emphasizes in the role this technology can play in design time governance scenarios but there is very little about its applicability in runtime governance scenarios. However, in this release MSE already includes various features that can serve as the foundation of future runtime governance technologies. It is not a secret that service repositories are at the center of every SOA governance technologies. Normally, these repositories catalog different service components such as contracts, binding, endpoints, etc. The centralized and/or federated (I honestly think that federated repositories are the future of SOA Governance technologies. But that's content for another post J) storage of endpoints is particularly useful to enterprise applications that need to dynamically resolve those components at runtime. The classical example is an application that queries the repository to find the endpoint of a specific service.
MSE includes a service catalog that it's responsible for storing service metadata that can be used for both design time and runtime governance scenarios. As its core, MSE's service catalog is composed by the following components:
- A SQL Server 2005 DB that stores the service metadata.
- A WCF-based service that can be used to query the metadata stored in the catalog. This WCF service its hosted in a variety of endpoints in order to maximize interoperability with different client applications.
- A Windows service that serve as the host of the above mentioned WCF service.
Although the WCF service interface is not widely documented in the current version; the operations it exposes are very descriptive and easy to figure out. At this point you might already know that the first case I used this WCF API for was for dynamic endpoint resolution. Unfortunately, I wasn't entirely happy with the results L. I founded the current version of the API too strongly typed and hardly extensible. For example, in order to resolve endpoints based on different criteria we need to invoke different operations of the WCF API. Traditionally this problem is addressed using a "query language" as proposed in the UDDI v3.0 and WS-Discovery specification or as implemented by successful Web Services APIs such as Salesforce.com and Amazon.com Flexible Payment System. Among the advantages of a query language we can list the following:
- Works better for a RESTful APIs
- Facilitates versioning
- Facilitates extensibility
- Can be used generically to resolve different services components such as contracts, endpoints of bindings.
Additionally the data model is very rigid to implement complex endpoint resolution scenarios. In the current implementation the only way to resolve endpoint is using a predefined unique identifier that is generated when the endpoint is stored in the MSE catalog.
Despite of its limitations I still think that the current version of the API can be really useful to some enterprise scenarios especially for endpoint discovery and resolution. Like I said in the previous paragraph, in order to resolve different service components in MSE you have to use a unique identifier that it is assigned to each item when is stored in the MSE's catalog. Lets start with a simple WCF service that performs a simple math operation.
[ServiceContract()] public interface IMyService { [OperationContract] int Add(int param1, int param2); }
public class MyService : IMyService { public int Add(int param1, int param2) { return param1 + param2; } } |
The service is registered in the MSE catalog as illustrated in the following picture.
In order to dynamically resolve the endpoint of this service we can use the identifier generated by MSE as illustrated in the following code.
private static void ResolveEndpointByID() { WCFCatalogSvcClient service = new WCFCatalogSvcClient(); Endpoint endpoint = service.GetEndpoint("2f062ff6-44e9-40aa-998d-1d774af6da96"); InvokeOperation("http://" + endpoint.Address, 11, 11); } private static void InvokeOperation(string endpointuri, int param1, int param2) { MyServiceClient service = new MyServiceClient(); service.Endpoint.Address = new EndpointAddress(endpointuri); int result= service.Add(param1, param2); } |
Similarly in case the id is no known at design time there are alternatives to resolve the endpoint based on the name of the operation we are trying to invoke.
private static void ResolveEndpointByOperation() { WCFCatalogSvcClient service = new WCFCatalogSvcClient(); string operationId= service.GetIDFromName("Add", EntityClass.Operation); Operation operation= service.GetOperation(operationId); InvokeOperation("http://" + operation.EndpointList.Endpoints[0].URI, 11, 11); } private static void InvokeOperation(string endpointuri, int param1, int param2) { MyServiceClient service = new MyServiceClient(); service.Endpoint.Address = new EndpointAddress(endpointuri); int result= service.Add(param1, param2); } |
If you have been dealing with endpoint resolution scenarios I am sure you can really appreciate this effort regardless the limitations of the API. In my case, I've lost count how many times I've implemented endpoint discovery solutions based on existing Microsoft technologies like BizTalk Server Business Rules, WF Business Rules, etc. Specifically in the case of BizTalk Server, the combination of dynamic ports and MSE can be a very interesting option for a lot of message routing enterprise scenarios.