Implementing a WCF Service in the Real World

0
305
18 min read

WCF is the acronym for Windows Communication Foundation. It is Microsoft’s latest technology that enables applications in a distributed environment to communicate with each other.

In this article by, Mike Liu, author of  WCF 4.0 Multi-tier Services Development with LINQ to Entities, we will create and test the WCF service by following these steps:

  • Create the project using a WCF Service Library template
  • Create the project using a WCF Service Application template
  • Create the Service Operation Contracts
  • Create the Data Contracts
  • Add a Product Entity project
  • Add a business logic layer project
  • Call the business logic layer from the service interface layer
  • Test the service

Here ,In this article, we will learn how to separate the service interface layer from the business logic layer

(Read more interesting articles on WCF 4.0 here.)

Why layer a service?

An important aspect of SOA design is that service boundaries should be explicit, which means hiding all the details of the implementation behind the service boundary. This includes revealing or dictating what particular technology was used.

Furthermore, inside the implementation of a service, the code responsible for the data manipulation should be separated from the code responsible for the business logic. So in the real world, it is always good practice to implement a WCF service in three or more layers. The three layers are the service interface layer, the business logic layer, and the data access layer.

  • Service interface layer: This layer will include the service contracts and operation contracts that are used to define the service interfaces that will be exposed at the service boundary. Data contracts are also defined to pass in and out of the service. If any exception is expected to be thrown outside of the service, then Fault contracts will also be defined at this layer.
  • Business logic layer: This layer will apply the actual business logic to the service operations. It will check the preconditions of each operation, perform business activities, and return any necessary results to the caller of the service.
  • Data access layer: This layer will take care of all of the tasks needed to access the underlying databases. It will use a specific data adapter to query and update the databases. This layer will handle connections to databases, transaction processing, and concurrency controlling. Neither the service interface layer nor the business logic layer needs to worry about these things.

Layering provides separation of concerns and better factoring of code, which gives you better maintainability and the ability to split out layers into separate physical tiers for scalability. The data access code should be separated into its own layer that focuses on performing translation services between the databases and the application domain. Services should be placed in a separate service layer that focuses on performing translation services between the service-oriented external world and the application domain.

The service interface layer will be compiled into a separate class assembly and hosted in a service host environment. The outside world will only know about and have access to this layer. Whenever a request is received by the service interface layer, the request will be dispatched to the business logic layer, and the business logic layer will get the actual work done. If any database support is needed by the business logic layer, it will always go through the data access layer.

Creating a new solution and project using WCF templates

We need to create a new solution for this example and add a new WCF project to this solution. This time we will use the built-in Visual Studio WCF templates for the new project.

Using the C# WCF service library template

There are a few built-in WCF service templates within Visual Studio 2010; two of them are Visual Studio WCF Service Library and Visual Studio WCF Service Application. In this article, we will use the service library template.

Follow these steps to create the RealNorthwind solution and the project using the service library template:

  1. Start Visual Studio 2010, select menu option File New | Project…|, and you will see the New Project dialog box. From this point onwards, we will create a completely new solution and save it in a different location.
  2. In the New Project window, specify Visual C# WCF | WCF| Service Library as the project template, RealNorthwindService as the (project) name, and RealNorthwind as the solution name. Make sure that the checkbox Create directory for solution is selected.

  3. Click on the OK button, and the solution is created with a WCF project inside it. The project already has an IService1.cs file to define a service interface and Service1.cs to implement the service. It also has an app.config file, which we will cover shortly.

Using the C# WCF service application template

Instead of using the Visual Studio WCF Service Library template to create our new WCF project, we can use the Visual Studio Service Application template to create the new WCF project.

Because we have created the solution, we will add a new project using the Visual Studio WCF Service Application template.

  1. Right-click on the solution item in Solution Explorer, select menu option Add New Project…| from the context menu, and you will see the Add New Project dialog box.
  2. In the Add New Project window, specify Visual C# | WCF Service Application as the project template, RealNorthwindService2 as the (project) name, and leave the default location of C:SOAWithWCFandLINQProjectsRealNorthwind unchanged.

    Implementing a WCF Service in the real world

  3. Click on the OK button and the new project will be added to the solution.The project already has an IService1.cs file to define a service interface, and Service1.svc.cs to implement the service. It also has a Service1.svc file and a web.config file, which are used to host the new WCF service. It has also had the necessary references added to the project such as System.ServiceModel.

You can follow these steps to test this service:

  • Change this new project, RealNorthwindService2, to be the startup project(right-click on it from Solution Explorer and select Set as Startup Project). Then run it (Ctrl + F5 or F5). You will see that it can now run. You will see that ASP.NET Development Server has been started, and a browser is open listing all of the files under the RealNorthwindService2 project folder.Clicking on the Service1.svc file will open the metadata page of the WCF service in this project.

If you have pressed F5 in the previous step to run this project, you might see a warning message box asking you if you want to enable debugging for the WCF service. As we said earlier, you can choose enable debugging or just run in the non-debugging mode.

You may also have noticed that the WCF Service Host is started together with ASP.NET Development Server. This is actually another way of hosting a WCF service in Visual Studio 2010. It has been started at this point because, within the same solution, there is a WCF service project (RealNorthwindService) created using the WCF Service Library template.

So far we have used two different Visual Studio WCF templates to create two projects. The first project, using the C# WCF Service Library template, is a more sophisticated one because this project is actually an application containing a WCF service, a hosting application (WcfSvcHost), and a WCF Test Client. This means that we don’t need to write any other code to host it, and as soon as we have implemented a service, we can use the built-in WCF Test Client to invoke it. This makes it very convenient for WCF development.

The second project, using the C# WCF Service Application template, is actually a website. This is the hosting application of the WCF service so you don’t have to create a separate hosting application for the WCF service. As we have already covered them and you now have a solid understanding of these styles, we will not discuss them further. But keep in mind that you have this option, although in most cases it is better to keep the WCF service as clean as possible, without any hosting functionalities attached to it.

To focus on the WCF service using the WCF Service Library template, we now need to remove the project RealNorthwindService2 from the solution.

In Solution Explorer, right-click on the RealNorthwindService2 project item and select Remove from the context menu. Then you will see a warning message box. Click on the OK button in this message box and the RealNorthwindService2 project will be removed from the solution. Note that all the files of this project are still on your hard drive. You will need to delete them using Windows Explorer.

Creating the service interface layer

In this article, we will create the service interface layer contracts.

Because two sample files have already been created for us, we will try to reuse them as much as possible. Then we will start customizing these two files to create the service contracts.

Creating the service interfaces

To create the service interfaces, we need to open the IService1.cs file and do the following:

  1. Change its namespace from RealNorthwindService to:

    MyWCFServices.RealNorthwindService

  2. Change the interface name from IService1 to IProductService. Don’t be worried if you see the warning message before the interface definition line, as we will change the web.config file in one of the following steps.
  3. Change the first operation contract definition from this line:

    string GetData(int value);

    to this line:

    Product GetProduct(int id);

  4. Change the second operation contract definition from this line:

    CompositeType GetDataUsingDataContract(CompositeType composite);

    to this line:

    bool UpdateProduct(Product product);

  5. Change the filename from IService1.cs to IProductService.cs.

With these changes, we have defined two service contracts. The first one can be used to get the product details for a specific product ID, while the second one can be used to update a specific product. The product type, which we used to define these service contracts, is still not defined.

The content of the service interface for RealNorthwindService.ProductService should look like this now:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace MyWCFServices.RealNorthwindService
{
[ServiceContract] public interface IProductService
{
[OperationContract] Product GetProduct(int id);
[OperationContract] bool UpdateProduct(Product product);
// TODO: Add your service operations here
}
}

This is not the whole content of the IProductService.cs file. The bottom part of this file should still have the class, CompositeType.

Creating the data contracts

Another important aspect of SOA design is that you shouldn’t assume that the consuming application supports a complex object model. One part of the service boundary definition is the data contract definition for the complex types that will be passed as operation parameters or return values.

For maximum interoperability and alignment with SOA principles, you should not pass any .NET-specific types such as DataSet or Exceptions across the service boundary. You should stick to fairly simple data structure objects such as classes with properties and backing member fields. You can pass objects that have nested complex types such as ‘Customer with an Order collection’. However, you shouldn’t make any assumption about the consumer being able to support object-oriented constructs such as inheritance or base-classes for interoperable web services.

In our example, we will create a complex data type to represent a product object. This data contract will have five properties: ProductID, ProductName, QuantityPerUnit, UnitPrice, and Discontinued. These will be used to communicate with client applications. For example, a supplier may call the web service to update the price of a particular product or to mark a product for discontinuation.

It is preferable to put data contracts in separate files within a separate assembly but, to simplify our example, we will put DataContract in the same file as the service contract. We will modify the file, IProductService.cs, as follows:

  1. Change the DataContract name from CompositeType to Product.
  2. Change the fields from the following lines:

    bool boolValue = true;
    string stringValue = “Hello “;

    to these seven lines:

    int productID;
    string productName;
    string quantityPerUnit;
    decimal unitPrice;
    bool discontinued;

  3. Delete the old boolValue and StringValue DataMember properties. Then, for each of the above fields, add a DataMember property. For example, for productID, we will have this DataMember property:

    [DataMember]public int ProductID
    {
    get { return productID; }
    set { productID = value; }
    }

A better way is to take advantage of the automatic property feature of C#, and add the following ProductID DataMember without defining the productID field:

[DataMember]public int ProductID { get; set; }

To save some space, we will use the latter format. So, we need to delete all of those field definitions and add an automatic property for each field, with the first letter capitalized.

The data contract part of the finished service contract file, IProductService.cs,should now look like this:

[DataContract]public class Product
{
[DataMember] public int ProductID { get; set; }
[DataMember] public string ProductName { get; set; }
[DataMember] public string QuantityPerUnit { get; set; }
[DataMember] public decimal UnitPrice { get; set; }
[DataMember] public bool Discontinued { get; set; }
}

Implementing the service contracts

To implement the two service interfaces that we defined, open the Service1.cs file and do the following:

    • Change its namespace from RealNorthwindService to MyWCFServices.RealNorthwindService.
    • Change the class name from Service1 to ProductService. Make it inherit from the IProductService interface, instead of IService1. The class definition line should be like this:

      public class ProductService : IProductService

    • Delete the GetData and GetDataUsingDataContract methods.
    • Add the following method, to get a product:

      public Product GetProduct(int id)
      {
      // TODO: call business logic layer to retrieve product
      Product product = new Product();
      product.ProductID = id;
      product.ProductName = “fake product name from service layer”;
      product.UnitPrice = (decimal)10.0;
      return product;
      }

In this method, we created a fake product and returned it to the client.Later, we will remove the hard-coded product from this method and call the business logic to get the real product.

  • Add the following method to update a product:

    public bool UpdateProduct(Product product)
    {
    // TODO: call business logic layer to update product
    if (product.UnitPrice <= 0)
    return false;
    else
    return true;
    }

    Also, in this method, we don’t update anything. Instead, we always return true if a valid price is passed in.

  • Change the filename from Service1.cs to ProductService.cs. The content of the ProductService.cs file should be like this:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    namespace MyWCFServices.RealNorthwindService
    {
    public class ProductService : IProductService
    {
    public Product GetProduct(int id)
    {
    // TODO: call business logic layer to retrieve product
    Product product = new Product();
    product.ProductID = id;
    product.ProductName = “fake product name
    from service layer”;
    product.UnitPrice = (decimal)10;
    return product;
    }
    public bool UpdateProduct(Product product)
    {
    // TODO: call business logic layer to update product
    if (product.UnitPrice <= 0)
    return false;
    else
    return true;
    }
    }
    }

Modifying the app.config file

Because we have changed the service name, we have to make the appropriate changes to the configuration file. Note that when you rename the service, if you have used the refactor feature of Visual Studio, some of the following tasks may have been done by Visual Studio.

Follow these steps to change the configuration file:

  1. Open the app.config file from Solution Explorer.
  2. Change all instances of the RealNorthwindService string except the one in baseAddress to MyWCFServices.RealNorthwindService. This is for the namespace change.
  3. Change the RealNorthwindService string in baseAddress to MyWCFServices/RealNorthwindService.
  4. Change all instances of the Service1 string to ProductService. This is for the actual service name change.
  5. Change the service address port from 8731 to 8080. This is to prepare for the client application, which we will create soon.
  6. You can also change Design_Time_Addresses to whatever address you want, or delete the baseAddress part from the service. This can be used to test your service locally. We will leave it unchanged for our example.

The content of the app.config file should now look like this:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>

<system.web>

<compilation debug=”true” />

</system.web>

<!– When deploying the service library project, the content of the
config file must be added to the host’s app.config file.
System.Configuration does not support config files for libraries. –>

<system.serviceModel>

<services>

<service name=”MyWCFServices.RealNorthwindService.
ProductService”>

<endpoint address=”” binding=”wsHttpBinding”
contract=”MyWCFServices.
RealNorthwindService.IProductService”>

<identity>

<dns value=”localhost” />

</identity>

</endpoint>

<endpoint address=”mex” binding=”mexHttpBinding”
contract=”IMetadataExchange” />

<host>

<baseAddresses>

<add baseAddress=”http://localhost:8080/Design_Time_
Addresses/MyWCFServices/
RealNorthwindService/ProductService/” />

</baseAddresses>

</host>

</service>

</services>

<behaviors>

<serviceBehaviors>
<behavior>
<!– To avoid disclosing metadata information,
set the value below to false and remove the metadata
endpoint above before deployment –>
<serviceMetadata httpGetEnabled=”True”/>
<!– To receive exception details in faults for debugging
purposes, set the value below to true. Set to false before
deployment
to avoid disclosing exception information –>

<serviceDebug includeExceptionDetailInFaults=”False” />

</behavior>

</serviceBehaviors>

</behaviors>

</system.serviceModel>

</configuration>

Testing the service using WCF Test Client

Because we are using the WCF Service Library template in this example, we are now ready to test this web service. As we pointed out when creating this project, this service will be hosted in the Visual Studio 2010 WCF Service Host environment.

To start the service, press F5 or Ctrl + F5. WcfSvcHost will be started and WCF Test Client is also started. This is a Visual Studio 2010 built-in test client for WCF Service Library projects.

In order to run the WCF Test Client you have to log into your machine as a local administrator. You also have to start Visual Studio as an administrator because we have changed the service port from 8732 to 8080 (port 8732 is pre-registered but 8080 is not).

Again, if you get an Access is denied error, make sure you run Visual Studio as an administrator (under Windows XP you need to log on as an administrator).

Now from this WCF Test Client we can double-click on an operation to test it.First, let us test the GetProduct operation.

Now the message Invoking Service… will be displayed in the status bar as the client is trying to connect to the server. It may take a while for this initial connection to be made as several things need to be done in the background. Once the connection has been established, a channel will be created and the client will call the service to perform the requested operation. Once the operation has been completed on the server side, the response package will be sent back to the client, and the WCF Test Client will display this response in the bottom panel.

If you started the test client in debugging mode (by pressing F5), you can set a breakpoint at a line inside the GetProduct method in the RealNorthwindService.cs file, and when the Invoke button is clicked, the breakpoint will be hit so that you can debug the service as we explained earlier. However, here you don’t need to attach to the WCF Service Host.

Note that the response is always the same, no matter what product ID you use to retrieve the product. Specifically, the product name is hard-coded, as shown in the diagram. Moreover, from the client response panel, we can see that several properties of the Product object have been assigned default values.

Also, because the product ID is an integer value from the WCF Test Client, you can only enter an integer for it. If a non-integer value is entered, when you click on the Invoke button, you will get an error message box to warn you that you have entered a value with the wrong type.

Now let’s test the operation, UpdateProduct.

The Request/Response packages are displayed in grids by default but you have the option of displaying them in XML format. Just select the XML tab at the bottom of the right-side panel, and you will see the XML-formatted Request/Response packages. From these XML strings, you can see that they are SOAP messages.

Besides testing operations, you can also look at the configuration settings of the web service. Just double-click on Config File from the left-side panel and the configuration file will be displayed in the right-side panel. This will show you the bindings for the service, the addresses of the service, and the contract for the service.

What you see here for the configuration file is not an exact image of the actual configuration file. It hides some information such as debugging mode and service behavior, and includes some additional information on reliable sessions and compression mode.

If you are satisfied with the test results, just close the WCF Test Client, and you will go back to Visual Studio IDE. Note that as soon as you close the client, the WCF Service Host is stopped. This is different from hosting a service inside ASP.NET Development Server, where ASP.NET Development Server still stays active even after you close the client.

LEAVE A REPLY

Please enter your comment!
Please enter your name here