2005 2006 2007 2008 2009 2010 2011 2015 2016 2017 aspnet azure csharp debugging elasticsearch exceptions firefox javascriptajax linux llblgen mongodb powershell projects python security services silverlight training videos wcf wpf xag xhtmlcss

Reusing .NET Assemblies in Silverlight

Table of Contents

Introduction

Long before Silverlight 1.0 was released, it was actually called WPF/E or WPF Everywhere.  The idea was to allow you to create WPF like interfaces in your web browser.  This can be seen in a very small way in Silverlight 1.0.  All it provided was very basic primitive objects with the ability for interact with client-side technologies like JavaScript.  However, with Silverlight 2.0, Silverlight is actually more than what was originally promised with the term "WPF/E".  Silverlight is now far much more than a graphical technology.  All this stuff about Silverlight being "WPF for the Web" is more to make the marketing folks happy than anything else.

As a technology parallel to .NET, Silverlight is not part of the .NET family.  Rather, it essentially mirrors the .NET platform to create a new platform inside of a web browser where you have a mini-CLR and mini-Framework Class Library (FCL).  However, even though they are parallel technologies, you would suspect that Microsoft would allow some level of reuse between the two.  As it turns out, most topics are completely reusable.  Among other things, Silverlight has delegates, reference types, value types, a System namespace, and the ability to write code in both C# and VB.

Furthermore, despite the rumors, Silverlight also shares the exact same module and assembly format as .NET.  This may seem completely shocking to some people given the fact that Visual Studio 2008 doesn't allow you to reference a .NET assembly in a Silverlight project.  In reality, however, there's no technical reason for this prohibition.  There isn't a single byte difference between a Silverlight and .NET assembly.  One way to see this is by referencing a Silverlight assembly in a .NET project.  Just try it.  It works great.  So, why doesn't Visual Studio allow .NET assemblies in Silverlight projects?

To answer this, we need to understand that just because an optional helper tool (i.e. Visual Studio) doesn't allow something, that doesn't mean the technology itself doesn't.  In this case, the reason why Visual Studio allows a .NET project to reference Silverlight assemblies, but not the other way around is probably because .NET assemblies can normally do more.  For example, .NET has all kinds of XML related entities in its System.Xml assembly.  If Silverlight were to try to use this, it would blow up at runtime.  However, both Silverlight and .NET have an mscorlib assembly thus giving them a sense of brotherhood.  Having said that, Silverlight has the System.Windows.Browser assembly which, upon access in .NET, would make your .NET application explode!  Thus, the Visual Studio restriction laws are flawed.

Fortunately, there are ways around Visual Studio's fascist regime.  I'm going to talk about two different ways of reusing .NET assemblies and code in Silverlight.  The first technique is the more powerful assembly-level technique, while the second is more flexible file-level technique.  Each technique is useful for its own particular scenarios.  Please keep naive comments of "I'm ALWAYS going to..." and "I'm NEVER going to..." to yourself.  You need to make decisions of which of these techniques or possibly another technique to use on a case by case basis.

The Assembly-Level Technique

For this technique, you need to understand what's going on under the covers when you try to add a .NET reference to your Silverlight application in Visual Studio.  It's actually incredibly simple.  Visual Studio isn't a monolith that controls all your code from a centralized location; sometimes it uses plug-ins to do it's dirty work.

In this case, Visual Studio 2008 uses the Microsoft.VisualStudio.Silverlight .NET assembly.  In this assembly is the Microsoft.VisualStudio.Silverlight.SLUtil class which contains the IsSilverlightAssembly method.  When you add an assembly to a Silverlight Project, this method is called internally to see if your assembly is Silverlight.  If it is, it will add it.  If not, it won't.  It's just that simple.  But, given that the Silverlight and .NET assembly format is the same, how can it know?

You may be shocked to find out that the reason behind this is completely artificial: if the assembly references the 2.0.5.X version of the mscorlib assembly, then Visual Studio says that it's a Silverlight assembly!  This test is essentially all the IsSilverlightAssembly does.  Therefore, if you take your .NET 2.x/3.x assembly and change the version of mscorlib that your assembly references from 2.0.0.0 to 2.0.5.0, you may then add the assembly as a reference.  Now let's talk about this with a more hands on approach.

Below is the sample code we will be working with for this part of the discussion.  Say this code is placed in an empty .NET project.  When it is compiled, we will have an assembly.  Let's call it DotNet.dll.

using System;
//+
namespace DotNet
{
    public class Test
    {
        public String GetText()
        {
            return String.Format("   ", "This", "is", "a", "test");
        }
    }
}

Before we go any further, lets' discuss the state of the universe at this point.  If you ever try to solve a problem without understanding how the system works, you will at best be hacking the system.  Professionals don't do this.   Therefore, let's try to understand what's going on. 

The first thing you need to know is that when you add an assembly to a project in Visual Studio, you are simply telling Visual Studio to tell the compiler what reference you have so that when the compiler translates your code into IL, it knows what assemblies to include as "extern assembly" sections.  Even then, only the assemblies that are actually used in your code will have "extern assembly" sections.  Thus, even if you added reference every single assembly in your entire system but only use two, the IL will only have two extern sections (i.e. references assemblies).  The second thing you need to know is that no matter what, your assemblies will always have a reference to mscorlib.  This is the root of all things and is where System.Object is stored.

To help you understand this, let's take a look at the IL produced by this class.  To look at this IL, we are going to use .NET's ILDasm utility.  Reflector will not be your tool of choice here.  Reflector is awesome for referencing code, but not for working with it.  It's more about form than function.  With ILDasm we are going to run the below command:

ILDasm DotNet.dll /out:DotNet.il

For the sake of your sanity, use the Visual Studio command prompt for this.  Otherwise you will need to either state the absolute path of ILDasm or set the path.

This command will produce two files: DotNet.il and DotNet.res.  The res file is completely meaningless for our discussion and, therefore, will be ignored.  Here is the IL code in DotNet.il:

.assembly extern mscorlib
{
    .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
    .ver 2:0:0:0
}
.assembly DotNet
{
    /** a lot of assembly level attributes have been left out **/

    .hash algorithm 0x00008004
    .ver 1:0:0:0
}
.module DotNet.dll
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 
.corflags 0x00000001     

.class public auto ansi beforefieldinit DotNet.Test extends [mscorlib]System.Object
{
    .method public hidebysig instance string GetText() cil managed
    {
        .maxstack    4
        .locals init ([0] object[] CS$0$0000)
        IL_0000:    ldstr "   "
        IL_0005:    ldc.i4.4
        IL_0006:    newarr [mscorlib]System.Object
        IL_000b:    stloc.0
        IL_000c:    ldloc.0
        IL_000d:    ldc.i4.0
        IL_000e:    ldstr "This"
        IL_0013:    stelem.ref
        IL_0014:    ldloc.0
        IL_0015:    ldc.i4.1
        IL_0016:    ldstr "is"
        IL_001b:    stelem.ref
        IL_001c:    ldloc.0
        IL_001d:    ldc.i4.2
        IL_001e:    ldstr "a"
        IL_0023:    stelem.ref
        IL_0024:    ldloc.0
        IL_0025:    ldc.i4.3
        IL_0026:    ldstr "test"
        IL_002b:    stelem.ref
        IL_002c:    ldloc.0
        IL_002d:    call  string [mscorlib]System.String::Format(string, object[])
        IL_0032:    ret
    }

    .method public hidebysig specialname rtspecialname 
         instance void    .ctor() cil managed
    {
        .maxstack    8
        IL_0000:    ldarg.0
        IL_0001:    call  instance void [mscorlib]System.Object::.ctor()
        IL_0006:    ret
    }
}

Right now we only care about the first section:

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 2:0:0:0
}

This ".assembly extern ASSEMBLYNAME" pattern is how your assembly references are stored in your assembly.  In this case, you can see that mscorlib is referenced using both it's version and it's public key.  For our current mission, all we need to do is change the second 0 to a 5.  The public key tokens used in Silverlight are completely different from the ones in .NET, but we are trying to fool Visual Studio, not Silverlight.  This is a compile-time issue, not a runtime-issue.  Speaking more technically, we don't care about the public key token because this information is only used when an assembly is to be loaded.  The correct mscorlib assembly will have already loaded by the Silverlight application itself long before our assembly comes on the scene.  So, in our case, this entire mscorlib reference is really just to make the assembly legal and to fool Visual Studio.

Once you make the change from 2:0:0:0 to 2:0:5:0, all you need to do is use ILAsm to restore the state of the universe (unlike Reflector with C#, ILAsm can put humpty dumpty back together again).  Here's our command for doing this (in this case the resource part is completely optional, but let's add it for completeness):

ilasm DotNet.il /dll /resource:DotNet.res /out:DotNet2.dll

You are now free to reference your .NET assembly in your Silverlight project or application.  As I've already mentioned, Silverlight and .NET have the same assembly format.  There's nothing in Silverlight that stops us from referencing .NET assemblies, it was only Visual Studio stopping us.

At this point you have just the basics of this topic.  However, it's not the end of the story.  As you should be aware, .NET's core assemblies use four-part names.  That is, they have a strong name.  This is used to disambiguate them from other assemblies.  That is, instead of the System assembly being called merely "System", which can easily conflict with other assemblies (obviously written by non-.NET developers who don't realize that System should be reserved), it's actually named "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".  When you reference an assembly, you need to make sure to match the name, version, culture, and public key token.  When it comes to using .NET assemblies in Silverlight, this is critically important.

Let's say, for instance, that you created a .NET project which referenced and used entities from the System, System.ServiceModel, and System.Runtime.Serialization assemblies.  In this case, the IL produced by the .NET compiler will create the following three extern assembly sections:

.assembly extern System
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
  .ver 2:0:0:0
}
.assembly extern System.ServiceModel
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
  .ver 3:0:0:0
}
.assembly extern System.Runtime.Serialization
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
  .ver 3:0:0:0
}

Notice the public key token on each.  Here all three are the same, but for other .NET assemblies they may be different.  What's important here, though, is that the keys are used to identity the assemblies for .NET, not Silverlight.  Thus, even though you did add your .NET assembly to your Silverlight application, an exception would be thrown in runtime at the point where your application tries to access something in one of these assemblies.

The following shows you what would happen in the extreme case of trying to use the System.Web assembly in your Silverlight.  You would get the same error if you tried to access something in one of the above assemblies as well.

AssemblyException

As it stands, though, we can fix this just as easily as we fixed the mscorlib problem in Visual Studio.  All we need to do is open our IL and change the public keys and versions to the Silverlight versions.  Below is a list of the common Silverlight assemblies each with their public key token and version:

.assembly extern mscorlib
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Core
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Net
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Runtime.Serialization
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Windows
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}
.assembly extern System.Windows.Browser
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E)
  .ver 2:0:5:0
}

//+ note the different public key token in the following
.assembly extern System.ServiceModel
{
  .publickeytoken = (31 BF 38 56 AD 36 4E 35)
  .ver 2:0:5:0
}
.assembly extern System.Json
{
  .publickeytoken = (31 BF 38 56 AD 36 4E 35)
  .ver 2:0:5:0
}

Just use the same ILDasm/Edit/ILAsm procedure already mentioned to tell the assembly to use the appropriate Silverlight assemblies instead of the .NET assemblies.  This is an extremely simple procedure consisting of nothing more than a replace, a procedure that could easily be automated with very minimal effort.  It shouldn't take you much time at all to write a simple .NET application to do this for you.  It would just be a simple .NET to Silverlight converter and validator (to test for assemblies not supported in Silverlight).  Put that application in your Post Build Events (one of the top 5 greatest features of Visual Studio!) and you're done.  No special binary hex value searching necessary.  All you're doing is changing two well documented settings (the public key token and version).

For certain assemblies, this isn't the end of the story.  If your .NET assembly has a strong name, then by modifying it's IL, you have effectively rendered it useless.  Aside from disambiguation, strong names are also used for tamper protection.  You can sort of think of them as a CRC32 in this sense.  If you were to modify the IL of an assembly with a strong name, you would get a compile-time error like the following:

StrongNameException 

However, as you know by the fact that we have looked at the raw text of the source code with our own eyes, the strong name does absolutely no encryption of the IL.  That's one of the most common misconceptions of strong names.  They are not used as for public key encryption of the assembly.  Therefore, we are able to get around this by removing the public key from our assembly before using ILAsm.  Below is what the public key will look like in your IL file.  Just delete this section and run ILAsm.

.publickey = (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00
              00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00
              37 3C 5A 7F 6D B6 3F 30 D8 3F DE E3 17 FE E5 2E
              68 43 16 A9 7C 42 69 5A 05 52 E6 73 C5 AC 58 7E
              B0 00 9F DC 1B 0A 78 57 79 12 79 53 E1 60 EB C9
              ED 49 7C 8C 73 1B 01 A7 BA 57 79 B5 53 83 8B CA
              8D F8 6F 3B BD A5 E4 BA 6A 12 B9 52 F2 E9 A3 FC
              42 17 E4 33 97 92 DC 21 30 57 B9 D3 63 7A F2 43
              73 42 70 18 89 8B 44 B9 D4 5A BA A9 21 A3 D9 E0
              86 20 3C 30 01 A9 B9 BB F4 D8 79 B7 7D 56 5A A9)

Upon using ILAsm to create the binary version of the same IL, you will be able to add your assembly, compile and run your application without a problem.  However, you can take this one step further by telling ILAsm to sign the assembly using your original strong name key.  To do this, just use the key command line option to specify the strong name key you would like to use.  Below is the new syntax for re-signing your assembly:

ILAsm DotNet.il /dll /resource:DotNet.res /out:DotNet11.dll /key=..\..\MyStrongNameKey.snk

At this point you have a strongly-named Silverlight assembly createdrom your existing .NET assembly.

Now, before moving on to explain a more flexible method of reuse, I want to cover a few miscellaneous topics.  First, for those of you who know some IL and are trying to be clever to make this process even simpler, you may think you could just do the following:

.assembly extern mscorlib { auto }

This won't work as ILAsm will look for "auto" and place the 2.0.0.0 version in it's place, thus leaving you right where you started.  Also, don't even think about leaving the entire mscorlib part off either.  That won't fool anyone since ILAsm will detect that it's missing and add it before continuing the assembly process.  You need to explicitly state that you want assembly version 2.0.5.0.

Second, you need to think twice before you add a Silverlight assembly to a .NET application.  In the Visual Studio world, if you add a .NET assembly, you add only that assembly. But, in the that assembly is a Silverlgiht assembly, then you will see all of the associated Silverlight assemblies added for each culture you have.  When I did this on my system, exactly 100 extra files were added to my Bin folder!  That's insane.  So, perhaps the Visual Studio team put a "Add Reference" block in the wrong place!

The File-Level Technique

Now all of this is great.  You can easily access your .NET assemblies in Silverlight.  But, many times this isn't even what you need.  You need to remember that every time you reference an assembly in Silverlight, you increase the size of your Silverlight XAP package.  Whereas .NET and Silverlight will only register assembly references in IL when they are actually used, Silverlight will package referenced assemblies in the XAP file regardless of use.  They assemblies will also be registered in the AppManifest.xaml file as an assembly part.  Though the XAP file is nothing more than a ZIP file, thereby shrinking the size of the assembly, this still spells "bloat" if all you need is just a few basic types from an assembly that's within your control.  For situations like this, there's a much simpler and much more flexible solution.

The solution to this again deals with understanding the internals of your system: whenever you add a file to your project in Visual Studio, all you are really doing is adding a file to an ItemGroup XML section in the .NET project file.  This is just a basic text file that describes the project.  As you may have guessed, the ItemGroup section simply contains groups of items.  In the case of compilation files (i.e. classes, structs, enums, etc...), they are Compile items.  Here's an example of a snippet from a .NET project:

<ItemGroup>
  <Compile Include="Client\PersonClient.cs" />
  <Compile Include="Agent\PersonAgent.cs" />
  <Compile Include="Properties\AssemblyInfo.cs" />
  <Compile Include="Configuration.cs" />
  <Compile Include="Information.cs" />
  <Compile Include="_DataContract\Person.cs" />
  <Compile Include="_ServiceContract\IPersonService.cs" />
</ItemGroup>

Given this information, all you need to do is (1) create a Silverlight version of this assembly, (2) open the project file and (3) copy/paste in the parts you want to use in your Silverlight project with the appropriate relative paths changed.  This will create a link from the Silverlight project's items to the physical items.  No copying is done.  They are pointing to the exact same file.  When they are compiled, there is no need to do any IL changes in your assemblies at all since the Silverlight assembly will be Silverlight and the .NET assembly will be .NET.

Now that you know about this under-the-covers approach, you should be aware that this is actually a fully supported option in Visual Studio.  Just go to add an existing item to your project and instead of clicking add or just hitting enter, hit the little arrow next to add and select "Add As Link".  This will do the exact same thing as what we did in our bulk copy/paste method in the project file.  Here's a screen shot of the option in Visual Studio:

AddAsLink

What may be more interesting to you is that this feature may be used anywhere in .NET.  You can use this to reuse any files in your entire system.  It's a very powerful technique to reuse specific items in assemblies.  It comes it very handy when two assemblies need to share classes and creating a third assembly which both may access leads to needless complexity.

Conclusion

Given these two techniques, you should be able to effectively architect a solution that scales to virtually any number of developers.  The first technique is easy to deploy using a custom utility and post build events, while the second is natively supported by any good version control systems.  Keep in mind though, that when using the first technique you may not always need to do this on every build.  The best approach I've seen for this is to have a centralized location on a network share that contains nightly (or whatever) builds of core assemblies.  Then, a login script will copy each of the assemblies to each developers machine.  This will cut down on the complexity of compilation and dramatically lower the time to compile any solution.

Regardless of which technique you use, you should feel a sense of freedom knowing of their existence.  This is especially true if all you are doing is trying to share data contracts between .NET and Silverlight.  As I've mentioned in my popular 70+ page "Understanding WCF in Silverlight 2" document, the "Add Service Reference" feature is not something that should be used in production.  In fact, it's painful in development as well.  Using the techniques described here, you can easily share your data contracts between your .NET server and the Silverlight client without the FrontPage/Word 95 style code generation.  For more information on this specific topics, see the aforementioned document.

Links

kick it on DotNetKicks.com

FREE Silverlight Training on the Web

In case you didn't know it, knowledge is free.  In fact, it always has been.  Some cultures make it hard to obtain, but it's free nonetheless.  The Internet gives you extremely close access this knowledge.  You can randomly choose just about any topic in the world and find at least one article, blog posting, or Wikipedia entry on the topic.  In fact, when I was in college I only showed up once to my Kansas State University Physics II class.  Instead I kepted up with the class from home by watching the MIT OpenCourseWare video courses.  When it comes to Internet-related technologies like Silverlight, knowledge is even easier to find.

I see all kinds of courses by some of the biggest training companies offering all sort of great Silverlight courses.  However, these are extremely pricey.  There are also many books on Silverlight coming out.  Again, not free.  But think about it, how do you think the trainers and authors get their information?  When I was offered my Silverlight 2 book deal (since being on a deadline sucks, I turned it down), where do you think I would get my information?  It's all free online.  Here in December 2008, there are all kinds of amazing free resource for learning Silverlight.  You do not need training.  You do not need to buy a book.  Here are some of these resources that I've found this year to help bring you from ground zero to being a Silverlight master:

First, there's the 53-part video series at Silverlight.net.  This series just about every single topic you will ever see in your Silverlight career.  However, I would consider these to be at the basic level.  They cover the fundamentals of each topic, give great tips, and progressively give more interesting examples as the videos progress.  If all you are going to be doing is under-using Silverlight 2 as an RIA platform and for general [boring] UI development, then this series may be 90% of what you need.  Link: http://silverlight.net/Learn/videocat.aspx?cat=2

Second, there's the 44-part video series from Mike Taulty.  This is the guy behind the MSDN Nuggets videos.  These videos are more at the intermediate-advanced level.  It's also somewhat focused at "under-the-covers" development.  Mike doesn't do drag-n-drop videos.  He teaches real technology.  Whereas the previous series will discuss concepts and how to do things "out of the box", Mike's videos show you how to work with things at a more mechanical level, thus giving you a much greater level of control.  If you don't know the topics he's discussing in the videos, you don't know Silverlight.  Link: http://channel9.msdn.com/posts/Dan/Mike-Taulty-44-Silverlight-20-Screencasts/

Third, let's not forget that Microsoft has its annual Mix and PDC conferences.  Microsoft makes sure that the content for these conferences are freely available online.  The Mix videos are very specific and, therefore, should probably be watched on an as-needed basis.   You can just follow the link to see the wide variety of topics.  Since it's at a conference, however, some of the information will be marketing-speaking, but there's a lot of good stuff in the videos as well.  The PDC however is much less marketing-ish and there were a few Silverlight 2 sessions.  Links: http://silverlight.net/learn/videocat.aspx?cat=8 and https://sessions.microsoftpdc.com/public/timeline.aspx.

Fourth, if you're the reading-type, then you may prefer the Silverlight 2 e-book at learn-silverlight-tutorial.com.  This e-book covers a ton of information.  Much like the 53-part series, I would mark this down as basic-level.  It covers a touches on a wide variety of topics.  However, much of the information is just that: "a touch".  It's not very deep, but it's rather wide.  Link: http://www.learn-silverlight-tutorial.com/

Fifth, Microsoft has always been good about providing QuickStarts.  These are kind of a cross between visual, text, and hands-on learning.  These are also the typical go to card for any one new to anything.  The ASP.NET quick starts are still incredibly popular these many years later.  The Silverlight ones are quite well done as well.  The topics are basic-intermediate and range from topics like general UI controls to cooler stuff like JavaScript/DOM interop.  However, you may feel completely free to absolutely ignore the completely worthless "web services" section.  Whoever wrote that thought he or she was writing about the hopelessly-flawed ASMX, not the image-of-beauty WCF and, therefore, didn't even remotely bother to obey the most fundamental of WCF purposes and practices (i.e. keep your address, binding, and contract away from your implementation!) Link: http://silverlight.net/quickstarts/

Speaking of WCF, the last resource I want to mention is my document entitled "Understanding WCF in Silverlight 2".  This one has received a lot of attention since I wrote it in November 2008.  In fact, it's now listed on the WCF MSDN home page.  It's there because I cover WCF from the ground up for both .NET and Silverlight in a very deep manner.  If you are new to WCF, SOA, or Silverlight, then this is a good place to start (of course, no bias here.)  I wrote this document to help both people new to WCF and Silverlight as well as those who have been working either either for a while.  Even if you're not too serious about Silverlight, you should still read this detailed document to understand WCF better.  I don't play around with introductory nonsense, I hit the ground running with best-practices and proper architectural principles.  Link: http://www.netfxharmonics.com/2008/11/Understanding-WCF-Services-in-Silverlight-2

Though it's not a straight learning resource, I support I would also like to mention that you can always check out the Silverlight tag in my Delicous account: http://delicious.com/quantum00/silverlight.  However, keep in mind that just because I bookmark something, it doesn't mean I'm recommending the resource.  It just means it was interesting and/or provided some value to me.  You can expect this to be updated for the months to come.  I live off of my delicious account.

Another thing I would like to mention is that if you know WPF and web development, then you almost get Silverlight knowledge naturally.  Silverlight is essential a subset of WPF for the web.  You just take WPF, rip out a bunch of features, add just a handful of topics, move it to the web, and you have Silverlight.  Much of your skills are reusable if you already know WPF.  Actually, a lot of your skills are reusable if you're a .NET developer in general.  Just whip open Reflector and start looking through the framework, you'll see that there's a lot less than what's in the .NET framework, thus requiring much less learning time.

So, don't waste your money on books.  The blog is the new book.  Don't bother asking your employer for Silverlight training.  OK, well, if you just want some time off from work, sure, go ahead and ask.  Really, though, these resources will give you what you need for your Silverlight development.  In fact, if you were to compare the syllabus for an expensive course with the topics found in the first two sections of videos mentioned (97 of them!), you will see that the ROI for the course is virtually non-existent.

Links Summary

Tim Ferris - Trial by Fire

This is beyond awesome.  Tim Ferris, author of one of the greatest books ever written, Four Hour Work Week, has announced that he has a new show called Trial by Fire.  I'm incredibly excited to hear this.  Time Ferris is one of my core role models for just about every area of life.  I regularly reread and reference his Four Hour Work Week book and am constantly studying his blog.  In fact, when you read my NetFXHarmonics web site, you are reading Ferris principles applied to the development world.

He calls himself a life hacker.  What it takes others years to master, he tries to learn in days.  This is the primary purpose of his Trial by Fire show.  It's also something I've been studying for years through my research in accelerated learning and experience induction.  Ferris sometimes mentions that his technique is to deconstruct, streamline, and remap.  If you read my recent posts on streamlining WCF and WCF in Silverlight, you've seen a taste of how you can apply these principles to development.  It's how I personally think, act, and speak.

For more information on Tim Ferris, his show, or his book, check out his blog at http://www.fourhourblog.com/.  His blog is essentially an extension to his book, Four Hour Work Week, a book every single person in the world needs to read and reread.  You absolutely must buy this book.  Get it in print or get it in audio, just get it.

Understanding WCF

If you like this document, please consider writing a recommendation for me on my LinkedIn account.

Contents

Introduction

One of the most beautiful things about the Windows Communication Foundation (WCF) is that it's a completely streamlined technology.  When you can provide solutions to myriad of diverse problems using the same principles, you know you're dealing with a work of genius.  This is the case with WCF.  With a single service implementation, you can provide access to ASMX, PHP, Java, TCP, named pipe, and JSON-based services by add a single XML element for each type of connection you want to support.  On the flip side, with a single WCF client you can connect to each of these types of services, again, by adding a single like of XML for each.  It's that simple and streamlined.  Not only that, this client scenario works the same for both .NET and Silverlight.

In this document, I'm going to talk about how to access WCF services using Silverlight 2 without magic.  There will be no proxies, no generated code, no 3rd party utilities, and no disgusting "Add Service Reference" usage.  Just raw WCF.  This document will cover WCF connectivity in quite some depth.  We will talk about service setup, various WCF, SOA, and Silverlight paradigms, client setup,  some security issues, and a few supplemental features and techniques to help you aide and optimize service access.  You will learn about various WCF attributes, some interfaces, and a bunch of internals.  Though this document will be in depth, nothing will ever surpass the depth of MSDN.  So, for a more full discussion on any topic, see the WCF documentation on MSDN.

Even though we're focusing on Silverlight, most of what will be explained will be discussed in a .NET context and then applied to Silverlight 2.  That is, instead of learning .NET WCF and Silverlight WCF, you will .NET WCF and how to vary this for Silverlight.  This comparative learning method should help you both remember and understand the concepts better.  Before we begin, though, let's begin with a certain WCF service setup.  After all, we you don't have a service, we can't talk about accessing it.

Service Setup In Depth

When working with WCF, you are working with a completely streamlined system.  The most fundamental concept in this system is the ABC.  This concept scales from Hello World to the most complex sales processing system.  That is, for all WCF communication, you need an address, a binding, and a contract.  Actually, this is for any communication anywhere, even when talking to another person.  You have to know to whom, how, and what.  If you don't have these three, then there can't be any communication.

With these three pieces of information, you either create a service-side endpoint which a client will access or a client-side channel which the client will use to communicate with the service.

WCF services are setup using a 3 step method:

  • First, create a service contract with one or more operation contracts.
  • Second, create a service implementation for those contracts. 
  • Third, configure a service host to provide that implementation with an endpoint for that specific contract.

Let's begin by defining a service contract.  This is just a simple .NET interface with the System.ServiceModel.ServiceContractAttribute attribute applied to it.  This interface will contain various operation contracts, which are simply method signatures with the System.ServiceModel.OperationContractAttribute applied to each.  Both of these attributes are in the System.ServiceModel assembly.

Do not under any circumstances apply the ServiceContract attribute directly to the implementation (i.e. the class).  The ability to do this is probably the absolute worst feature in WCF.  It defeats the entire purpose of using WCF: your address, your binding, your contract and your implementation are complete separate.  Because this essentially makes your implementation your contract, all your configuration files will be incredibly confusing to those of us who know WCF well.  When I look for a contract, I look for something that starts with an "I".  Don't confuse me with "PersonService" as my contract.  Person service means person... service.  Not only that, but later on you will see how to use a contract to access a service.  It makes no sense to have my service access my service; thus with the implementation being the contract, your code will look painfully confusing to anyone who knows WCF.

Here's the sample contract that we will use for the duration of this document:

using System;
using System.ServiceModel;
//+
namespace Contact.Service
{
    [ServiceContract(Namespace = Information.Namespace.Contact)]
    public interface IPersonService
    {
        //- GetPersonData -//
        [OperationContract]
        Person GetPersonData(String personGuid);
    }
}

Keep in mind that when you design for WCF, you need to keep your interfaces as simple as possible.  The general rule of thumb is that you should have somewhere between 3 to 7 operations per service contract.  When you hit the 12-14 mark, it's seriously time to factor out your operations.  This is very important.  As I'll mention again later, in any one of my WCF projects I'll have upwards of dozens of service contracts per service.  You need to continuously keep in mind what your purpose is for creating this service, filtering those purposes through the SOA filter.  Don't design WCF services like you would a framework, which, even then shouldn't have many access points!

The Namespace property set on the attribute specified the namespace used to logically organize services.  Much like how .NET uses namespaces to separate various classes, structs, and interfaces, SOAP services use namespaces to separate various actions.  The name space may be arbitrarily chosen, but the client and service must just agree on this namespace. In this case, the namespace is the URI http://www.netfxharmonics.com/service/Contact/2008/11/.  This namespace will also be on the client.  This isn't a physical URL (universal resource locator), but a logical URI (universal resource identifier).  Despite what some may say, both terms are in active use in daily life.  Neither is more important than the other and neither is "deprecated".  All URLs are URIs, but not all URIs are URLs as you can see here.

Notice in this interface, there is a method interface that returns Person.  This is a data contract.  Data contracts are classes which have the System.Runtime.Serialization.DataContractAttribute attribute applied to them.  These have one or more data members, which are public or private properties or fields that have the System.Runtime.Serialization.DataMemberAttribute attribute applied to them.  Both of these attributes are in the System.Runtime.Serialization assembly.  This is important to remember; if you forget, you will probably assume them to be in the System.ServiceModel assembly and your contract will never compile.

Notice I said that data members are private or public properties or fields.  That was not a typo.  Unlike the serializer for the System.SerializableAttribute attribute, the serializer for DataContract attribute allows you to have private data members.  This allows you to hide information from developers, but allow services to see it.  Related to this is the how classes with the DataContract attribute differ from classes with the Serializable attribute.  When you use the Serializable attribute, you are using an opt-out model.  This means that when the attribute is applied to the class, each members is serializable.  You then opt-out particular fields (not properties; thus one major inflexibility) using the System.NonSerializedAttribute attribute.  On the other hand, when you apply the DataContract attribute, you are using an opt-in model.  Thus, when you apply this attribute, you must opt-in each field or property you wish to be serialized by applying the DataMember attribute.  Now to finally look at the Person data contract:

[DataContract(Namespace = Information.Namespace.Contact)]
public class Person
{
    //- @Guid -//
    [DataMember]
    public String Guid { get; set; }

    //- @FirstName -//
    [DataMember]
    public String FirstName { get; set; }

    //- @LastName -//
    [DataMember]
    public String LastName { get; set; }

    //- @City -//
    [DataMember]
    public String City { get; set; }

    //- @State -//
    [DataMember]
    public String State { get; set; }

    //- @PostalCode -//
    [DataMember]
    public String PostalCode { get; set; }
}

Note how simple this class is.  This is incredibly important.  You need to remember what this class represents: data moving over the wire.  Because of this, you need to make absolutely sure that you are sending only what you need.  Just because your internal "business object" has 10,000 properties doesn't mean that your service client will ever be able to handle it.  You can't get blood from a turnip.  Your business desires will never change the physics of the universe.  You need to design with this specific scenario of service-orientation in mind.  In the case of Silverlight, this is even more important since you are dealing with information that needs to get delegated through a web browser before the plug-in ever sees it.  Not only that, but every time you send an extra property over the wire, you are making your Silverlight application that less responsive.

When I coach architects on database design, I always remind them to design for the specific system which they'll be using (i.e. SQL Server) and always keep performance, space, and API usability in mind (this is why it's the job of the architect, not the DBA, to design databases!)  In the same way, if you are designing a system that you know will be used over the wire, account for that scenario ahead of time.  Much like security, performance and proper API design aren't "features", they're core parts of the system.  Do not design 10 different classes, each representing a property which will be used in another class which, in turn, will be serialized and sent over the wire.  This will be so absolutely massive that no one will ever be able to handle it.  If you have more than around 15 properties in your entire object graph, it's seriously time to rethink what you want to send.  And, never, ever, ever send an instance of System.Data.DataSet over the wire.  There has never been, is not now, and never will be any reason to ever send any instance of this type anywhere.  It's beyond massive and makes the 10,000 property data transfer object seem lightweight.  The fact that something is serializable doesn't mean that it should be.

This is main reason you should not apply the Serializable attribute to all classes.  Remember, this attribute follows an opt-out model (and a weak one at that).  If you want your "business objects" to work in your framework as well as over the wire, you need to remove this attribute and apply the DataContract attribute.  This will allow you to specify via the DataMember attribute which properties will be used over the wire, while leaving your existing framework completely untouched.  This is the reason the DataContract attribute exists!  Microsoft realized that the Serializable attribute is not fine grained enough for SOA purposes.  They also realized that there's no reason to force everyone in the world to write special data transfer objects for every operation.  Even then, use DataContract sparingly.  Just as you should keep as much private as possible and as much internal as possible, you want to keep as much un-serializable as possible.  Less is more.

In my Creating Streamlined, Simplified, yet Scalable WCF Connectivity document, I explain that these contracts are considered public.  That is, both the client and the service need the information.  It's the actual implementation that's private.  The client needs only the above information, where as the service needs the above information as well as the service implementation.  Therefore, as my document explains, everything mentioned above should be in a publicly accessible assembly separate from the service implementation to maximize flexibility.  This will also allow you to rely on the original contracts instead of relying on a situation where the contracts are converted to metadata over the wire and then converted to sloppily generated contracts.  That's slower, adds latency, adds another point of failure, and completely destroys your hand crafted, highly-optimized contracts.  Simply add a reference to the same assembly on both the client and server-side and you're done.  If multiple people are using the service, just hand out the public assembly.

At this point, many will try to do what I've just mentioned in a Silverlight environment to find that it doesn't seem to work.  That is, when you try to add a reference to a .NET assembly in a Silverlight project, you will get the following error message:

DotNetSilverlightReferenceMessageBox

Fortunately, this isn't the end of the world.  In my document entitled Reusing .NET Assemblies in Silverlight, I explain that this is only a Visual Studio 2008 constraint.  There's absolutely no technical reason why Silverlight can't use .NET assemblies.  Both the assembly and module formats are the same for Silverlight and .NET.  When you try to reference an assembly in a Silverlight project, Visual Studio 2008 does a check to see what version of mscorlib the assembly references.  If it's not 2.X.5.X, then it says it's not a Silverlight assembly.  So, all you need to do is modify your assembly to have it use the appropriate mscorlib file.  Of course, then it's still referencing the .NET System.ServiceModel and System.Runtime.Serialization assemblies.  Not a big deal, just copy/paste the Silverlight references in.  My aforementioned document explains everything you need to automate this procedure.

Therefore, there's no real problem here at all.  You can reuse all your contracts on both the service-side and on the client-side in both a .NET Silverlight environment.  As you will see a bit later, Silverlight follows an async communication model and, therefore, must use async-compatible service contracts.  At that time you may begin to think that you can't simply have a one-stop shop for all your contract needs.  However, this isn't the case.  As it turns out .NET can do asynchronous communication too, so when you create that new contract, you can keep it right next to your original service contract.  Thus, once again, you have a single point where you keep all your contracts.

Moving on to step 2, we need to use these contracts to create an implementation.  The service implementation is just a class which implements a service contract.  The service implementation for our document here is actually incredibly simple:

using System;
//+
namespace Contact.Service
{
    public class PersonService : Contact.Service.IPersonService
    {
        //- @GetPersonData -//
        public Person GetPersonData(String personGuid)
        {
            return new Person
            {
                FirstName = "John",
                LastName = "Doe",
                City = "Unknown",
                Guid = personGuid,
                PostalCode = "66062",
                State = "KS"
            };
        }
    }
}

That's it.  So, if you already have some logic you know is architecturally sound and you would like to turn it into a service.  Create an interface for your class and add some attributes to the interface.  That's your entire service implementation.

Step 3 is to configure a service host with the appropriate endpoints.  In our document, we are going to be using an HTTP based service.  Thus after we setup a new web site, we create a Person.svc file in the root and add to it a service directive specifying our service implementation.  Here's the entire Person.svc file:

<%@ ServiceHost Service="Contact.Service.PersonService" %>

No, I'm not joking.  If you keep your implementation in this class as well, then you are not using WCF properly.  In WCF, you keep your address, your binding, your contract, and your implementation completely separate.  By putting your implementation in this file, you are essentially tying the address to the implementation.  This defeats the entire purpose of WCF.  So, again, the above code is all that should ever be in any svc file anywhere.  Sometimes you may have another attribute set on your service directive, but this is basically it.

This is an unconfigured service host.  Thus, we must configure it.  We will do this in the service web site's web.config file.  There's really only one step to this, but that one step has a prerequisite.  The step is this: setup a service endpoint, but this requires a declared service.  Thus, we will declare a service and add it to an endpoint.  An endpoint specifies the WCF ABC: an address (where), a binding (how), and a contract (what).  Below is the entire web.config file up to this point:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Contact.Service.PersonService">
        <endpoint address="" binding="basicHttpBinding" contract="Contact.Service.IPersonService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

This states that there can be "basicHttpBinding" communication through Contact.Service.IPersonService at address Person.svc to Contact.Service.PersonService.  Let's quickly cover each concept here.

The specified address is a relative address.  This means that the value of this attribute is appended onto the base address.  In this case the base address is the address specified by our web server.  In the case of a service outside of a web server, then you can specify an absolute address here.  But, remember, when using a web server, the web server is going to control the IP address and port bindings.  Our service is at Person.svc, thus we have already provided for us the base URL.  In this case the address is blank, but you will use this address attribute if you add more endpoints as you will see later.

The binding specifies how the information is to be format for transfer.  There's actually nothing too magical about a binding, though.  It's really just a collection of binding elements and pre-configured parameter defaults, which are easily changed in configuration.  Each binding element will have at a minimum two binding elements.  One of these is a message encoding binding element, which will specify how the message is formatted.  For example, the message could be text (via the TextMessageEncodingBindingElement class; note: binding elements are in the System.ServiceModel.Channels namespace), binary (via the BinaryMessageEncodingBindingElement class), or some other encoding.  The other required binding element is the transport binding element, which specified how the message is to go over the wire.  For example, the message could go over HTTP (via the HttpTransportBindingElement), HTTPS (via the HttpsTransportBindingElement), TCP (via the TcpTransportBindingElement), or even a bunch of others.  A binding may also have other binding elements to add more features.  I'll mention this again later, when we actually use a binding.

The last part of an endpoint, the contract, has already been discussed earlier.  One thing that you really need to remember about this though is that you are communication through a contract to the hosted service.  If you are familiar with interface based development in .NET or COM, then you already have a strong understanding of what this means.  However, let's review.

If a class implements an interface, you can access the instantiated object through the interface.  For example, in the following code, you are able to access the Dude object through the ISpeak interface:

interface ISpeak
{
    void Speak(String text);
}

class Dude : ISpeak
{
    public void Speak(String text)
    {
        //+ speak text
    }
}

public class Program
{
    public void Run()
    {
        ISpeak dude = new Dude();
        dude.Speak("Hello");
    }
}

You can think of accessing a WCF service as being exactly like that.  You can even push the comparison even further.  Say the Dude class implemented IEat as well.  Then we can access the instantiated Dude object through the IEat interface.  Here's what I mean:

interface ISpeak
{
    void Speak(String text);
}

interface IEat
{
    void Eat(String nameOfFood);
}

class Dude : ISpeak, IEat
{
    public void Speak(String text)
    {
        //+ speak text
    }
}

public class Program
{
    public void Run()
    {
        IEat dude = new Dude();
        dude.Eat("Pizza");
    }
}

In the same way, when configuring a WCF service, you will add an endpoint for contract through which you would like your service to be accessed.

Though it's beyond the scope of this document, WCF also allows you to version contracts.  Perhaps you added or removed a parameter from your contract.  Unless you want to break all the clients accessing the service, you must keep the old contract applied to your service (read: keep the old interface on the service class) and keep the old endpoint running by setting up a parallel endpoint.

You will add a new service endpoint every time you change your version, change your contract, or change your binding.  On a given service, you have have dozens of endpoints.  This is good thing.  Perhaps you provide for four different bindings with two of them having two separate configurations each, three different contracts, and 2 different versions of one of the contracts.  In this document, we are going to start out with one endpoint and add more later.

Now we have setup a complete service.  However, it's an incredibly simple service setup, thus not requiring too much architectural attention.  When you work with WCF in a real project, you will want to organize your WCF infrastructure to be a bit more architecturally friendly.  In my document entitled Creating Streamlined, Simplified, yet Scalable WCF Connectivity, I explain streamlining and simplifying WCF connectivity and how you can use a private/public project model to simplify your WCF connectivity.  See that document for more information on streamlining WCF services.

Service Access Without Magic

Now we may turn our attention to the client application.  To begin, let me start off by reminding everyone that you shouldn't ever use "Add Service Reference" in Visual Studio for magical service client creation.  The code is incredibly verbose, hard to manageable, edits are prone to being overwritten, and it's almost always used as an excuse to not actually learn WCF.  There are few things worse than having to deal with people who thing they know a product simply because they know how to use a mouse.  There are reasons why Juval Lowy, in all his books and talks, repeatedly tells people to avoid using this flawed feature.  Fortunately, as professionals, we have the ability to understand how to do things without magic.

As I've mentioned many times already, WCF relies on the concept of the ABC.  We've seen how we configure a WCF host by creating an endpoint specifying an address, binding and contract.  As it turns out, this is all that's required on the client side as well.  For both .NET and Silverlight, you merge an address and a binding with a contract in a channel factory to create a channel.  This isn't just fancy conceptual architect speak, this is exactly what your code would look like (the sign of really good architecture!)  Below is the .NET version of what I mean:

BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:1003/Person.svc");
IPersonService personService = new ChannelFactory<IPersonService>(basicHttpBinding, endpointAddress).CreateChannel();
//+
Person person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");

In this you have an address (the EndpointAddress object), a binding (BasicHttpBinding), and a contract (IPersonService) meeting in System.ServiceModel.ChannelFactory<TServiceContract> to create a channel which implements the IPersonService interface (and others).  We can then call through our local interface to the channel, which then calls the remote service through the service interface.  No magic is required.  You don't need any "proxy" or anything.  WCF is literally all about the ABC on the service and on the client.

A few moments ago I mentioned that a binding is nothing more than a series of binding elements.  At this time I would like to prove this to you.  In the above sample, we are using a BasicHttpBinding on the client to communicate to a BasicHttpBinding on the service.  This is slightly "magical".  Let's peel back the covers to see what's really going on.  The BasicHttpBinding is the WCF implementation of the WS-I Basic Profile standard used by ASMX services and most PHP clients.  In other words, it's the basic SOAP binding.  Internally though, it's really nothing more than a combination of the TextMessageEncodingBindingElement and, depending on your settings, either HttpTransportBindingElement or HttpsTransportBindingElement with the message version set to SOAP 1.1.

To prove this, let's completely remove the BasicHttpBinding from our client.  Then let's create an instance of the System.ServiceModel.Channels.CustomBinding class.  This class allows us to make our own bindings from our own or preexisting binding elements.  In this case, all we want to do is add the TextMessageEncodingBindingElement, setting the message version to SOAP 1.1 and add the HttpTransportBindingElement.  With this, we have creating a binding that fits exactly what our service expects.  Here's what we're talking about:

CustomBinding customBinding = new CustomBinding();
customBinding.Elements.Add(new TextMessageEncodingBindingElement
{
    MessageVersion = MessageVersion.Soap11
});
customBinding.Elements.Add(new HttpTransportBindingElement());
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:1003/Person.svc");
//+
IPersonService personService = new ChannelFactory<IPersonService>(customBinding, endpointAddress).CreateChannel();

If you think that's wild, you will be in shock when you realize that you don't even need to use code to create a custom binding.  Let's completely remove the CustomBinding and address from our code and just do the exact same thing in web.config.  Here is our new code:

IPersonService personService = new ChannelFactory<IPersonService>("PersonServiceCustomHttpBinding").CreateChannel();

Doesn't get much simpler than that.  Now take a look at our web.config:

<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="HttpTextCustomBinding">
        <textMessageEncoding messageVersion="Soap11" />
        <httpTransport/>
      </binding>
    </customBinding>
  </bindings>
  <client>
    <endpoint name="PersonServiceCustomHttpBinding" 
              bindingConfiguration="HttpTextCustomBinding" 
              address="http://localhost:1003/Person.svc" 
              binding="customBinding" 
              contract="Contact.Service.IPersonService" />
  </client>
</system.serviceModel>

Believe it or not, our service still works perfectly.

Up to this point we have been discussing WCF in general, it's now time to move towards Silverlight.  The ABC and channel concepts still apply, but, since we are in the world of the web, there's one difference in how we access the services from our clients: we are dealing with asynchronous calls.

The Async Pattern

If you are familiar with the concepts of AJAX calls, then you should already be familiar with what I'm talking about.  To put it simply, instead of calling a "do" method, you basically set a callback and call "beginDo".  Then, instead of obtaining a response from "beginDo", we wait for a callback from the service.  Think of it like phone tag between two people who never answer their phone.  Person A calls person B and says "call me back at X".  Then Person B calls Person A back at X; you don't sit there on someone's voicemail waiting for them to pick up (...like we did in the days of answering machines.)

When this idea is brought to the .NET/Silverlight world, we have something called the Async Pattern, which states that asynchronous methods are to follow the following pattern:

public IAsyncResult BeginOperation(/* <parameters> */, AsyncCallback callback, Object state)
public /* <return> */ EndOperation(IAsyncResult result)

If you're never seen this before, then, it's high time you become deeply familiar with it.  This pattern is used all over the place in myriad of different contexts.  You can use MSDN to find various examples involving this pattern, or just keep reading to see how it's used to get the general idea.  If you are going to take Silverlight seriously, then you absolutely must master this pattern.

Not only that, but you must also be very proficient with asynchronous call chains.  This is when you call one async operation, wait for the callback, then that callback begins another async operation, whose callback may call another async operation.  You just chain the async calls down the line to have a steady, deterministic program flow.  This, of course, requires knowledge of the Async Pattern to which we now return our focus.

When working with in Silverlight, this Async Pattern is the type of call pattern that you will be using for just about all service access with or without WCF.  For example, there will be no GetPersonData method which returns a Person object.  Instead, there will be a BeginGetPersonData method which returns an IAsyncResult object (which you may or may not use).  Then, you wait for a callback, which has an IAsyncResult again which you use to obtain a result from EndGetPersonData.  This actually means that our service contract in Silverlight will look slightly different than our service contract for .NET.  Here's our Silverlight version:

using System;
using System.ServiceModel;
//+
namespace Contact.Service
{
    [ServiceContract(Namespace = Information.Namespace.Contact)]
    public interface IPersonService
    {
        //- BeginGetPersonData -//
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginGetPersonData(String personGuid, AsyncCallback callback, Object state);

        //- LoadPerson -//
        Person EndGetPersonData(IAsyncResult result);
    }
}

Notice that we are now following the Async Pattern and that the OperationContract attribute has declaratively stated that we are following the pattern via the AsyncPattern property.  We may now rewrite our original .NET service-call code to follow the new paradigms and service contract to allow Silverlight interaction.  Here's our new code:

BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:1003/Person.svc");
IPersonService personService = new ChannelFactory<IPersonService>(basicHttpBinding, endpointAddress).CreateChannel();
//+
AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
    Person person = ((IPersonService)result.AsyncState).EndGetPersonData(result);
    this.Dispatcher.BeginInvoke(delegate
    {
        spMain.Children.Add(new TextBlock
        {
            Text = person.FirstName
        });
    });
};
personService.BeginGetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6", asyncCallBack, personService);

Notice the first three lines are identical.  After this, not much remains the same.  Instead of doing a simple service-call with a synchronous response, we must set a callback and begin a request.  In this particular example, the asyncCallBack object is being given an anonymous method to the BeginGetPersonData method.  This anonymous method block will be called when the service calls returns a response back.

Take note of the third parameter in the BeginGetPersonData.  Per the Async Pattern, this is "state".  This is similar to the Tag object found in VB and in WPF.  You can use this to place just about anything you want to send back to the callback.  In this case, since we're it's an anonymous method, it's optional, but if the callback were a named method, then the callback may obtain that state by pulling the AsyncState property from the IAsyncResult object passed to the callback.  In this example, I'm sending the channel itself as the state so that I can access the channel from the callback.  This is important because this is how I'm able to call the EndGetPersonData method and retrieve the service operation response data, a Person object in this case.

Notice also also that the callback has a call to Dispatcher.BeginInvoke.  You must do this if you are on a visual element and want to access visual elements in your callback.  This will grant you access to the UI thread.  Without this, an exception will be thrown.  In this case we are adding a TextBlock to a StackPanel.  For the duration of this document, the following method will be used to write our output to the StackPanel:

//- $Write -//
private void Write(String text)
{
    this.Dispatcher.BeginInvoke(delegate
    {
        spMain.Children.Add(new TextBlock
        {
            Text = text
        });
    });
}

External Web Site Access

Having said all that, if you were to try and run the code I sent to you based on our current service configuration, nothing would actually work.  Why's that?  Because in our original service-setup the service is hosted in a different web site than the web site itself.  The service web site does nothing but WCF hosting, while our application web site hosts our Silverlight application.  This basically allows you to keep all your entities highly cohesive and reusable.  However, in this case, we are running up against a security wall.  By default, you cannot use Silverlight to access a web site which differs by domain, IP address, or port number. 

Fortunately, there's an easy way around this: you just need to add a ClientAccessPolicy.xml file in the service root.  Here's a sample ClientAccessPolicy.xml file:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from>
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

This particular example basically allows everyone everywhere to access the service, granting access to everything.  This may be what you want or, perhaps, you want to lock it down a bit by placing a URI of the format http://www.tempuri.org/ in place of the *.  Perhaps you even want to add multiple domain elements or, on the other end of the spectrum, restrict access to only a particular service path.

Now while this file looks all well and good, our Silverlight service call still won't work. Why in the world not?  Because for WCF in Silverlight to call a service outside of the local web site, you must also specify what headers to allow.  In our case, we want to allow the SOAPAction header.  The SOAPAction header is what a SOAP service uses to specify what action to run on the service.

Here's our new policy:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Now our WCF Silverlight service will work flawlessly.

For all the information you would ever need on this file, see Network Security Access Restrictions in Silverlight 2 on MSDN.

Configuration Based Access

Our service client call at this point is fully programmatic.  This is nice, but perhaps you would like to utilize WCF configuration instead of creating Binding and Endpoint elements manually.  This is a great idea, but how in the world do we access configuration in Silverlight when Silverlight is on the client-side, running in a web browser?  As it turns out, Silverlight actually does include a configuration file, which gets embedded in to the final XAP file, the ServiceReferences.ClientConfig file.

To utilize this configuration feature, we first need to create the file and add it to our Silverlight project.  Then, we must set its build action to Content.  In Visual Studio 2008, you do this in the properties window for that file.  This will force the file to be zipped in with the rest of the contents of the XAP file, which, if you didn't know, is really nothing more than a ZIP file readable by any ZIP client, much like Word 2007's DOCX format.

At this point, you may just copy/paste the configuration from a .NET WCF client to this Silverlight configuration file.  Here's basically what it will look like at this point:

<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="http://localhost:1003/Person.svc" binding="basicHttpBinding" contract="Contact.Service.IPersonService" name="BasicHttpBinding_IPersonService" />
    </client>
  </system.serviceModel>
</configuration>

At this point can change our code to use the configuration instead of the created binding and endpoint address objects:

IPersonService personService = new ChannelFactory<IPersonService>("BasicHttpBinding_IPersonService").CreateChannel();
//+
AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
    Person person = ((IPersonService)result.AsyncState).EndGetPersonData(result);
    Write(person.FirstName);
};
personService.BeginGetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6", asyncCallBack, personService);

Now, once again, while this looks nice, when you compile and run the Silverlight application you will notice that it doesn't even pretend to work.  Why? For some reason, you actually need to declare a basicHttpBinding element in the configuration file.  Here's the new configuration file:

<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding />
    </bindings>
    <client>
      <endpoint address="http://localhost:1003/Person.svc" binding="basicHttpBinding" contract="Contact.Service.IPersonService" name="BasicHttpBinding_IPersonService" />
    </client>
  </system.serviceModel>
</configuration>

At this point, the Silverlight client will have full connectivity with the service.

Strongly Typed Client

At this point we could stop.  The thing works.  Mission Accomplished.  However, when designing software, you want to make sure people call fall into success.  In this case, a developer might forget how to create a WCF channel.  Even then, system internals have nothing to do with the core competency of what's going on.  Business developers need to be working on providing a business solution, not writing WCF interaction code.  Thus, it's often a good idea to hide the internals of something before anyone else uses it.  Even I, as a non-business developer, who love internals and gets great benefits from their understanding, prefer not to see internals in my every day development.  Therefore, I normally hide the internal mechanics of the WCF channel by creating a client abstraction.

As with WCF in .NET, you may use the System.ServiceModel.ClientBase<T> class to create an abstraction of the internal WCF channel mechanics.  However, due to the Async Pattern, using ClientBase in Silverlight is drastically different how I described it's usage for .NET in "Creating Streamlined, Simplified, yet Scalable WCF Connectivity".  Creating a concrete ClientBase class is still fairly straightforward though.

The first thing we need to do is create a class that inherits from ClientBase<IYourServiceContract> where IYourServiceContract is, well, your service contract.  However, unless you want a very complicated class, do not implement the IYourServiceContract on this ClientBase like you would normally do in .NET.  Instead, for each operation in your service contract, create a method in this class.  Don't worry about following the Async Pattern.  Our point in creating this abstraction is to hide the internals mechanics, not to simply rearrange them.  Having said that, you still need to have a callback parameter if your method returns a response.

In addition to this, make sure your method names make sense.  By convention, you should suffix each operation method in your ClientBase with "Async".  Then, inside the method, call your method prefixed with "Begin" on the channel created by the ClientBase class.  Totally confused?  Here's what I mean:

//- @GetPersonDataAsync -//
public void GetPersonDataAsync(String personGuid, EventHandler<ClientEventArgs> callback)
{
    Channel.BeginGetPersonData(personGuid, GetPersonDataCallback, callback);
}

In reality, all you're doing is taking a call and passing it to the Channel with different parameters.  Essentially you are hiding the Async Pattern used by this channel method with something that's more natural to developers.  In this channel call, the second parameter, GetPersonDataCallback, is the WCF callback which is called when the actual service call is complete and the third parameter is the state for the Async Pattern.  Here's the GetPersonDataCallback method:

//- $GetPersonDataCallback -//
private void GetPersonDataCallback(IAsyncResult result)
{
    EventHandler<ClientEventArgs> callBack = result.AsyncState as EventHandler<ClientEventArgs>;
    if (callBack != null)
    {
        callBack(this, new ClientEventArgs
        {
            Object = EndGetPersonData(result)
        });
    }
}

Since we set the callback as the state in the service call, it follows that we can pull that out and use it to send the response data back to the calling method using the standard .NET event pattern.  In this case, the ClientEventArgs class is a simple EventArgs class which holds the response object:

public class ClientEventArgs : EventArgs
{
    //- @Object -//
    public Object Object { get; set; }
}

Now notice that when we are populating this newly created ClientEventArgs, we are setting it's Object property to the result of the EndGetPersonData, which is the second of the two Async Pattern components.  It's implementation is extremely simple:

//- $EndGetPersonData -//
private Person EndGetPersonData(IAsyncResult result)
{
    return Channel.EndGetPersonData(result);
}

Notice also that our ClientBase callback and End methods are private, thus completely concealing the internal WCF mechanics from developers.

There's at least one more method we need to add to our class for it to be complete: the constructors.  Personally, I like to add a constructor which accepts a System.ServiceModel.Channels.Binding object and a System.ServiceModel.EndpointAddress object as well as an overload which accepts a string representing the endpoint configuration name.  These constructors basically do nothing but bridge to the base class:

//- @Ctor -//
public PersonClient(String endpointConfigurationName)
    : base(endpointConfigurationName) { }
public PersonClient(System.ServiceModel.Channels.Binding binding, EndpointAddress address)
    : base(binding, address) { }

Thus, we have successfully created a ClientBase class to abstract the internal mechanics for developers.  To sum up, here's the complete class:

using System;
using System.ServiceModel;
//+
namespace SilverlightClient
{
    public class PersonClient : ClientBase<Contact.Service.IPersonService>
    {
        //- @Ctor -//
        public PersonClient(String endpointConfigurationName)
            : base(endpointConfigurationName) { }
        public PersonClient(System.ServiceModel.Channels.Binding binding, EndpointAddress address)
            : base(binding, address) { }

        //+
        //- @GetPersonDataAsync -//
        public void GetPersonDataAsync(String personGuid, EventHandler<ClientEventArgs> callback)
        {
            Channel.BeginGetPersonData(personGuid, GetPersonDataCallback, callback);
        }

        //- $GetPersonDataCallback -//
        private void GetPersonDataCallback(IAsyncResult result)
        {
            EventHandler<ClientEventArgs> callBack = result.AsyncState as EventHandler<ClientEventArgs>;
            if (callBack != null)
            {
                callBack(this, new ClientEventArgs
                {
                    Object = EndGetPersonData(result)
                });
            }
        }

        //- $EndGetPersonData -//
        private Contact.Service.Person EndGetPersonData(IAsyncResult result)
        {
            return Channel.EndGetPersonData(result);
        }
    }
}

If you need to add more operations, and you most definitely will, all you need to do is copy/paste this pattern and do a which rename of a new things here and there.  You could create a Visual Studio code snippet to setup this pattern as well.  Using this class is now as simple as the following:

PersonClient personClient = new PersonClient("BasicHttpBinding_IPersonService");
personClient.GetPersonDataAsync("F488D20B-FC27-4631-9FB9-83AF616AB5A6", OnServiceCallback);

Then, of course, there's the callback method:

//- $OnServiceCallback -//
private void OnServiceCallback(Object sender, ClientEventArgs ea)
{
    Person person = ea.Object as Person;
    if (person == null)
    {
        return;
    }
    //+
    Write(person.FirstName);
}

As simple as this is, though, you could actually keep the simplicity of this usage and still upgrade the class to be a bit more general.  For this reason, I created my ObjectClient<TServiceContract> class.  Here's an example of using it:

ObjectClient<IPersonService> objectClient = new ObjectClient<IPersonService>("BasicHttpBinding_IPersonService");
objectClient.Begin("GetPersonData", OnObjectServiceCallback, null, "F488D20B-FC27-4631-9FB9-83AF616AB5A6");

Then, here's the service callback:

//- $OnObjectServiceCallback -//
private void OnObjectServiceCallback(Object sender, ObjectClient<IPersonService>.ClientEventArgs ea)
{
    Person person = ea.LoadResult<Person>();
    Write(person.LastName);
}

The mechanics of this class follow the same idea as the previous ClientBase, but this one does not use ClientBase, but, rather, creates the channel itself.  Then, when the "Begin" method is called, the class internally passes the parameters to the proper "BeginMethodName" method property via dynamic invocation.  Internally, the service callback also uses dynamic invocation to call "EndMethodName" to obtain the result.  The result is then passed to the original callback using the same ClientEventArgs as seen in the PersonClient example.

Below is the ObjectClient code in its entirety:

#region Copyright
//+ Copyright © Jampad Technology, Inc. 2008
//++ Lead Architect: David Betz [MVP] <dfb/davidbetz/net>
#endregion
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
//+
namespace Nalarium.ServiceModel
{
    public class ObjectClient<TServiceContract> where TServiceContract : class
    {
        //- @ClientEventArgs -//
        public class ClientEventArgs : EventArgs
        {
            //- @Object -//
            public Object Object { get; set; }

            //- @UserState -//
            public Object UserState { get; set; }

            //+
            //- @LoadResult -//
            public TResult LoadResult<TResult>()
            {
                if (this.Object is TResult)
                {
                    return (TResult)this.Object;
                }
                //+
                return default(TResult);
            }
        }

        //- $ObjectClientState -//
        private class ObjectClientState
        {
            //- @Callback -//
            public EventHandler<ClientEventArgs> Callback { get; set; }

            //- @MethodName -//
            public String MethodName { get; set; }

            //- @UserState -//
            public Object UserState { get; set; }
        }

        //+
        //- $Channel -//
        private TServiceContract Channel { get; set; }

        //- $ContractType -//
        private Type ContractType { get; set; }

        //+
        //- @Ctor
        private ObjectClient()
        {
            ContractType = typeof(TServiceContract);
        }
        public ObjectClient(Binding binding, EndpointAddress address)
            : this()
        {
            Channel = new ChannelFactory<TServiceContract>(binding, address).CreateChannel();
        }
        public ObjectClient(String endpointConfigurationName)
            : this()
        {
            Channel = new ChannelFactory<TServiceContract>(endpointConfigurationName).CreateChannel();
        }

        //+
        //- @Begin -//
        public void Begin(String methodName, Object state, params Object[] parameterArray)
        {
            Begin(methodName, null, state, parameterArray);
        }
        public void Begin(String methodName, EventHandler<ClientEventArgs> callback, Object state, params Object[] parameterArray)
        {
            if (parameterArray != null)
            {
                Array.Resize<Object>(ref parameterArray, parameterArray.Length + 2);
            }
            else
            {
                parameterArray = new Object[2];
            }
            parameterArray[parameterArray.Length - 1] = new ObjectClientState
            {
                Callback = callback,
                MethodName = methodName,
                UserState = state
            };
            parameterArray[parameterArray.Length - 2] = new AsyncCallback(OnCallback);
            ContractType.InvokeMember("Begin" + methodName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public, null, Channel, parameterArray);
        }

        //- $OnCallback -//
        private void OnCallback(IAsyncResult result)
        {
            ObjectClientState state = result.AsyncState as ObjectClientState;
            if (state == null)
            {
                return;
            }
            Object obj = ContractType.InvokeMember("End" + state.MethodName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public, null, Channel, new Object[] { result });
            if (state.Callback != null)
            {
                state.Callback(this, new ClientEventArgs
                {
                    Object = obj,
                    UserState = state.UserState
                });
            }
        }
    }
}

Feel free to upgrade it, modify it, or use it however you would like.

Security - Communication over SSL

At this point I would like to turn out attention to a critical part of WCF development: security. Many times, if not most of the time, you will be dealing with some sort of sensitive information in your application. This goes for Silverlight as much as it does for .NET. Fortunately, secure WCF interaction is essentially the same for both.  Before we begin though, we need to update our service in order for it to handle secure connectivity.  To do this, we are going to create a separate service from our Person service, called SecurePersonService.  In most situations, you would just have a single service to handle both, but for the sake of this document we're going to keep them separate.

Before we add security to our service though, we need to have an SSL certificate installed on the server.  This is the same type of certificate you would have if you wanted to provide a checkout experience on an e-commerce web site.  If you already have an SSL certificate, great, if not, then you will need to go through the motions to install one.  To install one for IIS6 or IIS7, just follow the instructions at http://blog.functionalfun.net/2008/05/how-to-create-server-certificate-for.html.  This post explains how you can easily get a free 90-day signed SSL certificate from a certificate provider.

Once you have the certificate installed, you need to then configure the service for SSL.  We haven't yet created the service, but that's OK.  We know what it's going to be called.  To configure our BasicHttpBinding service for SSL you essentially need to set the security mode to Transport in a binding configuration and specify the certificate in a service behavior.  Here's the new configuration:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="SecureBasicHttpBinding">
          <security mode="Transport" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="SecurePersonServiceBehavior">
          <serviceCredentials>
            <serviceCertificate 
              findValue="localhost" 
              storeLocation="LocalMachine" 
              storeName="My" 
              x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="Contact.Service.PersonService">
        <endpoint address="" binding="basicHttpBinding" contract="Contact.Service.IPersonService" />
      </service>
      <service name="Contact.Service.SecurePersonService" behaviorConfiguration="SecurePersonServiceBehavior">
        <endpoint bindingConfiguration="SecureBasicHttpBinding" 
                  address="" binding="basicHttpBinding" contract="Contact.Service.IPersonService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

There are two conceptual notes that should probably be mentioned at this point:

First, a binding configuration changes the defaults of a particular binding.  As I mentioned earlier, a binding is really just a collection of binding elements with some pre-set parameters.  In this case, we are applying a particular binding configuration to an endpoint to change the security from "None" to "Transport" (which is SSL in this case).

Second, behaviors essentially allow you to declaratively, either via configuration or programmatically via attributes, modify how a particular part of your service operates.  You can have all kinds of different behaviors at different levels.  For example, you can use an operation behavior to modify something about an operation.  We will see this later when we use an operation behavior to apply operation-level security.  In our configuration here, we are applying a service behavior to modify the service to use a particular certificate.

Next, for the time being, let's copy/paste our PersonService implementation as a new class called SecurePersonService.  Again, this is only for the sake of this demo.  In reality, there's no reason to use the word "Secure" for this service.  Then, let's create a SecurePerson.svc file in our service web site root and insert the following service declaration:

<%@ ServiceHost Service="Contact.Service.SecurePersonService" %>

At this point we have an SSL BasicHttpBinding service setup.  We can now alter alter our Silverlight client to use SSL.  This is really just a matter of setting the BasicHttpBinding security more to Transport and changing the URL from the HTTP based URL to the HTTPS one.  Here's how we have modified our previous Silverlight WCF client to allow SSL access:

BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
//+ step 1 of 2: set security mode
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.Transport;
//+ step 2 of 2: set to https _and_ set proper relative endpoint
EndpointAddress endpointAddress = new EndpointAddress("https://localhost/SecurePerson.svc");
IPersonService personService = new ChannelFactory<IPersonService>(basicHttpBinding, endpointAddress).CreateChannel();

Those two steps are the only steps involved.  Silverlight is not set to use the new SSL service.

Having said that, if you try to run the Silverlight client, it won't work.  Why?  Well, as Tim Heuer, Senior Program Manager for Silverlight points out, you can't rely on the existing ClientAccessPolicy.xml configuration we used previously.  Previously we allowed the "*" domain, which allows all non-secure clients in.  This does not include HTTPS clients.  Thus, we need to specify them explicitly.  Here is our new ClientAccessPolicy.xml file:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers= "SOAPAction">
        <domain uri="http://*"/>
        <domain uri="https://*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Now our Silverlight client will communicate successfully with the service over SSL.  But, SSL only secures the data going over the wire, it doesn't say anything about who can access the data.  For this we need to add some form of authentication.

Security - UserName Authentication

If we were working in .NET, we could just use the WsHttpBinding to use the WS-Security standard to send our username and password to our service.  Silverlight 2.0, however, doesn't include this binding.  This doesn't mean we can't make username/password authentication happen.  We could actually use a WebRequest technique that we will cover later to communicate with a WsHttpBinding service, but let's keep with BasicHttpBinding for the time being.  In this case, all we need to do is add the username and password to the message to be sent over our secure SSL connection and have it checked at the other end.  This is really as easy as it sounds.

Regardless of whether you are on the service-side or the client-side, you will have something called an operation context.  This houses the information for the current operation.  You can think of it as a the WCF operation version of HttpContext in ASP.NET.  In fact, much like HttpContext, the OperationContext object is a single.  You access it via System.ServiceModel.OperationContext.Current. As you progress in your WCF projects, you will find yourself going to the operation context time and time again for various reason.  It's an incredibly important feature of WCF that provides much value to service development on both the service and client side.

Of the many properties in this context, there is one called OutgoingMessageHeaders of type System.ServiceModel.Channels.MessageHeaders.  As the name suggestions this houses the message headers that are being sent out.  Likewise there's also an IncomingMessageHeaders object of the same type, which contains the header information that has been received.  These are just opposite sides of the coin.  Both outgoing and incoming headers are like request headers in the web world.  Outgoing headers are the "request headers" being sent and incoming headers are the "request headers" received on the other end.  This works the same for both the service-side and client-side.

To enable authorization, we just need to add both the username and password to the OutgoingMessageHeader object on the client and read them from the IncomingMessageHeader object on the service.  In Silverlight, this looks like this:

MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
messageHeadersElement.Add(MessageHeader.CreateHeader("UserName", "", "JohnDoe"));
messageHeadersElement.Add(MessageHeader.CreateHeader("Password", "", "MyPassword"));

Notice there is no mention of the service we are going to access.  When the service-call happens, the information will automatically be applied in the background and sent over the wire.

Now while this sounds great, we see a reoccurring theme: it doesn't work.  Why?  If you try to do this, you will find that OperationContext.Current is null.  The singleton has not yet been created.  Well, that kind of throws a wrench in things.  Fortunately, though, this is easily remedied.  All we need to do is declare an operation context scope.  This basically means instantiating a System.ServiceModel.OperationContextScope object, passing it an existing operation context or something which implements the System.ServiceModel.IContextChannel interface.  We obviously don't have the former, but what about the latter?

As it turns out, the channel created by our channel factory doesn't only implement our service contract (IPersonService), but it also implements IContextChannel.  Thus, we are able to pass this to the operation context scope, which will then create the operation context, allowing us to add the headers and make our call.  Here's our new service call:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)personService))
{
    MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
    messageHeadersElement.Add(MessageHeader.CreateHeader("UserName", "", "JohnDoe"));
    messageHeadersElement.Add(MessageHeader.CreateHeader("Password", "", "MyPassword"));
    //+
    Person person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
}

Note that the operation context scope implements the System.IDisposable interface, thus allowing you to wrap it in a using block in C#.

At this point we can turn our attention to the service.  This is actually about as simple as what we did on the client-side, if not simpler.  All we need to do is see if the IncomingMessageHeaders object on our operation context contains our UserName and Password headers.  If they do, then extract them and validate them.  If all if well, then run the service logic.

To check to see if a particular message header is in the IncomingMessageHeaders object, use the FindHeader method.  This will return the index of the header or -1 if the header was not found.  Since both of our headers must exist, the sum of the indexes must be at least 0.  -1 would mean that one of the two headers is missing whereas -2 would mean that both are missing.  Therefore, if the sum is at least 0, we can grab the header information, which we do using the GetHeader<T> method.  This is a generic method, so specify the type that you would like your header value to be as T.  In our case they will both be System.String.  Once we have pulled the username and password, we can validate them and run our service logic.  Here's our entire service up to this point:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
//+
namespace Contact.Service
{
    public class SecurePersonService : Contact.Service.IPersonService
    {
        //- @GetPersonData -//
        public Person GetPersonData(String personGuid)
        {
            MessageHeaders messageHeadersElement = OperationContext.Current.IncomingMessageHeaders;
            Int32 id = messageHeadersElement.FindHeader("UserName", "") + messageHeadersElement.FindHeader("Password", "");
            if (id > -1)
            {
                String username = messageHeadersElement.GetHeader<String>("UserName", "");
                String password = messageHeadersElement.GetHeader<String>("Password", "");
                if (username == "JohnDoe" && password == "MyPassword")
                {
                    return new PersonService().GetPersonData(personGuid);
                }
            }
            //+
            return null;
        }
    }
}

Now at this point we could reuse this same technique to secure each operation in our service.  However, the technical term for doing this is insanity.  This is absolutely crazy.  There absolutely has to be a better way of doing this than dealing with the internal mechanics of message headers for each and every single operation in your service.  We need something that will validate the username and password information before our logic ever runs so that we never, ever have to see it.  Fortunately, there is.  This is exactly the value an operation behavior provides.  They are also incredibly straightforward to implement.

Before we do that though, we need to create operation invoker.  We do this by creating a class which implements the System.ServiceModel.Dispatcher.IOperationInvoker interface.  There are many member signatures in this interface, but we only care about the Invoke method.  Every time you call an operation, you "invoke" the operation much like how you "invoke" a method via reflection.  Earlier we saw how we passed an anonymous method to an Invoke method in WPF so we could access the UI thread.  This is the same idea.  When you run something, you "invoke" it.  For an operation invoker, when an operation is called, the Invoke method is called to run the actual operation logic.  Our mission is to house validation logic in our invoker and, if validation succeeds, have the invoker call the original service operation invoker.

We install an operation invoker using an operation behavior.  An operation behavior is a class which implements the System.ServiceModel.Description.IOperationBehavior interface.  This interface has four method signatures, but we really only care about one of them.  Not only that, but the only thing this method will do is set our Invoker.  Before this can matter though, we have to have a way to apply our bit to our operation.  The operation behavior may set the operation invoker, but who sets the operation behavior?  As it turns out, operation behaviors may be applied declaratively through attributes.  This is rather interesting as it allows us to have our operation behavior class inherit from System.Attribute, thus making our operation behavior completely self-sufficient.

It's that time again to move from the lecture hall to the lab.  We will first turn our attention to the operation behavior.  Below is the entire operation behavior:

using System;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
//+
namespace Contact.Service.Behavior
{
    [AttributeUsage(AttributeTargets.Method)]
    public class SecurityOperationBehavior : Attribute, IOperationBehavior
    {
        //- @AddBindingParameters -//
        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            //+ blank
        }

        //- @ApplyClientBehavior -//
        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
            //+ blank
        }

        //- @ApplyDispatchBehavior -//
        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.Invoker = new SecurityOperationInvoker(dispatchOperation.Invoker);
        }

        //- @Validate -//
        public void Validate(OperationDescription operationDescription)
        {
            //+ blank
        }
    }
}

As you can see, it's just a simple attribute whose attribute usage states that it may only be applied to methods.  Notice also that the only method we care is the ApplyDispatchBehavior method and, as mentioned before, the only thing were doing is setting the new invoker, passing the original invoker to its constructor.  Let's now turn to our operation invoker:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
//+
namespace Contact.Service.Behavior
{
    public class SecurityOperationInvoker : IOperationInvoker
    {
        //- $InnerOperationInvoker -//
        private IOperationInvoker InnerOperationInvoker { get; set; }

        //+
        //- @Ctor -//
        public SecurityOperationInvoker(IOperationInvoker operationInvoker)
        {
            this.InnerOperationInvoker = operationInvoker;
        }

        //+
        //- @AllocateInputs -//
        public Object[] AllocateInputs()
        {
            return InnerOperationInvoker.AllocateInputs();
        }

        //- @Invoke -//
        public Object Invoke(Object instance, Object[] inputs, out Object[] outputs)
        {
            //+ authorization
            MessageHeaders messageHeadersElement = OperationContext.Current.IncomingMessageHeaders;
            Int32 id = messageHeadersElement.FindHeader("UserName", "") + messageHeadersElement.FindHeader("Password", "");
            if (id > -1)
            {
                String username = messageHeadersElement.GetHeader<String>("UserName", "");
                String password = messageHeadersElement.GetHeader<String>("Password", "");
                SecurityValidator.Authenticate(username, password);
                //+
                return InnerOperationInvoker.Invoke(instance, inputs, out outputs);
            }
            //+
            throw new FaultException<InvalidOperationException>(new InvalidOperationException(SecurityValidator.Message.InvalidCredentials), SecurityValidator.Message.InvalidCredentials);
        }

        //- @InvokeBegin -//
        public IAsyncResult InvokeBegin(Object instance, Object[] inputs, AsyncCallback callback, Object state)
        {
            return InnerOperationInvoker.InvokeBegin(instance, inputs, callback, state);
        }

        //- @InvokeEnd -//
        public Object InvokeEnd(Object instance, out Object[] outputs, IAsyncResult result)
        {
            return InnerOperationInvoker.InvokeEnd(instance, out outputs, result);
        }

        //- @IsSynchronous -//
        public Boolean IsSynchronous
        {
            get { return InnerOperationInvoker.IsSynchronous; }
        }
    }
}

At first glance it may seem like there's a lot going on here, but if you look closely you will see that there are only three things of note here.  First, there is the InternalOperationInvoker property.  This just hold the original operation invoker so we can call it later.  Second, every other member except Invoke does nothing but call the invoker in InternalOperationInvoker.  Third, the Invoke method is not really doing anything but what we've already seen in the service operation.  The only difference is that upon validation, instead of doing the actual logic, the Invoke method just calls the Invoke method of our InternalOperationInvoker property.  So, it's not really all that busy after all.

With our operation behavior created, we can now return to modify our service operation.  All we need to do is remove all the validation logic and apply our new SecurityOperationBehavior attribute.  Our service operation now looks like this:

//- @GetPersonData -//
[SecurityOperationBehavior]
public Person GetPersonData(String personGuid)
{
    return new PersonService().GetPersonData(personGuid);
}

That's a lot better than before, isn't it?  With this new toy at your disposal, whenever you want to secure a new operation in your service, just apply the attribute and move on. 

Before moving on, note that if you would like to see another example of using operation behaviors, see my Minima Blog Engine 3.1 source code.  Minima is my training software to demonstrate many areas of .NET and it relies heavily on WCF.

Handling Exceptions

We now have an authentication model for our WCF connectivity in our Silverlight application.  There is one more thing we could do to improve this.  Returning null from a service when validation failed is a good way to cause no end to confusion.  The worst error is seeing no error.  Therefore, we need to throw an exception if validation fails.  Continuing in how we have been discussing things, let's move our attention back to the .NET world to discuss some concepts and theory.  Then let's angle our knowledge a bit to make way for the Silverlight world.

To begin, you need to understand that the concept of an exception is a .NET concept.  The messages over the wire have absolutely nothing to do with .NET and, therefore, have no idea what an exception is.  Instead, messages over the wire and service-oriented architecture in general have a concept called a fault, which essentially serves the same purpose as an exception.  Therefore, if you were to throw an exception in a service, the SOA world won't have the first clue what you're talking about.  Not only that, but when your client hears about the exception, it won't see an exception, but, rather a signal that there was some sort of a catastrophic error, thus closing your client channel (our IPersonService instance).  In other words, the following in the service will break your client:

String message = "Invalid credentials";
throw new System.InvalidOperationException(message);

You can, however, get around this by telling your WCF service to include exception information in fault.  You can set this in configuration or in your service host factory.  I'm not going to demonstrate this because I don't want to encourage this cop-out technique.  This is only to be used for debugging.  Do you really want the fully-detailed exception message and stack trace to go out into all the world to see?  This would be even worst than turning ASP.NET custom errors off.  This is the image of a security flaw.

WCF provides the proper mechanism for dealing with exceptions with the System.ServiceModel.FaultException<T> class.  This allows us to to throw exceptions as fault.  There's also a System.ServiceModel.FaultException, from which FaultException<T> inherits.  You can either throw the non-generic one to send a simple message or you can use the generic one to send a message and the exception type.  The generic one will probably be the one you use most often.

To use FaultException<T>, first instantiate the exception you would like to throw then pass that object as well as the exception message to the FaultException<T> instance.  Then you may throw the FaultException<T> instance.  That is, instead of throwing the InvalidOperationException as seen in the last example, do the following:

String message = "Invalid credentials";
throw new FaultException<System.InvalidOperationException>(new System.InvalidOperationException(message), message);

This will allow your client code to catch the exception gracefully and won't send your private stack trace for the world to see.  Here's the code to handle this:

try
{
    person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
}
catch (FaultException ex)
{
    Response.Write(ex.Message);
}

At this point our service-side fault exception code is the same as the following:

throw new FaultException("Invalid credentials");

As I've already mentioned, using the FaultException class will send back a message.  This is exactly what FaultException<T> at this point too.  To make FaultException<T> work the way it was designed, you need to declare a fault contract on your service-side service contract.  You do this by applying the System.ServiceModel.FaultContract attribute to your operation contract.  Here's our new service contract:

using System;
using System.ServiceModel;
//+
namespace Contact.Service
{
    [ServiceContract(Namespace = Information.Namespace.Contact)]
    public interface IPersonService
    {
        //- GetPersonData -//
        [OperationContract]
        [FaultContract(typeof(InvalidOperationException))]
        Person GetPersonData(String personGuid);
    }
}

Now we are able to catch the various different fault exceptions a service may return:

try
{
    person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
}
catch (FaultException<InvalidOperationException> ex)
{
    Response.Write(ex.Message);
}

At this point some may suggest that, since we are only interested in security validation, we should turn our attention toSystem.Security.SecurityException as follows:

throw new System.Security.SecurityException("Invalid credentials");

This special exception will actually be a fault over the wire, give you graceful error handling, and it also doesn't publish your stack trace.  One thing you need to remember about this exception, though, is that you don't catch the same exception that has been thrown.  You actually catch System.ServiceModel.Security.SecurityAccessDeniedException.  Not only that but the message that was sent from the service, isn't the message that will show in your client.  The client side exception will always say "Access is denied.".  Here's an example:

try
{
    person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
}
catch (System.ServiceModel.Security.SecurityAccessDeniedException ex)
{
    Response.Write(ex.Message);
}

You probably shouldn't rely on this mechanism though.  WCF will replace the SecurityException with a Fault over the wire, but not in all places.  For example, the above code will work beautifully if you are throw the exception from an operation, but if you throw it in an operation behavior, your client will see, not SecurityAccessDeniedException, but rather a FaultException (not the generic one either).  You should use FaultException<SecurityException> either as this can cause the real exception to be System.Net.Sockets.SocketException, which is absolutely catastrophic.  For a security validation error, I use FaultException<InvalidOperationException> as we've already seen.

Now, I must apologize at this point for getting you excited about all the awesomeness of faults handling in WCF, because... none of that works in Silverlight.  Yeah.  I know.  It's like "why didn't you say that earlier!!??"  Well, it's important to understand the underlying mechanics of the ideal, before you can work around them into the real-- otherwise, you're just making stuff up as you go.  Not only that, you need to make sure you understand WCF in general before you understand WCF in Silverlight.  Chances are that your WCF services will do more than simply serve Silverlight.

The reason none of this works in the Silverlight world is because has absolutely no concept of a fault.  It actually can't.  With this specific service, when your service call fails validation, your Silverlight application will only see a 404 error with the text "The remote server returned an error: NotFound".  When a fault is thrown, regardless of how pretty you make it, the HTTP status code is not 200, where 200 means that everything went OK.  This is a problem for Silverlight.

Silverlight, as we know, runs in the context of a web browser.  Because of this, Silverlight is only provided the information that a web browser allows it.  When a response is returned to Silverlight with a status code other than 200, the web browser intercepts it and never tells Silverlight about it.  It's kind of like when you're at the office and you go to search for a critical piece of information only to find that your company's content filter blocks that particular technology web site thinking it was inappropriate.

There are various ways around this and every single technique that I know of requires you to modify your service.  The method we are going to use modifies the service a tiny bit, but it does so in a reusable way.  We are essentially going to create a custom FaultDetail class which we will implement in our Person data contract.  If an exception is thrown on the service, a fault detail will be created and added to our Person object.  Then, when we receive a response on the client side, we can check to see if FaultDetail is null.  If not, then there was a fault. 

However, I don't want to do this for all my service-clients.  Service clients that can handle service faults are going to see the real fault.  There's no reason to confuse whoever is accessing our service by having a separate FaultDetail.  Having an error in two places can lead to disasters and mass confusion.  Mindless consistency is often the fastest way to catastrophic disaster.  You can't say you drive 40 miles per hour at all times because you strive for consistency.  This can kill pedestrians in school zones and kill you on the interstate.  We must be flexible to the context of each situation.  We must seek congruency, not consistency.  Therefore, we will only set the FaultDetail object when a specific message header is present.  For our service, we will call this message header "DoesNotHandleFault".  Note this isn't "IsSilverlight".  This makes our FaultDetail technique reusable for other technologies that do not handle faults.

Enough lecture, back to the lab.  First, let's create our FaultDetail object.  This can simply be a class with some properties.  In this example, I have a Message property as well two constructors, one to accept a message and open to accept an exception:

using System;
using System.ServiceModel;
//+
namespace General.Service
{
    public class FaultDetail
    {
        //- @Message -//
        public String Message { get; set; }

        //+
        //- @CreateFaultDetail -//
        public static FaultDetail CreateFaultDetail(Exception exception)
        {
            return CreateFaultDetail(exception.Message);
        }
        public static FaultDetail CreateFaultDetail(String message)
        {
            return new FaultDetail
            {
                 Message = message
            };
        }
    }
}

At this point, you could take this idea further and iterate through the InnerExceptions of the exception and add nested FaultDetail messages.  That's a mission for you, if you choose you accept it.

Next, let's create an interface that will signal to us that a particular service-side data contract can handle a FaultDetail:

namespace General.Service
{
    public interface IContainsFaultDetail
    {
        FaultDetail FaultDetail { get; set; }
    }
}

Let's now implement the interface:

using System;
using System.Runtime.Serialization;
//+
using General.Service;
//+
namespace Contact.Service
{
    [DataContract(Namespace = Information.Namespace.Contact)]
    public class Person : IContainsFaultDetail
    {
        //++
        //+ more properties here
        //++
        //- @FaultDetail -//
        [DataMember]
        public FaultDetail FaultDetail { get; set; }
    }
}

You may be curious to know how this service-side data contract change will affect the rest of the clients which consume this service.  It's actually really simple: it doesn't.  The client will not break simply because it doesn't know how to deserialize something.  Actually, in .NET, if the client-side data contract didn't have data members the service was sending back to it, but implemented System.Runtime.Serialization.IExtensibleDataObject, the data would go into the data contract's ExtensionData property, or as I like to call it "the data member bucket". So, you aren't breaking anything by adding data members to your service-side data contracts.  As a side note, this works the other way too.  If your client sends more information than the service knows about, the service won't break either and, if its data contract implemented IExtensibleDataObject on a service-side data contract, the data will likewise go into the ExtensionData property.  Like I said though, this is in .NET.  Silverlight does not support this interface.  Of course, Silverlight can still send extra stuff to the service, which will be in .NET.

The last task on the service-side is to add the FaultDetail functionality to our service.  We could either add the functional to each and every single operation or we could simply extend the operation behavior that we had already created.  I'm voting for the later.  Essentially what we are going to do is wrap all the logic in our operation invoker Invoke logic in a try-catch block.  Then, if an exception is thrown, we can check to see if the "DoesNotHandleFault" message header is set.  If it is, set the FaultDetail on the return object.  If it isn't, then simply rethrow the exception.

This all seems pretty simple, right?  Well, there are some problems with this.  First, you want to make this reusable.  Therefore, you cannot assume anything about the operation return type other than the fact that everything inherits from System.Object.  You could easily get around this by checking to see if our IContainsFaultDetail interface is on the object.  If it is, then you can set the FaultDetail through this interface.  You don't even need to know the actual type.  However, what if the object is null?  Just instantiate it first, right?  Again, you don't know the type.  Fortunately, however, the wonderful world of reflection is at our disposal.

To get around this problem, we need to first see if there is even a problem at all.  This means checking to see if our return object is null.  If not, then you're all set to check for the interface and set the FaultDetail through that interface.  If it is null, then we need to use reflection to obtain the type of the return object.  This is actually hidden in our InnerOperationInvoker which we saved when we instantiated our operation invoker.  To be more specific, inside our InnerOperationInvoker is a property named Method.  This method is of type System.Reflection.MethodInfo, which, in turn, has a property named ReturnType of type System.Type which is exactly what we need.  Then, we use the System.Activator::CreateInstance method to create an instantiated object using the value of ReturnType.  At this point we are able to check for our IContainsFaultDetail interface and setting the FaultDetail.

Once more, let's switch from lecture to lab.  Below is our new Invoke method for our operation invoker based on the concepts I've just explained:

//- @Invoke -//
public Object Invoke(Object instance, Object[] inputs, out Object[] outputs)
{
    outputs = new Object[] { };
    MessageHeaders messageHeadersElement = OperationContext.Current.IncomingMessageHeaders;
    Object returnObject = null;
    try
    {
        //+ authorization
        Int32 id = messageHeadersElement.FindHeader("UserName", "") + messageHeadersElement.FindHeader("Password", "");
        if (id > -1)
        {
            String username = messageHeadersElement.GetHeader<String>("UserName", "");
            String password = messageHeadersElement.GetHeader<String>("Password", "");
            SecurityValidator.Authenticate(username, password);
            //+
            return InnerOperationInvoker.Invoke(instance, inputs, out outputs);
        }
        //+
        throw new FaultException<InvalidOperationException>(new InvalidOperationException(SecurityValidator.Message.InvalidCredentials), SecurityValidator.Message.InvalidCredentials);
    }
    catch (Exception ex)
    {
        if (messageHeadersElement.FindHeader("DoesNotHandleFault", "") > -1)
        {
            if (returnObject == null)
            {
                Type invokerType = InnerOperationInvoker.GetType();
                PropertyInfo pi = invokerType.GetProperty("Method");
                MethodInfo mi = (MethodInfo)pi.GetValue(InnerOperationInvoker, null);
                Type returnType = mi.ReturnType;
                Type interfaceType = returnType.GetInterface("General.Service.IContainsFaultDetail");
                if (interfaceType != null)
                {
                    returnObject = Activator.CreateInstance(returnType);
                }
            }
            if (returnObject != null && returnObject is IContainsFaultDetail)
            {
                ((IContainsFaultDetail)returnObject).FaultDetail = FaultDetail.CreateFaultDetail(ex.Message);
            }
        }
        else
        {
            throw;
        }
    }
    //+
    return returnObject;
}

The explanation that I have already provided should help you understand each part of what's going on here.  There is, however, one part of this that may cause you problems if you don't implement this technique correctly.  Notice the Invoke method accepts an out parameter named outputs.  And out parameter is an incredibly powerful C# feature that requires the method on which it is placed to give the parameter a value, which the method caller may then.  If your method does not give the parameter a value, your code will not compile.  In many cases, setting an out parameter to null will be sufficient.  In this case, this will cause a serialization error when the service reply is created.  Therefore, in this example, I'm setting the outputs parameter to an empty object array.  This will satisfy both the compiler as well as WCF.

At this point, we can move to the client-side.  The first thing we need to do is copy our FaultDetail, IContainsFaultDetail, and new Person data contract to our Silverlight project.  Note that you do NOT need to do this for any other clients for the reasons I've already already mentioned.  The only clients that need these changes are the clients which are going to use the FaultDetail directly.

Next, let's add our "DoesNotHandleFault" message header in our Silverlight client.  You can do this in the same place you set your other message headers:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)personService))
{
    MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;
    messageHeadersElement.Add(MessageHeader.CreateHeader("UserName", "", "JohnDoe"));
    messageHeadersElement.Add(MessageHeader.CreateHeader("Password", "", "MyPassword12341234"));
    //+ allows returning of a FaultDetail object
    messageHeadersElement.Add(MessageHeader.CreateHeader("DoesNotHandleFault", "", true));
    //+
    personService.BeginGetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6", asyncCallBack, personService);
}

Then, in our callback, check for the FaultDetail object:

AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
    Person person = ((IPersonService)result.AsyncState).EndGetPersonData(result);
    String text = String.Empty;
    if (person.FaultDetail != null)
    {
        text = person.FaultDetail.Message;
    }
    else
    {
        text = person.FirstName;
    }
    //+ the rest of your callback here
};

Now you have the ability to catch faults in Silverlight 2.  There's, however, one quite serious problem with this method though.  What happens when your operation doesn't return a data transfer object (DTO) like our Person class?  There's no setting a FaultDetail on an array, a list, an Int32, or a string.

Though it's generally a redundant and architecturally questionable idea, in these cases you really need to create a wrapper response class.  As a service-oriented architect, I only care about the service contracts.  If the service contracts have nothing more than a bunch of request response messages, then I'm seriously slowed down.  They tell me absolutely nothing.  How can I know anything about an operation's response by looking at GetPersonDataResponse?  In these situations, it takes me much longer to get at the heart of what's going on because I need to understand with X number of methods and (2 * X) number of custom objects (and look them up on a chart every time I forget what's what!)

Thus, though services are to accept a very specific set of parameters and return a very specific element.  For our scenario, however, you need to do this.  To create a DTO, just create a class which contains a property for your operation return object and as well as a FaultDetail property.  As I've mentioned, this is incredibly redundant as what I've just described is exactly what SOAP envelope does with a fault.  But, since Silverlight will never see those messages, we are rather forced to emulate them.

JSON Service Connectivity

If you've been paying attention to the examples thus far, we have only been using the BasicHttpBinding binding.  This is because Silverlight doesn't handle bindings like WsHttpBinding, NetTcpBinding, or NetNamedPipeBinding.  However, since we're on the web, we might create a Silverlight application to replace an AJAX component which used JSON to communicate to a WebHttpBinding WCF service endpoint.  Or, perhaps, you just prefer to use a WebHttpBinding on your WCF service.  Therefore, we need the ability to access JSON services efficiently.  To do this, we turn to the System.Net namespace, namely the WebRequest class.

Essentially what we want to do is create an instance of the System.Net.WebRequest class and setup an async call chain.  If you recall, an async chain is when the callback of one call makes another call and its callback may potentially make another call.  Before you can do any of this, though, you need to know the full URI you are going to access.  This URI is the base endpoint address of the service combined with the relative endpoint address combined with the name of the service operation you are going to access.

We know from our service setup that the base address of our service is http://localhost:1003/Person.svc.  The relative address is configured on the service side.  Here's a configuration snippet from the service:

<service name="Contact.Service.PersonService">
  <endpoint address="json" binding="webHttpBinding" contract="Contact.Service.IPersonService" behaviorConfiguration="JsonEndpointBehavior" />
</service>

The endpoint address, "json", is the second piece of information required, the relative endpoint address.  The third piece of information in our case is "GetPersonData".  Thus the full URI we need to pass to our WebRequest object is http://localhost:1003/Person.svc/json/GetPersonData.

Once we create a WebRequest object, we need to make sure the content type is set to "application/json" and make sure the HTTP method is set to POST.  Without both of these set, we will get nothing but errors all over the place.  With these set, we are then able to enter into an async chain of the steps that occur in a WebRequest.

The process begins by calling the BeginGetRequestStream method on our WebRequest object, passing it a callback.  When that callback is called, we are then, per the Async Pattern, we able to call the EndGetRequestStream, which, if you recall, requires the IAsyncResult which was passed to our callback.  At this point we are able to write information to the service and call BeginGetResponse, passing it another callback.  Then, when that callback is called, we can call the EndGetResponse, passing it the new IAsyncResult object to obtain a System.Net.WebResponse object.  Finally, we call GetResponseStream on this WebResponse object, which gives us the response data sent back to us from the service.  Here is a complete example of using the WebRequest object in this way:

using System;
using System.Collections.Generic;
using System.Json;
using System.Net;
//+
namespace SilverlightClient
{
    public class WcfJsonClient
    {
        //- @JsonValueEventArgs -//
        public class JsonValueEventArgs : EventArgs
        {
            //- @JsonValue -//
            public JsonValue JsonValue { get; set; }

            //- @JsonType -//
            public JsonType JsonType { get; set; }

            //- @ValueAsText -//
            public String ValueAsText
            {
                get
                {
                    System.Text.StringBuilder builder = new System.Text.StringBuilder();
                    System.IO.StringWriter writer = new System.IO.StringWriter(builder, System.Globalization.CultureInfo.CurrentCulture);
                    JsonValue.Save(writer);
                    //+
                    return builder.ToString();
                }
            }
        }

        //- @Complete -//
        public event EventHandler<JsonValueEventArgs> Callback;

        //+
        //- $PostJsonData -//
        private String PostJsonData { get; set; }

        //+
        //- @PostHttpRequest -//
        public void PostHttpRequest(String endpoint, String methodName)
        {
            PostHttpRequest(endpoint, methodName, String.Empty, null);
        }
        public void PostHttpRequest(String endpoint, String methodName, String jsonData)
        {
            PostHttpRequest(endpoint, methodName, jsonData, null);
        }
        public void PostHttpRequest(String endpoint, String methodName, String jsonData, Dictionary<String, String> headerDictionary)
        {
            WebRequest request = WebRequest.Create(new Uri(endpoint + "/" + methodName));
            this.PostJsonData = jsonData;
            request.Method = "POST";
            request.ContentType = "application/json";
            if (headerDictionary != null)
            {
                foreach (String key in headerDictionary.Keys)
                {
                    request.Headers[key] = headerDictionary[key];
                }
            }
            request.BeginGetRequestStream(new AsyncCallback(OnPostBegin), request);
        }

        //- $OnPostBegin -//
        private void OnPostBegin(IAsyncResult result)
        {
            WebRequest request = result.AsyncState as WebRequest;
            using (System.IO.StreamWriter writer = new System.IO.StreamWriter(request.EndGetRequestStream(result)))
            {
                if (!String.IsNullOrEmpty(this.PostJsonData))
                {
                    writer.Write(this.PostJsonData);
                }
                writer.Close();
                //+ response
                request.BeginGetResponse(new AsyncCallback(OnPostComplete), request);
            }
        }

        //- $OnPostComplete -//
        private void OnPostComplete(IAsyncResult result)
        {
            WebRequest request = result.AsyncState as WebRequest;
            using (WebResponse response = request.EndGetResponse(result))
            {
                OnComplete(new System.IO.StreamReader(response.GetResponseStream()).ReadToEnd());
            }
        }

        //- #OnComplete -//
        protected void OnComplete(String data)
        {
            if (Callback != null)
            {
                JsonValue jsonValue = (JsonValue)JsonObject.Load(new System.IO.StringReader(data))["d"];
                Callback(this, new JsonValueEventArgs
                {
                    JsonValue = jsonValue,
                    JsonType = jsonValue is JsonArray ? JsonType.Array : JsonType.Object
                });
            }
        }
    }
}

Here you can see the WebRequest setup as well as the async chain.  Notice also how this example accepts a System.Collections.Generic.Dictionary<T1, T2> object.  Using this we are able to set custom HTTP headers on to our client.  Using HTTP headers is an awesome way of communicating with a service.  We have already seen that SOAP services use the SOAPAction header to specify what operation to run at the other end.  You could do something similar in your JSON services as well.

Normally at this point I would like show you an example of using this client, but we aren't done explaining it.  One part of this client example that we haven't discussed is how to deal with the response JSON data.  At this point our JSON data is just raw text.  Ideally, we would take this raw text, run it through deserialization and be done with things.  However, one hitch here is that an unmodified WCF JSON service likes to send back JSON with full namespaces for each member.  Here's an example of what I mean:

{
    "d": {
        "__type": "Person:http:\/\/www.netfxharmonics.com\/service\/Contact\/2008\/11\/",
        "City": "Unknown",
        "FirstName": "John",
        "Guid": "F488D20B-FC27-4631-9FB9-83AF616AB5A6",
        "LastName": "Doe",
        "PostalCode": "66062",
        "State": "KS"
    }
}

This kind of gets in the way of simple deserialization.  Fortunately, that's not a problem as Silverlight 2 provides a different way to access JSON data through it's System.Json.JsonObject housed in the System.Json assembly.  Be careful, though, every time you add an assembly to your Silverlight application, you increase the size of the Silverlight XAP file.  When you add the 52k System.JSON assembly, you add 21k to the size of the XAP file.  In this case, this takes the size of the XAP file from 12k to 33k.  That's a huge increase.  So, think ahead on how and if you really want to access JSON WCF services using this technique.

If you notice from the client, when we the last client callback is called, the static System.Json.JsonObject.Load method is called to load a stream or TextReader into a System.Web.JsonValue object.  This gives us a representation we can use to access any information we want by accessing the indexer of the object.  Before we can access our data, though, we need to open the data envelope.  This is that "d" section in the WCF JSON response message.  This is as simple as accessing the "d" indexer on the JsonValue object as this example shows:

JsonValue jsonValue = (JsonValue)JsonObject.Load(new StringReader(data))["d"];

This JsonValue object created here contains the WCF response information.  The JsonValue class itself is the base class for System.Json.JsonArray and System.Json.JsonObject. Unless you know what your service is returning, you need to test which type the JsonObject.Load class created.  This is as simple as the following:

JsonType jsonType = value is JsonArray ? JsonType.Array : JsonType.Object;

If you're working with a JsonObject, you may then access any member of the JSON data you want.  You do this by reading values from a JsonValue into a stream or text writer.  For example, here's the code to access the FirstName value:

StringBuilder builder = new StringBuilder();
StringWriter writer = new StringWriter(builder);
jsonValue["FirstName"].Save(writer);
//+
String firstName = builder.ToString().Replace("\"", "");

Since you would be using this regularly, it's a good idea for us to place this in a method (or even in a "Reader" class):

//- $ReadJsonValue -//
private string ReadJsonValue(JsonValue jsonValue, String field)
{
    StringBuilder builder = new StringBuilder();
    jsonValue[field].Save(new StringWriter(builder));
    //+
    return builder.ToString().Replace("\"", "");
}

At this point, you have enough information to see how this WcfJsonClient class can be used.  Here's how we can use it:

WcfJsonClient client = new WcfJsonClient();
client.Complete += OnJsonServiceCallback;
client.PostHttpRequest("http://localhost:1003/Person.svc/json", "GetPersonData", @"{ ""personGuid"": ""F488D20B-FC27-4631-9FB9-83AF616AB5A6"" }");

This is, of course, not complete without the callback method:

//- $OnJsonServiceCallback -//
private void OnJsonServiceCallback(Object sender, WcfJsonClient.JsonValueEventArgs ea)
{
    Write(ReadJsonValue(ea.JsonValue, "State"));
}

As I've mentioned, we can work with arrays as well.  In .NET though, we really only talk about arrays for value types.  If we have a series of reference types, a collection feels much better.  Therefore, let's assume that we the following operation to our service:

//- GetPersonList -//
[OperationContract]
List<Person> GetPersonList( );

What's interesting about this is that System.Collections.Generic.List<T> likes to become an array when going over the wire.  When dealing with SOAP services, a List is an array over the wire.  The same goes for JSON as well.  This is where that JsonArray type comes in to play.  This object is incredibly easy to work with.  Essentially it's a series of JsonValue objects.  Not only that, but JsonArray has an indexer and it implements the IEnumerable<JsonValue> interface, thus allowing us to access it's elements via a foreach loop.  In our case, each of these elements will be of the type JsonObject, which we already know how to deal with.  Here's a complete example of interacting with the above service operation:

WcfJsonClient wcfJsonClient = new WcfJsonClient();
wcfJsonClient.Callback += delegate(Object sender, WcfJsonClient.JsonValueEventArgs ea)
{
    List<Person> personList = new List<Person>();
    JsonArray array = (JsonArray)ea.JsonValue;
    foreach (JsonValue jsonValue in array)
    {
        Person person = new Person
        {
            City = ReadJsonValue(jsonValue, "City"),
            FirstName = ReadJsonValue(jsonValue, "FirstName"),
            LastName = ReadJsonValue(jsonValue, "LastName"),
            PostalCode = ReadJsonValue(jsonValue, "PostalCode"),
            State = ReadJsonValue(jsonValue, "State"),
            Guid = ReadJsonValue(jsonValue, "Guid"),
        };
        personList.Add(person);
        //+
        Write(person.FirstName);
    }
    //+
    Write("Person count: " + personList.Count.ToString());
};
wcfJsonClient.PostHttpRequest("http://localhost:1003/Person.svc/json", "GetPersonList");

One aspect of this WcfJsonClient class that you may not have realized is that you could easily make it dual purpose with very few changes.  If you added a second callback for XML parsing and change the content type, your "WcfJsonClient" becomes "WcfXmlJsonClient".  This WebRequest technique itself can be used for just about anything.  You could load CVS data or even access SOAP services manually if you wanted, giving you the ability to interact with WsHttpBinding services.  If you know how to communicate with an HTTP service at the wire-level, then the WebRequest can probably make the connection happen.

The only other type of response you would ever really need to parse is a primitive, which is represented by the System.Json.JsonPrimitive, which also inherits from JsonValue.  You don't need to do anything special with these at all.  Just pull the value from them just as you would a value from JsonObject.  In our case, this means running it through the ReadJsonValue method.

Thread Waiting

As we have just seen with our JSON client, many times when working in the Async Pattern, you will have an async chain.  This is an effective way to manage the order or events in an application.  However, depending on what you're doing, this model may not be the entirely optimal.  Fortunately, we have another option: a thread wait.

Thread waiting has been in .NET since the beginning and is very effective in Silverlight to help us control the workflow of our applications.  To use a thread wait, you create an System.Threading.AutoResetEvent object and call it's WaitOne method.  This causes execution in the current thread to pause.  Execution will resume when the object's Set method is called.

So, you can call WaitOne immediately after a service call and have the service call's callback call Set to continue execution.  This allows you to keep a linear flow of your application instead of doing async chaining.  An important note about this, though, is that you don't want to call WaitOne on the UI thread.  This will basically lock up your web browser.  Instead, wrap your service calls and WaitOne call in a new thread.  This will cause that thread to pause, not the UI thread.  Here's the basic usage:

private AutoResetEvent wait = new AutoResetEvent(false);

//+
//- @OnButtonClick -//
public void OnButtonClick(Object sender, System.Windows.RoutedEventArgs ea)
{
    new Thread(new ThreadStart(delegate
    {
        //+ basicHttpBinding call
        ObjectClient<IPersonService> objectClient = new ObjectClient<IPersonService>("BasicHttpBinding_IPersonService");
        objectClient.Callback += OnServiceCallback;
        objectClient.Begin("GetPersonData", "F488D20B-FC27-4631-9FB9-83AF616AB5A6");
        wait.WaitOne();
        //+ webHttpBinding call
        WcfJsonClient wcfJsonClient = new WcfJsonClient();
        wcfJsonClient.Complete += OnJsonServiceCallback;
        wcfJsonClient.PostHttpRequest("http://localhost:1003/Person.svc/json", "GetPersonData", @"{ ""personGuid"": ""F488D20B-FC27-4631-9FB9-83AF616AB5A6"" }");
    })).Start();
}

In this example, a new thread will start and make an ObjectClient service call.  The thread will then be immediately pause.  It will remain paused until the following callback runs the wait.Set method, which will resume execution allowing the WcfJsonClient to then run.

//- $OnServiceCallback -//
private void OnServiceCallback(Object sender, ObjectClient<IPersonService>.ClientEventArgs ea)
{
    this.Dispatcher.BeginInvoke(delegate
    {
        //+ do stuff here
        wait.Set();
    });
}

Using DevServer

If you get seriously deep into HTTP-based service-development in either a Silverlight, AJAX, or general .NET context, there will definitely come a time your work when you need to know what messages are going over the wire, or if messages are going over the wire.  In a strictly Silverlight context, you might even want to make sure your Silverlight client is even looking for a ClientAccessPolicy.xml file.  Fortunately, there is a way to view all this information in a streamlined manner.

My NetFXHarmonics DevServer is a development web server which provides multi-instance web server hosting and the ability to look at the traffic in and out of each web server.  In addition, using DevServer profiles, you can load up entire sets of web servers to quickly setup and teardown different development environments.

To use it, just register your servers in the DevServer configuration file, setup a profile, and either set the startup profile or use a command line argument to specify what profile to load.  This will load up all your development web servers at once.  Here's a sample configuration:

<jampad.devServer>
  <startupProfiles activeProfile="Client">
    <profile name="Client">
      <server key="ClientWS" />
      <server key="ClientSVC" />
    </profile>
  </startupProfiles>
  <servers>
    <server key="ClientWS" name="ClientWS" port="1001"
                virtualPath="/" physicalPath="C:\Project\WCFService\WebSite">
    </server>
    <server key="ClientSVC" name="ClientSVC" port="1003"
                virtualPath="/" physicalPath="C:\Project\WCFService\Service">
    </server>
  </servers>
</jampad.devServer>

You can also change the binding of each server to allow remote or Virtual PC access for testing purposes.  For full documentation on DevServer see http://www.netfxharmonics.com/2008/04/NetFXHarmonics-DevServer-Released.

For now, though, just know that if you enable tracing as well as verbose tracing, you will see all requests that come into a particular web server, thus allowing you to see if your Silverlight application is even looking for the ClientAccessPolicy.xml file and allowing you to see service messages.  Sometimes you don't want to write a full UI to see what a service is sending and you don't feel like attaching a debugger to look at an object's content.  Using DevServer, you can just look at the raw data the server is sending.  DevServer will automatically format anything it thinks is JSON or XML, allowing you to view it in its pretty form (of course, there's also a raw data view as well).  Here's a screen shot of what I got when I ran the sample for this document:

DevServer

As you can see, this can be tremendously helpful when you need to know how to parse or deserialize the incoming data or even to see if a response is even coming back from the server.

Conclusion

As you can see, there's more to Silverlight connectivity in WCF than the naive "Add Service Reference" option.  By simply understanding the mechanics of what's going on, we are able to tailor a solution to our specific needs.  WCF requires nothing more than an address, a binding, and a contract. With this information we can create a channel to access our service.  Then, with a few changes here and there we can optimize our experience for both security and fault tolerance.  Or, in the case of JSON, we can use tools already provided to us to obtain the exact JSON fields we need.  Hopefully you understand the often hidden concepts of WCF for .NET and Silverlight much better than you did before.

As a quick closing note, if you like going into technology at this level of depth, but also like thorough explanations, you seriously need to check out Juval Lowy's book, Programming WCF (2nd Edition).

Links

kick it on DotNetKicks.com

Architectural Overview: Creating Streamlined, Simplified, yet Scalable WCF Connectivity

Contents

Introduction

One of the most awesome things about WCF is that the concepts scale extremely well.  If you understand the ABCs of WCF, then you can do anything from creating a simple Hello World to a complex sales processing service.  It's all based on having an address, a binding, and a contract.  All the other concepts like behaviors, validators, and service factories are simply supplemental to the core of the system.  When you understand the basics, you have the general essence of all of WCF.

Because of this fully-scalable ABC concept, I'm able to use the same pattern for WCF architecture and development for every solution.  This is really nice because it makes it so that I don't have to wait time designing a new setup every time a new problem comes along.  In this discussion, I would like to demonstrate how you can create your own extremely efficient WCF solution based on my template.  Along the way, you will also learn a few pieces of WCF internals to help you understand WCF better.

Before I begin the explanation though, keep in mind that most concepts mentioned here are demonstrated in my Minima Blog Engine 3.1.  This is my training software demonstrating an enormous world of modern technologies.  It's regularly refactored and often fully re-architected to be in line with newer technologies.  This blog engine relies heavily on WCF as it's a service-oriented blog engine.  Regardless of how many blogs you have (or any other series of "content entries"-- for example, the documentation section of the Themelia web site is Minima), you have a single set of services that your entire organization uses.  If you understand the WCF usage in Minima, you will understand WCF very well.

Now, onto the meat (or salad, for the vegetarians) of the discussion...

Service Structure

On any one of my solutions, you will find a X.Service project and a X.ServiceImpl project where X is the solution "code" (either the solution name or some other word that represents the essence of the solution).  The former is the public .NET project which contains service contracts, data contracts, service configuration, and service clients.  The latter is the private .NET project which contains the service implementations, behaviors, fault management, service hosts, validators, and other service-side-only, black-boxes portions of the service.  All projects have access to the former, only the service itself will ever even know about the latter.

This is a very simple setup based upon a public/private model, like in public key cryptography.  The idea is that everything private is protected with all your might and everything public is released for anyone, within the context of the solution, to see.

For example, below is the Minima.Service project for Minima Blog Engine 3.1.  Feel free to ignore the folder structure, no one cares about that.  Just because I make each folder a namespace with prefixed folder names for exclusions, doesn't mean anyone else in the world does.  I find it to be the most optimal way to manage namespaced and non-namespaced groups, but the point of this discussion is the separation of concerns in the projects.

MinimaService

For the time being, simply notice that data contracts and service contracts are considered public.  Everything else in the file is either meaningless to this discussion or will be discussed later.

Here is the Minima.ServiceImpl project for the same solution:

MinimaServiceImpl

Here you can see anything from the host factory to various behaviors to validators to fault management to LINQ-to-SQL capabilities.  Everything here is considered private.  The outside world doesn't need to know, therefore shouldn't know.

For the sake of a more simplified discussion, let's switch from the full-scale solution example of Minima to a smaller "Person" service example.  This "Person" service is part of the overall "Contact" solution.  Here's the Contact.Service for our Contact solution:

PersonService

As you can see, you have a standard data contract, a service contract, and a few other things, which will be discussed in a bit.

For this example, we don't need validators, fault management, or behaviors, or host factories, all we need is a simple service in our Contact.ServiceImpl project:

PersonServiceImpl

By utilizing this model separating the private from the public you can easily send the Contact.Service assembly to anyone you want without requiring them to create their own client proxy or use the painfully horrible code generated by "Add Service Reference", which ranks in my lists as one of the worst code generators right next to FrontPage 95 and Word 2000.

As a side note, I should mention that I have colleagues who actually take this a step further and make a X.Service.Client project which houses the WCF client classes.  They are basically following a Service/Client/Implementation model where as I'm following a Public/Private model.  Just use which ever model makes sense for you.

The last piece needed in this WCF setup is the host itself.  This is just a matter of creating a new folder for the web site root, adding a web.config, and adding a X.svc file.  Period.  This is the entire service web site.

In the Person service example, the service host has only two files: web.config and Person.svc.

Below is the web.config, which declares two endpoints for the same service.  One of the endpoints is a plain old fashioned ASMX style "basic profile" endpoint and the other is one to be used for JSON connectivity.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
    <behavior name="JsonEndpointBehavior">
      <enableWebScript />
    </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="Contact.Service.PersonService">
    <endpoint address="json" binding="webHttpBinding" contract="Contact.Service.IPersonService" behaviorConfiguration="JsonEndpointBehavior" />
    <endpoint address="" binding="basicHttpBinding" contract="Contact.Service.IPersonService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

The Person.svc is even most basic:

<%@ ServiceHost Service="Person.Service.PersonService" %>

This type of solution scales to any level.  If you want to add a service, just add a new X.svc file and register as a new service.  If you want to add another endpoint, just add that line.  It's incredibly simple and scales to solutions of any size and even works well with non-HTTP services like netTcpBinding services.

Service MetaData

Now let's look at each of these files to see how they are optimized.  First, lets' look at the data contract, Person:

using System;
using System.Runtime.Serialization;
//+
namespace Contact.Service
{
    [DataContract(Namespace = Information.Namespace.Contact)]
    public class Person
    {
    //- @Guid -//
    [DataMember]
    public String Guid { get; set; }

    //- @FirstName -//
    [DataMember]
    public String FirstName { get; set; }

    //- @LastName -//
    [DataMember]
    public String LastName { get; set; }

    //- @City -//
    [DataMember]
    public String City { get; set; }

    //- @State -//
    [DataMember]
    public String State { get; set; }

    //- @PostalCode -//
    [DataMember]
    public String PostalCode { get; set; }
    }
}

Everything about this file should be self explanatory.  There's a data contract attribute on the class and data member attributes on each member.  Simple.  But what's with the data contract namespace?

Well, earlier this year, a co-architect of mine mentioned to me that you can centralize your namespaces in static locations.  Genius.  No more typing the same namespace on each and every data and service contract.  Thus, the following file is included in each of my projects:

using System;
//+
namespace Contact.Service
{
    public class Information
    {
    //- @NamespaceRoot -//
    public const String NamespaceRoot = "http://www.netfxharmonics.com/service/";

    //+
    //- @Namespace -//
    public class Namespace
    {
        public const String Contact = Information.NamespaceRoot + "Contact/2008/11/";
    }
    }
}

If there are multiple services in a project, and in 95%+ of the situations there will be, then you can simply add more services to the Namespace class and reference them from your data and service contracts.  Thus, you never, EVER have to update your service namespaces in more than one location.  You can see this in the service contract as well:

using System;
using System.ServiceModel;
//+
namespace Contact.Service
{
    [ServiceContract(Namespace = Information.Namespace.Contact)]
    public interface IPersonService
    {
    //- GetPersonData -//
    [OperationContract]
    Person GetPersonData(String personGuid);
    }
}

This service contract doesn't get much simpler.  There's no reason to discuss it any longer.

Service Implementation

For the sake of our discussion, I'm not going to talk very much at all about the service implementation.  If you want to see a hardcore implementation, go look at my Minima Blog Engine 3.1.  You will see validators, fault management, operation behaviors, message headers, and on and on.  You will seriously learn a lot from the Minima project.

For our discussion, here's our Person service:

using System;
//+
namespace Contact.Service
{
    public class PersonService : Contact.Service.IPersonService
    {
    //- @GetPersonData -//
    public Person GetPersonData(String personGuid)
    {
        return new Person
        {
        FirstName = "John",
        LastName = "Doe",
        City = "Unknown",
        Guid = personGuid,
        PostalCode = "66062",
        State = "KS"
        };
    }
    }
}

Not too excited, eh?  But as it is, this is all that's required to create a WCF service implementation.  Just create an every day ol' class and implement a service contract.

As I've mentioned, though, you could do a ton more in your private service implementation.  To give you a little idea, say you wanted to make absolutely sure that no one turned off metadata exchange for your service.  This is something that I do for various projects and it's incredibly straight-forward: just create a service host factory, which creates the service host and programmatically adds endpoints and modified behaviors. Given that WCF is an incredibly streamlined system, I'm able to add other endpoints or other behaviors in the exact same way.

Here's what I mean:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
//+
namespace Contact.Service.Activation
{
    public class PersonServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
    {
    //- @CreateServiceHost -//
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ServiceHost host = new ServiceHost(typeof(PersonService), baseAddresses);
        //+ add metadata exchange
        ServiceMetadataBehavior serviceMetadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if (serviceMetadataBehavior == null)
        {
        serviceMetadataBehavior = new ServiceMetadataBehavior();
        host.Description.Behaviors.Add(serviceMetadataBehavior);
        }
        serviceMetadataBehavior.HttpGetEnabled = true;
        ServiceEndpoint serviceEndpoint = host.Description.Endpoints.Find(typeof(IMetadataExchange));
        if (serviceEndpoint == null)
        {
        host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
        }
        //+
        return host;
    }
    }
}

Then, just modify your service host line:

<%@ ServiceHost Service="Person.Service.PersonService" Factory="Person.Service.PersonServiceFactory" %>

My point in mentioning that is to demonstrate how well your service will scale based upon a properly setup base infrastructure.  Each thing that you add will require a linear amount of work.  This isn't like WSE where you need three doctorates in order to modify the slightest thing.

Service Client without Magic

At this point, a few of my colleagues end their X.Service project and begin a X.Service.Client class.  That's fine.  Keeping the client away from the service metadata is nice, but its not required.  So, for the sake of this discussion, let's continue with the public/private model instead of the service/client/implementation model.

Thankfully, I have absolutely no colleagues who would ever hit "Add Service Reference".  I've actually never worked with a person who does this either.  This is good news because, as previously mentioned, the code generated by the add service reference is a complete disaster.  You also can't modify it directly without risking your changing being overwritten.  Even then, the code is SO bad, you wouldn't want to edit it.  There's no reason to have hundreds or THOUSANDS of lines of code to create a client to your service.

A much simpler and much more manageable solution is to keep your code centralized and DRY (don't repeat yourself).  To do this, you just need to realize that the publicly accessible X.Service project already contains the vast majority of everything needed to create a WCF client.  Because of this, you may access the service using WCF's built in mechanisms.  You don't need anything fancy, it's all built right in.

Remember, WCF simply requires the ABC: and address, binding, and contract.  On the client-side, WCF uses this information to create a channel.  This channel implements your service contract, thus allowing you to directly access your WCF service without any extra work required.  You already have the contract, so you just have to do is declare the address and binding.  Here's what I mean:

//+ address
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:1003/Person.svc");
//+ binding
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
//+ contract
IPersonService personService = ChannelFactory<IPersonService>.CreateChannel(basicHttpBinding, endpointAddress);
//+ just use it!
Person person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
String firstName = person.FirstName;

No 3,000 line client generated code, no excess classes, no configuration.  Just direct access to your side.

Of course, if you want to use a configuration file, that's great too.  All you need to do in create a system.serviceModel section in your project or web site and declare your service endpoint.  What's really nice about this in WCF is that, since the concept for WCF are ABC on both the client and server, most of the configuration is already done for you.  You can just copy and paste the endpoint from the service configuration to your client configuration and add a name element.

<system.serviceModel>
  <client>
    <endpoint name="PersonServiceBasicHttpBinding" address="http://localhost:1003/Person.svc" binding="basicHttpBinding" contract="Simple.Service.IPersonService" />
  </client>
</system.serviceModel>

For the most part, you will also need to keep any bindings on the service side as well, though you wouldn't copy over validation information.

At this point you can just change the previously used WCF channel code to use an endpoint, but that's an architectural disaster.  You never want to compile configuration information into your system.  Instead of tying them directly, I like to create a custom configuration for my solution to allow the endpoint configuration to change.  For the sake of this discussion though, let's just use appSettings (do NOT rely on appSettings for everything!  That's a cop-out.  Create a custom configuration section!).  Here's our appSetting:

<appSettings>
  <add key="PersonServiceActiveEndpoint" value="PersonServiceBasicHttpBinding" />
</appSettings>

At this point, I can explain that Configuration class found in the public Contact.Service project:

using System;
//+
namespace Contact.Service
{
    public static class Configuration
    {
    //- @ActivePersonServiceEndpoint -//
    public static String ActivePersonServiceEndpoint
    {
        get
        {
        return System.Configuration.ConfigurationManager.AppSettings["PersonServiceActiveEndpoint"] ?? String.Empty;
        }
    }
    }
}

As you can see, this class just gives me strongly-typed access to my endpoint name.  Thus allowing me to access my WCF endpoint via a loosely connected configuration:

//+ configuration and contract
IPersonService personService = new ChannelFactory<IPersonService>(ServiceConfiguration.ActivePersonServiceEndpoint).CreateChannel();
//+ just use it!
Person person = personService.GetPersonData("F488D20B-FC27-4631-9FB9-83AF616AB5A6");
String firstName = person.FirstName;

When I feel like using a different endpoint, I don't modify the client endpoint, but just add another one with a new name and update the appSettings pointer (if you're info fancy names, this is essentially the bridge pattern).

Now, while this is a great way to directly access data by people who understand WCF architecture, it's probably not a good idea to allow your developers to have direct access to system internals.  Entry-level developers need to focus on the core competency of your company (i.e. sales, marketing, data management, etc), not ponder the awesomeness of system internals.  Thus, to allow other developers to work on a solution without having to remember WCF internals, I normally create two layers of abstraction on top of what I've already shown.

For the first layer, I create a concrete ClientBase class to hide the WCF channel mechanics.  This is the type of class that "Add Service Reference" would have created if your newbie developers accidentally used it.  However, the one we will create won't have meaningless attributes and virtually manageable excess code.

Below is our entire client class:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
//+
namespace Contact.Service
{
    public class PersonClient : System.ServiceModel.ClientBase<IPersonService>, IPersonService
    {
    //- @Ctor-//
    public PersonClient(String endpointConfigurationName)
        : base(endpointConfigurationName) { }

    //+
    //- @GetPersonData -//
    public Person GetPersonData(String personGuid)
    {
        return Channel.GetPersonData(personGuid);
    }
    }
}

The pattern here is incredibly simple: create a class which inherits from System.ServiceModel.ClientBase<IServiceContractName> and implements your service contract.  When you implement the class, the only implementation you need to add is a call to the base channel.  In essence, all this class does is accept calls and pass them off to a pre-created channel.  When you add a new operation to your service contract, just implement the interface and add a single line of connecting code to wire up the client class.

The channel creation mechanics that I demonstrated earlier is now done provided automatically by the ClientBase class.  You can also modify this class a little by bridging up to a total of 10 different constructors provided by ClientBase.  For example, the following constructor call will allow developers to specify a specific binding and endpoint:

public PersonClient(Binding binding, EndpointAddress address)
    : base(binding, address) { }

At this point, we have something that protects developers from having to remember how to create a channel.  However, they still have to mess with configuration names and must remember to dispose this client object (there's an open channel, remember).  Therefore, I normally add another layer of abstraction.  This one will be directly accessibly for developer user.

This layer consists of a series of service agents.  Each service has its own agent and is essentially a series of static methods which provide the most efficient means of making a service call.  Here's what I mean:

using System;
//+
namespace Contact.Service
{
    public static class PersonAgent
    {
    //- @GetPersonData -//
    public static Person GetPersonData(String personGuid)
    {
        using (PersonClient client = new PersonClient(ServiceConfiguration.ActivePersonServiceEndpoint))
        {
        return client.GetPersonData(personGuid);
        }
    }
    }
}

As you can see, the pre-configured service endpoint is automatically used and the PersonClient is automatically disposed at the end of the call (ClientBase<T> implements IDisposable).  If you want to use a different service endpoint, then just change it in your appSettings configuration.

Conclusion

At this point, I've explained every class or each project in my WCF service project model.  It's up to you to decide how to best create and manage your data and service contracts as well as clients.  But, if you want a streamlined, efficient, model for all your service projects, you will want to create a publicly accessible project to house all your reusable elements.

Also, remember you don't need a full-on client class to access a service.  WCF communicates with channels and channel creation simply requires an address, binding, and contract.  If you have that information, just create your channel and make your call.  You can abstract the internals of this by using a ClientBase object, but this is entirely optional.  If the project you are working on requires hardcore WCF knowledge, there's no reason to pretty it up.  However, if non-WCF experts will be working with your system, abstractions are easy to create.

Links

Love Sudoku?  Love competition?  Try the new Sudokian.com experience today.

kick it on DotNetKicks.com

Powered by
Python / Django / Elasticsearch / Azure / Nginx / CentOS 7

Mini-icons are part of the Silk Icons set of icons at famfamfam.com