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</