WCF Fundamentals

WCF lets developers build service-oriented applications on the Windows platform using a unified programming model. You can use the same service-oriented programming model with WCF to develop outward-facing Web service applications, intranet Web services, peer-to-peer intranet applications, or server-to-server distributed applications. The WCF programming model is flexible because it provides a layered approach to services, based on channels, bindings, contracts, endpoints, and behaviors. Through the layered approach, behaviors are added to an endpoint during configuration, and multiple endpoints with alternative behaviors and bindings can be created in the hosting application. The constant is the programming model—regardless of the binding or behavior, the service programming model is unified. Figure 2-2 shows the layered approach to WCF programming.

WCF uses a layered approach to service programming.

Figure 2-2. WCF uses a layered approach to service programming.

Service contracts are created by applying contract attributes to an interface. The interface is then implemented by a class that defines the implementation. There is nothing "special" about a service class, and it does not inherit a base class such as the ASMX Web service class—it is just a type that implements the service interface that is marked with WCF attributes.

Endpoints expose service contracts through a URI (Uniform Resource Identifier) such as http://knowledgebase/dataservice.svc, which in ASP.NET is based on an SVC file deployed to the Web application. Bindings are applied to the endpoint and specify which protocol to use, either a simple Web binding, a Web Service binding using SOAP, or a custom binding. The binding is used by the hosting application to create service channels with a bound protocol. In specifying the transport mechanism and protocol for communication, the binding separates the service from the transport technology. Within an ASP.NET Web application, the bindings you use most often include wsHttpBinding, which is an HTTP binding for SOAP Web services, and webHttpBinding, which is an HTTP binding for simple Web services without SOAP. An AJAX client most often uses webHttpBinding, and remote clients most often use wsHttpBinding. Silverlight 2.0 and other ASMX-compatible clients use the basic binding, basicHttpBinding.

In the following sections I’ll describe contracts, endpoints, bindings, and behaviors in more detail. First, however, let’s look at simple examples using a HelloWorld implementation and then at a more complete example of an application that we’ll carry into later chapters.

WCF Contracts

Service-oriented applications are based on contracts. Contracts define the data schema and operational contracts for the service and the interface for remote clients. The contract is all that a remote application will know about—it will not know about the internals or implementation details of the service. With SOAP-based Web services, contracts are exposed by Web Service Description Language (WSDL). With .NET Web services, including ASMX (ASP.NET 1.1 and ASP.NET 2.0 Web services) and WCF services, WSDL is generated by the service runtime and is used by Visual Studio or svcutil.exe to generate proxy classes for remote clients. The great part about WSDL is that you don’t really need to read it, even though it plays an important role in the service-oriented architecture: it’s just plumbing that our tools create and consume. More information about WSDL and svcutil.exe is available on http://msdn.microsoft.com/aa347733.aspx and in the book references cited in this chapter.

A service contract is defined in code through attributes applied to the service interface. Although you can apply service interface attributes to a concrete class, the service interface should always be defined as an interface type to provide the most maintainable code. Using an interface keeps your code more stable for remote clients because it is easier to catch breaking changes at compile time. For example, the following code defines a simple interface for a HelloWorld service with a single method, Hello:

public interface IHelloWorld{
        string Hello();
}

To use this interface as a WCF service, you need to add the ServiceContract and OperationContract attributes. The attribute ServiceContract is applied to an interface or class to enable it as a WCF service. The attribute OperationContract is applied to service methods. The following example enables the IHelloWorld interface to be used as a WCF service contract:

[ServiceContract]
public interface IHelloWorld{
        [OperationContract]
        string Hello();
}

Tip

Tip

If you’ve implemented Web services using ASMX in .NET 2.0, you’re already familiar with the attribute-based model. The WCF ServiceContract attribute is similar to the ASMX WebService attribute, and the WCF OperationContract attribute is similar to the ASMX ServiceMethod attribute.

The ServiceContract attribute also has the parameters Name and Namespace, which are used to further identify the contract. The OperationContract has the Name attribute. The Name and Namespace parameters specify the XML name and namespace of the service and operation in the WSDL contracts. The XML namespace is a conceptual URI that identifies your service and XML schema. These URIs are similar to .NET namespaces, but they are applied to XML to disambiguate data schemes. They do not have to be real URLs; they are most often based on the developer’s public URL. For example, Microsoft defines the XML namespace for Simple List Extensions at the URI http://www.microsoft.com/schemas/rss/core/2005. This isn’t a "real" URL because no page is present at that location. Instead it is an identifier. These namespaces might not seem important to the casual developer, but they are critical in service-oriented architectures. If you don’t define an XML namespace, the namespace http://tempuri.org is assigned. It’s a best practice to always define the XML name and namespace on the contract, as in the following example applied to IHelloWorld:

[ServiceContract(Name="HelloWorld", Namespace="http://example.com/exampleServices")]
public interface IHelloWorld{
        [OperationContract(Name="Hello")]
        string Hello();
}

In defining the service interface, you define the public service contract that is used for generating WSDL and for exposing the service class through WCF. The contract has nothing to do with implementation; it only specifies the operation and the data schema. By implementing an interface you can guarantee that you won’t break any service clients. Published interfaces of a public API are considered immutable, but you can always add additional interfaces. To complete the Hello World example, examine the interface IHelloWorld in Example 2-1. In addition to the previously published Hello method, I’ve added the Goodbye method. The addition of the second method is not a breaking change for client applications. Additionally, the WebGet attribute is applied to these methods, which I’ll discuss briefly in the following section about WebServiceHostFactory and in depth in Chapter 3.

Tip

Tip

Code for this book is available online at http://www.microsoft.com/mspress/companion/9780735625914. The code for this chapter is in the file Chapter 2.zip.

Example 2-1. The IHelloWorld contract defines the service and its operations (ExampleServices/IHelloWorld.cs).

using System;
using System.ServiceModel;

namespace ExampleServices
{
    [ServiceContract (Name="HelloWorld",
            Namespace="http://example.com/exampleServices")]
    public interface IHelloWorld
    {
        [WebGet]
        [OperationContract(Name="Hello")]
        string Hello();

        [WebGet]
        [OperationContract(Name="Goodbye")]
        string Goodbye();
    }
}

As I mentioned previously, applying the ServiceContract attribute to the interface lets the interface be used as a service contract. Each method exposed to the service must be marked with the OperationContract attribute. Example 2-2 defines the HelloWorld service that implements the IHelloWorld contract. I’ll use this service in the following sections to demonstrate endpoints, bindings, and behaviors. Because the service plumbing is handled in the interface, the service class can handle implementation without additional service markup.

Example 2-2. The HelloWorld service implements the IHelloWorld interface (ExampleServices/HelloWorld.cs).

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace ExampleServices
{
    public class HelloWorld : IHelloWorld
    {
        public string Hello()
        {
            return "Hello, world!";
        }

        public string Goodbye()
        {
            return "Goodbye, cruel world!";
        }
    }
}

Be cause I implemented an interface for the service that is separate from the implementation of the service itself, I have more maintainable code over the lifetime of the application. I know that code modifications in the HelloWorld class do not break the service contract at compile time. The WCF service endpoint enables access to the service interface and class through configuration settings.

WCF Endpoints

Endpoints define the address or URI at which a service is available. An endpoint is enabled through a service host that creates service channels and bindings. The service host is used to run a service, configure its endpoints, and apply security settings. The host can be created through a console application, a service application, Windows Process Activation Service (WAS), IIS, or ASP.NET. In this book I will describe ASP.NET-hosted services.

In ASP.NET, service host files let ASP.NET create and run the WCF service hosts. The service host file simply defines the service activation endpoint and is roughly equivalent to an ASMX Web service file for ASP.NET 2.0. The service host file in ASP.NET uses the .svc file extension and is deployed to the ASP.NET file system.

The ASP.NET service host file activates the service and passes the call to the WCF runtime. The service host file defines the service implementation class (not the interface) and is further configured through the web.config file, where the interface, binding, and behaviors are also configured. The following service host file defines the service ExampleServices.HelloWorld, which will be hosted using ServiceHostFactory and the generic ServiceHost host class:

<%@ ServiceHost Service="ExampleServices.HelloWorld" %>

Tip

Tip

The ServiceHost and ServiceHostFactory classes are generally handled by the ASP.NET runtime and are configured through web.config and .svc files. You won’t need to create or instantiate these classes in ASP.NET hosted WCF.

If you do not specify additional details, the service host used will be the generic ServiceHost, and ServiceHostFactory will be used to create it. The ServiceHost and ServiceHostFactory classes require configuration in web.config, as discussed in the following sections. In ASP.NET you can also specify WebServiceHostFactory or WebScriptServiceHostFactory as the host factory, an approach that does not require additional configuration but is also less flexible. The following SVC file creates a WebServiceHost using WebServiceHostFactory and requires no configuration in web.config:

<%@ ServiceHost Service="ExampleServices.HelloWorld"
    Factory="System.ServiceModel.Activation.WebServiceHostFactory"%>

WebServiceHostFactory creates a host running in the ASP.NET application and applies webHttpBinding and webHttpBehavior to the endpoint. You need to add the WebGet attribute to any GET-enabled endpoints to take advantage of webHttpBehavior, which exposes the Web service over HTTP GET requests. I’ll talk more about GET and webHttpBehavior in Chapter 3.

Likewise, the WebScriptServiceFactory class creates a host running in the ASP.NET application and applies webHttpBinding and enableWebScriptBehavior to the endpoint. The following SVC file creates a WebScriptServiceHost using WebScriptServiceHostFactory without any changes to web.config:

<%@ ServiceHost Service="ExampleServices.HelloWorld"
    Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"%>

Important

Important

While the WebServiceHostFactory and WebScriptServiceFactory classes don’t require configuration entries in web.config, they are less flexible in how you can define endpoints.

If you are using the generic ServiceHost host (which is the default if you do not use the ServiceHostFactory classes discussed previously), you must also define the service in web.config. The SVC file serves as the activation point and the configuration file specifies the relative endpoint address, interface, binding, and behavior. We’ll talk about bindings and behaviors next. For now, wsHttpBinding specifies that the endpoint uses SOAP, as opposed to webHttp-Binding, which specifies the simple URL protocol.

The following service configuration from web.config specifies that the HelloWorld type should expose the IHelloWorld interface through wsHttpBinding when it is accessed from the URL "HelloWorld.svc/soap". Notice that the endpoint address defined is relative to the SVC file.

<service name="ExampleServices.HelloWorld">
    <endpoint address="soap" binding="wsHttpBinding"
            contract="ExampleServices.IHelloWorld" />
</service>

WCF Bindings

A binding defines the transport mechanism of the service. This mechanism binds the service to a SOAP protocol or a Web request–based protocol. For AJAX services, you use the webHttpBinding binding, which enables simple HTTP access. (We’ll look at the Web programming model of WCF using simple GET and POST requests in the next chapter.) The webHttpBinding binding also enables WebScriptEnablingBehavior, which automatically builds JavaScript proxies for WCF services. As I mentioned previously, you typically use wsHttp-Binding when exposing your service to remote clients through SOAP, but you usually use webHttpBinding when exposing services to the JavaScript client. Additionally, Silverlight 2.0 uses basicHttpBinding, which is also used to maintain compatibility with ASMX Web service clients.

The following endpoint definition adds to the previous example by adding an endpoint that uses webHttpBinding and is defined at the URL HelloWorld.svc/ajax.:

<service name="ExampleServices.HelloWorld">
    <endpoint address="soap" binding="wsHttpBinding"
            contract="ExampleServices.IHelloWorld" />
    <endpoint address="ajax" binding="webHttpBinding"
            contract="ExampleServices.IHelloWorld" />
</service>

WCF Behaviors

Behaviors in WCF enable extensions to the service. Behaviors can be scoped to a service, an endpoint, a contract, or an operation. A WCF behavior is custom code that is applied to the service call by modifying the run-time operation. For example, WebScriptEnablingBehavior allows a WCF method to accept calls from the JavaScript client. It also generates a JavaScript proxy when accessed through the /js or /jsdebug endpoints, making the WCF operation simple to call from AJAX code.

Behaviors are defined in web.config in the node configuration/system.serviceModel/behaviors. Many behaviors are possible, including behaviors you write yourself, but the behaviors we care about most enable discovery of the service and AJAX integration of the endpoint.

More Information

More Information

In this book we’ll only look at built-in WCF behaviors, but you can create your own behaviors as well. For more information about custom WCF behaviors, see Aaron Skonnard’s article at http://msdn2.microsoft.com/en-us/magazine/cc163302.aspx.

On the service level, the serviceMetaData behavior enables the generation of WSDL and Metadata Exchange (MEX), which lets clients consume the service. This behavior, defined in serviceBehaviors, is specified as

<serviceMetadata httpGetEnabled="true" />

The serviceDebug element helps a developer debug the service by displaying error messages in SOAP faults, something that you will want to enable so that your AJAX client can handle exceptions. The serviceDebug element is defined as

