Posts Tagged 'configuration'

Best Practices for Configuring WCF 4.5

In my last few posts I looked at the new options that WCF 4.5 provides for managing the most awkward part of WCF: configuring the services. I looked at the new options for configuring IIS hosted services in code, configuring (from code) service libraries that support multiple endpoints, loading your config files from a central location (in both service libraries and IIS-hosted services).

So what should you do with these new WCF features? I’m still leery of the using code based configuration because, as I move my service from development to test to production, I’ll want to change the service’s configuration. For instance, at the very least, I want all three versions of the service to have different endpoints. I’m also uncomfortable with letting anyone get access to one of my Web Service’s contract just by tacking “?wsdl” to the end of the service’s endpoint. So, while I’ll leave that feature in place for testing, I prefer to turn it off in the production system. Instead, before moving a Web Service to production, I’ll extract the WSDL document, store it some safe place, and make potential consumers request it from me. Among other benefits, that lets me maintain a list of those consumers so I’ll have some clue who I should contact if I make any changes to my Web Service. Finally, while I want to turn to include all the detail in my exceptions in the test version of my service, I want to turn that off in production, also.

If I’m doing my configuration in code (as opposed to in a configuration file), making those changes is harder, though not impossible. If the parameters are all in a configuration file, I can read the current values from the file using NotePad and update them without having to recompile if I need to. Changing my config file means that I don’t need to modify my code as I move the service from development through to production. Often, I will simply create three versions of my config files for development, test, and production, put the files in place, and just not update them during the release process. That way, as the code moves from test to production, it just picks up the config file at the site (that does mean that I need a separate release process on those occasions when I do need to update the config file). But, even then, configuring in code doesn’t really prevent me from doing that: I can just make sure that my configuration code reads in any critical parameters from my application’s settings. That will get me virtually the same benefits as keeping the whole configuration in a file. If I do that, it’s just a matter of managing the application’s settings in each of my development, test, and production environments (and I’m probably doing that already for other parts of my application that are using application settings).

However, I have to admit, that I do like WCF 4.5’s new feature that allows me to programmatically load config files from a central location. That allows me to keep a separate set of configuration files for each of development, test, and production but not have them spread out in several different locations. By keeping my all three versions of the file in one place, the only thing I have to change in the service as I move it from development to production is the name of the file being loaded by my code in the new environment. But, having said that, I’ll probably keep the name of the file in my application’s settings so I really haven’t changed the problem much: instead of keeping multiple pieces of information in application’s settings (address, metadata accessibility, error detail), I’ll be keeping only one (path to the configuration file). If you think managing one piece of information isn’t that more difficult than managing multiple pieces and find configuring your service with code attractive, you may make a different choice than me. However, I will say that, by keeping my configuration in a file, I can make any configuration change I want without recompiling my code—using code means that you can only make those changes that you planned for in writing your Configure method.

Technology is all very good but deciding when and how to use it is “context sensitive”—different value systems will cause developers to make different choices. One of the things I like best about Learning Tree’s .NET Best Practices and Design Patterns course is that it makes that point and lays out the costs and benefits for the best practices it addresses.

Peter Vogel

Managing WCF 4.5 Configuration Files in WCF Service Applications

In the last few posts I’ve been looking at the new options that WCF 4.5 gives you for configuring your services. The first two posts showed how to configure a Web Service in an ASP.NET application and how to configure a service both as a Web Service and as higher-performance TCP-based service in a Service Library. My last post was about how to load your service’s configuration from a central file location. However, I only discussed how that process worked in a Service Library—other than a brief note, I ignored a WCF service in an ASP.NET application (a Service Application). In this post, I’m going to address how to load a service’s configuration file from something other than the web.config file.

One note: I am working with the beta version of Visual Studio 11 and the .NET Framework 4.5 so it’s entirely possible that what I say here may change by the time both products get released to manufacturing.

To begin with, the code you use to load the configuration file in a WCF Service Application isn’t any different from the code you’d use in a WCF Service Library. You still add a static/Shared method called Configure to your service class and put this code in it, pointing to the file containing your service’s configuration:

PublicSharedSub Configure(sc AsServiceConfiguration)  Dim cfMap As New System.Configuration.ExeConfigurationFileMap With {  .ExeConfigFilename = "c:\configs\Service1.config"}  Dim cf As System.Configuration.Configuration cf = System.Configuration.ConfigurationManager.  OpenMappedExeConfiguration(cfMap,  System.Configuration.ConfigurationUserLevel.None)  sc.LoadFromConfiguration(cf) End Sub 

The problem is what you should put in that Service1.config file. In the Service Library, you could fundamentally just copy the system.servicemodel element to the configuration file—the only change you had to make was to convert any relative addresses to absolute addresses. You could avoid even that change by leaving the host/baseaddress elements in your app.config file (you didn’t even have to remove the host element from the config file you were loading—WCF 4.5 just ignored them).

