Sunday, April 5, 2009

Environment-Specific ServiceReferences.ClientConfig for Silverlight

Pretty much every project I work on requires the ability to have environment-specific configuration settings: local, development, testing, and production. It's the last thing I ever want to think about when I'm just trying to get my first iteration of a new project working--and I always regret not building it in from the beginning (especially when it comes time to put the project into Continuous Integration).

Things are no different working with Silverlight. If your Silverlight application makes any service calls, there is a good chance you need to call different Uri's in each environment. The configuration for these services is stored in a file called ServiceReferences.ClientConfig.

Additionally, the web site that hosts your Silverlight application may have the same type of environment-specific requirements. Wouldn't it be nice to have one way of solving this problem?

There are plenty of techniques for accomplishing this type of task, especially for app.config in WinForms and web.config in ASP.NET projects. The usual suspects are:

  • Create a NAnt/MSBuild script that replaces the config file at build-time with the proper one for the environment being built
  • Create an MSI that contains all versions of the config file and deploys the one for the environment from a user-selected chosen by the user (or via command-line in quiet mode
  • Create multiple Solution Configurations for each environment, and replace the config at build-time using a pre-build command.

I've used all three techniques over the years. It turns out that the first two don't make much sense for Silverlight, as the ServiceReferences.ClientConfig is bundled into the XAP file that is created at build time. Sure, you can create some type of post-build step that replaces the ClientConfig file in the XAP, but that could get interesting to manage. You don't have an MSI for a XAP, so that option is out as well.

I heavily favor option 3--especially for Silverlight development. The best description I have seen for accomplishing option 3 is good ol' Scott Hanselman's blog entry on Managing Multiple Configuration Environments with Pre-Build Events. Right at the beginning, he says:

"Here's the general idea. It's not too hard. I'll use an ASP.NET Web Site and web.config as an example, but this will work with most any kind of project, exe's or .dll's."

He's right. It works great for Silverlight projects as well! No ripping apart/adding to XAP files after they're built. No NAnt or MSBuild script required. No manual changing of urls when it comes time to deploy. Just follow his post with the following differences:

  1. Make environment-specific ServiceReferences.ClientConfig files (instead of web.config).
  2. Use a slightly different Pre-Build Event that updates ServiceReferences.ClientConfig instead of web.config
  3. Optionally, update the copyifnewer.bat file to use xcopy /R /Y if you use TFS as your source control (thank you, TFS, for making files read-only...argh.)

I will only describe the differences below.

Make the environment-specific ClientConfig files

Just copy the ServiceReference.ClientConfig file that is built for you:


  
    
      
        
          
        
      
    
    
      
    
  

    

and paste the original file into configuration-specific files, such as ServiceReferences.ClientConfig.dev, ServiceReferences.ClientConfig.testing, and ServicesReferences.ClientConfig.production (and don't forget the .debug and .release versions to cover your default solution configurations).

Here's an example of ServiceReferences.ClientConfig.Testing (notice how the highlighted areas are different between the two files; this is the typical place where all of the ClientConfigs differ).


  
    
      
        
          
        
      
    
    
      
    
  

    

Create the Pre-Build Event to Copy the ClientConfig

Instead of replacing the web.config file, change the Pre-Build Event to replace the ServiceReferences.ClientConfig (only when it is different from what's already there):

"$(ProjectDir)copyifnewer.bat" "$(ProjectDir)ServiceReferences.ClientConfig.$(ConfigurationName)" "$(ProjectDir)ServiceReferences.ClientConfig"
        

Add the copyifnewer.bat File

And don't forget to add the copyifnewer.bat file to the root of your project (see Scott's post, lined above) for details on that. Remember, if you use TFS (or some other source control that insists on marking checked in files as Read-Only, you will need to update the .bat file to overwrite without prompting even if the file is Read-Only (xcopy /R /Y worked like a champ).

The Result

Here's a shot of the project structure, once these files are all added:

I love this solution as it works locally, within the IDE as well as on a build server using MSBuild, NAnt calling MSBuild, or NAnt calling devenv.exe directly!

3 comments:

Fire Dragon said...

Nếu bạn đang cần chuyển hàng từ thái lan về việt nam hãy liên hệ với chúng tôi. Chúng tôi sẽ giúp bạn mua hàng thái lan online một cách dễ dàng. Chỉ cần đưa thông tin sản phẩm bạn cần cho chúng tôi, chúng tôi sẽ mua và vận chuyển về Việt Nam. Khi chỉ là mỗi Thái Lan chúng tôi còn có các dịch vụ khác như: dịch vụ chuyển hàng từ mỹ về việt nam, dịch vụ vận chuyển hàng đi campuchia, dịch vụ đặt hàng quảng châu giá rẻ, .... Nếu bạn cần mua hàng trung quốc giá rẻ hay cần mua hàng trên taobao hãy liên hệ và sử dụng
dịch vụ order hàng trung quốc của chúng tôi. Chúng tôi sẽ giúp bạn
chuyển hàng trung quốc về việt nam một cách nhanh chóng và tiện lợi nhất.

Fire Dragon said...
This comment has been removed by the author.
Vương Nguyễn said...

Dịch vụ đấu giá trên ebay
Đấu giá ebay là gì
Dịch vụ đấu giá trên ebay
Hướng dẫn đấu giá trên eBay
Đấu giá hộ trên ebay
Làm thế nào để đấu giá trên ebay
Hướng dẫn mua hàng eBay.com
[Mua hàng eBay] Dịch vụ mua hàng trên eBay
chuyển nhà trọn gói phan nguyễn express
dịch vụ chuyển nhà trọn gói hồ chí minh
Dịch vụ chuyển nhà trọn gói hồ chí minh
chuyển văn phòng trọn gói hồ chí minh
mua hàng trên amazon
mua hàng trên amazon