in

Foo Theory

Partners in Community - serving up some ice cold Kool-Aid!
Welcome to footheory.com.  The bloggers and contributing members on this site are consultants, project/program managers and software architects working across the US.  Our community will focus on Microsoft technologies, .NET architecture, software patterns & practices and just plain stream of consciousness.

Bennie's Weblog

July 2007 - Posts

  • New Features in C# 3.0. Part 2

    Introduction

    In the previous section of this post, we looked at implicitly typed local variables, and how they enable us to write rich LINQ queries. In this section, we take a look at  another extension to the C# 3.0 type system, namely anonymous types. If you have not read the section on implicitly typed local variables yet, I recommend that you read that section first, since we will be referring to a number of the concepts mentioned in that post.

    The code for this sample can be downloaded from our downloads section.

    Anonymous Types

    Problem Definition

    In the previous versions of C#, if you wanted to represent a Pet, you typically would have to author a class  that looks something like this:

    1 public class Pet 2 { 3 private string m_furColor; 4 private string m_ownerName; 5 private string m_name; 6 private long m_tagNumber; 7 private int m_weight; 8 private int m_height; 9 10 // public read/write properties here.. 11 12 // constructors here... 13 14 } // class Pet

    While the IDE now offers a lot of refactoring and other editing tools, and C# 3.0 offers now offers a great time-saving feature called "automatic properties", writing a class like the one shown above is still very time consuming and tedious (some would call it 'monkey work' ;-).

    When we are writing LINQ queries, we will be writing code, the structure of which looks like this:

    var query = from p in ListOfPets select new { p.FurColor, p.TagNumber, p.OwnerName };

    The key here is that we are querying arbitrary groups a data (in this case "FurColor, TagNumber and OwnerName). When I am querying "Pets", and the selected fields are a subset of the Pet class, then it would be quite a bit of work if we first had to completely define the structure of this "class", or "clumb of data", before I could use this class. Especially, because we would not have a need for this class outside of the scope of the query. What we really need is the ability to define arbitrary structures of data on the fly at runtime.

    The Solution: Anonymous Types

    The solution to the problem described above is offered by anonymous types. Anonymous types allow you to represent arbitrary groups of related data, without having the requirement to declare a class with it's detailed structure first. Below is an example.

    var donBox = new { FirstName="Don", LastName="Box", Height="190", Weight="150" };

    The above line of code will work even if you would not have defined a Pet class in advance. Anonymous methods let you arbitrarily create new structures to represent your data, without having to define them at "coding time" first.

    The above line of code simply generates a class behind the scene (You never really see it, although I create a utility that lets you do some "spelunking" around in an anonymous class, see later). This generated anonymous class would look something like this:

    [CompilerGenerated, DebuggerDisplay(@"\{ Weight = {Weight}, Height = {Height}, FirstName = {FirstName}, LastName = {LastName} }", Type="<Anonymous Type>")] internal sealed class <>f__AnonymousType0<<Weight>j__TPar, <Height>j__TPar, <FirstName>j__TPar, <LastName>j__TPar> { // Fields [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly <FirstName>j__TPar <FirstName>i__Field; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly <Height>j__TPar <Height>i__Field; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly <LastName>j__TPar <LastName>i__Field; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly <Weight>j__TPar <Weight>i__Field; // Methods [DebuggerHidden] public <>f__AnonymousType0(<Weight>j__TPar Weight, <Height>j__TPar Height, <FirstName>j__TPar FirstName, <LastName>j__TPar LastName); [DebuggerHidden] public override bool Equals(object value); [DebuggerHidden] public override int GetHashCode(); [DebuggerHidden] public override string ToString(); // Properties public <FirstName>j__TPar FirstName { get; } public <Height>j__TPar Height { get; } public <LastName>j__TPar LastName { get; } public <Weight>j__TPar Weight { get; } } Expand Methods

    Notice that I was lazy and used reflector to generate this source code

    As you can see, the compiler does generate a (albeit complex) name for anonymous class, and it has all of the fields and properties that we expect. Note that each of the fields in the anonymous type is really of a "var", so it is really an implicitly typed local variable. But the important fact is that this class is a real valid .NET type, with the same features and the hand-crafted class shown earlier.

    Note that anonymous types combined with LINQ now allows us to query for an arbitrary set of data, without the need to first declare the structure of the queried data (which really would have been a non-starter for LINQ).

    Applied Anonymous Types

    Below is a simple C# 3.0 function that illustrates some of the anonymous type functionality:

    1 /// <summary> 2 /// This method demonstrates some anonymous types features 3 /// </summary> 4 private static void createSampleAnonymousTypes() 5 { 6 7 var v1 = new { Weight = 180.5, Height = 170, FirstName = "Neil", LastName = "Armstrong" }; 8 var v2 = new { Weight = 145.2, Height = 190, FirstName = "Demi", LastName = "Moore" }; 9 10 Console.WriteLine("Contents of v1: '{0} {1}'", v1.FirstName, v1.LastName); 11 Console.WriteLine("\tWeight: {0}, Height: {1}, FirstName: {2}, LastName: {3}", 12 v1.Weight, v1.Height, v1.FirstName, v1.LastName); 13 14 Console.WriteLine("Contents of v2: '{0} {1}'", v2.FirstName, v2.LastName); 15 Console.WriteLine("\tWeight: {0}, Height: {1}, FirstName: {2}, LastName: {3}", 16 v2.Weight, v2.Height, v2.FirstName, v2.LastName); 17 18 Console.WriteLine(Environment.NewLine); 19 Console.WriteLine("Type of v1:\n {0}", v1.GetType()); 20 Console.WriteLine("Type of v2:\n {0}", v2.GetType()); 21 if (v1.GetType() == v2.GetType()) 22 { 23 Console.WriteLine("The types of v1 and v2 are identical!"); 24 } 25 } // method createSampleAnonymousTypes 26

    In lines 7 and 8, we create two anonymous type instances (v1 and v2).  Note that  since the fields in both instances are identical in both name and type, the compiler will be smart enough to generate only one anonymous type (we will verify this later on in this method).

    Note that you have to use an implicitly typed local variables (i.e. a "var") as the type of both instances. The compiler will be smart enough to match up the type of v1 and v2 to the name it generated for the anonymous type.

    In lines 10 through 16 we are accessing the fields in our anonymous class instances, note that we can use the standard <variable Name>.<Field Name> syntax, since an anonymous type in still a standard .NET types, with all of its features.

    In lines 18 through 20, we are writing out the type names of both v1 and v2, and in the final lines of the functions, we indeed verify that the both types are indeed identical.

    The output of this function is shown below:

    consoleAnonymousTypes

    When you take a closer look at how the type name of the anonymous type is built, we notice it uses:

    • The "<>f__AnonymousType" prefix
    • The CLR types names of the fields:
      • System.Double for the "Weight" field
      • System.Int32 for the "Height" field
      • System.String for both first and last name

    and again, as we mentioned before, the compiler noticed that both anonymous types contain the same fields, so it only generated one type.

    Anonymous Types in Depth

     Now, to REALLY verify that the compiler indeed generates a new class, a seasoned developer will reach into his/her toolbox and use ILDASM, and open up the compiled assembly. If you expand the tree view, this is what you will see:

    ILDASMAnonmounsTypes

    When you look closely at the full name, you will recognize the "<f>__AnonymousType" prefix. You will also notice that the fields (FirstName, LastName, Height and Weight) have been generated, together with their property getters and setters.

    Note also that since the anonymous type inherits from object (after all, it IS a valid .NET class, and any .NET class inherits from Object), you see the overrides for the Equals(), GetHashCode() and ToString() methods.

    Finally, the anonymous type contains a constructor, which takes the values of the fields as arguments, and sets the field values based upon the passed-in parameters.

    The dumpAnonumousType() method

    Now, it is not always simple to look at the details at ILDASM, and for that purpose I created a simple routine which takes an anonymous type instance, and writes out a human-readable presentation on the console.

    Note that when I say that it "takes an anonymous type instance" this should create some questions for you. Before, I mentioned that an anonymous type instance is always an implicitly typed local variable, so how can I pass it to a function. The trick here is to not forget that an anonymous type still derives from System.Object, so you can still pass it as an object, as is shown below:

    1 var v1 = new { Weight = 180.5, Height = 170, FirstName = "Neil", LastName = "Armstrong" }; 2 dumpAnonymousType(v1); 3 4 } 5 6 /// <summary> 7 /// This method has the ability to dump the most important 8 /// characteristics of an anonymous type 9 /// </summary> 10 /// <param name="myTypeValue"></param> 11 private static void dumpAnonymousType(object myTypeValue) 12 { 13 ..... 14 } // method dumpAnonymousType

    so, we see that our dumpAnonymousType() method takes a object reference instead of a "var", which would generated a compile error.

    The implementation of the dumpAnonymousType method is very straightforward. It uses standard reflection to parse apart the fields, properties and methods, as shown below:

    1 private static void dumpAnonymousType(object myTypeValue) 2 { 3 // These are the standard binding flags that we are going to use 4 BindingFlags flags = 5 BindingFlags.Public | 6 BindingFlags.NonPublic | 7 BindingFlags.Instance; 8 9 Type myType = myTypeValue.GetType(); 10 Console.WriteLine("Type: {0}", myType); 11 12 // Write out the fields 13 Console.WriteLine("\tType Fields: "); 14 foreach (MemberInfo member in myType.GetFields(flags)) 15 { 16 FieldInfo fi = member as FieldInfo; 17 var myValue = fi.GetValue(myTypeValue); 18 Console.WriteLine("\t\tMember: {0}, Member Type: {1}, Data Type: {2}, Value: {3}", 19 member.Name, 20 member.MemberType.ToString(), 21 myValue.GetType().Name, 22 myValue.ToString()); 23 } 24 25 // Write out the properties 26 Console.WriteLine("\tType Properties: "); 27 foreach (MemberInfo member in myType.GetProperties(flags)) 28 { 29 PropertyInfo pi = member as PropertyInfo; 30 var myValue = pi.GetValue(myTypeValue, null); 31 32 Console.WriteLine("\t\tMember: {0}, Member Type: {1}, Data Type: {2}, Value: {3}", 33 member.Name, 34 member.MemberType.ToString(), 35 myValue.GetType().Name, 36 myValue.ToString()); 37 } 38 39 // Write out the methods 40 Console.WriteLine("\tType Methods: "); 41 foreach (MemberInfo member in myType.GetMethods(flags)) 42 { 43 Console.WriteLine("\t\tMember: {0}, Member Type: {1}, Data Type: {2}", 44 member.Name, 45 member.MemberType.ToString(), 46 member.GetType().UnderlyingSystemType.Name); 47 } 48 } // method dumpAnonumousType

    The interesting part of this method is that when your get a field or a property, and you want to get the value of the field or property, you have to use an implicitly typed local field (i.e. a "var"), since internally, they really are stored as such (as you can see in the reflector and ILDASM output). Since I use the indirection of first converting the field or type to a var, and then getting its Type info, I can show the "real type" in my output.

     

    A sample output is shown below:

    dumpOutput

    Conclusion

    Anonymous Types are a very important feature in the toolset of C# 3.0, and is on the features that enables us to write LINQ queries (together with Lambda BLOCKED EXPRESSION. They have the ability to greatly reduce to amount of code we have to write if  we want to perform a "one-time" processing of a logical "clump" of data.

  • New Features in C# 3.0 - Part 1

    Overview

    Beta2 of Orcas has shipped yesterday. You can download it either as a standalone-download, or as a VPC.  Of course THE biggest feature in Orcas that everybody keeps talking about is LINQ. LINQ is a methodology that simplifies and unifies the implementation of any kind of data access. LINQ does not force you to use a specific architecture; it facilitates the implementation of several existing architectures for accessing data.

    In .NET 3.5 LINQ is made possible because of a number of new technologies:

    • A net set of assemblies that are based upon .NET 2.0
    • A number of powerful new features in the C# 3.0 language.

    In the series of blog entries, I would like to take a look at these enabling C# 3.0 features.W e will look at each feature in turn, and in our downloads section, we will provide a small sample for each covered feature.

    Once you get a feel for these new features, not only will you have as easier way integrating LINQ into your application, but you will also be able to use these powerful features in your own programming situations, independent of LINQ. And of course, look to this blog for extensive coverage of LINQ and the other new features in Orcas (such as the improved WF and WCF integration) soon!

    A 30,000 feet view of Orcas

    Before we begin our coverage, it is important to note that when you build a C# 3.0 program, this program will still be executing on the good old .NET 2.0 CLR. Indeed, no changes were required to the CLR to facilitate LINQ, or any of the features outlined in this series of posts. I think this is a real compliments to the resilience of the .NET CLR! On the other hand, it get's kind of hard to explain what is part of the redistributable's of Orcas, and the different compilers and .Net assemblies involved. After all you will have:

    1. The "good old" .NET 2.0 assemblies that we all know and love.
    2. The .NET 3.0 assemblies, which cover the new "foursome" that we love to play with so much (WCF, WF, WPF and WCS).
    3. The new .NET 3.5 assemblies, which implement the brand new features, such as LINQ.

    When you use the New Project wizard in Orcas, it actually provides a drop drop in the upper left corner, which lets you select the version of the .NET framework that you are targeting, as is shown below:

    NewProjectOrcas

    Of course, some features such as LINQ will be unavailable if you target the 2.0 compiler, but it is nice that you can use the nice new Orcas environment to target the "good old" .NET 2.0 or 3.0 frameworks.

    Extensions to the C# Type system

    Implicitly typed local variables ("var")

    Old Style Declarations

    In previous versions of C#, you always had to specify the data type of a variable when declaring the variable. For example, this was valid syntax for a method-scoped variable:

    int beersConsumedByMatt;

    You could also directly initialize the variable as so:

    int beersConsumedByMatt = 5;

    In general, the syntax for a declaration is:

    <datatype> <variablename> [= <initializer>];

    In the above discussion, the important point is that at any point in time we know the exact data type of beersConsumedByMatt, which is this case is a Long. (or System.Int32 for the CLR).

    Implicitly typed Local Variables

    Now, in C# 3.0 I can write a statement like this (at method scope):

    var beersConsumedByJeremy = 15;

    Notice the "var" keyword. "var" is a C# keyword that results in our variable to be of the same data type as the initializer, in this case an int, so in this case the above statement results in the creating of a local variable called beersConsumedByJeremy, which has a data type of "integer" (or System.Int32). We call beersConsumedByJeremy an implicitly typed local variable.

    Now, for some old COM rats, this might bring back very bad memories to the "Variant" data type! Please do not break out in hives, do not start having nightmares! The Variant type was a memory hog, which occupied a lot of memory, and was not strong typed.

    In contrast, a variable declared with the "var" keyword will immediately  be strongly typed. The compiler will look at the initializer (which is NOT optional, and cannot be null), and match it to the closed possible data type for you. So, in our case, the compiler will assign the type of int to our beersConsumedByJeremy variable.

    You can also create an implicitly typed local array. In this case, the compiler will look at the elements contained in the initializer, and set the base type of the array accordingly.

     Below is a complete sample of implicitly typed local variables from the corresponding download:

    1 private static void implicitlyTypedVariablesDemo() 2 { 3 Console.WriteLine("----- Start of Implicitly Typed Variables -----"); 4 5 // C# 2.0 notation 6 long beersConsumedByMatt = 5; 7 Console.WriteLine("Type of beersConsumedByMatt: " + beersConsumedByMatt.GetType()); 8 9 // C# 3.0 implicitly-typed variable 10 var beersConsumedByJeremy = 15; 11 Console.WriteLine("Type of beersConsumedByJeremy: " + beersConsumedByJeremy.GetType()); 12 13 // C# 3.0 Implicitly-typed array 14 var myArray = new[] {1.2, 6.3, 7.1, 9.4, 4.2 }; 15 Console.WriteLine("Type of myArray: " + myArray.GetType()); 16 for (int i = 0; i < myArray.Length; i++) 17 { 18 Console.WriteLine("\tArray Element: {0}, value: {1}, Type: {2}", 19 i, myArrayIdea, myArrayIdea.GetType()); 20 } 21 22 Console.WriteLine("----- End of Implicitly Typed Variables -----"); 23 } 24

    The output of the function is shown below:

    ConsoleOutput1

    Reasoning for having Implicitly Typed Local Variables

    Now, why go through all of this fuss? What advantage do implicitly typed local variables give us, and especially, what are there benefits in connection to LINQ?

    Let's take a look at the function below:

    1 private static void whyImplicitlyTypedVariables() 2 { 3 string[] words = { "apple", "strwawberry", "grape", "peach", "banana" }; 4 IEnumerable<String> wordQuery = 5 from word in words 6 where word[0] == 'g' 7 select word; 8 foreach (string word in wordQuery) 9 { 10 Console.WriteLine("\tWord:{0}", word); 11 } 12 13 // Example #2: var is required. 14 Customer[] customers = 15 { new Customer { CustomerId = 12, Name = "Bennie Haelen"}, 16 new Customer { CustomerId = 20, Name = "Matt Ortiz" }, 17 new Customer { CustomerId = 120, Name = "Pete Miller" } 18 }; 19 20 var customerQuery = from cust in customers 21 where cust.CustomerId < 100 22 select new { cust.CustomerId, cust.Name }; 23 foreach (var item in customerQuery) 24 { 25 Console.WriteLine("CustomerID={0}, Name={1}", item.CustomerId, item.Name); 26 } 27 } 28

    In the first example (lines 2 through 10), we have no need to use a implicitly typed local variable, since our query returns a "word", which we know is of type string. Therefore, we can use IEnumerable<String> as the query result of our first query.

    In the second example (lines 14 through 26), we MUST use a var as the result of the query, since the query returns an array of anonymous types ( select new { cust.CustomerId, cust.Name } ). We will talk more about anonymous types later in this series. Also, note that when we display our results in the foreach enumeration we have to use a var, because the type of each item is not available until the compiler determines it at runtime.

    The output of this sample is shown below:

    ConsoleOutput2

    Note that we do not see the Customer instance with CustomerID = 120, since our query restricts the results to all customers with an ID less than 100.

    You can get a sample with this code from this location. Any comments and feedback is always welcome!

    Technorati Tags: , ,
  • Handling Data Contract Object Hierarchies in WCF

    In this post, we will illustrate some lesser-known features of WCF, which will sooner or later become valuable tools in your WCF toolbox. The topics we are looking at are the following:

    • How to handle sessions in WCF interfaces, services and clients
    • If you are using an object hierarchy for your data objects, and you are only using the base types in your operation contract specification of your interfaces, how do you ensure that your WSDL generated on the client side is aware of these derived types.
    • If you have an interface that returns a generic type (e.g. List<X>), how do you avoid that the generated proxy translates this into an array instead of a list?
    • How do I use svcUtil.exe to customize the generation of my proxy code?

    The code for this article can be downloaded from the downloads section of this site.

    Application Description

    Requirements

    In this case, we want to create an WCF service which maintains the state of a pet kennel (or coral). In this scenario the coral can only contain our cats or dogs. The service should provide the following functionality:

    1. Check in a pet (be it a cat or a dog) in the coral.
    2. Check out (remove) a pet from from the coral.
    3. Get a complete list of all of my pets that are currently in the coral.

    WCF Server Implementation

    The Data Contracts

    A data contract describes how a CLR type will map to an XSD schema definition, which will ultimately become part of  the WSDL of our service. Data Contracts are the preferred way to enable serialization of complex types included in the the operation signatures of a service, be it as a parameter or as a return value.

    All of our Data Contracts are defined in the PetTypes.dll assembly.

    In this case, we have to entities to deal with:

    • Cat
    • Dog

    Since both of these entities have a number of attributes in common, it makes sense to create a base class called Pet, which defines these common attributes. The class hierarchy used is shown below:

    Overview1

    So, some of the base attributes, such as FurColor, Name and BornAt at located at the base class, while the dog and cat-specific attributes are moved down to their specific classes.

    To mark a class as a Data Contract, you use the DataContractAttribute attribute. It is always  a good idea to specify a namespace for the data contract, which reflects the current version of your code, as is shown below:

    // This is our Pet base class [DataContract(Namespace = "http://footheory.com/KnownTypes/2007/07")] public class Pet {

    In this case, we used the "2007/07" postfix, which will help us identify the version of the data contract later.

    To include members in serialization you mark them with the DataMemberAttribute. Unlike with XML Serialization, the Default WCF DataContractSerializer uses an opt-in model, so your client will only see members marked with the DataMemberAttribute. Also, this process has nothing to do with the visibility of the member (public, protected or private).

    Below is the complete code for the Pet base class:

    1 using System; 2 using System.ServiceModel; 3 using System.Runtime.Serialization; 4 5 namespace PetTypes 6 { 7 // This is our Pet base class 8 [DataContract(Namespace = "http://footheory.com/KnownTypes/2007/07")] 9 public class Pet 10 { 11 #region private fields 12 13 private string m_name; 14 15 /// <summary> 16 /// Note that we might not exactly know when our pet was born 17 /// (for example, when it was adopted), hence we use a nullable 18 /// type here 19 /// </summary> 20 private DateTime? m_bornAt; 21 22 private string m_furColor; 23 24 #endregion private fields 25 26 #region public properties 27 28 [DataMember] 29 public string Name 30 { 31 get { return m_name; } 32 set { m_name = value; } 33 } 34 35 [DataMember] 36 public Nullable<DateTime> BornAt 37 { 38 get { return m_bornAt; } 39 set { m_bornAt = value; } 40 } 41 42 [DataMember] 43 public string FurColor 44 { 45 get { return m_furColor; } 46 set { m_furColor = value; } 47 } 48 49 #endregion public properties 50 51 } // class Pet 52 } 53

    When you use the [DataMember] attribute, one of the first decisions that you have to make is wether you are going to use it only a data field, or on the property. While both approaches will work, I recommend applying them to the properties, because of the following reasons:

    • The client code will be easier to read and maintain. For example, you will be able to use ".Name", instead of ".m_name".
    • You get the benefit of extra validation (if implemented in the setters of the attributes).

    Notice also that we have decided to make the m_bornAt field nullable, so no data value has to be provided by the client. Note that we use the C# shorthand

    1 /// <summary> 2 /// Note that we might not exactly know when our pet was born 3 /// (for example, when it was adopted), hence we use a nullable 4 /// type here 5 /// </summary> 6 private DateTime? m_bornAt; 7

    in the field definition, and the more formal:

    1 [DataMember] 2 public Nullable<DateTime> BornAt 3 { 4 get { return m_bornAt; } 5 set { m_bornAt = value; } 6 } 7

    notation at the property level. Note that there is no extra information that we need to provide in the [DataMember] attribute. In he resulting xsd schema generated for our service, BornAt will now be marked as nillable, as is shown below:

    <xs:element minOccurs="0" name="BornAt" nillable="true" type="xs:dateTime" />

    The Dog and Cat classes derive from the Pet classes, and simply add one attribute as is shown below:

    1 // This class represents a Dog. Since a Dog "is a" Pet, we inherit 2 // directly from the Pet class 3 [DataContract(Namespace = "http://footheory.com/KnownTypes/2007/07")] 4 public class Dog : Pet 5 { 6 #region private fields 7 8 private bool m_hasPedigree; 9 10 #endregion private fields 11 12 #region public properties 13 14 // Of course our dog will have a pedigree! 15 // We don't deal with "mutts"! 16 [DataMember] 17 public bool HasPedigree 18 { 19 get { return m_hasPedigree = true; } 20 set { m_hasPedigree = value; } 21 } 22 23 #endregion public properties 24 25 } // class Dog

    1 // Since some people say that a Cat "is a" pet (not sure I agree), we 2 // inherit this class directly from Pet 3 [DataContract(Namespace = "http://footheory.com/KnownTypes/2007/07")] 4 public class Cat : Pet 5 { 6 #region private fields 7 8 private bool m_listensToOwner = false; 9 10 #endregion private fields 11 12 #region public properties 13 14 // Cats never listen to their owner! 15 [DataMember] 16 public bool ListensToOwner 17 { 18 get { return m_listensToOwner; } 19 set { m_listensToOwner = false; } 20 } 21 22 #endregion public properties 23 } // class Cat 24

    Note: There is absolutely no preference of the author towards the canine population, any appearance of this fact is purely coincidental ;-)

    The Service Contract

    We use the [ServiceContract] attribute to mark our interface as a service contract. Each exposed method in our service contract needs to be decorated with [OperationContract] attribute. For our Service Contract, we need to keep a couple of things in mind:

    1. We might want to use the same Namespace attribute value as we used for our data contract, to simplify versioning later.
    2. Since we want to maintain state in between calls, we need to have session support. For this purpose, the ServiceContractAttribute  offers the SessionMode enumeration, which can be set to the following values:
      • SessionMode.Allowed: This specifies that the contract supports session if the incoming binding supports them.
      • SessionMode.NotAllowed: This specifies that the contract never supports bindings that initiate sessions
      • SessionMode.Required: This specifies that the contract requires a sessionful binding. In this case an exception will be thrown in the binding is not configured to support sessions.

    In our case, we want a session, so we can maintain the animals we have in our coral, so we use SessionMode = SessionMode.Required.

    1 /// <summary> 2 /// This is our PetCoral Service. Note that this interface expects to be 3 /// implemented by a service that supports sessions, since we want to 4 /// suppport state 5 /// </summary> 6 [ServiceContract(Namespace = "http://footheory.com/KnownTypes/2007/07", 7 SessionMode = SessionMode.Required)] 8 public interface IPetCoral 9 { 10 /// <summary> 11 /// This method allows the owner to bring in a pet. 12 /// Because this method supports both cats and dogs, 13 /// we just use a "Pet" parameter 14 /// </summary> 15 /// <param name="pet"></param> 16 [OperationContract] 17 void BringPet(Pet pet); 18 19 /// <summary> 20 /// This operation allows us to take a pet home. 21 /// Again, this method does not care if you are 22 /// taking home a Dog or a cat 23 /// </summary> 24 /// <param name="pet"></param> 25 [OperationContract] 26 void TakePetHome(Pet pet); 27 28 /// <summary> 29 /// This method allows me to look at all of my 30 /// pets in the coral 31 /// </summary> 32 /// <returns></returns> 33 [OperationContract] 34 List<Pet> GetAllPets(); 35 36 } // interface IPetCoral

    Note that none of these method needs to use the Dog or a Cat Types, but instead takes the more generic Pet type. This also makes our service interface more extensible, for example in the future we might want to add support for the PetPig class ;-).  Note that the GetAllPets() method returns the List<Pet> type, we will look at this again when we create the client proxy for our service.

    The Service Implementation

    The implementation of our IPetCoral interface is also located in the PetCoral.dll assembly.

    When we create our service implementation class (PetCoralService.cs), we need to make sure that we use the correct instancing mode. Instancing modes in WCF control the way that service objects are allocated to a request. In our case, we need one single service object for each client, or in other words, we want an InstanceContextMode that is set to InstanceContextMode.PerSession. Other possible values of the InstanceContextMode enumeration are:

    • PerCall: In this case, a new service object is created for each call to the service. This is the model that you will very likely use in an enterprise environment, where you need a highly scalable, stateless solution.  In our case, we purposely avoided this mode to illustrate some session specifics, but I recommend that you use this instancing mode unless you have a very good reason not to do so.
    • Single: A single service object is created and used for all calls from all clients. This type of instancing model should only be used in very specific situations, since you are effectively creating a singleton, with all of it's associated concurrency issues. In a commercial environment, you are not likely to have a need for a WCF service with an instancing model set to InstanceContextMode.Single.

    The InstanceContextMode is a parameter of the ServiceBehaviorAttribute, as is shown below:

    1 /// <summary> 2 /// This is our service which implements our IPetCoral service. Since this 3 /// service maintains state for the caller, we use an instance mode of 4 /// "PerSession", so one instance of this object will be created per 5 /// caller 6 /// </summary> 7 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] 8 public class PetCoralService : IPetCoral 9 {

    Otherwise, the implementation of the PetCoralService is very simple. All added pets are maintained in a generic List<Pet> instance  (which is why we need the "Per Session" behavior), as is is shown below:

    1 #region private fields 2 3 /// <summary> 4 /// This list contains all of the Pets that are currently 5 /// in our Coral 6 /// </summary> 7 private List<Pet> m_petsInCoral = new List<Pet>(); 8 9 #endregion

    The implementation of the BringPet() method simply adds the pet to our List<Pet>:

    1 /// <summary> 2 /// This method allows the caller to bring in a Pet 3 /// </summary> 4 /// <param name="pet"></param> 5 public void BringPet(Pet pet) 6 { 7 m_petsInCoral.Add(pet); 8 9 } // method BringPet 10

    The implementation of our TakePetHome() method will throw a FaultException if our List if empty (i.e. all Pets have been taken home). Otherwise, it uses Array.Find with an anonymous delegate to locate the pet, using name, the born date and the fur color of the Pet (we make the simple assumption that these attributes make a Pet unique). If the Pet is found, it is removed from the collection. If the Pet is not found, an FaultException<ArgumentOutOfRangeException> is thrown to indicate that the Pet could not be found.

    Note that this post does not focus on exception handling in WCF, so we are using generic FaultExceptions here, without making them part of the service contract. Look for a future post with a lot more detail on this topic.

    1 /// <summary> 2 /// This method allows the caller to take a pet home 3 /// </summary> 4 /// <param name="pet"></param> 5 public void TakePetHome(Pet petToTakeHome) 6 { 7 // First, we check if we have any pets left. If not, we throw 8 // a Fault Exception 9 if (m_petsInCoral.Count == 0) 10 { 11 throw new FaultException("All Pets have been taken home already"); 12 } 13 14 // Take the Pet Home 15 if (petToTakeHome != null) 16 { 17 Pet petFound = Array.Find<Pet>(m_petsInCoral.ToArray(), delegate(Pet pet) 18 { 19 if (pet.Name == petToTakeHome.Name && 20 pet.BornAt == petToTakeHome.BornAt && 21 pet.FurColor == petToTakeHome.FurColor) 22 { 23 return true; 24 } 25 else 26 { 27 return false; 28 } 29 }); 30 31 if (petFound != null) 32 { 33 m_petsInCoral.Remove(petFound); 34 } 35 else 36 { 37 throw new FaultException<ArgumentOutOfRangeException>( 38 new ArgumentOutOfRangeException("Pet Not Found")); 39 } 40 } 41 42 } // method TakePetHome 43

    The implementation of the GetAllPets() method simply returns the generic List of Pets:

    1 /// <summary> 2 /// This method returns all of my Pets in the Coral 3 /// </summary> 4 /// <returns></returns> 5 public List<Pet> GetAllPets() 6 { 7 return m_petsInCoral; 8 9 } // method GetAllPets 10

    Hosting the Service

    Now that we have a service implementation, we need a host. In this case, we have opted for Self-Hosting in a simple Console application, since it is very easy to debug.  Our Service will expose two endpoints:

    1. The first endpoint uses the netTcpBinding to expose the PetCoral.IPetCoral interface.
    2. The second endpoint uses a mexHttpBinding to expose the service metadata through the IMetadataExchange Interface.

    The full app.config file for the service host is shown below:

    <?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="PetCoral.PetCoralService" behaviorConfiguration="myBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:7000"/> <add baseAddress="net.tcp://localhost:7001"/> </baseAddresses> </host> <endpoint address="PetCoral" contract="PetCoral.IPetCoral" binding="netTcpBinding" /> <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="myBehavior"> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>

    Building the Client

    In this case, we will build a small WinForms client (Yes, I know I'm a big wimp, I am still getting up to speed on WPF, but I promise that the next client will be implemented in WPF).

    First of all, we need to generate our proxy. Basically, you have two ways to generate a proxy for a service:

    1. You can right-click your client project and select "Add Service Reference" (the "girly-man" way).
    2. You can use svcutil.exe to manually generate the proxy (the "real way").

    All kidding aside, I really think that as a WCF developer you should become intimately familiar with svcutil.exe, because of it's inherent power and flexibility.

     In it's simples form, we simply have to specify where the metadata of our service lives, and what the name is of the proxy and client configuration file we want to generate, as shown below:

    svcutil /config:app.config /out:PetCoralServiceClient.cs http://localhost:7000/mex

    You can run this command from any Visual Studio command prompt. Make sure that you run the host first, otherwise svcutil.exe will never be able to locate the metadata.

    After this command completes, it will have create two new files:

    1. An app.config file with all of the client settings. You should be able to add that file to your project without any changes
    2. A called PetCoralServiceClient.cs, which contains our proxy code. 

    However, when we open this file and take a look at it we notice that the code does contain a definition for the Pet data contract, as shown below:

    1 public partial class Pet : object, System.Runtime.Serialization.IExtensibleDataObject 2 { 3 4 private System.Runtime.Serialization.ExtensionDataObject extensionDataField; 5 6 private System.Nullable<System.DateTime> BornAtField; 7 8 private string FurColorField; 9 10 private string NameField; 11 12 public System.Runtime.Serialization.ExtensionDataObject ExtensionData 13 { 14 get 15 { 16 return this.extensionDataField; 17 } 18 set 19 { 20 this.extensionDataField = value; 21 } 22 } 23 24 [System.Runtime.Serialization.DataMemberAttribute()] 25 public System.Nullable<System.DateTime> BornAt 26 { 27 get 28 { 29 return this.BornAtField; 30 } 31 set 32 { 33 this.BornAtField = value; 34 } 35 } 36 37 [System.Runtime.Serialization.DataMemberAttribute()] 38 public string FurColor 39 { 40 get 41 { 42 return this.FurColorField; 43 } 44 set 45 { 46 this.FurColorField = value; 47 } 48 } 49 50 [System.Runtime.Serialization.DataMemberAttribute()] 51 public string Name 52 { 53 get 54 { 55 return this.NameField; 56 } 57 set 58 { 59 this.NameField = value; 60 } 61 } 62 } 63

    but nowhere are there any Cats or Dogs to be found! This is not good, because our client would like to work with both Cats and Dogs. This problem originates from the follow fact: The service description will only include data contracts that are known to the DataContractSerializer. By default, this means only data contracts explicitly included in at least on operation signature marked with the [OperationContract] attribute. When operations use a base type (like we did), other types that inherit those base types and interface are not known during serialization, and therefore, are not generated in the proxy.

    To solve this problem, you need a way to tell the DataContractSerializer  about other polymorphic types that may be included in calls to such operations. This is achieved with known types.

    There are basically three different ways to add these known types to the service contract:

    1. Apply one or more KnowTypeAttribute to a type indicating the polymorphic type with which it is compatible.
    2. Apply the ServiceKnownType attribute to the service contract or to a particular operation indicating any polymorphic types that should be supported.
    3. Configure known types globally for the DataContractSerializer.

    Regardless of how you configure known types, the result is that the service description (and therefore your generated proxy) will included these types. Let's take a quick look at each of these approaches:

    KnownTypeAttribute

    Base types can supply a list of known types by applying one or more KnownTypeAttribute indicating related polymorphic types. In our case, this would mean that the add the following lines of code to the Pet class:

    1 // This is our Pet base class 2 [DataContract(Namespace = "http://footheory.com/KnownTypes/2007/07")] 3 [KnownType(typeof(Dog))] 4 [KnownType(typeof(Cat))] 5 public class Pet 6

    Now, if you rebuild, and re-run the host, and the svcutil.exe command, you will see both the Dog and Cat classes in the proxy:

    1 public partial class Pet : object, System.Runtime.Serialization.IExtensibleDataObject 2 { 3 4 ... 5 } 6 7 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")] 8 [System.Runtime.Serialization.DataContractAttribute()] 9 public partial class Dog : footheory.com.KnownTypes._2007._07.Pet 10 { 11 12 .... 13 } 14 15 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")] 16 [System.Runtime.Serialization.DataContractAttribute()] 17 public partial class Cat : footheory.com.KnownTypes._2007._07.Pet 18 { 19 20 ... 21 } 22
    ServiceKnownTypeAttribute

    Another way to support known types is to apply the ServiceKnownTypeAttribute. This attribute can be applied to the entire service contract to associate known types with all operations, or to individual operation in order to control which types are associated with each. Below is an example where I applied the ServiceKnownAttribute to the contract itself:

    1 [ServiceContract(Namespace = "http://footheory.com/KnownTypes/2007/07", 2 SessionMode = SessionMode.Required)] 3 [ServiceKnownType(typeof(Cat))] 4 [ServiceKnownType(typeof(Dog))] 5 public interface IPetCoral 6 {

    Note that in this case you no longer need the KnownType attributes on the base Pet type. Now, if you run the host and svcutil, you will also get the Cat and Dog types in the generated proxy.

    Declarative known types

    In some cases you may not know all of those known types when you build he service and related data contracts. It is also possible that you add new polymorphic types after you publish the service. To add known type support with recompiling assemblies that contain service contracts or data contracts, you can reconfigure then declaratively in the <system.runtime.serialization> section of your app.config file. Please refer to the the WCF documentation for this more seldom used practice.

    further tweaking svcutil.exe

    When you look at the output of svcutil.exe, you will notice that all of the classes are  placed in a namespace that corresponds to the namespace specified in your data- and service contracts, for example:

    1 namespace footheory.com.KnownTypes._2007._07 2 { 3 using System.Runtime.Serialization; 4 5 6 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")] 7 [System.Runtime.Serialization.DataContractAttribute()] 8 [System.Runtime.Serialization.KnownTypeAttribute(typeof(footheory.com.KnownTypes._2007._07.Cat))] 9 [System.Runtime.Serialization.KnownTypeAttribute(typeof(footheory.com.KnownTypes._2007._07.Dog))] 10 public partial class Pet : object, System.Runtime.Serialization.IExtensibleDataObject 11 { 12

    Sometimes, you just want to use a simpler namespace. You can use the "/n" switch (or the longer "/namespace" version), for example, to ensure that all of our types are in the PetCoral namespace, we use the following command:

    svcutil /config:app.config /out:PetCoralServiceClient.cs /n:*,PetCoral http://localhost:7000/mex

    Now, when you look at the proxy, you see the more friendly "PetCoral" namespace, as shown below:

    1 namespace PetCoral 2 { 3 using System.Runtime.Serialization; 4 5 6 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")] 7 [System.Runtime.Serialization.DataContractAttribute(Namespace="http://footheory.com/KnownTypes/2007/07")] 8 [System.Runtime.Serialization.KnownTypeAttribute(typeof(PetCoral.Cat))] 9 [System.Runtime.Serialization.KnownTypeAttribute(typeof(PetCoral.Dog))] 10 public partial class Pet : object, System.Runtime.Serialization.IExtensibleDataObject 11 {

    Finally, in our service contract we specified that the GetAllPets() method returns a List<Pets> type as shown below:

    /// <summary> /// This method allows me to look at all of my /// pets in the coral /// </summary> /// <returns></returns> [OperationContract] List<Pet> GetAllPets();

    but, we when look in the generated proxy, we see that the generic collection has been translated into an array:

    1 [System.ServiceModel.OperationContractAttribute(Action="http://footheory.com/KnownTypes/2007/07/IPetCoral/GetAllPets", 2 ReplyAction="http://footheory.com/KnownTypes/2007/07/IPetCoral/GetAllPetsResponse")] 3 PetCoral.Pet[] GetAllPets();

    You can use the "/ct" or the longer "/collectiontype" switch to specify the type that should be used. If you do so, make sure that you reference the type in which this type is located, as is shown below:

    1 svcutil /r:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll 2 /ct:System.Collections.Generic.List`1 3 /config:app.config 4 /out:PetCoralServiceClient.cs 5 /n:*,PetCoral 6 http://localhost:7000/mex

    note the slightly strange '1 notation when specifying the collection type.

    Now, after running svcutil, you should have the correct return type:

    1 [System.ServiceModel.OperationContractAttribute'( 2 Action="http://footheory.com/KnownTypes/2007/07/IPetCoral/GetAllPets", 3 ReplyAction="http://footheory.com/KnownTypes/2007/07/IPetCoral/GetAllPetsResponse")] 4 System.Collections.Generic.List<PetCoral.Pet> GetAllPets(); 5

    Summary

    This post addressed a number of issues, all of which are very easy to solve, but might cause you some headaches in the process. If you have any additional tips or corrections, please do not hesitate to contact me.

  • New WCF sample in downloads

    I just downloaded a new sample in the downloads section.

    This sample application demonstrates a number of concepts including:

    • How to handle sessions in WCF interfaces, services and clients
    • If you are using an object hierarchy for your data objects, and you are only using the base types in your interfaces, how do you ensure that your WSDL generated on the client side is aware of these derived types.
    • If you have an interface that returns a generic type (.e.g. List<X>), how do you avoid that the generated proxy translates this into an array instead of a list?
    • How do I use svcUtil.exe to customize the generation of my proxy code?

    I am currently working on a detailed article which will cover each of these aspects in detail. Stay tuned for this post in the next couple of days.

  • WCF Webcasts Series on MSDN by Michelle Leroux Bustamante

    For those of you who would like to come up to speed quickly on WCF, Microsoft just created a great Webcast series featuring Michelle Leroux  Bustamante. Michelle is the chief architect at IDesign, and is also a Microsoft Regional Director for San Diego, and a Microsoft MVP for Connected System and Technical Directory for that "other company" called BEA. Michelle is also a member of the board of directors for the International Association of Software Architects (IASA).

    Michelle has been involved with WCF since the early beta days, and has recently written a great book called "Learning WCF", published by O'Reilly. To me, this book, together with Juval Lowy's book call "Programming .NET 3.0 Services" are the best books that are currently available on WCF.

    I am almost finished reading Michelle's book, I will provide a detailed review of the book, both on this blog and on amazon.com, but I can assure you, this book is one of the best technical books ever published!

    Michelle will be presenting a series of 15 Webcasts on WCF this summer, from July through September. The first four of these events have already been presented, but you can view the replay on the event site. The full schedule of all Webcasts is available on Michelle's Web Site. All presentations are either level 100 or level 200, so it's a great way to ease into WCF.

    Personally, if I was completely new to WCF, I would recommend the following approach:

    1. Watch Michelle's Webcasts.
    2. Read her book ("Learning WCF")
    3. Read Juval's book ("Programming .NET 3.0 Services).

    An of course, in the mean time return frequently to this site, because we will be publishing some interesting WCF information ourselves! ;-)

    Technorati Tags: - -

  • Idea for .NET 3.0 Blackjack Game

    OK guys (and girls), this something I have been thinking about for a while, and I was very interested in your feedback. I would like to create a ".NET 3.0 Blackjack game". The idea is as follows:

    1. There are a number of components to the game:
      • The Dealer
      • One or more Players
    2. From a technology point of view, both the Dealer and the Player could be implemented as WCF services. I want folks to be able to play the game on remote computers, so we should probably use the wsdualHttpBinding in Internet scenarios and the netTcpBinding when we are within the firewall.
    3. The "core logic" or both the Deal and the Player could be controlled by a workflow (probably a State-Machine workflow, because of the event-driven nature of the game). Note that the workflow would not make ALL decisions for you, but it would know when you are busted, when you must take another card etc. When multiple choices are open, it would let make the final decision. Same for the dealer, we could develop a workflow for him also.
    4. The User Interface of the app would be displayed on all screens, and would be controlled by the WCF services, and of course, would be written in WPF.

    So, clearly this is just rambling on my part, but I am very interested in your feedback. We could make this a real cool, showcase application, maybe even have it on CodePlex later. This application would easily lend itself to be "farmed out" to different contributors once the core architecture and interfaces have been defined.

    This game would nicely bring together most .NET 3.0 technologies (WFC, WPF and WF), and who knows, we can add some Windows CardSpace features later?

    We would definitely need a solid designer and WFP person. Believe me, you don't want to touching the UI! People who have worked with me before know that! Maybe this would be a good way to try out expression blend?

    Anyway folks, I am looking forward to your feedback!

    Bennie Haelen (bhaelen@statera.com).

    Technorati Tags: - - - - - -

Copyright ASIQS Corporation © 2006, All rights reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems