Friday, August 25, 2017

Microsoft 70-487: Configure WCF services by using configuration settings

Exam Objectives

Configure service behaviors; configure service endpoints; configure bindings including WebSocket bindings; specify a service contract; expose service metadata (XSDs, WSDL, and metadata exchange endpoint); configure message compression and encoding


Quick Overview of Training Materials


Configuration Editing Methods


The Exam Ref focuses almost exclusively on the Service Configuration Editor for demonstrating how to manipulate the config file.  I found it interesting that I had not encountered this tool in any of the WCF PluralSight courses, and I don't recall seeing it mentioned in other tutorials I've seen, which mostly focus on editing the System.ServiceModel section of the App or Web config file directly.  To open the Config Editor, right click on App.config and choose "Edit WCF configuration"



I'm generally one to just edit the XML directly, but for completeness I'll demonstrate the configuration tasks in both.  Here is an example of basic service configuration XML:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
  <system.serviceModel>
    <services>
      <service name="PetService.CatService">
        <endpoint address="http://localhost:8081/pets/cat"
                  binding="basicHttpBinding"
                  contract="PetService.ICatService"/>
        <endpoint address="net.tcp://localhost:8082/pets/cat"
                  binding="netTcpBinding"
                  contract="PetService.ICatService"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Default">
          <serviceMetadata httpGetEnabled="true" 
                           httpGetUrl="http://localhost:8081/pets"/>
          
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>



Configure Service (and Endpoint) Behavior


In the Configuration Editor, service behaviors are configured under the "Advanced" subfolder.  Right clicking "Service Behaviors" will allow you to create a new service behavior, to which you can then add a great variety of behavior extension elements:



In the example App.config above, the "Default" service behavior is configured under behaviors => serviceBehaviors => behavior.  The following behaviors are built in (the descriptions are quoted verbatim for the most part):
  • Microsoft.VisualStudio.Diagnostics
    • ServiceModelSink - oddly, this doesn't appear to have an MSDN page. Evidently it has something to do with debugging WCF services.
  • System.ServiceModel.Activities.Description
    • BufferedReceive - enables your service to use buffered receive processing.
    • EtwTracking - allows a service to utilize ETW tracking using an EtwTrackingParticipant. ETW is "Event Tracing in Windows"
    • SqlWorkflowInstanceStore - allows you to configure the SqlWorkflowInstanceStore feature (used to persist workflow state information).
    • WorkflowIdle - controls when idle workflow instances are unloaded and persisted.
    • WorkflowInstanceManagement - adds a workflow control endpoint with a fixed configuration to the service host.
    • WorkflowRuntime [Obsolete] - Seems to be used for configuring the Workflow Foundation runtime, deprecated when WF4 released.
    • WorkflowUnhandledException - enables you to specify the action to take when an unhandled exception occurs within a workflow service.
  • System.Runtime.Serialization
    • DataContractSerializer - Contains configuration data for the DataContractSerializer. While DCS is in Runtime.Serialization, the class representing the service behavior is actually in the System.ServiceModel.Dispatcher namespace in .NET 4.7...
  • System.ServiceModel.Persistence
    • PersistenceProvider [Obsolete] - Specifies the implementation type and time-out for the persistence provider. The behavior class is actually part of the ServiceModel.Description
  • System.ServiceModel.Routing
    • Routing (element) - Provides run-time access to the routing service to allow dynamic modification of the routing configuration. Used to configure the destination endpoints, filters and filtering options to be used during routing.
  • System.ServiceModel.Discovery
  • System.ServiceModel.Description


As an aside, poking around in the .NET library code (which Microsoft has now published) is quite an educational exercise.

In addition to the service behaviors that are built in, it is possible to extend WCF by creating a custom service behavior.  These are configured under the extensions => behaviorExtensions element, an example of which is below (from the ChatService created in my demo for the Objective 3.1 post):

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Metadata">
          <serviceMetadata httpGetEnabled="true"/>
          <profanityInterceptor/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="Metadata" name="ChatShared.ChatManagerService">
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <extensions>
      <behaviorExtensions>
        <add name="profanityInterceptor" type="..."/>
      </behaviorExtensions>
    </extensions>
  </system.serviceModel>

The "type" of the custom behavior extension must inherit from BehaviorExtensionElement, and in my case Visual Studio complained about XML validation, but that could probably be fixed with proper setup of VS.  The behavior itself is an implementations of the IServiceBehavior interface.

Endpoint behaviors are a related concept.  They provide similar facilities as service behaviors, but are specific to an endpoint rather than applying to the whole service. Endpoint behaviors implement the IEndpointBehavior interface, which is nearly identical to the IServiceBehavior interfacing, adding one additional method for applying behavior on the client side (ApplyClientBehavior).  The methods also have different signatures, with the service variety generally taking a service description, and the endpoint behavior taking a service endpoint.



Many of the endpoints can be found in the System.ServiceModel.Description namespace:
  • System.ServiceModel.Description
    • CallbackDebug - Enables service debugging
    • CallbackTimeouts [code] - Specifies the timeout value when flowing transactions from server to client.in a duplex callback contract scenario.
    • ClientCredentials - Enables the user to configure client and service credentials as well as service credential authentication settings for use on the client side of communication.
    • ClientVia - used by clients to specify the URI for which the transport channel should be created.
    • DispatcherSynchronization - enables service to send replies asynchronously.
    • SynchronousReceive - Controls whether channels listen synchronously or asynchronously.
    • TransactionBatching - optimizes the receive operations for transports that support transactional receives.
    • WebHttp - Enables the Web programming model for a service.
    • WebScriptEnabling (enableWebScript) - extends WebHttp to provide support for AJAX
  • System.ServiceModel.Discovery
    • EndpointDiscovery [code] - Specifies the various discovery settings for an endpoint, such as its discoverability, scopes, and any custom extensions to its metadata.
  • System.ServiceModel.Routing
    • SoapProcessing - used to marshal messages between different binding types and message versions.

I found a couple examples [1][2] of using the ClientCredential endpoint behavior in my Claims Based Identity repo.  The first sample is using it to set "PeerOrTrustChain" to true, while the second is using it to specify which certificate to use from the local store to authenticate with the service.  There is also an example using the WebHttp behavior.  I used this behavior myself in my WCFProxy to forward requests for the WSDL (well, I tried anyway).

      <behaviors>
        <serviceBehaviors>
          <behavior>
            <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>
        <endpointBehaviors>
          <behavior name="poxBehavior">
            <webHttp defaultOutgoingResponseFormat="Xml"/>
          </behavior>
        </endpointBehaviors>
      </behaviors>


This snippet of config also shows using the serviceDebug service behavior.  When we ran into issues with the deployed service, setting this to true proved very helpful.

For both service and endpoint behaviors, it is important to know about the way configuration files are merged.  In our applications, depending on the hosting environment, our configuration is stored in either Web.config (for IIS) or App.config (for everything else).  There is also a Machine.config, which is usually stored in the installation directory for the .NET framework (per StackOverflow).  Configured setting in the Machine.config file, as well as Web.config files in the parent folder path, are "merged" together, so that a service compiled at the end of the path will act as though it was configured with all the behaviors.

In cases where this is undesirable, it is possible to use <clear/> or <remove name=""/> to either clear every configured behavior, or just a single behavior by name, respectively.



Configure Service Endpoints


While I could have addressed endpoint behaviors here, I thought it better to lump it in with the service behaviors, and here stick with the ABCs of endpoints: address, binding, contract.

The address for a service endpoint can be either the absolute URI that will host the endpoint, or a relative URI with respect to the base URI of the service.  This base URI may be configured in the <services> element, or it may be added programmatically with the ServiceHost hosting the service is created.

The next two screenshots show where endpoints and the host are configured in the service config tool:



The resulting XML will look something like this:

    <services>
      <service name="PetService.CatService">
        <endpoint address="cat" binding="basicHttpBinding"
          name="HTTPEndpoint" contract="PetService.ICatService" />
        <endpoint address="net.tcp://localhost:8082/pets/cat" binding="netTcpBinding"
          name="TCPEndpoint" contract="PetService.ICatService" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8081/pets" />
          </baseAddresses>
        </host>
      </service>
    </services>

In addition to the ABC's, it is also useful to specify a behavior configuration on a service.  For service behaviors, if only one behavior is defined, it acts as the default service behavior configuration.  For endpoint behaviors, they must be named.  Once a behavior is specified (as described above), the "behaviorConfiguration" attribute is set to the behavior name.



Configure Bindings


Bindings are used to specify the specifics of the transport and protocol that services and clients use to communicate with each other [source].  Since .NET 4, when the WCF configuration model was simplified with many default values, it is possible to specify a binding on an endpoint, and never have to specifically configure that binding, as long as the defaults are acceptable.



Quick rundown of the more common built-in bindings:

  • BasicHttpBinding - use to configure and expose endpoints that are able to communicate with ASMX-based Web services and clients and other services that conform to the WS-I Basic Profile 1.1.  Also an Https variety.
  • BasicHttpContextBinding - Provides a context-enabled binding for the BasicHttpBinding binding. Judging by the code, as well as older documentation, cookies appear to be used to pass context around. 
  • CustomBinding - Use a custom binding when one of the system-provided bindings does not meet the requirements of your service. For example, if you need Soap 1.2 support (which is provided by WSHttpBinding), but you don't want Soap addressing.
  • mex*Binding - "Metadata Exchange" binding, returns a WSDL describing your service.
  • MSMQ Bindings (StackOverflow Comparison):
    • MsmqIntegrationBinding - This binding can be used to enable WCF applications to send and receive messages to and from existing MSMQ applications that use COM, native C++ APIs or the types defined in the System.Messaging namespace.
    • NetMsmqBinding - Represents a queued binding that is suitable for cross-machine communication.  Can only be used with other .NET clients.
  • ws*Bindings - Bindings that adhere to the ws* standards, offering support for distributed transactions and secure, reliable sessions.
  • net*Bindings - These bindings allow for communication between .NET applications
    • NetNamedPipeBinding - Provides a secure and reliable binding that is optimized for on-machine communication.
    • NetTcpBinding - A secure, reliable binding suitable for cross-machine communication.
    • NetHttpBinding - http binding that supports websockets on Windows 8 and above.
  • UdpBinding - Communicate with UDP.  Cannot be used with WAS host.
  • WebHttpBinding - exposes endpoints through pure HTTP instead of SOAP.



These two screenshots and the snippet of config xml show an example of a basicHttpBinding.  The buffer sizes have been maxed out in the config tool, which is reflected in the resulting XML.




<bindings>
  <basicHttpBinding>
    <binding name="Outbound" maxBufferPoolSize="2147483647" maxBufferSize="2147483647"
      maxReceivedMessageSize="2147483647">
      <security mode="Transport">
        <transport clientCredentialType="Windows" proxyCredentialType="None"
          realm="" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>



Specify a Service Contract


With the Service Configuration Editor, there are a couple of ways to specify a new service.  One is to open the "New Service Element Wizard" by choosing File > Add New Item > Service..., and the other is to right click the "Services" folder in the configuration window and select "New Service".  While the wizard walks you through the entire service config, adding the service through the configuration view creates an empty shell of a service that you can fill in.

The first step in both is to select the Service Type, which is done through a window that looks suspiciously like File Explorer, but is a little different.  For one, there is a link to "GAC" in the upper left, so you can search for the service type in the Global Assembly Cache.  If you are browsing to a service type in a project folder, you don't actually select a source file, instead selecting the .dll or .exe file containing the compiled version of the service.



The Exam Ref spends pretty much the entire chapter walking through the "add service" wizard... I'm going to go out on a limb and assume anyone still reading by now knows how to follow a wizard.  The fact is that there really isn't much to the <service> element that needs configuring.  The <endpoints> and <host>, which I already talked about, and <clear/> and <remove name=""/>, which have the same general semantics for service as they do for behaviors.




The <remove> element can be used to remove a number of different configuration settings:





Expose Service Metadata


Adding service metadata is as simple as adding one service behavior, and one standard metadata endpoint.  The behavior is specified with the <serviceMetadata/> element.  Alone, this only enables WS-MetadataExchange (mex, basically SOAP), while adding the httpGetEnabled="true" will enable you to retrieve the WSDL through an HTTP GET request (per Carlos Figueira's reply on a post in the Microsoft forums).

<services>
  <service name="PetService.CatService" behaviorConfiguration="Default">
    ...
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="Default">
      <serviceMetadata httpGetEnabled="true"/>
    </behavior>
  </serviceBehaviors>
</behaviors>


WCF is so helpful, it will even tell you exactly how to fix it if you try to retrieve the metadata and don't have it configured:



I think since I already covered specifying endpoints and behaviors in the Service Configuration Editor, I can spare you yet another UI screenshot haha.



Configure Compression and Encoding


It is possible to customize the way messages are encoded, including with compression, by specifying a message encoder on the binding configuration.  There are five elements included in the .NET framework, all of which inherit from MessageEncodingBindingElement:



It is also possible to create custom message encoders by inheriting from the MessageEncoder class, as described in this article from Microsoft.  Among the built in encoders, the Binary, Text, and MTOM encoders are intended for use with SOAP services, each with their own tradeoffs.  Text is most flexible, interoperable, and simple, while binary is the smallest and most performant, but least interoperable.  MTOM attempts to strike a balance.

The binary encoder supports compression, but customizing a message encoder requires using a custom binding (other bindings have an attribute "MessageEncoding"):


Both the basicHttpBinding and the wsHttpBinding allows only Text and Mtom as values for "messageEncoding", while netTcpBinding and netMsmqBinding didn't allow the element at all.  The netHttpBinding allows Binary as well as Text and Mtom.  



This will produce a binding something like this:

      <customBinding>
        <binding >
          <binaryMessageEncoding compressionFormat="GZip"/>
        </binding>
      </customBinding>


No comments:

Post a Comment