Category Archives: .Net 4

How To : Access SAP Business Data From Silverlight 4 Clients Using WCF RIA Services And LINQ to SAP

Introduction

The introduction of Microsoft’s WCF RIA Services for Silverlight 4 simplified very much the development process of N-tier business applications using Silverlight and ASP.NET. By using this new technology, we can also easily access and integrate SAP business data in Silverlight clients.

This article shows how to provide a SAP domain service as web service that will be consumed by a Silverlight client. The sample application will allow the user to query customer data. The service uses LINQ to SAP from Theobald Software to connect to a SAP R/3 system.

Project Setup

The first step in setting up a new Silverlight 4 project with WCF RIA Services is to create a solution using the Visual Studio template Silverlight Navigation Application:

Screenshot-01.png - Click to enlarge imageVisual Studio 2010 then asks you to create an additional web application, which hosts the Silverlight application. It’s important to select the checkbox Enable WCF RIA Services (see screenshot below):

SAP2Silverlight/Screenshot-02.pngAfter clicking the Ok button, Visual Studio generates a solution with two projects, one Silverlight 4 project and one ASP.NET project. In the next section, we will create the SAP data access layer using the LINQ to SAP designer.

LINQ to SAP

The LINQ to SAP provider and its Visual Studio 2010 designer offers a very handy way to design SAP interfaces visually. The designer will generate the code for the SAP data access layer automatically, similar to LINQ to SQL. The LINQ provider is part of the .NET library ERPConnect.net from Theobald Software. The company offers a demo version for download on its homepage.

The next step is to create the needed LINQ to SAP file by opening the Add New Item dialog:

Screenshot-03.png - Click to enlarge imageLINQ to SAP is internally called LINQ to ERP.

Clicking the Add button will create a new ERP file and opens the LINQ designer. Now, drag the Function object from the toolbox and drop it onto the designer surface. If you have not entered the SAP connection data so far, you are now asked to do so:

Screenshot-04.png - Click to enlarge imageEnter the connection data for your SAP R/3 system and then click the Ok button. Next, search for and select the SAP function module named SD_RFC_CUSTOMER_GET. The function module provides a list of customer data.

The RFC Function modules dialog opens and lets you define the necessary parameters:

SAP2Silverlight/Screenshot-05.pngIn the above function dialog, change the method name to GetCustomers and mark the Pass checkbox for theNAME1 parameter in the Exports tab. Also set the variable name to namePattern. On the Tables tab, mark the Return checkbox for the table parameter CUSTOMER_T and set the table and structure name to CustomerTable andCustomerRow:

SAP2Silverlight/Screenshot-06.pngAfter clicking the Ok button and saving the ERP file, the LINQ designer will generate a SAPContext class which contains a method called GetCustomers with an input parameter named namePattern. This method executes a search for SAP customer data allowing the user to enter a wildcard pattern. The method returns a table of customer data:

SAP2Silverlight/Screenshot-07.pngOn the LINQ designer level (click on the free part of the LINQ designer surface) property, Create Object Outside Of Context Class must be set to True:

Screenshot-08.png - Click to enlarge imageNow, we finally add a Customer class which we use in our SAP domain service later on. This class and its values will be transmitted to the Silverlight client by the WCF RIA Services. It’s important to set the Key attribute on the identifier fields for WCF RIA Services, otherwise the project will not compile:

Screenshot-09.png - Click to enlarge imageThat’s it! We now have our SAP data access layer ready to use and can start adding the domain service in the next section.

SAP Domain Service

The next step is to add the SAP domain service to our web project. A domain service is a specialized WCF service and is one of the core constructs of WCF RIA Services. The service exposes operations that can be called from the client generated code. On the client side, we use the domain context to access the domain service on the server side.

Add a new Domain Service Class and name it SAPService:

Screenshot-10.png - Click to enlarge imageIn the upcoming dialog, create an empty domain service class by just clicking the Ok button:

SAP2Silverlight/Screenshot-11.pngNext, we add the service operation GetCustomers to the SAP service with a name pattern parameter. The operation then returns a list of Customer objects. The Query attribute limits the result set to 200 entries.

The operation uses the visually designed SAP data access logic to retrieve the SAP customer data. First of all, an instance of the SAPContext class will be created using a connection string (see sample in code). For more details regarding the SAP connection string, see the ERPConnect.net manual.

The LINQ to SAP context class contains the GetCustomers method which we will call using the given namePatternparameter. Next, the operation creates an instance of the Customer class for each customer record returned by SAP.

The license code for the ERPConnect.net library is set in the constructor of our domain service class.

Screenshot-12.png - Click to enlarge imageThat’s all we need on the server side.

In the next section, we will implement the Silverlight client.

Silverlight Client

The implementation of the client side is straightforward. The home view contains a DataGrid control to display the list of customer data as well as a search area with TextBox and Button controls to allow users to enter name search pattern.

The click event handler of the load button, called OnLoadButtonClick, will execute the SAP service. The boilerplate code to access the web service was generated by WCF RIA Services in the subfolder Generated_Code in the Silverlight project.

First of all, an instance of the SAPContext will be created. Then, we load the query GetCustomersQuery and execute the service operation on the server side using WCF RIA Services. If the domain service returns an error, the callback anonymous method will mark the error as handled and display the error message.

If the execution of the service operation succeeded, the result set gets displayed in the DataGrid control.

Screenshot-13.png - Click to enlarge imageThe next screenshot shows the final result:

Screenshot-14.png - Click to enlarge imageThat’s it.

Summary

This article has shown how easily SAP customer data can be integrated within Silverlight clients using tools like WCF RIA Services and LINQ to SAP. It is quite simple to extend the SAP service to integrate all kinds of operations.

Advertisements

How To : SAP Integration with .Net 4.0 (SAP Connection Manager) & SharePoint

This is a simple, C# class library project to connect .NET applications with SAP.

ppt_img[1]

 

This component internally implements SAP .NET Connector 3.0. The SAP .NET Connector is a development environment that enables communication between the Microsoft .NET platform and SAP systems.

This connector supports RFCs and Web services, and allows you to write different applications such as Web form, Windows form, or console applications in the Microsoft Visual Studio .NET.

With the SAP .NET Connector, you can use all common programming languages, such as Visual Basic. NET, C#, or Managed C++.

Features
Using the SAP .NET Connector you can:

Write .NET Windows and Web form applications that have access to SAP business objects (BAPIs).

Develop client applications for the SAP Server.

Write RFC server applications that run in a .NET environment and can be installed starting from the SAP system.

Following are the steps to configure this utility on your project

Download and extract the attached file and place it on your machine. This package contains 3 libraries:

SAPConnectionManager.dll
sapnco.dll
sapnco_utils.dll

Now go to your project and add the reference of all these four libraries. Sapnco.dll and sapnco_utils.dll are inbuilt libraries used by SAP .NET Connector. SAPConnectionManager.dll is the main component which provides the connection between .NET and SAP.

Once the above steps are complete, you need to make certain entries related to SAP server on your configuration file. Here are the sample entries that you have to maintain on your own project. You need to change only the values which are marked in Bold. Rest remains unchanged.

<appSettings>
<add key=”ServerHost” value=”127.0.0.1″/>
<add key=”SystemNumber” value=”00″/>
<add key=”User” value=”sample”/>
<add key=”Password” value=”pass”/>
<add key=”Client” value=”50″/>
<add key=”Language” value=”EN”/>
<add key=”PoolSize” value=”5″/>
<add key=”PeakConnectionsLimit” value=”10″/>
<add key=”IdleTimeout” value=”600″/>
</appSettings>

To test this component, create one windows application. Add the reference of sapnco.dll, sapnco_utils.dll, andSAPConnectionManager.dll on your project.

Paste the below code on your Form lode event

SAPSystemConnect sapCfg = new SAPSystemConnect();
RfcDestinationManager.RegisterDestinationConfiguration(sapCfg);
RfcDestination rfcDest = null;
rfcDest = RfcDestinationManager.GetDestination(“Dev”);

sap_integration_en_round[1]
That’s it. Now you are successfully connected with your SAP Server. Next you need to call SAP business objects (BAPIs) and extract the data and stored it in DataSet or list.

Demo Code available on request!!

How To : Use the Microsoft Monitoring Agent to Monitor apps in deployment

You can locally monitor IIS-hosted ASP.NET web apps and SharePoint 2010 or 2013 applications for errors, performance issues, or other problems by using Microsoft Monitoring Agent. You can save diagnostic events from the agent to an IntelliTrace log (.iTrace) file. You can then open the log in Visual Studio Ultimate 2013 to debug problems with all the Visual Studio diagnostic tools.

If you use System Center 2012, use Microsoft Monitoring Agent with Operations Manager to get alerts about problems and create Team Foundation Server work items with links to the saved IntelliTrace logs. You can then assign these work items to others for further debugging.

See Integrating Operations Manager with Development Processes and Monitoring with Microsoft Monitoring Agent.

Before you start, check that you have the matching source and symbols for the built and deployed code. This helps you go directly to the application code when you start debugging and browsing diagnostic events in the IntelliTrace log. Set up your builds so that Visual Studio can automatically find and open the matching source for your deployed code.

  1. Set up Microsoft Monitoring Agent.
  2. Start monitoring your app.
  3. Save the recorded events.
Set up the standalone agent on your web server to perform local monitoring without changing your application. If you use System Center 2012, see Installing Microsoft Monitoring Agent.

Set up the standalone agent

  1. Make sure that:
  2. Download the free Microsoft Monitoring Agent, either the 32-bit version MMASetup-i386.exe or 64-bit version MMASetup-AMD64.exe, from the Microsoft Download Center to your web server.
  3. Run the downloaded executable to start the installation wizard.
  4. Create a secure directory on your web server to store the IntelliTrace logs, for example, C:\IntelliTraceLogs.

    Make sure that you create this directory before you start monitoring. To avoid slowing down your app, choose a location on a local high-speed disk that’s not very active.

     

    Security note Security Note
    IntelliTrace logs might contain personal and sensitive data. Restrict this directory to only those identities that must work with the files. Check your company’s privacy policies.
  5. To run detailed, function-level monitoring or to monitor SharePoint applications, give the application pool that hosts your web app or SharePoint application read and write permissions to the IntelliTrace log directory. How do I set up permissions for the application pool?
  1. On your web server, open a Windows PowerShell or Windows PowerShell ISE command prompt window as an administrator.

     

    Open Windows PowerShell as administrator 

  2. Run the Start-WebApplicationMonitoring command to start monitoring your app. This will restart all the web apps on your web server.

     

    Here’s the short syntax:

     

    Start-WebApplicationMonitoring “<appName>” <monitoringMode> “<outputPath>” <UInt32> “<collectionPlanPathAndFileName>”

     

    Here’s an example that uses just the web app name and lightweight Monitor mode:

     

    PS C:\>Start-WebApplicationMonitoring “Fabrikam\FabrikamFiber.Web” Monitor “C:\IntelliTraceLogs”

     

    Here’s an example that uses the IIS path and lightweight Monitor mode:

     

    PS C:\>Start-WebApplicationMonitoring “IIS:\sites\Fabrikam\FabrikamFiber.Web” Monitor “C:\IntelliTraceLogs”

     

    After you start monitoring, you might see the Microsoft Monitoring Agent pause while your apps restart.

     

    Start monitoring with MMA confirmation 

    “<appName>” Specify the path to the web site and web app name in IIS. You can also include the IIS path, if you prefer.

     

    “<IISWebsiteName>\<IISWebAppName>”

    -or-

    “IIS:\sites \<IISWebsiteName>\<IISWebAppName>”

     

    You can find this path in IIS Manager. For example:

     

    Path to IIS web site and web app 

    You can also use the Get-WebSite and Get WebApplication commands.

    <monitoringMode> Specify the monitoring mode:

     

    • Monitor: Record minimal details about exception events and performance events. This mode uses the default collection plan.
    • Trace: Record function-level details or monitor SharePoint 2010 and SharePoint 2013 applications by using the specified collection plan. This mode might make your app run more slowly.

       

       

      This example records events for a SharePoint app hosted on a SharePoint site:

       

      Start-WebApplicationMonitoring “FabrikamSharePointSite\FabrikamSharePointApp” Trace “C:\Program Files\Microsoft Monitoring Agent\Agent\IntelliTraceCollector\collection_plan.ASP.NET.default.xml” “C:\IntelliTraceLogs”

       

    • Custom: Record custom details by using specified custom collection plan. You’ll have to restart monitoring if you edit the collection plan after monitoring has already started.
    “<outputPath>” Specify the full directory path to store the IntelliTrace logs. Make sure that you create this directory before you start monitoring.
    <UInt32> Specify the maximum size for the IntelliTrace log. The default maximum size of the IntelliTrace log is 250 MB.

    When the log reaches this limit, the agent overwrites the earliest entries to make space for more entries. To change this limit, use the -MaximumFileSizeInMegabytes option or edit the MaximumLogFileSize attribute in the collection plan.

    “<collectionPlanPathAndFileName>” Specify the full path or relative path and the file name of the collection plan. This plan is an .xml file that configures settings for the agent.

    These plans are included with the agent and work with web apps and SharePoint applications:

    • collection_plan.ASP.NET.default.xml

      Collects only events, such as exceptions, performance events, database calls, and Web server requests.

    • collection_plan.ASP.NET.trace.xml

      Collects function-level calls plus all the data in default collection plan. This plan is good for detailed analysis but might slow down your app.

     

    You can find localized versions of these plans in the agent’s subfolders. You can also customize these plans or create your own plans to avoid slowing down your app. Put any custom plans in the same secure location as the agent.

     

    How else can I get the most data without slowing down my app?

     

    For the more information about the full syntax and other examples, run the get-help Start-WebApplicationMonitoring –detailed command or the get-help Start-WebApplicationMonitoring –examples command.

  3. To check the status of all monitored web apps, run the Get-WebApplicationMonitoringStatus command.

How To : Implement a WCF 4 Routing Manager

Contents

 

Features

  • Manageable Routing Service
  • Mapping physical to logical endpoints
  • Managing routing messages from Repository
  • No Service interruptions
  • Adding more outbound endpoints on the fly
  • Changing routing rules on the fly
  • .Net 4 Technologies

 Introduction

Recently released Microsoft .Net 4 Technology represents a foundation technology for metadata driven model applications. This article focuses on one of the unique components from the WCF 4 model for logical connectivity such as a Routing Service. I will demonstrate how we can extend its usage for enterprise application driven by metadata stored in the Runtime Repository. For more details about the concept, strategy and implementation of the metadata driven applications, please visit my previous articles such as Contract Model and Manageable Services.   

I will highlight the main features of the Routing Service, more details can be found in the following links [1], [2], [3].

From the architectural style, the Router represents a logical connection between the inbound and outbound endpoints. This is a “short wire” virtual connection in the same appDomain space described by metadata stored in the router table. Based on these rules, the messages are exchanged via the router in the specific built-in router pattern. For instance, the WCF Routing Service allows the following Message Exchange Pattern (MEP) with contract options:

  • OneWay (SessionMode.Required, SessionMode.Allowed, TrasactionFlowOption.Allowed)
  • Duplex (OneWay, SessionMode.Required, CallbackContract, TrasactionFlowOption.Allowed)
  • RequestResponse (SessionMode.Allowed, TrasactionFlowOption.Allowed)

In addition to the standard MEPs, the Routing Service has a built-in pattern for Multicast messaging and Error handling.

 

 

The router process is very straightforward, where the untyped message received by inbound endpoint is forwarding to the outbound endpoint or multiple endpoints based on the prioritized rules represented by message filter types. The evaluation rules are started by highest priority. The router complexity is depended by number of inbound and outbound endpoints, type of message filters, MEPs and priorities.

Note, that the MEP pattern between the routed inbound and outbound endpoints must be the same, for example: the OneWay message can be routed only to the OneWay endpoint, therefore for routing Request/Response message to the OneWay endpoint, the service mediator must be invoked to change the MEP and then back to the router.

A routing service enables an application to physically decouple a process into the business oriented services and then logical connected (tight) in the centralized repository using a declaratively programming. From the architecture point of view, we can consider a routing service as a central integration point (hub) for private and public communication.

The following picture shows this architecture:

 

 

As we can see in the above picture, a centralized place of the connectivity represented by Routing Table. The Routing Table is the key component of the Routing service, where all connectivity is declaratively described. These metadata are projected on runtime for message flowing between the inbound to outbound points. Messages are routing between the endpoints in the full transparent manner. The above picture shows the service integration with the MSMQ Technology via routing. The queues can be plugged-in to the Routing Table integration part like another service.

From the metadata driven model point of view, the Routing Table metadata are part of the logical business model, centralized in the Repository. The following picture shows an abstraction of the Routing Service to the Composite Application:

 

 

 

The virtualization of the connectivity allows encapsulating a composite application from the physical connectivity. This is a great advantage for model driven architecture, where internally, all connectivity can be used well know contracts. Note, that the private channels (see the above picture – logical connectivity) are between the well know endpoints such as Routing Service and Composite Application. 

Decoupling sources (consumers) from the target endpoints and their logical connection driven by metadata will enable our application integration process for additional features such as:   

  • Mapping physical to logical endpoints
  • Virtualization connectivity
  • Centralized entry point
  • Error handling with alternative endpoints
  • Service versioning
  • Message versioning
  • Service aggregation
  • Business encapsulation
  • Message filtering based on priority routing
  • Metadata driven model
  • Protocol bridging
  • Transacted message routing

As I mentioned earlier, in the model driven architecture, the Routing Table is a part of the metadata stored in the Repository as a Logical Centralized Model. The model is created by design time and then physical decentralized to the target. Note, deploying model for its runtime projecting will require recycling the host process. To minimize this interruption, the Routing Service can help to isolate this glitch by managing the Routing Table dynamically.

The WCF Routing Service has built-in a feature for updating a Routing Table at the runtime. The default bootstrap of the routing service is loading the table from the config file (routing section). We need to plug-in a custom service for updating the routing table in the runtime. That’s the job for Routing Manager component, see the following picture:

 

 

Routing Manager is a custom WCF Service responsible for refreshing the Table located in the Routing Service from the config file or Repository. The first inbound message (after the host process is opened) will boot the Table from the Repository automatically. During the runtime time, when the routing service is active, the Routing Manager must receive an inquiry message to load a routing metadata from the Repository and then update the Table.

Basically, the Routing Manager enables our virtualized composite application to manage this integration process without recycling a host process. There is one conceptual architectural change in this model. As we know, the Repository pushed (deployed) metadata for its runtime projecting to the host environment (for instance: IIS, WAS, etc.). This runtime metadata is stored in the local, private repository such as file system and it is used for booting our application, services.

That’s a standard Push phase such as Model->Repository->Deploy. The Routing Service is a good candidate for introducing a concept of the Pull phase such as Runtime->Repository, where the model created during the design time can be changed during its processing in the transparent manner. Therefore, we can decide about the runtime metadata used by Pull model during the design time as well.

Isolating metadata for boot projector and runtime update enables our Repository to administrate application without interruptions, for instance, we can change physical endpoint, binding, plug-in a new service version, new contract, etc. Of course, we can build more sophisticated tuning system, where runtime metadata can be created and/or modified by analyzer, etc. In this case, we have a full control loop between the Repository and Runtime.

Finally, the following picture is an example of the manageable routing service:

 

 

As the above picture shows, the manageable Routing Service represents central virtualizations of the connectivity between workflow services, services, queues and web services. The Runtime Repository represents a routing metadata for booting process and also runtime changes. The routing behavior can be changed on the fly in the common shareable database (Repository) and then it can be synchronized with runtime model by Routing Manager.

One more “hidden” feature of the Routing Service can be seen in the above picture, such as scalability. Decomposition of the application into the small business oriented services and composition via a routing service; we can control scalability of the application. We can assign localhost or cluster address of the logical endpoints based on the routing rules.

From the virtualization point of the view, the following picture shows a manageable composite application:

 

As you can see, the Composite Application is driven by logical endpoints, therefore can be declared within the logical model without the physical knowledge where they are located. Only the Runtime Repository knows these locations and can be easily managed based on requirements, for example: dev, staging, QA, production, etc.

This article is focusing on the Routing Manager hosted on IIS/WAS. I am assuming you have some working experience or understand features of the WCF4 Routing Service.

OK, let’s get started with Concept and Design of the Manageable Routing Service.

 

Concept and Design

The concept and design of the Routing Manager hosted on IIS/WAS is based on the extension of the WCF4 Routing Service for additional features such as downloading metadata from Repository in the loosely coupled manner. The plumbing part is implemented as a common extension to services (RoutingService and RoutingManager) named as routingManager. Adding the routingManager behavior to the routing behavior (see the following code snippet), we can boot a routing service from the repositoryEndpointName.

The routingManager behavior has the same attributes like routing one with additional attribute for declaration of the repository endpoint. As you can see, it is very straightforward configuration for startup routing service. Note, that the routingManager behavior is a pair to the routing behavior.

Now, in the case of updating routing behavior on the runtime, we need to plug-in a Routing Manager service and its service behavior routingManager. The following code snippet shows an example of activations without the .svc file within the same application:

and its service behavior:

Note, that the repositoryEndpointName can be addressed to different Repository than we have at the process startup.

 

Routing Manager Contract

Routing Manager Contract allows to communicate with Routing Manager service out of the appDomain. The Contract Operations are designed for broadcasting and point to point patterns. Operation can be specified for specific target or for unknown target (*) based on the machine and application names. The following code snippet shows the IRoutingManager contract:

[ServiceContract(Namespace = "urn:rkiss/2010/09/ms/core/routing", 
  SessionMode = SessionMode.Allowed)]
public interface IRoutingManager
{
  [OperationContract(IsOneWay = true)]
  void Refresh(string machineName, string applicationName);

  [OperationContract]
  void Set(string machineName, string applicationName, RoutingMetadata metadata);

  [OperationContract]
  void Reset(string machineName, string applicationName);

  [OperationContract]
  string GetStatus(string machineName, string applicationName);
}

The Refresh operation represents an inquiry event for refreshing a routing table from the Repository. Based on this event, the Routing Manager is going to pick-up a “fresh” routing metadata from the Repository (addressed by repositoryEndpointName) and update the routing table.

Routing Metadata Contract

This is a Data contract between the Routing Manager and Repository. I decided to use it for the contract routing configuration section as xml formatted text. This selection gives me an integration and implementation simplicity and easy future migration. The following code snippet is an example of the routing section:

and the following is Data Contract for repository:

[DataContract(Namespace = "urn:rkiss/2010/09/ms/core/routing")]
public class RoutingMetadata
{
  [DataMember]
  public string Config { get; set; }

  [DataMember]
  public bool RouteOnHeadersOnly { get; set; }

  [DataMember]
  public bool SoapProcessingEnabled { get; set; }

  [DataMember]
  public string TableName { get; set; }

  [DataMember]
  public string Version { get; set; }
}

OK, that should be all from the concept and design point on the view, except one thing what was necessary to figure out, especially for hosting services on the IIS/WAS. As we know [1], there is a RoutingExtension class in the System.ServiceModel.Routing namespace with a “horse” method ApplyConfiguration for updating routing service internal tables. 

I used the following “small trick” to access this RoutingExtension from another service such as RoutingManager hosted by its own factory.

The first routing message will stored the reference of the RoutingExtension into the AppDomain Data Slot under the well-known name, such as value of the CurrentVirtualPath.

serviceHostBase.Opened += delegate(object sender, EventArgs e)
{
    ServiceHostBase host = sender as ServiceHostBase;
    RoutingExtension re = host.Extensions.Find<RoutingExtension>();
    if (configuration != null && re != null)
    {
        re.ApplyConfiguration(configuration);

        lock (AppDomain.CurrentDomain.FriendlyName)
        {
            AppDomain.CurrentDomain.SetData(this.RouterKey, re);
        }
    }
};

Note, that both services such as RoutingService and RoutingManager are hosted under the same virtual path, therefore the RoutingManager can get this Data Slot value and cast it to the RoutingExtension. The following code snippet shows this fragment:

private RoutingExtension GetRouter(RoutingManagerBehavior manager)
{
  // ...
      
  lock (AppDomain.CurrentDomain.FriendlyName)
  {
    return AppDomain.CurrentDomain.GetData(manager.RouterKey) as RoutingExtension;
  }         
}

Ok, now it is the time to show the usage of the Routing Manager.

 

Usage and Test

The Manageable Router (RoutingService + RoutingManager) features and usage, hosted on the IIS/WAS, can be demonstrated via the following test solution. The solution consists of the Router and simulators for Client, Services and LocalRepository. 

The primary focus is on the Router, as shown in the above picture. As you can see, there are no .svc files, etc., just configuration file only. That’s right. All tasks to setup and configure manageable Router are based on the metadata stored in the web.config and Repository (see later discussion).

The Router project has been created as an empty web project under http://localhost/Router/ virtualpath, adding an assembly reference from RoutingManager project and declaring the following sections in the web.config.

Let’s describe these sections in more details.

Part 1. – Activations

These sections are mandatory for any Router such as activation of the RoutingService and RoutingManager service, behavior extension for routingManager and declaring client endpoint for Repository connectivity. The following picture shows these sections:

Note, this part also declares relative address for our Router. In the above example, the entry point for routing message is ~/Pilot.svc and access to RoutingManager has address ~/PilotManager.svc.

Part 2. – Service Endpoints

In these sections, we have to declare endpoints for two services such as RoutingService and RoutingManager. The RoutingService endpoints have untyped contracts defined in the System.ServiceModel.Routing namespace. In this test solution, we are using two contracts, one for notification (OneWay) and the other one is for RequestReply message exchange. The binding is used by basicHttpBinding, but it can be any standard or custom binding based on the requirements.

The RoutingManager service is configured with simple basicHttpBinding endpoint, but in the production version, it should use a custom udp channel for broadcasting message to trigger the pull metadata process from the Repository across the cluster.

 

Part 3. – Plumbing RoutingService and Manager together

This section will attach a RoutingService to the RoutingManager for accessing its RoutingExtension in the runtime.

The first extBehavior section is a configuration of the routing boot process. The second one is a section for downloading routing metadata during the runtime.

 OK, that’s all for creating a manageable Router.

The following picture shows a full picture of the solution:

 

 

As you can see, there is the Manageable Router (hosted in the IIS/WAS) for integration of the composite application. On the left hand side is the Client simulator to generate two operations (Notify and Echo) to the Service1 and/or Service2 based on the routing rules. The Client and Services are regular WCF self-hosted applications, the client can talk directly to the Services or via the Router.

Local Repository

Local Repository represents a metadata storage of the metadata such as logical centralized application model, deployment model, runtime model, etc. Models are created during the design time and based on the deployment model are pushed (physical decentralized) to the targets where they are projecting on the runtime. For example: The RouterManager assembly and web.config are metadata for deploying model from the Repository to the IIS/WAS Target.

During the runtime, some components have capability to update behavior based on the new metadata pulled from the Repository. For example, this component is a manageable Router (RouterService + RouterManager). Building Enterprise Repository and Tools is not a simple task, see more details about Microsoft strategy here [6] and interesting example here [7], [8].

In this article, I included very simple Local Repository for Routing metadata with self-hosting service to demonstrate a capability of the RoutingManager Service. The Routing metadata is described by system.serviceModel section. The following picture shows a configuration root section for remote routing metadata:

 

As you can see, the content of the system.ServiceModel section is similar to the target web.config. Note, that the Repository is holding these sections only. They are related to the Routing metadata. By selecting RoutingTable tab, the routing rules will be displayed in the table form:

Any changes in the Routing Table will update a local routing metadata by pressing the button Finnish, but runtime Router must be notified about this change by pressing button Refresh. In this scenario, the LocalRepository will send an inquiry message to the RoutingManager for pulling a new routing metadata. You can see this action in the Status tab.

Routing Rules

The above picture shows a Routing Table as a representation of the Routing Rules mapped to the routing section in the configuration metadata. This test solution has a pre-build routing ruleset with four rules. Let’s describes these rules. Note, we are using an XPath filter for message body, therefore the option RouteOnHeadersOnly must be unchecked. Otherwise the Router will throw an exception.

The Router is deployed with two inbound endpoints such as SimplexDatagram and RequestReply, therefore the received message will be routed based on the following rules:

Request/Reply rules

First, as the highest priority (level 3) the message is buffered for xpath body expression

starts-with(/s11:Envelope/s11:Body/rk:Echo/rk:topic, 2)

if the xpath expression is true, then the copied message is routing to the outbound endpoint TE_Service1, else the copied message is forwarded to the TE_Service2 (see the filter aa)

SimplexDatagram rules

This is a multicast routing (same priority 2) to the two outbound endpoints such as TE_Service1 and TE_Service2. If the message cannot be delivered to the TE_Service2, the alternative endpoint from the backup list is used, such as Test1 (queue). Note, that the message is not buffered, it is passed directly (filterType = EndpointName) from endpointNotify endpoint.

 

Test

Testing Router is a very simple process. Launch the Client, Service1, Service2 and Local Repository programs, create VirtualDirectory in IIS/WAS for http://localhost/Router project and the solution is ready for testing. The following are instruction steps:

  1. On the Client form, press button Echo. You should see a message routed to the Service2
  2. Press button Echo again, the message is routed to the Service1
  3. Press button Echo again, the message is routed to the Service2
  4. Change Router combo box to: http://localhost/Router/Pilot.svc/Notify
  5. Press button Event, see notification messages in both services

You can play with Local Repository to change the routing rules to see how the Router will handle the delivery messages.

For testing a backup rule, create a transactional queue Test1 and close the Service2 console program and follow the Step 2. and 3. You should see messages in the Service1 and queue.

 

Troubleshooting

There are two kinds of troubleshooting in the manageable Router. The first one is a built-in standard WCF tracing log and its viewing by Microsoft Service Trace Viewer program. The Router web.config file has already specified this section for diagnostics, but it is commented.

The second way to troubleshoot router with focus on the message flowing is built-in custom message trace inspector. This inspector is injected automatically by RoutingManager and its service behavior. We can use DebugView utility program from Windows Sysinternals to view the trace outputs from the Router.

 

Some Router Tips

1. Centralizing physical outbound connections into one Router enables the usage of logical connections (alias addresses) for multiple applications. The following picture shows this schema:

Instead of using physical outbound endpoints for each application router, we can create one master Router for virtualization of all public outbound endpoints. In this scenario, we need to manage only the master router for each physical outbound connection. The same strategy can be used for physical inbound endpoints. Another advantage of this router hierarchy is centralizing pre-processing and post-processing services.

2. As I mentioned earlier, the Router enables decomposition of the business workflow into small business oriented services, for instance: managers, workers, etc. The composition of the business workflow is declared by Routing Table which represents some kind of dispatcher of the messages to the correct service. We should use ws binding with a custom headers to simplify dispatching messages via a router based on the headers only.

 

Implementation

Based on the concept and design, there are two pieces for implementation, such as RoutingManager service and its extension behavior. Both modules are using the same custom config library, where useful static methods are located for getting clr types from the metadata stored in the xml formatted resource. I used this library in my previous articles (.Net 3) and I extended it for the new routing section. 

In the following code snippet I will show you how straightforward implementation is done.

The following code snippet is a demonstration of the Refresh implementation for RoutingManager Service. We need to get some configurable properties from the routingManager behavior and access to the RouterExtension. Once we have them, the RepositoryProxy.GetRouting method is invoked to obtain routing metadata from the Repository.

We get the configuration section in the xml formatted text like from the application config file. Now, using the “horse” config library, we can deserialize a text resource into the clr object, such as  MessageFilterTable<IEnumerable<ServiceEndpoint>>.

Then the RoutingConfiguration instance is created and passed to the router.ApplyConfiguration process. The rest of the magic is done in the RoutingService.

public void Refresh(string machineName, string applicationName)
{
  RoutingConfiguration rc = null;
  
  RoutingManagerBehavior manager = 
    OperationContext.Current.Host.Description.Behaviors.Find<RoutingManagerBehavior>();
  
  RoutingExtension router = this.GetRouter(machineName, applicationName, manager);

  try
  {
    if (router != null)
    {
      RoutingMetadata metadata = 
        RepositoryProxy.GetRouting(manager.RepositoryEndpointName, 
         Environment.MachineName, manager.RouterKey, manager.FilterTableName);
         
      string tn = metadata.TableName == null ? 
                  manager.FilterTableName : metadata.TableName;
        
      var ft = ServiceModelConfigHelper.CreateFilterTable(metadata.Config, tn);

      rc = new RoutingConfiguration(ft, metadata.RouteOnHeadersOnly);
      rc.SoapProcessingEnabled = metadata.SoapProcessingEnabled;
         
      router.ApplyConfiguration(rc);

      // insert a routing message inspector
      foreach (var filter in rc.FilterTable)
      {
        foreach (var se in filter.Value as IEnumerable<ServiceEndpoint>)
        {
          if (se.Behaviors.Find<TraceMessageEndpointBehavior>() == null)
            se.Behaviors.Add(new TraceMessageEndpointBehavior());
        }
      }
    }
  }
  catch (Exception ex)
  {
     RepositoryProxy.Event( ...);
  }
}

The last action in the above Refresh method is injecting the TraceMessageEndpointBehavior for troubleshooting messages within the RoutingService on the Trace output device.

The next code snippets show some details from the ConfigHelper library:

public static MessageFilterTable<IEnumerable<ServiceEndpoint>>CreateFilterTable(string config, string tableName)
{
  var model = ConfigHelper.DeserializeSection<ServiceModelSection>(config);
  
  if (model == null || model.Routing == null || model.Client == null)
    throw new Exception("Failed for validation ...");

  return CreateFilterTable(model, tableName);
}

 

The following code snippet shows a generic method for deserializing a specific type section from the config xml formatted text:

public static T DeserializeSection<T>(string config) where T : class
{
  T cfgSection = Activator.CreateInstance<T>();
  byte[] buffer = 
    new ASCIIEncoding().GetBytes(config.TrimStart(new char[]{'\r','\n',' '}));
  XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
  xmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment;

  using (MemoryStream ms = new MemoryStream(buffer))
  {
    using (XmlReader reader = XmlReader.Create(ms, xmlReaderSettings))
    {
      try
      {
        Type cfgType = typeof(ConfigurationSection);
        
        MethodInfo mi = cfgType.GetMethod("DeserializeSection", 
                BindingFlags.Instance | BindingFlags.NonPublic);
                
        mi.Invoke(cfgSection, new object[] { reader });
      }
      catch (Exception ex)
      {
        throw new Exception("....");
      }
    }
  }
  return cfgSection;
}

Note, the above static method is a very powerful and useful method for getting any type of config section from the xml formatted text resource, which allows us using the metadata stored in the database instead of the file system – application config file. 

 

 

Conclusion

In conclusion, this article described a manageable Router based on the WCF4 Routing Service. Manageable Router is allowing dynamically change routing rules from the centralized logical model stored in the Repository. The Router represents a virtualization component for mapping logical endpoints to the physical ones and it is a fundamental component in the model driven distributed architecture.

 

References:

[1] http://msdn.microsoft.com/en-us/library/ee517421(v=VS.100).aspx

[2] http://blogs.msdn.com/routingrules/archive/2010/02/09/routing-service-features-dynamic-reconfiguration.aspx

[3] http://weblogs.thinktecture.com/cweyer/2009/05/whats-new-in-wcf4-routing-service—or-look-ma-just-one-service-to-talk-to.html

[4] http://dannycohen.info/2010/03/02/wcf-4-routing-service-multicast-sample/

[5] http://blogs.profitbase.com/tsenn/?p=23

[6] SQL Server Modeling CTP and Model-Driven Applications

[7] Model Driven Content Based Routing using SQL Server Modeling CTP – Part I

[8] Model Driven Content Based Routing using SQL Server Modeling CTP – Part II

[9] Intermediate Routing