devxlogo

WCF the Manual Way…the Right Way

WCF the Manual Way…the Right Way

isual Studio 2008 and the .NET 3.0 extensions for Visual Studio 2005 add several new templates that simplify creating .NET 3.0 items such as WPF forms, Workflows, and WCF services. Developers have used templates such as these since the beginning of time to create traditional application elements such as Windows Forms, Web Forms, and User Controls?so you might think that these templates are equally great. Unfortunately, creating WCF projects or project items come with more baggage than you can imagine. They also don’t exactly promote some best practices when designing WCF services.

So if you don’t use the built-in templates to create your services, what do you use? Well keep reading and I’ll show you how to create everything you need manually with ease while maintaining good design and coding practices.

WCF is probably one of the absolutely coolest technologies to come out of Microsoft. I think the unified model toward developing message-based applications and service-oriented applications is long overdue in our industry, and I’m glad to see that it came from Microsoft. That said, I’m not too crazy about the templates that come with Visual Studio 2008 or the 3.0 extensions for Visual Studio 2005. I feel Microsoft could have done a better job with code separation and the enforcement of good practices?never mind best practices.

Another area where I see developers doing things automatically and falling a bit short is in referencing services from client application. When developers used mainly web services, the choices were limited, but such is no longer the case. Adding service references automatically may not be the best way to write service consumers.

Fortunately you can easily solve these problems by creating all your service components manually; it’s not even that hard to do. This article assumes you have some basic knowledge of WCF services and the elements that comprise them; not too much, just a bit.

The Problem with WCF Templates
I love getting into political conversations, and one of my pet peeves is when politicians criticize and destroy current policy without offering a better solution for how things should be done. I won’t fall into that trap; instead, I’ll tell you exactly what I feel is wrong with the WCF-related project and item templates that come with Visual Studio, and then I’ll tell you how I think you can overcome these problems.

The current WCF templates in Visual Studio as well as the “Add Service Reference” tool suffer from one major problem: they do too much. Developers would have benefited a lot more from having more templates that do less. When you add a service, Visual Studio automatically creates both the contract and the service in your project?two things that should be in separate projects (for reasons I will explain later). Creating service web projects not only creates these two items but also the service host?which again, I feel should be in its own assembly. Both situations also add to the configuration file. While this is good for educational purposes, it can also clutter up an existing clean configuration file.

Instead, Visual Studio should include templates for individually creating all these elements. In addition, I’d like to see a project template to create a self-host project that’s not IIS-based. The Add Service Reference tool creates too much for you, and does not promote good code reuse. Not only does it create proxies for you, but it adds an immense amount of configuration information.

To illustrate what I mean, I’ll walk you through a project using the WCF templates and tools to develop a simple service and client. Then I’ll analyze what’s wrong with the results and provide alternatives.

Editor’s Note: This article was first published in the September/October 2008 issue of CoDe Magazine, and is reprinted here by permission.

Developing a Service and Consumer with Templates
This section shows how to develop a quick service and consumer using all the automated templates and tools that Visual Studio provides. But before getting started, this article assumes a little knowledge of WCF and thus uses several terms that are specific to the world of WCF, which I’ll define here:

  • Service Contract: An interface housing the operation definitions of a service.
  • Operation Contract: A method definition within the service contract which will be implemented by the service.
  • Service: A class implementing one or more service contracts, providing the implementation defined in the contracts.
  • Host: An application platform that serves as a listener for service requests.
  • Proxy: A class on the consume side that’s responsible for opening a channel between the consumer and the service and initiating calls to the service operations.
  • Endpoint: Defines where, how, and what a service will provide. This is used on both the service host side and the client side and can be defined in either code or declaratively.
  • ABCs of WCF: The three elements that make up a service endpoint definition: address, binding, and contract
  • Address: A URI location for a service.
  • Binding: The transport protocol to be used in communicating with a service.
  • Contract: The service contract exposed by an endpoint.

Creating a New Service Project
Visual Studio has three WCF-related project templates. Two are web-related; both are called “WCF Service” and do pretty much the same thing. There are two of them because one is available by selecting “Add New Project” and the other by selecting “Add New Web Site”. Both these project templates create five things for you:

  • An IIS-based service host
  • References to System.ServiceModel and System.Runtime.Serialization
  • An interface-based service contract
  • A service class
  • Configuration entries in the web.config file

The third project template, called the “WCF Service Library”, creates everything above except the service host. The project template adds configuration information in an app.config file. I find this a bit misleading because configuration files are used only in the client application and not in a library project. I understand that the addition of this configuration file is educational?it helps you see what the service parameters will look like?but of course you’d eventually need to copy that information to the client project’s configuration file.

I’m going to create a new “WCF Service” project. You’ll find the template in the web tree node of the project template dialog. Creating this project provides you with a new web application project that will serve as the service’s host. It also creates a code file called IService1 and a service file called Service1.svc. This latter file is analogous to an old web service’s ASMX file, and includes a code-behind class file. Since I created a web application project with this project template, the code-behind class for this SVC file is directly under it. If I had selected “Add New Web Site” instead, and chosen the “WCF Service” project template, the SVC file’s code-behind class as well as the IService1 code file would have been placed in the App_Code folder.

You might expect that the IService1 code file would contain the IService1 interface that serves as the service contract, but if you open it up you will see that it contains both the IService1 service contract and a class called CompositeType, which serves as a sample data contract. Here are the contents of the IService1 code file:

   [ServiceContract]   public interface IService1   {       [OperationContract]       string GetData(int value);          [OperationContract]       CompositeType GetDataUsingDataContract(         CompositeType composite);          // TODO: Add your service operations here   }      [DataContract]   public class CompositeType   {       bool boolValue = true;       string stringValue = "Hello ";          [DataMember]       public bool BoolValue       {           get { return boolValue; }           set { boolValue = value; }       }          [DataMember]       public string StringValue       {           get { return stringValue; }           set { stringValue = value; }       }   }

The Service1.svc file’s code-behind class implements the IService1 interface and provides operation implementations for both defined operations; one that uses the data contract class and one that does not. Look at the code for the actual service:

   public class Service1 : IService1   {      public string GetData(int value)      {          return string.Format("You entered: {0}",            value);      }         public CompositeType GetDataUsingDataContract(         CompositeType composite)      {          if (composite.BoolValue)          {              composite.StringValue += "Suffix";          }          return composite;      }   }

While I understand that the code samples that the built-in templates provides are merely starting points for making your own services and service elements, I feel strongly that Microsoft could have achieved the same results using other (non-existent) templates, such as a “Service Contract” template or a “Data Contract” template.

The Service1.svc file serves as the entry point for this service and looks like this:

   <%@ ServiceHost Language="C#" Debug="true"   Service="WcfService1.Service1"   CodeBehind="Service1.svc.cs" %>

In many ways this resembles an old ASMX file, and like an old ASMX file, the only attribute needed here is the Service attribute, which points to the service class that will be executed when this service entry point is reached.

All the code I’ve just shown you resides in my new web application project. The web application itself serves as the host for my service and requires a certain amount of configuration. Here’s the configuration that Visual Studio added automatically when I created this project:

                                                                                                                                                         

I won’t over-criticize this configuration because it’s not really overkill. Although the minimum configuration required to host the service is considerably less, the extra information can be pretty useful. When I mention a service’s minimum configuration, I’m referring to the service’s endpoint(s). The additional information in the preceding configuration supports the exposure of more detailed error information in fault cases and the exposure of metadata for use when clients use the “Add Service Reference.” Using this feature is one of the habits I want to get you out of in this article, so I prefer not to have this included in my configuration.

Consuming the Service
Any type of application can be a service consumer. Just as with old-fashioned web services, consumers need proxy classes to communicate with the services. Visual Studio makes it easy to create all this when you use the “Add Service Reference” option. You can use this feature to browse to a service and consume it from your client. Later, I’ll go over everything I see wrong with this process, but I’ll start by actually performing this task and examining what happens.

I created a Windows Forms application to consume the service I created earlier. When I right-click on my project and choose “Add Service Reference,” I can browse to the service address (see Figure 1) or simply drop-down the “Discover” button and select a service in my solution (where mine happens to reside). Because this technique creates proxy classes, service contracts, and data contracts in my client application, I need to choose a namespace in which to put them. For this example, I’ll accept the default namespace of ServiceReference1.

?
Figure 1. “Add Service Reference” Dialog: Select a service address or click the Discover button to select a service in your solution.

After adding the reference, Visual Studio creates several items in the client project, including a reference to System.ServiceModel and a new project tree section called “Service References” that contains one item called ServiceReference1. This is the namespace name I provided when I added the reference.

Several additional files are not visible unless you turn on the “Show All Files” option in Solutions Explorer. A couple of levels deep in the file tree beneath the “Service References” you’ll find a file called Reference.cs. This file contains the three elements mentioned: a class that represents the data contract the referenced service uses, an interface representing the service contract, and a proxy class used to access the service’s methods. Visual Studio places all these in a namespace composed of the project’s name and the ServiceReference1 name that was the default in the Add Reference dialog. Incidentally, if you add a reference to another service, you cannot reuse the same namespace. The created proxy class name is the referenced service name followed by the word “Client,” in this case, “Service1Client.”

To access the service my client application simply needs to instantiate the Service1Client class and call its methods, which have the same names as the methods defined in the IService1 interface.

The configuration automatically created by adding a reference is quite extensive. In fact, Visual Studio creates a binding configuration that displays every available attribute, each set to its default values (see Listing 1). Again, this is nice when you want to learn about all the attributes, otherwise? well, I’ll get back to that thought later.

The Critique
Using the conventional techniques for creating services and consumers, you can hit the ground running rather quickly; but is this a good thing? Here’s a brief analysis of what I find wrong with everything that you’ve just seen:

  • Problem: Data contracts and service contracts should be in their own assembly.
    Reason: When consumers are .NET, the contracts can be shared by them.
  • Problem: Services should be in their own assembly.
    Reason: Placing services in a separate assembly decouples them from the host.
  • Problem: Service host should be a separate project.
    Reason: Same as previous reason.
  • Problem: Service host’s web.config contains extraneous information.
    Reason: Metadata endpoints won’t be necessary for the techniques I’m planning to use.
  • Problem: Client proxies should be in their own assembly.
    Reason: More than one client application may want to use these services.
  • Problem: Adding a service reference?bad idea.
    Reason: Service and data contracts are duplicated, you have little control over the namespace name, and the process creates bloated configuration.

I’ll revisit each of these and provide alternative approaches in the next section. While I’ve described the absence of certain project and item templates as a shortcoming, and I’ll show you how to create everything manually, you can certainly create your own templates to compensate for those I feel are missing from Visual Studio is missing. There’s a lot of documentation on the web on how to do this; among which is Matt Milner’s MSDN Magazine article.

The Manual Way?the Right Way
Having Visual Studio do everything for you may seem nice initially, but as you noticed above, it adds a significant amount of extra details to both my service and my consumer that are simply not needed?and in my opinion, not recommended. I recommend you do it all manually.

Assembly Separation
Now I’ll talk about one of my biggest gripes, first and foremost. Accept the fact that when you design a service-oriented system, you’re going to be dealing with many assemblies. There’s nothing wrong with this in any type of design; so long as there are beneficial reasons for it.

When I design a WCF-based system, I’ll create separate assemblies for the following components:

  • Service and data contracts
  • Services
  • Business/ORM engines
  • Service hosts
  • Client proxies
  • Client applications

After describing how to separate out the WCF-based components, I’ll provide a step-by-step example by setting up an actual WCF-based application for both the service side and the client side.

The Contracts
The first piece of a service-oriented design I want to pull into its own assembly is the contracts. Though one of the tenets of SOA is that services should be able to service any type of client, .NET developers mostly deal with .NET on both sides. To anticipate this, I like to have both my service contracts and data contracts in their own assemblies. In the previous section I told you that Visual Studio created a copy of these on my consumer. Because I’ll use a different technique to consume the service this time around, I’ll need to create my own copies of the service and data contracts. And by placing them in their own assembly I’ll be able to reuse this assembly in both my service and consumer.

Splitting up your contracts into their own assemblies does not mean you should put every contract in a different assembly, nor does it mean separating service contracts from data contracts. Use logical judgment to decide how the separation should happen. Unless I find a reason not to, I keep service contracts and their associated data contracts in the same project. The decision as to whether to put all the contracts in one assembly or have multiple assemblies should be based on some kind of logical contract grouping. The groupings may be determined by the services that will be using my contracts. For example, this project has Order and Product services in the design, and those are very specific to the business solution I am designing, so I’d group their contracts together in a single assembly. I’ll follow that same grouping logic with the other services in the example.

One service in my system deals with obtaining geographical information. This service could certainly benefit other applications, so I chose to place the data and service contracts associated with it in its own assembly.

Another reason to consider splitting an assembly is security. Service contracts each have their own endpoint. One service can certainly implement multiple service contracts, thus having multiple endpoints. Perhaps one endpoint will be used for private access over the Intranet and another for public access over the Internet. I may chose to separate these contracts, which will make it easier to later create multiple proxy assemblies that different applications will use. One application may consume both the private and public contract, while another might require only the public one. Separating the assemblies ensures that projects don’t have access to things they does not need or should not access. I’ll go over the details of the contract implementation and service consumption later.

The Services
The next pieces of my design that I want in their own assemblies are the services themselves. I’ll split these up into one or more assemblies based on the categorization I mentioned earlier. I might end up with one assembly for all my services, but chances are I’ll have several, depending on how many services I have and their potential for inter-project reusability. Service projects will reference one or more of the contract assemblies I described previously. Also, depending on what these services do, there may be one or more business engines behind the scenes performing business logic or object-relational-mapping. The layers from the service level to the database are similar to a conventional business layer/data layer separation of concerns. Note that the service layer acts as a procedural entry point into what can be an elaborate object model, proving that OOP did not die because of SOA.

So far, this assembly separation provides the groundwork for some good reusability scenarios and promotes some good decoupling. My service projects reference only the contracts they need, and the services implement only those referenced contracts. The project contains nothing it doesn’t need.

The Host
The service host should also be in its own assembly. Decoupling the services from the host lets you host your services in whatever type of host you want, and to change that host any time. Now, the host could be an IIS application, Windows Activation Services, or any self-hosting application including console applications, Windows Forms applications, Windows Services, etc. Decisions about the type of host and the bindings you want to use should not have any effect on the actual services themselves; a host should be able to reference service and contract assemblies and host them with little or no coupling. The only exception to my last statement would be in an MSMQ scenario, but that scenario’s is outside the scope of this article. Hosts will find the service configuration information in either a web.config file or an app.config file, and that configuration should contain only what you need to expose your service the way you want and with the specifications you want. At a minimum, I’ll need configuration information containing entries with one endpoint per contract.

The Client
Now that my assembly separation is designed for my services, I can focus on the potential service clients, or consumers.

I won’t use the “Add Service Reference” feature in Visual Studio. This is the largest culprit for anti-reusability and configuration bloat. Not only that, I don’t even want to address my services directly from my clients. Service consumers use a proxy class to access a service’s implementation. The proxy class is not difficult to write and, in fact, attacking this manually gives you a couple of different choices. I’m working here under the assumption that both sides of my application are .NET of course. If I had a Java client or some other type of .NET consumer, creating the proxy and parsing the service’s message stream would be much different, and would use technology specific to that consumer.

A .NET service consumer not only needs a proxy class, but also service contracts that represent the messages that are being used. Now that I’ve decided to place my service and data contracts into their own assembly, I can now reuse that assembly by simply referencing it from my service consumer. The service consumer that contains the service proxies will also become its own assembly, giving me the ability to use the proxies from more than one client application. Remember, a client application does not necessarily have to be a UI application; it might equally well be an automatic process. Placing service client proxies in their own assembly is analogous to branching out the business layer of a conventional object-oriented architecture, making it accessible by a number of client tiers. Later, I’ll go into more detail about how to create proxies and the choices available to you.

The last set of assemblies I need are the clients for my service proxies?the UI applications or unmanned processes that use the services.

Applying the Concepts
To illustrate all these concepts, I’ll build a simple system with all the aforementioned components. Figure 2 and Figure 3 illustrate the application architecture and assembly separation in the examples.

Author’s Note: Although the diagrams illustrate a complete system model with both Product and Order services, for the purposes of this article, I will concentrate only on the Product part of the system, and will not show any error handling or fault contract code in the examples. I take those as a given when developing real applications.

?
Figure 2. Application Architecture: The figure illustrates the architectural layers of the application.
?
Figure 3. Assembly Separation: Data contracts, service contracts, services, and client proxies should reside in separate assemblies.

The Service Side
I’ll code the service side first, so you can see the detailed separation of the components.

Data Contracts
I’ll start at the bottom of the stack and design my data contracts first. Because I’m going to concentrate only on the Product side of the system, I need one data contract called “ProductData.” This contract will contain product information data. For the rest of this article, I’ll keep all my examples as simple as possible. I’ll place my data contract class into an assembly I’ll call “Contracts,” which will later contain the service contract as well. The ProductData class will use the DataContract and DataMember attributes that come from the required reference to the System.Runtime.Serialization assembly. You can see this class in Listing 2.

Service Contracts
The Contracts project also contains two product service contracts, IProductBrowser and IProductAdmin. There’s no need to place these into separate assemblies.

IProductBrowser contains operations that allow browsing a product catalog. It defines operations that support the retrieval of a single product or an entire product listing. It will also contain operations that search for products, given some incoming search specifications.

IProductAdmin contains operations for adding and maintaining the product catalog. These two contracts are separate because later you’ll see that service endpoints are defined on a per-contract basis. Separate contracts let me control access to these two sets of operations individually. Listing 3 shows the full code for these two service contracts. The ServiceContract and OperationContract attributes used in these interfaces are defined in the System.ServiceModel namespace, another assembly I need to reference: System.ServiceModel.dll. Also notice that the ServiceContract attribute defines the name and unique namespace for my service contracts. True to the polymorphic nature of interfaces, these service contracts merely define the operations, which is all that clients really need to know about (as the proxies will demonstrate later). The next project contains the implementation details and will remain behind the services layer.

Services
Now it’s time to create the services. Besides the benefit of reusing my contracts from my client proxies later, separating them from this “services” project also allow me to create multiple implementations of each contract if I so desire.

This project will be called “Service” and references not only System.ServiceModel but my Contracts assembly as well. The project contains one service class called “ProductService.” Here’s where it gets interesting. This service will provide implementations for both the IProductBrowser and IProductAdmin contracts, but this in no way means that a consuming client must be exposed to both implementations, as you’ll see later. The implementation in this service will be the meat of my service and can call out to anything it needs to perform its functionality. In the interest of time and printed space I won’t provide a detailed implementation, so you’ll have to settle for commented pseudo-code. Just remember that this is the code layer that can call out to either another service and/or one or more business engines or ORM layers to perform its tasks and return information to the calling client. Listing 4 shows the code for the ProductService class.

Hosting
Here’s a recap of the process so far. I have my contracts (both data and service) in one assembly, which is referenced by another project containing my service. I’m in good shape so far for contracts and I’ve also left myself open for any hosting scenario I want. I’ve chosen to create two hosting applications, one running under IIS and another that’s a console app, demonstrating self-hosting.

I chose the two hosting scenarios so I can expose a public service using IIS in HTTP and a private service using TCP being hosted in the console application. Remember earlier I said that endpoints are created on a per-contract basis. You also saw that I split off my public and admin functions into two separate service contracts. Given this information, you can conclude that each service contract will need to be exposed using its own endpoint and can thus be exposed using its own host.

In this case, I want to host the IProductBrowser contract using IIS and HTTP so I don’t have to deal with any firewall issues and can deploy as seamlessly as possible, allowing access by clients of any type, not just .NET WCF ones. In contrast, the IProductAdmin contract will be exposed using a TCP host running in a console application, because it will sit inside a firewall. This service will benefit from the speed of TCP and will be consumed only by .NET clients.

I could have certainly chosen to host both service contracts using IIS, but I would be limited to HTTP transport on a service that would not be public and can sit inside a firewall. You can probably already see the benefits of decoupling the hosts from the rest of the components.

With that in mind, I’ve created two more projects in my solution: a console app and an ASP.NET application. Both projects must reference the System.ServiceModel assembly and the Service and Contracts assemblies. Notice that I didn’t create a WCF Service Application to serve as my host; I used a standard ASP.NET application and simply deleted the Default.aspx page, added my references, and cleaned up the web.config file a bit. In this project, I’ll need a SVC file to serve as my service’s browsing point?but I don’t want to create one using the “Add New Item” feature. That will bloat my web.config file and I just finished cleaning that thing up! Instead I added a text file item to my application and renamed it ProductService.svc. Unlike the “everything automatic” walkthrough I gave you at the beginning of this article, this SVC file will not have a code-behind file containing the service implementation (remember, I already have that in the referenced Service project). Instead, I’ll point this SVC file to the ProductService class by manually creating the directive:

   <%@       ServiceHost       Service=      "CoDeMagazine.ServiceArticle.ProductService"    %>

It’s important to note that the address of the service hosted here is the URL corresponding to the deployment location of this web application, followed by ProductService.svc, but more about that in a minute.

Now let’s switch to the console host. My console application is called Host?and like all good console applications, starts with a class called ‘Program” and a static method called Main. Self-hosting a service simply means instantiating the System.ServiceModel.ServiceHost class, giving it information about the service, and opening the host. The rest is all in the configuration (something my IIS host will need as well). Here’s the console host code:

   static void Main(string[] args)   {       ServiceHost serviceHost =           new ServiceHost(typeof(ProductService));              serviceHost.Open();          Console.WriteLine(          "Service running.  Please 'Enter'            to exit...");          Console.ReadLine();   }

Notice that the code for self-hosting is actually quite simple. At minimum, the ServiceHost class needs the type of service it will be hosting. Then all you have to do is call its Open method to start the host. At this point, the host is “listening” for service requests from consumers. The “console” code that follows is there simply so that the console application displays something on the screen. Then it waits until a user presses Enter before closing.

So now both my service hosts know what service they will be servicing?but not what contract and binding they will expose and use. So now it’s time to talk about configuration. If I had created these hosts using the project templates, I would have been given a lot of unneeded configuration information. I much prefer to create it by starting with the bare minimum, and then adding what I need as I feel I need it.

The bare minimum a service needs in order to be hosted is the ABCs of WCF: an Address, a Binding, and a Contract. These three things make up a service’s endpoint. You define them in the section inside the section of the configuration file. The two hosting applications both host the same service, but each exposes a different service contract through a different binding. The ASP.NET hosting application’s configuration file contains this configuration:

                                       

The console application’s configuration file uses this configuration:

                                       

Notice that the ASP.NET app’s configuration does not have an address. Again, that’s because the service address is the deployment URL of the ASP.NET application followed by the name of the SVC file. The console app, on the other hand, does have an address in the configuration.

Also note the bindings each endpoint uses. The last part is the contract that each endpoint exposes. As planned, the public HTTP service host exposes the IProductBrowser contract and its operations to either .NET or non-.NET consumers; while the more restrictive TCP service host exposes the IProductAdmin contract specifically to .NET consumers.

The Consumer Side
The last step is to code the consumer side of the equation to show you how the specific component separation applies here as well.

Client Proxies
A client application uses client proxy classes to connect to a service and use its operations. Along with copies of data and service contracts, Visual Studio creates client proxies automatically when you use the “Add Service Reference” feature?but that comes with a lot of excess unneeded configuration. Besides, one point of separating the contracts into their own assembly is so I can reuse them. .NET ships with a utility called SvcUtil that you can use to create proxy classes and contract copies, given a services endpoint, but the results have the same problem as the “Add Service Reference” option. Therefore, not only will I create my client proxies manually, but I’ll put them into their own project called ClientProxies. This lets me reuse them from any client application. I can certainly create more than one proxy client project if needed, but for simplicity, I’ll build just one project here. I will have more than one class, though: ProductClient and AdminClient.

I’ll use two different techniques to code the two proxy classes for reasons that I’ll explain as I go along.

The ProductClient class uses the same technique that Visual Studio does when you use the “Add Service Reference” feature. The class needs to import the System.ServiceModel namespace, so the ClientProxies project needs to reference the System.ServiceModel assembly. The ProductClient class will inherit from the ClientBase class and pass as the generic argument the service contract I want this proxy to access, in this case, IProductBrowser. The result of this generic-oriented inheritance is that the ClientBase class’s Channel property adopts all the operations of the IProductBrowser service contract.

The next thing that the class needs to do is to implement the IProductBrowser interface to inherit its operations. Putting these two characteristics together, you get the following:

   using System;   using System.ServiceModel;      namespace CoDeMagazine.ServiceArticle   {       public class ProductClient           : ClientBase,             IProductBrowser       {              #region IProductBrowser Members              public ProductData GetProduct(              Guid productID)           {               return Channel.GetProduct(productID);           }              public ProductData[] GetAllProducts()           {               return Channel.GetAllProducts();           }              public ProductData[] FindProducts(              string productNameWildcard)           {               return Channel.FindProducts(                  productNameWildcard);           }              #endregion       }      }

As you can see, the ProductClient class literally becomes a proxy to my service; an entry point into accessing the services implementation. Except for configuration, which will reside at the client application level, that’s all there is to this technique of proxy class creation.

The second technique is handy because?as you can see?the ProductClient class inherits from ClientBase using up its sole base class candidate. Because .NET allows only single inheritance, I’m stuck with inheriting from this class if I want to access my channel. However, there may be situations where I want to set up an object model of my own, yet still have the ability to access a services channel, in which case I would want to inherit from a class in my object model, not the ClientBase class.

Another situation where the previous technique would not suffice is if I want to create a proxy class to handle more than one service contract. Inheriting from the ClientBase class restricts the client proxy class to only one service contract. Fortunately, there is a way to obtain a service’s channel without automatically having a class like ClientBase create it for me.

This time, I’ll use the ChannelFactory class to create a channel for me. When I instantiate this class, I pass it the service contract I want to represent, then call the CreateChannel method. The end result is a channel class returned as the type of the service contract interface I gave the ChannelFactory class. You can then use the variable holding the results of this call to access the service contract’s operations. The proxy class is free to implement one or more service contract interfaces. Here’s how you can use the channel object in method implementations:

   using System;   using System.ServiceModel;      namespace CoDeMagazine.ServiceArticle   {       public class AdminClient : IProductAdmin       {           public AdminClient()           {               IProductAdmin productAdminChannel =                  new ChannelFactory().                 CreateChannel();           }              IProductAdmin productAdminChannel = null;              #region IProductAdmin Members              public void UpdateProduct(             ProductData product)           {               productAdminChannel.UpdateProduct(                 product);           }              public void DeleteProduct(Guid productID)           {               productAdminChannel.DeleteProduct(                 productID);           }              #endregion       }      }

The idea here is that if I were implementing the entire architecture illustrated in Figure 2, I would also have an OrderClient proxy class, which would be used to access the operations on the IOrderPlacement service contract. However, I would like the IOrderBrowser and IOrderAdmin service contracts to be handled by the AdminClient proxy client, in which case I couldn’t inherit from ClientBase. Instead I would use the technique I’ve just illustrated and also implement the other two interfaces. I would, of course, have two more channel objects in the class.

Whether this is the ideal way of implementing the architecture is certainly a topic for discussion, but my primary intent here was to free you from the built-in templates, illustrate examples of multiple techniques, and provide reasons for using them.

With the proxy classes completed, I can compile this assembly and reference it from any client application I want. The client applications can instantiate ProductClient and AdminClient objects and use their methods the same way they’d use any other object.

Client Applications
I won’t bore with details about how I would write my client applications, but it’s worth repeating the main point: Any client application can access any of the service contracts merely by referencing the appropriate client proxy assembly and instantiating its proxy classes. However, I will give one example, primarily to show you how to configure the client.

The client applications require not only references to the proxy assemblies, but also some configuration information. The proxies are designed to access specific service contracts but the configuration defines where those contracts can be found. In the same way that service hosts expose endpoints in a section, clients require the endpoint definitions in a section:

                              

As you can see here, I’m defining two endpoints, one for each service contract. If you recall, each of these was implemented by the same service then hosted by two different hosting applications; so you can see the flexibility potential here.

If I want to use the operations defined in the IProductBrowser service contract, I simply need to instantiate whichever proxy class opens a channel to that endpoint. I this case, it would be the ProductClient class, and from here it’s simply a matter of accessing its methods as so:

   ProductClient proxy = new ProductClient();   Guid productID = Guid.NewGuid();   ProductData product = proxy.GetProduct(productID);   MessageBox.Show("The product retrieved is: " +       product.ProductName);

The preceding code makes it clear that the object can indeed be treated like any other object with methods that you’ve used in the past. In fact you can take a proxy object like the one stored in the proxy variable above and use it in data binding. I constantly hear arguments against service-oriented architecture saying that it goes against object-orientation because it’s too procedural, or that you can’t use it in data binding, or that you can’t use business frameworks because most of them promote state and persistence and SOA does not. I’m here to tell you that this is absolutely not the case.

One of my areas of expertise is in the popular CSLA business framework developed by Rockford Lhotka. CSLA is a framework that offers much to both Windows and ASP.NET development, but due to the fundamental differences between these two platforms, lends itself to being more feature rich in a Windows platform. As an official CSLA instructor I often debate with students on the value of CSLA if they wish to implement a service-oriented architecture; their fears being that CSLA is designed to build business objects with advanced features like validation, authorization, and data binding. CSLA does indeed give you features like this but who says that the data-access portion of CSLA-based objects need to use ADO.NET (or a data-access-layer) in order for them to work? A CSLA business object’s data methods can create service channels using the ChannelFactory class, access a service to retrieve information, build the rest of the business object, and still benefit from all the features that the framework offers. The technique required in such a situation is the one that uses ChannelFactory because CSLA, like most business frameworks, gives you base classes from which to inherit so using the ClientBase class is out of the question. Perhaps that’s a topic for a future article.

Creating all the components of a WCF-based system manually is easy and allows for a more calculated design process, maximizing reusability and maintainability. Remember that assemblies should be logically grouped within a given category, meaning contracts, services, hosts, or proxies. But they should definitely not cover multiple categories, with the exception of data contracts and service contracts. Service orientation is not a replacement for object orientation or component orientation. Just like component-oriented architectures build on the principles of object-oriented programming, service-oriented designs use concepts of component design and bring other concepts on top of that, such as decoupled design, interoperability, and separation of concerns.

I hope I was successful in not coming across like I was bashing what Microsoft preaches for WCF and what Visual Studio does with it because I still think Visual Studio is the best IDE on the market and I think of WCF as one of the single greatest technologies ever to come out of our friends in Redmond.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist