.NET, Featured, Silverlight, Headline, WCF »

[18 Feb 2011 | 0 Comments]

cow_clipartAfter my previous post on how to use a Channel Factory in Silverlight, I received quite a few questions through Twitter, the main one being: “how do you pass in parameters to an operation?”  Next to that, someone also suggested to use a custom binding with binary encoding instead of the default basicHttpBinding.  So I decided to write a post explaining how to achieve those two things – welcome to part 2: binary cows & new-born calves! :)

 

First up: passing in parameters to the operation.  To keep in theme with the last solution, we’re going to allow the user to create a new-born calve on the client, and send that to the server.  For the sake of the demo, the only thing we’ll do on the server is fill out the correct ImageUri, and we’ll send the resulting Cow object back to the client. 

 

public Domain.Cow AddCow(Domain.Cow newBorn)
{
    newBorn.ImageUri = new Uri(http://localhost:5873/calve_clipart.png, 
UriKind.Absolute);
  
    return newBorn;
}

 

The part that confused some people was how to write the correct async signature to match the regular operation contract.  It’s actually quite simple: in the Begin method, you should add the parameter(s) you want to pass in before the IAsyncResult and state parameters:

 

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginAddCow(Cow newBorn, AsyncCallback callback, Object state);

Cow EndAddCow(IAsyncResult result);

 

To call this method, you should write code like this:

 

private void AddCowExecution()
{
    Cow newBorn = new Cow() { Name = "New born" };

    // call CowService WCF service
    ICowService channel = GetCowServiceFactoryChannel();

    var y = channel.BeginAddCow(newBorn,
       (asyncResult) =>
       {
           // add Cow
           var returnVal = channel.EndAddCow(asyncResult);

           Deployment.Current.Dispatcher.BeginInvoke(() =>
           {
               // add to collection
               Cows.Add(returnVal);
           });
       }
       ,  null);
}

 

Now, how do you make sure you use binary encoded messages through a custom binding?  Two things should be done for this: when creating the Channel Factory on the client, you should create your custom binding and pass that in.  On the server, you need an endpoint that uses the same kind of custom binding.  That means you have to change two things: first, the client-side code: we create a custom binding and add the necessary binding elements (binary encoding over http transport):

 

CustomBinding customBinding = new CustomBinding();
customBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
customBinding.Elements.Add(new HttpTransportBindingElement());

EndpointAddress endpointAddress = new EndpointAddress(CowServiceEndpointAddress);
CowServiceChannelFactory = new ChannelFactory<ICowService>
(customBinding, endpointAddress);

 

… and then the web.config to make sure it has a correct endpoint: define the custom binding, and add the binding & binding configuration elements to your endpoint:

 

<bindings>
    <customBinding>
        <binding name="ChannelFactoryWithCows.CustomBinaryBinding">
            <binaryMessageEncoding />
            <httpTransport />
        </binding>
    </customBinding>
</bindings>

 

and:

 

<service name="ChannelFactoryWithCows.Web.CowService">
    <endpoint address="" binding="customBinding" 
              bindingConfiguration="ChannelFactoryWithCows.CustomBinaryBinding" 
              contract="ChannelFactoryWithCows.Contracts.ICowService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

 

So there we go – we now have a cow farm, compressing the cows before travel and allowing new calves to be born :-)  You can download the source code here.

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! :-)

Silverlight, WCF »

[3 Feb 2009 | 0 Comments]

When talking about security for service calls, there are actually a few things to consider.  First of all, how do you make sure the data sent over the wire is encrypted?  That's your first level of security: always make sure the data that's being sent over the wire is encrypted.  After all, unless we're working in an intranet environment, anyone could potentially look at the packets that are being sent. 

Luckily, securing this is easy to do: use SSL/https.  As far as SL/WCF is concerned, this comes down to setting your security mode to "Transport" in your binding.  That's really all there is to it.

On to the next level, what this is all about: securing your calls (for reference, I've made a Visual Studio solution documenting different ways of doing this - you can download that at the bottom of this post).  Lots of projects have some kind of requirement stating only certain people can call certain service operations - for example, you might only want people with a valid username/pw-combination to be able to call your operations, instead of letting everyone call them.  Seeing your servicehost will probably be publicly available (again, unless you're working in an intranet-environment),  anyone could potentially write a client to communicate with your services.  This obviously poses some serious risks.

So, on to username authentication on your service operations.  The idea is that you will require every service call to provide you with a username/pw-combination.  In the service operation, this combination will be validated and  the call will only continue if the combination is valid.  Thus blocking off everyone who hasn't got a valid  combination from using your services! Since we're using SSL/https to encrypt our message, we can safely send the username/pw over the wire.  A comparable method already exists out of the box with WsHttpBinding, but in  Silverlight, we're limited to basicHttpBinding, so we can't use that one.

This project shows different ways of implementing this:

  • No authentication.  This is a regular service call, everyone will be able to call the service, no username/pw is passed or sent over the wire, no authentication is done.  This is, obviously, not secure, and shouldn't be done outside of a controlled environment.
  • Authentication through method parameters. Username/pw are provided via parameters to the service method. Authentication is done in the service method.  This will work, but it isn't exactly a beautiful solution: all your service method signatures will have to have 2 additional parameters: username & pw.
  • Authentication through message headers. Instead of passing the username/pw to the method via parameters, they are passed by adding them to the message header of the message which is sent over the wire. Once in the service method, they are extracted and authentication is done.  This is already a lot better than the previous method: no additional parameters are required.
  • Authentication through message headers by implementing an operation behavior. Same as the previous method, but instead of writing code in every method to check username/pw, we write this code once in a custom operation behavior. Every method decorated with this attribute will automatically perform username/pw authentication. This is the preferred way to implement username/pw authentication.

Conclusion: nice code, not too much clutter, encrypted messages & safe calls! :-)
For those of you who want to read more about this (and then some), I got A LOT of help from the reference made by David Betz - give it a read if you find the time.

As usual, full source code is included.  You can download that here.  Enjoy!