Self-Hosting WCF Services
September 2, 2011Windows Reimagined
September 14, 2011In this post I will explain how you can use Synergy .NET to expose a WCF service. I’ll be showing you how to create WCF service and data contracts totally from scratch, using Synergy .NET. We’ll be defining new classes, not working with existing routines and records. That’s not to say that you can’t work with existing routines and records, in fact you may well chose to do so WITHIN a service that you create, but the focus of this post is on writing new code for the future.
This is the sixth in a series of posts relating to the various ways in which Synergy developers can use of Windows Communication Foundation (WCF) when building their applications. The posts in the series are:
- Building Distributed Apps with Synergy/DE and WCF
- Exposing WCF Services using xfNetLink .NET
- Hosting WCF Services in an ASP.NET Web Application
- Exposing WCF services using Synergy .NET Interop
- Self-Hosting WCF Services
- Exposing WCF services using Synergy .NET (this post)
In earlier posts I demonstrated how it was possible to expose WCF services using existing source code, either by transforming an xfNetLink .NET assembly into a WCF service, or by adding the traditional Synergy subroutines and functions that existed “underneath” an xfNetLink .NET assembly to a new Synergy .NET Interop project. There are valid use cases for both of these strategies, depending on what you’re starting with, however there are also some disadvantages to both approaches.
Perhaps the most significant disadvantage is that the external interface of the WCF service contracts that get exposed are defined by the parameters and return values of one or more traditional Synergy routines. And the data contracts are defined by Synergy record layouts defined in a repository. Also the actual WCF contracts that are exposed are under the control of the code generators that create the contracts, either GENCS, or the logic within the Interop project. This means that as a developer you’re kind of stuck with the defaults that those tools provide.
WCF has diverse capabilities which are defined and controlled through a large number of code and configuration options, and many of these are controlled via in-code attributes which are applied to the service and data contracts that make up a service. But when you work with services that are generated for you you don’t get to determine what options are used. So in some cases you might find that working with generated services is a little too restrictive.
This post will show how to create your own WCF services from scratch, in a way that makes all of the capabilities of WCF available to you.
The WCF Service Library Template
Although it has been possible to create WCF services with Synergy .NET since the product was introduced in version 9.5.1, the process became a lot easier in 9.5.1a. This was because we added a new project template called WCF Service Library. To create a new WCF service we simply start Visual Studio and create a new project based on the WCF Service Library template:
When you use the project template you create a new class library which is pre-configured appropriately for the development of WCF service and data contract classes.
Over and above a regular class library, a WCF Service Library development project will include:
- References to the following .NET Framework assembles
- System.Core
- System.Runtime.Serialization
- System.ServiceModel
- System.Xml
- An example of how to define WCF service and data contracts.
- IService1.dbl
- An example of how to implement the service defined by a service contract.
- Service1.dbl
Before we go too much further let me make it clear that I don’t particularly like the example code that is provided by the project template, despite being the one who actually provided it for the distribution! But there is a good reason why the example code is the way that it is. That reason is that the example implements in Synergy the the exact same example that Microsoft provide when you create a new WCF Service Library using either C# or Visual Basic.
Service Contracts
So what do we have in the example? Most developers agree that it is good practice to separate the definition of a service contract from the actual implementation of the contract, and for service contracts this is achieved using an interface. In the example file called IService1.dbl you will find code like this:
- import System
- import System.Collections.Generic
- import System.Runtime.Serialization
- import System.ServiceModel
- import System.Text
- namespace MyWcfServices
- {ServiceContract}
- public interface IService1
- {OperationContract}
- method GetData, string
- required in val, int
- endmethod
- {OperationContract}
- method GetDataUsingDataContract, @CompositeType
- composite, @CompositeType
- endmethod
- ;;TODO: Add your service operations here
- endinterface
- endnamespace
The example defines a WCF service in a class named Service1 and therefore, following accepted best practices, the name of the interface that defines the external view of the class is prefixed with a capital I. You will notice that the {ServiceContract} attribute is applied to the interface, which essentially means that any class which implements the interface will expose a WCF service contract.
Within the interface you will see that the example code defined two methods, named GetData and GetDataUsingDataContract. Both of these methods have the {OperationContract} attribute applied, which means that the methods will be exposed as operations of the WCF service … or in other words they are methods that a remote client accessing the service may call.
The GetData method accepts a single parameter which is an integer number, and has a return type of string.
The GetDataUsingDataContract method on the other hand has a single single parameter which is an object of type “CompositeType” and also returns an object of the same type. CompositeType is a class representing a complex data type (think OO version of a record) and is defined a little further down in the code:
By the way, you will notice that the methods that are described in the interface do not have accessibility specified. This is because by convention, all members of an interface are considered public. You will also notice that there is no procedure division specified … there is no PROC statement. This is because the role of an interface is simply to DEFINE requirements for a class, or rather for the external interface of a class. Interfaces do not include any logic … that will be added in a class which IMPLEMENTS the interface.
Data Contracts
Data contracts define complex data types (data classes) that can be passed from a client to a service or returned from a service back to a client, and are simply defined via a class with public properties of the appropriate types.
In the example the class named CompositeType has two public properties, one of type boolean named BoolValue, and one of type string named StringValue. As is often the case, the value of the public properties is propagated within the class by storing the actual value of the property in private variables, in this case the mBoolValue and mStringValue fields.
- import System
- import System.Collections.Generic
- import System.Runtime.Serialization
- import System.ServiceModel
- import System.Text
- namespace MyWcfServices
- ;;Use a data contract as illustrated in the sample below to
- ;;add composite types to service operations
- {DataContract}
- public class CompositeType
- private mBoolValue, Boolean, true
- private mStringValue, String, “Hello “
- {DataMember}
- public property BoolValue, Boolean
- method get
- proc
- mreturn mBoolValue
- endmethod
- method set
- proc
- mBoolValue = value
- endmethod
- endproperty
- {DataMember}
- public property StringValue, String
- method get
- proc
- mreturn mStringValue
- endmethod
- method set
- proc
- mStringValue = value
- endmethod
- endproperty
- endclass
- endnamespace
What makes the CompositeType class a WCF data contract is the presence of the {DataContract} attribute immediately before the class declaration, and the {DataMember} attributes immediately before the declaration of each of the public properties. The {DataContract} attribute is used to ensure that it is possible to serialize an instance of the class for transmission over the wire between a client and a server, and the {DataMember} attributes define which members of the class will be included in that serialization, or in simpler terms, which members will be visible to client applications.
It should be noted that, despite being the case in the simple example provided by the project template, it is somewhat unusual to define multiple types within a single source file as is the case here. In a real application it is likely that each interface would be defined in its own source file, as would each data class. There is nothing technically wrong with the approach used in the example, and it does keep the definition of all of the contracts for a service together in one place, but you don’t have to do it that way.
Implementing a WCF Service
So in the simple example provided by the WCF Service Library project template we have looked at the definition of the service and data contracts for Service1 in the source file IService1.dbl. Now it’s time to look at the code that actually implements the service itself. That code is found in Service1.dbl.
- import System
- import System.Collections.Generic
- import System.Runtime.Serialization
- import System.ServiceModel
- import System.Text
- namespace MyWcfServices
- public class Service1 implements IService1
- public method GetData, String
- required in val, int
- endparams
- proc
- mreturn String.Format(“You entered: {0}”, val)
- endmethod
- public method GetDataUsingDataContract, @CompositeType
- composite, @CompositeType
- endparams
- proc
- if (composite==^null)
- throw new ArgumentNullException(“composite”)
- if (composite.BoolValue)
- composite.StringValue = composite.StringValue + “Suffix”
- mreturn composite
- endmethod
- endclass
- endnamespace
The code above is the code that implements Service1. You will notice that this is achieved by writing a class which implements the interface that describes the service contract that we talked about earlier.
Writing a class which implements an interface is simply a matter of ensuring that the class includes at least the members that are described by the interface … in this case the GetData and GetDataUsingDataContract methods. The class may also include other members not described in the interface, but MUST at least contain the members described by the interface.
You will also notice that both of the methods required by the interface are declared with PUBLIC accessibility. As mentioned earlier this is a requirement when implementing an interface. When we implement an interface we include the code that each method in the interface will execute, so here is where the actual functionality of the service is defined.
In the example code the GetData method simply takes the integer value that was received from the client and uses that value in a string which is returned to the client. So if a client application connects to an instance of this service and calls the GetData method passing a value of 5, the return value of the method call will be the string You Entered: 5.
The GetDataUsingDataContract method checks to ensure that an instance of the CompositeType class was received, than if the objects BoolValue property is set to true it appends the string Suffix to whatever is the current value of the objects StringValue property. The object is then returned via the method return value. Yea, I know, the dev at Microsoft must have been smoking something pretty questionable when they wrote this example. Something more meaningful would have been nice, but it is what it is!
Writing a WCF Service
So, there you have it. Writing a WCF service in Synergy .NET is pretty straight forward. You basically need to:
- Create a new assembly using the WCF Service Library project template.
- Define the external interface of your service via an interface that describes the service and operation contracts, and any data classes that may be required to define the data contracts that you need.
- Create a class which implements the service contract and includes the necessary functionality.
And remember we’re working in Synergy .NET here, so we have the full power of Synergy at out fingertips. If we need to access Synergy data that’s local to where the service will be hosted then we can go ahead and access that data directly, but if the data is remote then we can use xfServer to get to it – regardless of the system it resides on. We could also use an xfNetLink .NET assembly to allow us to get back into our traditional Synergy business logic, for all or part of the logic for the service. And of course we still have access to the SQL Connection API in order to access any relational databases that we may need to use. Of course we could also use other mechanisms in the .NET Framework to access a wide variety of data sources too.
Hosting the Service
If you’ve read the earlier posts in this series then you will already know that creating a WCF service is only part of the story, it also needs to be hosted somewhere. This has already been discussed in two earlier posts, so I don’t intend to repeat the information here.