<serviceDebug includeExceptionDetailInFaults="true" />

The serviceDebug element has the optional attributes httpHelpPageEnabled and httpHelpPageUrl, which enable help pages for the service.

The following configuration creates a service behavior (with the name ExampleServicesBehavior) that can be applied to services to enable service metadata and service debugging information:

<serviceBehaviors>
    <behavior name="ExampleServicesBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug httpHelpPageEnabled="false" includeExceptionDetailInFaults="true" />
    </behavior>
</serviceBehaviors>

After defining the service behavior configuration, you can apply it to multiple services. The following code applies our behavior configuration to the ExampleServices.HelloWorld service.

<service name="ExampleServices.HelloWorld" behaviorConfiguration="ExampleServicesBehavior">
  <endpoint address="soap" binding="wsHttpBinding"
            contract="ExampleServices.IHelloWorld" />
  <endpoint address="ajax" binding="webHttpBinding"
            contract="ExampleServices.IHelloWorld" />
</service>

The other behavior that is most important to AJAX development is the endpoint behavior enableWebScript. The enableWebScript behavior is defined in the type System.ServiceModel.Description.WebScriptEnablingBehavior and enables dynamic generation of JavaScript service proxies and JavaScript integration support for service endpoints. The following configuration defines the ExampleAjaxBehavior configuration, which includes the enableWebScript behavior. ExampleAjaxBehavior is an arbitrary name that is assigned to the endpoint in the endpoint configuration.

<behaviors>
    <endpointBehaviors>
        <behavior name="ExampleAjaxBehavior">
            <enableWebScript />
        </behavior>
    </endpointBehaviors>
</behaviors>

To apply the ExampleAjaxBehavior configuration to a service endpoint, add the behavior-Configuration attribute to the endpoint, as in the following example. You can apply the enableWebScript behavior only to webHttpBinding. All other bindings cause a failure upon service activation. The following configuration adds the ExampleAjaxBehavior to the "ajax" endpoint that uses webHttpBinding.

<service name="ExampleServices.HelloWorld" behaviorConfiguration="ExampleServicesBehavior">
    <endpoint address="soap" binding="wsHttpBinding"
            contract="ExampleServices.IHelloWorld" />
    <endpoint address="ajax" binding="webHttpBinding"
            behaviorConfiguration="ExampleAjaxBehavior"
            contract="ExampleServices.IHelloWorld" />
</service>

Important

Important

The webHttpBinding binding is required for services exposed to the ASP.NET AJAX runtime with the enableWebScript behavior. The enableWebScript behavior applied to a service configured with wsHttpBinding results in an activation failure.

I previously listed the code for the HelloWorld service in Example 2-1 and Example 2-2. Example 2-3 and Example 2-4 contain the SVC and web.config sample configuration code for the HelloWorld service implementation. The service is implemented in the ExampleServices.dll assembly, referenced through the ExampleService.SVC file, and finally configured through the web.config file.

Example 2-3. The ExampleServices.svc service activation file is deployed to the ASP.NET Web application (Web/ExampleService.svc).

<%@ ServiceHost Service="ExampleServices.HelloWorld"  %>

Example 2-4. The service is configured with endpoints, bindings, and behaviors in web.config (Web/web.config).

<configuration>
  <!-- ASP.NET configuration omitted... -->
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <behaviors>
      <serviceBehaviors>
        <behavior name="ExampleServicesBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug httpHelpPageEnabled="false"
              includeExceptionDetailInFaults="true"  />
          <serviceAuthorization principalPermissionMode="UseAspNetRoles" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="ExampleAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <services>
      <service name="ExampleServices.HelloWorld"
        behaviorConfiguration="ExampleServicesBehavior">

        <endpoint address="soap" binding="wsHttpBinding"
                  contract="ExampleServices.IHelloWorld" />

        <endpoint address="ajax" binding="webHttpBinding"
                  behaviorConfiguration="ExampleAjaxBehavior"
                  contract="ExampleServices.IHelloWorld" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

Although more configuration might be required to deploy WCF services rather than ASP.NET 2.0 Web services, the flexibility that configuration gives you lets you change endpoints, bindings, and behaviors without recompiling code. For example, in ASMX Web services, the attribute ScriptService must be applied to the compiled Web service class, whereas with WCF services you can simply attach the enableWebScript behavior in configuration. With ASMX Web services you cannot expose client script proxies through configuration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset