Silverlight, .NET, WCF RIA Services, RIA, WCF »

[4 Jul 2009 | 1 Comments]

In the first part of this series, I talked about some general concepts, and went into reading, updating, adding, deleting data using RIA Services.  If you haven't read it yet, you might want to read up on that, and maybe read up on the introductory post as well.


In this part, I'll talk about an interesting option you have when updating your data: the change set.


As some people asked for it, I've uploaded the sourcecode of my demo project.  This code will be updated with every new part in the series.  To use the demo code, you'll need to change the connection string for the Entity Model to your own local copy of the AdventureWorks SL database - once that's done, you're ready to go! :-)


As mentioned in the previous part, persisting your changes to the underlying datastore boils down to calling SubmitChanges() on your (clientside) DomainContext.  This will automatically make sure the correct server side methods (in the demo: InsertCustomer, UpdateCustomer or DeleteCustomer) are called for each of your entities. 


Then what is a change set?  A change set should be seen as a complete collection of all the changes you've made on your context, before having them submitted and thus persisted to your datastore.  This principle makes sure server-side methods don't have to be called every time you make a change to your data: the changes will be tracked client-side, and will be submitted once you explicitly call SubmitChanges() to persist your change set.


To visualize this, I've added a few things to the demo application.  To the right side of the datagrid, there's a grid which will track the changes.  This grid contains some textblocks, bound to the number of modified, added, removed entities, and it contains a reject & submit button:




Now, to track the changes, I need to get the changeset from my DomainContext.  I will do this in my datagrid's RowEditEnded-event (which gets fired right after I've edited a row), and this change set will be the datacontext of the grid used to track the changes:




As you can see, context.Entities.GetChanges() returns an EntityChangeSet.  This object contains a list of changes, divided into different lists for AddedEntities, ModifiedEntities, ...  (I've also added a way to delete items from the datagrid, have a look at the source code for that.) 


So, now we've got a list of changes, and thanks to some databinding, these changes are automatically reflected in our UI.  Now, we need to submit or reject this change set.


Rejecting changes is easy: just execute RejectChanges() on your context, and every change you've made that hasn't been submitted yet will be undone.  To submit your changes, call the SubmitChanges()-method on your context:




There is, of course, more to it than just that.  When you submit your changes, a few things will happen.  This is what will be done on your DomainService after you've called that command (copy/paste from the RIA Services documentation):

1. Submit – the service entry point that receives the changeset and begins the changeset processing pipeline
2. AuthorizeChangeSet – Verifies Permission/Authorization for each operation. If any operations are not permitted, processing stops and an error is returned to the client
3. ValidateChangeSet – Validation for all operations in the changeset is run. If any operations fail validation, processing stops and errors are returned to the client
4. ExecuteChangeSet – The corresponding method for each operation in the changeset is invoked. This is the point in time when your business logic is run. If any operations failed, processing stops and errors are returned to the client
5. PersistChangeSet – At this point all the domain operations have been executed, and this method is called to finalize the changes.
6. ResolveChangeSet – If there were any optimistic concurrency errors, this method is called to resolve them.


All these methods are virtual, so they can be overridden as needed!  As you can see, a few things can go wrong (eg, something isn't valid, the necessary permissions aren't available, ...), so it's important to include error handling.  To do this, add an event handler to your context's Submitted-event:



By the way, this is not enough for correct, complete error handling.  For example, in this demo it's quite easy to change the ID of a customer to something that's not valid anymore - best way to solve this is, of course, make sure it's not editable (an internal ID is NOT something you'd want to be editable), or not visible.  But this does show that not all errors are caught: it isn't exactly a Conflict (used for concurrency) and it isn't exactly a a ValidationError (no validation exists on that field) either.  So while this specific example isn't something that would occur in real-life situations, it does show that it's important to put validation on your data where needed AND to include some more general error handling in your code.


But as far as change sets are concerned: you're done!  This is what change sets can mean for you - using them carefully will make sure you don't have unnecessary client-server-communication, and thanks to some databinding, you can easily track the changes in your UI. 


Stay tuned for the next update, in a few days! :-)


Sourcode download.

Silverlight, .NET, WCF RIA Services, RIA, WCF »

[18 Jun 2009 | 2 Comments]

Welcome to the first in a series of RIA Services How-To's.  Unless mentioned otherwise, all these tidbits will use the latest drop of RIA Services (at the moment, this is the May 2009 drop).  When new drops arrive, changes may have to be made, inherent to beta software. 


But, first things first: how do you start using RIA Services?


Step 1:  getting started


Start a new Silverlight-project.  Assuming you've installed everything correctly (I'm using the May drop of RIA Services, SL3 beta, VS2008 SP1), you'll notice a new checkbox, "Link to ASP .NET server project".




If you check this checkbox, RIA Services will be enabled.  You'll end up with 2 projects as usual: your Silverlight-app, and a webapp hosting this Silverlight-app.  You'll notice extra references added to your project to enable RIA Services. 


Tip: you can enable or disable this ability later on, by looking at the project properties of your SL app: you'll notice a combobox, ASP .NET Server Project Link.  Here, you can select the webproject you'll want to link to to use RIA Services.  This effectively means you can enable RIA Services on existing applications, simply by selecting a webproject from your solution.


Step 2: your datastore


You'll need to add some kind of datastore to your webapp.  It doesn't really matter what kind of store this is: it can be an Entity Framework model, but might as well be some simple POCO classes with dummy data.  The client (your SL-app) doesn't need to know what kind of datastore you have - it's totally unaware of this.  I've installed the Lite version of the AdventureWorks-DB, and will use a few tables from it.  So, I right-click my webapp and choose to add a new ADO .NET Entity Model, and select the Customer and CustomerAddress tables from AdventureWorksLT.  I end up with something looking like this:



Step 3: expose your data


Here's where the magic begins! ;-) You need to expose your data to your SL-app.  To do this, you need to create a DomainService.  This is a new class, with which RIA Services will take care of sharing your data/methods across tiers.  To add one, right-click your webapp -> add new item -> Domain Service Class.  Give it a name, and you'll see a screen looking like this:




Of course, you need to check "Enable client access".  :-)  Next, select the datacontext you wish to expose.  In this example, it's the AdventureWorksLT-model I created in the previous step.  Now, you can select which enitities you want to add to your Domain Service.  For each entity you select, methods will automatically be generated to read data from your datastore, and if you check "Enable editing", subsequent insert, update and delete-methods will be generated. 


Tip: if you don't see your datacontext in the dropdownlist, build your application before adding the domain service class.


Last but not least, you can also check "Generate associated classes for metadata".  When this is checked, a metadata-class will be generated, allowing you to do stuff like validation accross tiers, define how your data should look when using a dataform, ...  I always check this option (do you know a lot of apps that don't require validation or don't require the need do define how your data should look? ;-)), but I'll go into detail on that in a future post.


Now, click "OK", and... magic! Visual Studio will start generating lots of code.  On your webapp-side, you'll see your DomainService-class.  It contains all the necessary CRUD-methods (GetCustomer, InsertCustomer, ...).  You can add methods to this class, or change the existing methods as needed: this is the place where you'd put your application logic:




Now, build your solution.  If you check "click all files" on your Silverlight-app, you'll notice a new folder, called, "GeneratedCode".  This is essentially the client-side, generated code that corresponds with the server-side methods.  It contains client-side versions of the classes (entities) you've exposed through your DomainService-class. It also contains a DomainContext, which is the client-side representation of your server-side DomainService.  Through this context, you can access all the functionality of your domain service.  You'll also notice the DomainContext containing Load-methods for your entity-lists.



Tip: the names of these methods are automatically generated - by default, an entity "Customer" will have a "GetCustomer"-method server-side, and a "LoadCustomer"-method client-side.  If you want to choose what name the generated client-side method must have, you can use the [Query]-attribute.  Check my previous post for more info on that.


Step 4: accessing your data from your SL-app


All necessary code has been generated, so now you need to access this data from your Silverlight-application.  As I explained, on your client, Load-methods have been generated (methods like this will be generated for every method you write in your server-side domain service class which returns an IQueryable list).  First, you need to instantiate your client-side generated DomainContext.  You'll notice that that instance contains the generated Load-Methods, and also collections of your entities (eg: the Customers-property is actually an EntityList of Customer):




Now, you want to call the client-side LoadCustomer-method to load the customers.  When this statement is executed, the GetCustomer-method on your server-side DomainService will be executed.




To display the data you've got in your app, bind it to, for example, a datagrid.  You'll end up with something looking like this:




And you're done! ;-) As you'll notice, you've also got events on your DomainContext like Loaded / Loading / PropertyChanged: you can add Event Handlers to these as needed.


Step 5: adding, deleting, updating your data


Next steps are of course deleting, adding, updating, ... your data.  This is actually quite simple: what you need to do is manipulate the EntityLists you've got in the DomainContext on your client side: Customers, for example.  Add elements, update elements or delete elements from that list.  Now, your DomainContext instance has a method called SubmitChanges & RejectChanges.  As you might have guessed by now, executing the SubmitChanges-method will persist the changes you've made on the collections to your database (it will call the corresponding server-side methods for this automatically).  RejectChanges, well, rejects your changes ;-)  There is, of course, much & much more to this - you can work with transactions, changesets, check for changes, et cetera - more on that in one of the next articles. 


That's it! This article should've covered the basics of working with RIA Services.  I hope this helps some of you out - check back regularly for more! ;-)


A word of advice: RIA Services is beta-software, and lots of code gets generated automatically.  In most scenario's, you'd want to split your Domain Services into another namespace (or even assembly).  However: this doesn't really work as you'd expect at the moment of writing.  You'll notice code generation going bonkers when trying this, so for now: just keep everything in the same namespace.  I assume (hope ;)) this will be fixed in future drops.

Silverlight, .NET, WCF RIA Services, RIA, WCF »

[15 Jun 2009 | 0 Comments]

First of all, welcome to a completely new blog-look! :-) 


The last few weeks, I've been playing around with RIA Services (for Silverlight 3), which "simplifies the traditional n-tier application pattern by bringing together the ASP.NET and Silverlight platforms. The RIA Services provides a pattern to write application logic that runs on the mid-tier and controls access to data for queries, changes and custom operations. It also provides end-to-end support for common tasks such as data validation, authentication and roles by integrating with Silverlight components on the client and ASP.NET on the mid-tier." (uhm, yeah, I borrowed that part from Brad Abrams  ;-)).


To clarify this a bit: we're all used to writing service-oriented SL-apps.  Typically, you'd have a webservice or WCF-service residing somewhere, and you'd use the "Add Service Reference"-option in Visual Studio or a WebClient to get your data.  I actually like that approach, but it's a fact that most people are used to working in a typical n-tier environment (just check the numerous posts on the Silverlight .NET forums asking about how to convert an existing n-tier app to a Silverlight app, or about strategies to get data into a Silverlight-app). 


Well, RIA Services bridge this gap; you're still working service-oriented, but it looks and feels different - it feels more as if you were programming in a typical n-tier architecture.  On top of that, it offers easy validation & authentication, and useful client-side controls like the DomainDataSource with built-in sorting, filtering, ... capabilities.  And I'm actually starting to like this as well :-)


How do you get started with all this?  You'll need Visual Studio 2008 SP1, Silverlight 3 & the last drop (at the moment of writing, this is the May drop) of the services.  All downloads can be found at Silverlight .NET, as well as a few good tutorials.  For an in-depth view, I'd suggest having a look at the released documentation, which can be found on MSDN's download page.  It's pretty big (about 116 pages), but it covers a lot of what RIA Services have to offer.  You can also find official sample applications here.  Don't want to read through all the documentation?  Well, I found Martin Mihaylov's tutorials at SilverlightShow.NET very useful, you might want to check 'em out!


Or... you might want to come back to this site every few days :-)  In the next few days, I'm going to start adding posts about these RIA Services and what you can do with 'em - such as paging, sorting, validation, authentication & authorization, how to submit changes or even changesets, ...  These will come in simple & to the point "How do I ...?"-format, for easy reference afterwards (for myself, and hopefully for you as well ;-)).  So stay tuned!


So what about that "something you might not yet know" I mentioned in the title?  Well, from the moment you start working with RIA Services, you'll notice that it automatically generates Load-methods on the client for the Get-methods you have on your server.  Eg: if you've got a GetCustomer-method on your server (which returns an IQueryable<Customer>), a LoadCustomer-method will automatically be generated on your client.  But what if you don't like that prefix?  I kind of like my methods to have the same name across different layers (tends to avoid confusion).  Good thing is, RIA Services is very customizable in the way it generates code - typically by decorating your code with a few attributes, you can control the code that's generated client-side.  To make sure the client-side method will have the same name as your server-side method, use the following attribute:


   1: [Query(PreserveName = true)]

   2: public IQueryable<Customer> GetCustomer()

   3: {

   4:     return this.Context.Customer.OrderBy(c => c.CompanyName);

   5: }



From now on, GetCustomer will still be called GetCustomer on your client.  Nice & easy :-)

General, Presentations and sessions »

[26 May 2009 | 0 Comments]

Quick "plug" ;-) 


In the upcoming weeks, Maarten Balliauw (one of my collegues, an expert in ASP .NET MVC & PHP) and I will be giving a few sessions together in The Netherlands: on Friday the 29th of May, we'll be speaking @ Microsoft's DevDays in Den Haag, and on Friday the 12th, we'll be speaking @ the Dutch PHP Conference in Amsterdam.  The session we're delivering is called "PHP & Silverlight".


What can you expect?  Well, we'll have a look at how to integrate PHP & Silverlight, and at the SL programming model in general.  I'm delivering the Silverlight-part, my collegue Maarten is delivering the PHP-part of the session.  It's not an in-depth level 400 session, but it's meant to give you an idea of how you can use PHP & Silverlight together (creating a SL-project in Eclipse, hosting SL on a PHP-page, using a PHP-webservice from SL), and at the same time give an intro on what Silverlight can do, focussing on the - in my opinion - 4 keywords everyone should know & understand when developing Silverlight: DataContext, DataBinding, INotifyPropertyChanged and IValueConverter. 


So, if you happen to be in the neighbourhood, come check us out and/or join us at the bar for a drink after the session! ;-)


PS, if you're coming to the Amsterdam session, make sure you take a few extra days to stroll around the city - it's not Barcelona, but it's a really nice and relaxing city with a few great places to visit; one of my favourite cities in Europe, actually.

Silverlight, .NET, RIA »

[18 May 2009 | 0 Comments]

One day, two posts! :-)  A member of the Silverlight .NET forum asked how he could go about making a Silverlight combobox editable.  Well, it's actually easier than you might think, so for all of you who want this kind of behaviour: here's how you do it! :-)  The same technique can also be used to make an editable listbox, and usual, sourcecode is included at the end of this post.


I designed a dummy data-object for binding to the combobox.  This is a small class which has a Description-propery, an ID and an InEdit-property (to  and it implements the INotifyPropertyChanged-interface, so it can notify the UI when its value changes.

   1: public class Dummy : INotifyPropertyChanged

   2:     {

   3:         public int ID { get; set; }


   5:         private bool pInEdit;

   6:         public bool InEdit

   7:         {

   8:             get

   9:             {

  10:                 return pInEdit;

  11:             }

  12:             set

  13:             {

  14:                 pInEdit = value;

  15:                 NotifyPropertyChanged("InEdit");

  16:             }

  17:         }


  19:         private string pDescription;

  20:         public string Description

  21:         {

  22:             get

  23:             {

  24:                 return pDescription;

  25:             }

  26:             set

  27:             {

  28:                 pDescription = value;

  29:                 NotifyPropertyChanged("Description");

  30:             }

  31:         }


  33:         #region INotifyPropertyChanged Members


  35:         public event PropertyChangedEventHandler PropertyChanged;


  37:         public void NotifyPropertyChanged(string propertyName)

  38:         {

  39:             if (PropertyChanged != null)

  40:             {

  41:                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

  42:             }

  43:         }


  45:         #endregion

  46:     }

Next, we need to build the datatemplate of our combobox.  Essentially, we'll have two "views": a normal view, and an editable view.  We'll use a button to switch between these views.

   1: <ComboBox.ItemTemplate>

   2:     <DataTemplate>

   3:         <Grid>

   4:             <Grid.ColumnDefinitions>

   5:                 <ColumnDefinition Width="200"></ColumnDefinition>

   6:                 <ColumnDefinition Width="Auto"></ColumnDefinition>

   7:             </Grid.ColumnDefinitions>



  10:             <TextBlock Text="{Binding Description, Mode=TwoWay}" 

  11:                        HorizontalAlignment="Left" VerticalAlignment="Center"

  12:                        IsHitTestVisible="False" 

  13:                        Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=contra}"/>


  15:             <TextBox Text="{Binding Description, Mode=TwoWay}" 

  16:                     Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=pro}"

  17:                      HorizontalAlignment="Left" VerticalAlignment="Center"/>


  19:             <Button Width="60" x:Name="btnEdit" Click="btnEditConfirm_Click" Content="Edit" Grid.Column="1" 

  20:                     Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=contra}" />


  22:             <Button Width="60" x:Name="btnConfirm" Click="btnEditConfirm_Click" Content="Confirm" Grid.Column="1"

  23:                     Visibility="{Binding InEdit, Converter={StaticResource BoolToVisibilityConverter}}"/>


  25:         </Grid>

  26:     </DataTemplate>

  27: </ComboBox.ItemTemplate>

To make sure the correct view is shown, I use a convertor to convert the InEdit-value of my object to a Visibility-property.  When InEdit is true, the textbox & confirm-button will be shown, when it's false you'll only see a textblock and an edit button.  For reference, here's what the convertor looks like:

   1: public class BoolToVisibilityConverter: IValueConverter

   2:     {


   4:         #region IValueConverter Members


   6:         /// <summary>

   7:         /// Convert method from bool to visibility

   8:         /// </summary>

   9:         /// <param name="value">the boolean/visibility value value</param>

  10:         /// <param name="targetType"></param>

  11:         /// <param name="parameter">mappingmode = pro or contra.  Pro will map true to visible, contra

  12:         /// will map true to collapsed</param>

  13:         /// <param name="culture"></param>

  14:         /// <returns></returns>

  15:         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

  16:         {

  17:             bool normalDirection = true;


  19:             if (parameter != null)

  20:             {

  21:                 if (parameter.ToString().Trim().ToLower() == "contra")

  22:                    normalDirection = false;

  23:             }


  25:             if (value is bool)

  26:             {

  27:                 if ((bool)value)

  28:                 {

  29:                     return normalDirection ? Visibility.Visible : Visibility.Collapsed;

  30:                 }

  31:                 else

  32:                 {

  33:                     return normalDirection ? Visibility.Collapsed : Visibility.Visible;

  34:                 }

  35:             }

  36:             else

  37:             {

  38:                 return Visibility.Visible;

  39:             }

  40:         }


  42:         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

  43:         {

  44:             bool normalDirection = true;


  46:             if (parameter.ToString().Trim().ToLower() == "contra")

  47:                 normalDirection = false;


  49:             if (value is Visibility)

  50:             {

  51:                 if ((Visibility)value == Visibility.Visible)

  52:                 {

  53:                     return normalDirection ? true : false;

  54:                 }

  55:                 else

  56:                 {

  57:                     return normalDirection ? false : true;

  58:                 }

  59:             }

  60:             else

  61:             {

  62:                 return true;

  63:             }

  64:         }


  66:         #endregion

  67:     }

All we need to do now is handle the click-event of the edit & confirm button.  Thanks to the rich, two-way-databinding, all we need to do in these handlers is change the edit-mode: we use the DataContext of the sender to access the underlying object, and change the edit-mode-property.  We do not need to write our changes to the underlying collection nor commit them manually in any way, nor update the UI when a value is changed - Silverlights' databinding & notifypropertychanged-interface handles this for us. 

   1: private void btnEditConfirm_Click(object sender, RoutedEventArgs e)

   2:         {

   3:             Dummy tmpDummy = (Dummy)(((Button)sender).DataContext);

   4:             tmpDummy.InEdit = !tmpDummy.InEdit;

   5:         }

... and that's it, really. :-)  As said, the same technique can also be used to make your listbox editable (or any itemscontrol for that matter). 

As promised: sourcecode.  Enjoy!

Silverlight, .NET »

[18 May 2009 | 0 Comments]

A few weeks ago, a client asked me to come in to have a look at their Silverlight-application, since they were facing some problems with the asynchronous calls to services.  In particular: how do you go about blocking your UI when such a call is being made?  Mind you, I don't mean the type of "blocking" that hangs the UI, I mean the type that blocks the user from continuing or entering invalid info :-)


As I wrote a while ago: when you face problems like this, DO NOT try to attempt to make the service call behave as if it were synchronous.  Why?  Well, in short, it never rrrreeallly works, and it kind of defeats the purpose of using async calls to avoid an application that feels like it's hanging :-)


So, what can you do?  What if you have, for example, a button on your application which should not execute it's handler unless a few conditions are true, and what if one of those conditions is validated through a service?  Say you have a textbox, and depending on the value inputted in that textbox, the button should be clickable or not.  But: it takes some time to return from the async call checking the value in the textbox, so a fast user just might be able to click your button, even though the value in the textbox validates to false, meaning the button shouldn't be clickable.  In a non-async world, you could simply put your validation rules behind the button click, but in the async SL-world, this isn't an option anymore - if one of the validation rules requires a service call, you're stuck.


Don't fear though :-)  A few really simple rules apply to make sure your async calls won't pose problems when concerning user input, validation, etc.  This post will outline (some of) 'em, and provide you with a downloadable example project at the end of this post.


  1. the first one: change the way you handle your validation: instead of assuming something is valid until proven otherwise, assume it's invalid until proven otherwise.  Eg, if a button should only be clickable if every input field is valid, disable it by default, and only enable it after every field has been validated to true.  You might want to add handlers for validation to the lostfocus-event of your input fields, for example. 
  2. a second rule: do not execute async server side validation on the click of the button which defines wether or not the user can continue with the application.  Validate when you can, when it's needed, not at the last possible moment: otherwise, you might run into the problem where you want to execute code depending on what value is returned from your async call, but you have no way of telling WHEN it will return.  Therefore, I like to validate my fields on, for example, their lostfocus-event.
  3. third one: when validating or doing a server-side call, show this to your user.  Show a loading-icon or progress indicator, so the user won't start yelling at his computer screen, because the value he inputted in the textbox is valid, yet the button to continue is still greyed out.
  4. fourth one: disabling input, clicks, et cetera can be done in various ways: removing handlers, disabling a visual or setting the IsHitTestVisible-property to true could all be considered.
  5. fifth one, not a rule, rather a suggestion: to avoid hammering, you might want to consider to "block" your application from starting too much service calls when validating.  You can do this by overlaying your application with a stretched canvas while the service call is being made (and consequently remove the overlay when the call returns).  This, however, should be handled with care, 'cause using it too much might give the impression of a non-responsive app.


A small example project using a few of these techniques can be found here.  Hope this helps some of you out! :-)

Silverlight, WCF »

[7 May 2009 | 0 Comments]

Ever ran into the problem, when talking via WCF to a service, all your service calls fail because the servicehost-address in the generated WSDL is wrong?  In that case, this post is for you! :-)

Think of a network setup like this:

  • you've got a Silverlight-app, speaking with a bunch of services through WCF, over https.
  • however, your app doesn't talk directly to your servicehost.  It talks to a proxy.  And that proxy forwards to an internal load balancer.  And that load balancer in turn forwards to different web servers containing the servicehost installations.

This is the setup I was dealing with @ a certain company.  The app worked correctly in dev & test, where no proxy/load balancer was used.  However, when rolling it out to the production environment, everything started to go horribly wrong... every service call failed.


After taking a look at the WSDL of one of the services, it seemed that the problem was related to the network setup: the address in the WSDL wasn't the external address anymore, it was the address of (one of the) the internal web server(s) (yes, even behind the load balancer) where the servicehost was installed.  Needless to say, this was reason all the calls failed, seeing the internal address was off course inaccessible from outside.


Pretty annoying problem.  I started looking around a bit, and found out more people seemed to have this problem.  I've read various posts describing possible solutions with custom bindings (not that easy when using Silverlight, since not everything WCF-related is available), and the general sentiment portrayed in the posts seemed to be that this was a shortcoming of WCF.  Another post described a new setting in 3.5 SP1, baseAddressPrefixFilter, that was supposed to solve this problem. However, that didn’t do the trick. In the end, we could off course have opted to just write a custom factory – that would definitely solve this problem; but that just didn’t feel right – surely, there must be a better way to solve this problem? After all, the network setup described isn’t that uncommon in Enterprise scenarios.


After a lot of searching & trial and error, it was one of my collegues (our WCF specialist) who put me on the right track: he figured this wasn’t a WCF problem – after all, WCF gets it’s addresses from IIS bindings, so he thought the problem was IIS-related, not WCF-related. And after looking into this, turns out he was right! Using appcmd.exe, we set the bindings in IIS on our website behind the loadbalancer to bind to the external address we wanted to see in the WSDL. After doing this, when WCF gets to the load balancer, this last one knows through the bindings what address to return, and thus the generated WSDL contains the correct (external) address for service locations!


So, quick tip for everyone: if you’re using a network setup as described above, and you get a WSDL that contains the wrong hosts/service op locations, first have a look at your IIS configuration/bindings, before diving into (or blaming…) the lesser-known depths of WCF! :-)