Unfortunately, with a Service Application in WCF 4.5 you don’t have a complete set of tags in your Web.config file to copy. This is the result of another change in WCF 4.5: “WCF simplification”. If an element in the config file is setting the default value for the element then, by default, that element is omitted from the Web.config file. This means that a Web.config file in the .NET Framework 4.5 set up for testing/development can look as simple as this:

<system.serviceModel>  <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true"  httpsGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors>  </behaviors>  </system.serviceModel>

If you just copy this to your config file (Service1.config in my sample code) you won’t be able to use the WCF Test Client to test your application because the Test Client won’t be able to retrieve the metadata it needs to figure out what methods your service exposes. To fix that problem, you need to add a service tag (within a services element) that references your service by namespace and name. And, as long as you’re doing that, during development you probably also want to include all the exception detail in any faults your service raises so you should add the serviceDebug element that lets you specify that with its includeExceptionDetailInFaults attribute.

Putting that altogether, your configuration file should look like this:

<configuration>  <system.serviceModel>  <services>  <service name="WcConfigWeb.Service1"/>  </services>  <behaviors>  <serviceBehaviors>  <behavior name="HttpGetMetadata">  <serviceMetadata httpGetEnabled="true" />  <serviceDebug includeExceptionDetailInFaults="true" /> </behavior>  </serviceBehaviors>  </behaviors>  </system.serviceModel>  </configuration> 

That file will be successfully loaded by the code I showed earlier and make your service available for testing.

Peter Vogel

Manage WCF 4.5 Service Configurations from One Location

In an earlier post, I showed how you can configure a WCF 4.5 Web Service in an ASP.NET site with a few lines of code in the beta version of the .NET Framework 4.5; in a later post, I showed how you could configure a WCF 4.5 service both as a TCP-based service and a Web Service in a WCF service library, again using nothing but code (and, again, in the beta). But the beta of WCF 4.5 has another goodie in its pack: The ability to load configurations from a file location of your choice which lets you centralize your service configurations. By default, when a WCF Service or client starts up, it reads configuration information from the application’s config file. Using this new feature, however, you can override that default to specify any file you want

As in with the other code-based configuration features in WCF 4.5, to use this feature you’ll need to add a Shared/static method to your service class called Configure (WCF will call this method before trying to use your service). WCF passes this method a ServiceConfiguration object that has a LoadConfiguration method you can call to load a configuration from any file you want. To use this feature, you’ll also need to make sure that your project has a reference to System.Configuration to pick up some of the classes you’ll need.

The first step in the process is to define an ExeConfigurationFileMap object. This object allows you to specify which files WCF is to look in for your service’s configuration information. There are a number of properties that you can set, including specifying what file to use instead of the machine config file that controls settings for the .NET installation on the computer and the file to use for a WCF client. However, for a WCF service, you want to set the ExeConfigFilename to the path for the file containing your configuration settings. This example points WCF at a file called Service1.config in a folder called configs off the root folder:

Dim cfMap AsNew System.Configuration.
               ExeConfigurationFileMap With 
                 { .ExeConfigFilename = "c:\configs\Service1.config"} 

This configuration file must contain your system.serviceModel element enclosed in a <configuration> element, like this:

<configuration> 
  <system.serviceModel>  
  </system.serviceModel> 
</configuration> 

Now that you have your filemap object you can create a configuration object from it. To do this, you call the ConfigurationManager’s OpenMappedExeConfiguration method passing your filemap and a ConfigurationUserLevel of None, as this example does:

cf = System.Configuration.ConfigurationManager. 
       OpenMappedExeConfiguration(cfMap, 
           System.Configuration.ConfigurationUserLevel.None) 

Finally, you pass your configuration object to the ServiceConfiguration parameter using its LoadFromConfiguration method:

sc.LoadFromConfiguration(cf)

There is one wrinkle here: You’re not allowed to have any host elements in the configuration file loaded through the LoadFromConfiguration method (well, you can have host elements in your configuration file but they’ll be ignored). The host element is normally used to set the base address of the service’s endpoints and that’s considered the responsibility of the host rather than the service (for instance, in a WCF service hosted in an ASP.NET site, the site sets the base URL for all services). This is an issue if, in a WCF Service library, you’re using relative addresses for the endPoint elements in your service’s configuration. This example, for instance, specifies that the service’s endpoint is “Service1” added to whatever base address is specified in the host element:


<services>  
  <service name="WCFCentralConfig.Service1">  
    <endpoint address="Service1" binding="basicHttpBinding"  
                                contract="WCFCentralConfig.IService1"> 

If so, you’ll need to leave a host element in your service library’s config file to specify your base address:

 <system.serviceModel>
  <services>
    <servicename="WCFCentralConfig.Service1">
      <host> 
        <baseAddresses>
          <addbaseAddress = "http://localhost:8733/WCFCentralConfig/"/> 
        </baseAddresses> 
      </host>  
    </service> 
  </services> 
</system.serviceModel> 

However, if the endpoints in your Service Library specify absolute addresses then you’ll be able to completely delete the system.serviceModel element in your application’s config file. You’ll need to specify the absolute address not only for the endpoint for your service but also, if you’re testing with the WCF Test Client or using the Discover button in the Add Service Reference dialog, for the endpoint used to retrieve the contract for your service (the mex binding) and the httpGetUrl attribute of the serviceMetaData element. You’ll also probably want to specify that, for testing, all the exception detail is to be included in any fault messages you get from your service. Putting it all together, it means that your configuration file will look something like this in a Service Library:

 <configuration> <system.serviceModel> 
  <services> 
    <service name="WCFCentralConfig.Service1"> 
      <endpoint 
          address="http://localhost:8733/WCFCentralConfig/Service1" 
          binding="basicHttpBinding" 
          contract="WCFCentralConfig.IService1"> 
        <identity> 
          <dns value="localhost"/> 
        </identity> 
      </endpoint> 
      <endpoint 
         address="http://localhost:8733/WCFCentralConfig/Service1/mex" 
         binding="mexHttpBinding" contract="IMetadataExchange"/> 
    </service> 
  </services> 
  <behaviors> 
    <serviceBehaviors> 
      <behavior> 
        <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" 
         httpGetUrl="http://localhost:8733/WCFCentralConfig/Service1/"/> 
        <serviceDebug includeExceptionDetailInFaults="true"/> 
      </behavior> 
    </serviceBehaviors> 
  </behaviors> 
</system.serviceModel> 
</configuration> 

Peter Vogel

Beyond Configuring Web Services in WCF 4.5

In my previous post, I looked at how easy it was to add a basic HTTP Web Service to a Web site in the beta of the .NET Framework 4.5 through code: Just add a shared/static method called Configure to your service and put some code in it to configure the ServiceConfiguration object passed to the method. In fact, because of the defaults that WCF 4.5 takes for a WCF service in a Web Site you don’t really need to add any code at all. In my example I did add some code to explicitly enable my service as a basic HTTP Web Service. I also chose to configure the service to return a contract and verbose error messages (both of which are turned off by default) to support testing.

But the power of WCF is in providing multiple ways of accessing the same code–as a basic Web Service or as a high performance TCP-based service. Adding TCP access requires a change in the project type:  Testing a TCP-based service from Visual Studio is awkward (at best). Instead, you’ll want to create a WCF Service library where you service is hosted by WAS rather than IIS. While that makes testing your TCP access is simplified, the defaults don’t give you a service automatically and you’ll need to use a few more lines of code.

After creating your WCF Service library project add a new WCF Service to it, giving the service some meaningful name (I used “CustomerService”). Then, to demonstrate the power of configuring by code, go to your app.config file and delete the entire system.model element. You’re now ready to control your service from code.

These two lines of code make your service available as a Web Service and as a TCP-based service (which will have orders-of-magnitude better performance than the HTTP-based Web service):

PublicSharedSub Configure(sc AsServiceConfiguration) 
sc.EnableProtocol(New BasicHttpBinding)  
sc.EnableProtocol(New NetTcpBinding) 

While that (in theory) makes your service accessible, it doesn’t make the information about the service (the metadata) available. As a result, you won’t be able to either use Visual Studio’s WCF Test Client or be able add a service reference for your service to another project by using the Add Service Reference dialog’s Discover button. To enable the metadata you use the same code that I had in my previous post but with one extra line of code that specifies the address where the metadata is available. In that line you create a System.URI object specifying the address (the address must reference your computer name but the port and service name are up to you) and use it to set the HttpGetUrl property:

Dim behavior As New Description.ServiceMetadataBehavior 
behavior.HttpGetEnabled = True 
behavior.HttpGetUrl = New System.Uri("http://localhost:1868/Customers") 
sc.Description.Behaviors.Add(behavior) 

You also need to add endpoints for HTTP and TCP access to your service. For that, you use the AddServiceEndpoint method on the ServiceConfiguration object passed to your Configure method. The first parameter to the AddServiceEndpoint is the type of the interface that your service implements (“ICustomers” in this example), the second parameter is the binding class for the endpoint, and the final parameter is the address itself (make sure that you use different addresses for each endpoint):

sc.AddServiceEndpoint(GetType(ICustomerService), 
         New BasicHttpBinding(), 
         "http://localhost:1868/Customers") 
sc.AddServiceEndpoint(GetType(ICustomer), 
         New NetTcpBinding(),  
         "net.tcp://localhost:1867/Customers")

There is an annoyance when you go to test your service: In a Service Library, in the absence of any entries in the config file, the test client can’t retrieve the information about the service. You’ll first get a dialog that the “WCF Service Host cannot find any service metadata”–just click the No button to continue. When the Test Client appears, it won’t display any services. You’ll need to go to the Test Client’s File menu and select Add Service to display the Add Service dialog box. In the box, enter the URL you used to set the HttpGetUrl property followed by “?wsdl” (e.g. “http://localhost:1868/Customers?wsdl”—and make sure you type the URL exactly the way it appears in your code). When you click the OK button, the Test Client will finally grab the service information and you’ll be able to test your service. The good news here is that, once you enter the URL with ?wsdl successfully, you won’t have to enter it again (you will still need to go through all the dialogs, though).

And there you go: With less than a dozen lines of code you’ve configured a service as both a basic HTTP service and TCP-based service. Adding additional access methods (e.g. named pipes, advanced web services, https) should just consist of enabling the protocol with the EnableProtocol method and adding a compatible endpoint.

As before, your best Learning Tree source for WCF information is Programming WCF Web Services for .NET: A Comprehensive Hands-On Introduction.

Peter Vogel

One Line of Code to Configure WCF 4.5

The WCF 4.5 beta simplifies configuring WCF, provides better support for code-based configuration, and makes it easier to do code-based configuration in Web sites. Don’t get me wrong: I like the WCF configuration files but, I gather, I may be in a minority. Many developers prefer to configure their WCF services from code where possible. Unfortunately, one of the places where that isn’t possible is the most common place to host WCF services: in a Web application (well, I’m told it was possible but only in the sense that it’s possible to remove your own appendix).

WCF 4.5 (at least, in the beta) provides a simple solution: Add a static/shared method called Configure to your service class and fill it with the code required to configure your service. WCF will call that Configure method at the appropriate moment and pass the method an instance of the ServiceHost class. In your Configure method, you can work with that ServiceHost to configure your service.

What’s especially impressive is how simple it is. The default settings alone mean that if you add an svc file to your Web site then you have a Web Service. You can make that explicit, however, with a single line of code. This example makes the service containing this method available as a Web Service with no WCF-related tags required in the config file at all:

Public Shared Sub Configure(sc AsServiceConfiguration) 
 sc.EnableProtocol(NewBasicHttpBinding()) 
End Sub 

You can configure these services by instantiating behavior classes, configuring them, and adding them to the ServiceConfiguration’s Description property’s Behaviors collection. That’s a good thing because, while my previous example was all the code you need (in fact one more line than you needed), it’s probably not all the code you want, for two reasons.

Configuring the Service

First, with just that code you won’t be able to retrieve the WSDL contract for this service (what WCF refers to as service’s “metadata”) so you won’t be able to use Visual Studio’s WCF test client (you also won’t be able to use the Discover button in Visual Studio’s Add Service Reference dialog). For testing purposes, and until you can save to a separate file the WSDL contract that you can give to the developers building the clients/consumers for this service, you’ll want to configure your service to return a WSDL contract. To tell your service to make its metadata available you add code like the following to your Configure method. This code creates a ServiceMetadataBehavior object, sets its HttpGetEnabled property to True (that actually turns on the feature), and add the configured behavior to the Behaviors collection:

Dim behavior As New Description.ServiceMetadataBehavior 
behavior.HttpGetEnabled = True 
sc.Description.Behaviors.Add(behavior) 

Second, by default, WCF services don’t return a lot of information in their exception messages. That’s a good thing: While that information is very useful in debugging, it probably isn’t something you want to share with the general public. However, in testing, you probably do want that those chattier error messages and you can enable the with this code in the Configure method:

Dim debugBehavior As New Description.ServiceDebugBehavior 
debugBehavior.IncludeExceptionDetailInFaults = True 
sc.Description.Behaviors.Add(debugBehavior) 

But both of these changes highlight an issue with code-based configuration. In production, you probably don’t want your service freely giving up its contract to whoever asks for it. Instead you probably want to control access to your service’s contracts so that you have some idea who’s using your service and can contact those users when you’re making changes to your service. And you certainly don’t want to send out those verbose error messages from your production system. So, before moving your service to production you’re going to want to change the values used in this code.

The problem is that, with the code I’ve used here, there’s no simple way to inspect the assembly you’re deploying to production to determine if the settings are correct: the code is compiled and is unreadable. One of the nice features of the config files is that you could inspect them (and even change them) with Notepad. The right answer is probably to move settings that will change from one installation to another (e.g. test and production) into your AppSettings where you’ll still have visibility to them.

Many of Learning Tree’s courses touch on WCF but your best source for information is Programming WCF Web Services for .NET. It’s four intensive days of everything you’d want to know about WCF.

Peter Vogel


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

%d bloggers like this: