Ryan Dawson on Longhorn

The software we think, but do not write

WinFS does Customer Relations Management



Source Code can be found here


What are the intentions of WinFS?


There are numerous intentions for an embedded database system.  But, don’t be duped.  Some things don’t quite need it, yet.  So be realistic when it comes to using the power.  Primarily, it is the vehicle which users will drive for search.  I don’t think it makes a whole lot of sense to make the Windows directory take the plunge.  Secondly, assemblies really don’t need to be in there.  When was the last time you performed a search for an assembly (without job requirements)?  So, keep those files in Program Files.  On the other hand, program and user data make a whole lot of sense.  I have come to the conclusion that a program which hoards my content is an enemy.  Seriously, any program that remotely thinks that the content I create while using the program, belongs to it, has a fundamental flaw.  For example, I am a procrastinator when it comes to updating software, but the other day Office 2003 beta expired, so I had to.  But, for some reason, I did not have the option to Export my data from Outlook.  Through the whole install process I pondered how mad I would be if my data were lost.  All of my contacts, calendar items, and emails, down the drain.  This is the reason for WinFS.  The question is this: should I have even had to worry about this happening?  No. No. No.  My data is my data; it should not be tied to any program in any sort of fashion. 


So, the other reality of the puzzle is the notion of a system that only cares about file streams is nonsense.  People deal in objects.  Hell, even modern programming deals in objects (semantics mixed, but oh well).  Discrete items and objects are what make the world.  To try to define everything in nature as a particle is unjust, as is describing everything as a file stream within Windows.  Technologically, this is also the storage scheme for quick and rich searching, so there should be no more discussion.


Is it there, yet?


Let me be blunt, no.  I hope to only do a service to the WinFS team by telling them that their work is rough at best.  Here are the main points that I have picked:


·         Surfing the System.Storage namespace is like sailing the Pacific without a compass.  Everything is very convoluted, and redundant.  Why put things in System.Storage.Core and then place closely related items to the one we are using in System.Storage.Location.  I would consider the Framework Class Libraries a navigable sea, not the case for WinFS.

·         Considering that WinFS is a pillar of longhorn (of only 3), the documentation is horrible.  I could understand, but I have Indigo and Avalon to use as a comparison.  I can barely find my way around using every resource on the internet, SDK, and the PDC.  And, you expect this feature to be heavily used in Longhorn?  The key to WinFS is to get every developer to use it with his/her application.  The more the merrier, as the search engine would say, anyway.

·         I probably shouldn’t go on with the list, because a proper documentation would cure most other ailments.  Why is the WinFS team so far behind?  It is in bad shape for release with Longhorn.  I can understand there are a lot of performance difficulties facing the team, but it is time to get it together.





*I am going to steer clear of everything unrelated to WinFS, since other posts and articles on LonghornBlogs.com and MSDN will probably have more information and do a better job of explaining.


The Goal:


The goal of the application is to build a realistic situation for using WinFS data types.  I must admit, I was a little disappointed when I first heard that the PDC bits would not contain Extensions.  An extension is the plumbing that enables me to actually create my own schema types.  In this case, if I wanted, I could create a CRM type.  It is probably unrealistic to have a huge data structure for CRM, not to mention the job of explaining it, but you can imagine certain chunks inside CRM being quite large.  For example, I would probably create a new type that extends Contact and then add in all the subtleties of customer relationships.  The other nicety of Extensions is that you can actually register it with Windows, all of a sudden, small things seem so professional.


            Caveat Emptor:


There are certain quirks in my code (StorageManager.cs) that should not be replicated without experimentation.  For example, it is highly recommended that the ContextItem be Closed before exiting the scope of it’s use.  In my situation, I was getting oddities where I would get all of a Contact on one query, and none of it on others.  Basically, WinFS access is similar to ADO.NET, so if you are familiar with the basic flow, you will not have a problem writing the code.  The flaws may be fixed by beta, so it is no time to cause fits.


First piece of Code:

The first piece of code should be easy, since it is basically the one line of code you see in every demo:


ItemContext context = ItemContext.Open();


            Adding on to my rant above, the code should be as follows:


            using(ItemContext context = ItemContext.Open())


            // ...



The ItemContext is similar to drawing context in semantics.  It is the begin and end-all of WinFS.  When calling the Open function, you can actually pass a location, if you want to open a different volume than the default.  This may be beneficial in professional cases, since client Contacts don’t fit in the PersonalContactsFolder very well.  Anyway, just remember that you need an ItemContext instance somewhere down the line to query WinFS.  In essence, it is sort of like a placeholder.


Creating a Folder:


In our case, we are actually going to create a folder within the UserDataFolder instead of working on a different volume, as explained above:


            Folder udf = UserDataFolder.FindMyUserDataFolder(context);

Folder sampleDataFolder = udf.GetOneMemberWithName(folderName) as Folder;

if (sampleDataFolder == null)


            sampleDataFolder = new Folder(udf, folderName);

            sampleDataFolder.DisplayName = folderName;



First of all, we grab a reference to the UserDataFolder, which is a logical place to store the data for an example.  As mentioned, we have to pass the ItemContext as an argument in order to get the Folder.  Then, we are using the GetOneMemberWithName method to get a reference to the folder we are interested in.   The key thing to know when working with folders: anything can be a member.  So, in this case, we cast it to a Folder.  On the other hand, there are a variety of similar methods that allow for finding a member, but we knew the name, so we chose this one.  To my knowledge, every data type within the WinFS schema extends Item, which is analogous to Object within the CLR world. 


So, as you will see, we new up a Folder, passing the parent Folder, and the name that WinFS will use to identify the Folder (Also called a link name).  It is important not to assign the same link name to different objects within table (or, Folder in this case).  The reason should be apparent, just as you cannot give an item in a WinXP Folder the name as another.  You may recall that we did not use our ItemContext in creating the folder, but in actuality, we did, it is just implicit as we passed it to the folder that we passed to the constructor.


Now, we make the DisplayName the same as the link name.  The DisplayName is self explanatory; it is the name that should be shown to the user to identify the resource, unlike the link name.  As you will recall, I mentioned that everything extends Item, so each object obviously must inherit a contract.  One member of Item is DisplayName.



            There is one crucial piece that has yet to be mentioned:




This piece instructs the context to update the store with the changes we have made.  So, if we do not update, the folder we just created will not show up.  It is important to update after any significant or necessary change.


The Vast ocean of Schema types:


I will give you this sample as a taste tester to how many schema types you have access to as a WinFS developer.  I am sure, by shipping time, they will have created every imaginable type in existence.


Person client = new Person(sampleDataFolder, "Bob Stagger");


client.DisplayName = "Bob Stagger";


client.PrimaryName.GivenName = "Bob";

client.PrimaryName.Surname = "Stagger";


InstantMessagingAddress im = new InstantMessagingAddress();

im.Address = "bob1993";

im.ProviderUri = "MSN";



Address a = new Address();

a.AddressLine = "1347 Highway 99";

a.PrimaryCity = "Vancouver";

a.PostalCode = "32458";

a.CountryRegion = "Canada";



SmtpEmailAddress sea = new SmtpEmailAddress("bobs@earthlink.net");



TelephoneNumber tn = new TelephoneNumber();

tn.AreaCode = "786";

tn.Number = "3346783";



I will not go into any details because there are some quarks that I do not understand, and it is pretty self-explanatory.  One question to the reader, though: Where is the State field in Address?  There is a SecondaryCity, but no State to be found.  Anyway, you have just created a Person type and populated it with common information.





The relationship is one concept that I thought was hard to swallow, at first.  Now, there is one important detail you have to remember and it will pretty much fall into place: Items can physically be created anywhere in the WinFS store, but it is the Relationship that ties them together.  This is also the characteristic that enables 2 folders to reference the same item, as if they both had a local instance.  So, in reality, it really doesn’t matter where the object is physically stored.  If you will remember, the Folder has a Property named Members.  Gee, what ever could it mean besides a collection of the relationships or links.  As a side note, don’t be fooled by my words, a link and a relationship may be different, but in terms of explanation, they make sense as similar entities (Do some reading in the SDK for more clarification, if it exists.  I think a link is more generic than a relationship.  So in that case, a relationship is a link, but not the other way around.).  Let’s look at an example from the program:


sampleDataFolder.MemberRelationships.Add(new FolderMembersRelationship(client, (string)client.DisplayName, false));


For this particular case, we are adding a relationship from the Person to the Folder.  So, as is imagined, it is of type FolderMembersRealtionship.


Other Schema types:




System.Storage.Core.Document doc = new Document(sampleDataFolder, "Dogs");


      doc.Title = "Hunting Dogs";

      doc.DisplayName = "Hunting Dogs";




      Author author = new Author();

      author.TargetItem = client;

      author.DisplayName = client.DisplayName;

      author.Name = client.DisplayName;


      doc.Body = System.Text.Encoding.UTF8.GetBytes(…);


            There are 2 interesting lines I would like to point out:

1.      author.TargetItem = client;

We are actually looping back the Author of the document to the Person that was created above.  This is a relationship (or a link?).


2.      doc.Body = System.Text.Encoding.UTF8.GetBytes(data.Note);

There is another type of document actually called OfficeDocument, which is more suited towards Office, but in this case, we are able to throw the actual byte array right into the Item.  The Document type also supports linking to an existing Document, instead of specifying the Body.






System.Storage.Core.Event e = new System.Storage.Core.Event(sampleDataFolder, "Get Coffee with Bob");


      e.Description = "Meet Bob at Starbucks for coffee.";

      e.DisplayName = "Get Coffee with Bob";

      e.EventTime = DateTime.Parse("2/12/2004");







Since the goal of WinFS is primarily for searching, you should expect that there are numerous ways to get at the same thing.  You can perform searches that are limited to folders, or you can search the whole volume, but those choices rely on scenario details.


FindResult result = sampleDataFolder.GetAllMembersOfType(typeof(Person));


ArrayList list = new ArrayList();

foreach(Person client in result)





Every search function, no matter the form, is probably going to return an object called FindResult.  A FindResult is an Item collection, as you may have guessed.  In the case above, we called the method GetAllMembersOfType on our Folder.  In this particular situation, we are searching based on the schema type, which is Person.  A simple foreach statement will allow you to iterate through the result collection and look at the items.  Be careful when you try to replicate the code above.  If you do not search based on only one type, the FindResult collection could contain different schema types, like Person and Event mixed together.


And, another example:


FindResult result = sampleDataFolder.GetAllMembersOfType("DisplayName LIKE '%" + query + "%'");


In this case, we are searching based on an OPath expression (which stands for Object Path).  OPath queries are extremely similar to T-SQL, so you can actually imagine a long and drawn out expression for a complicated FindResult.  Remember that DisplayName is a property of every Item, so we are basically searching through every Item in the folder.  I will not go into the details of OPath, since everyone is probably familiar with T-SQL, but the % symbol is a wildcard (This means that in place of the symbol, we can have a zero or more length string of any value).



Parts of the Application:


Now, this could be a very interesting example, yet Extensions are not supported in the PDC bits.  In place, I have redundantly repeated the same steps for different schema types.


·         Query all clients (of Person type) within the Folder

·         Query all Events within the Folder

·         Query all notes (of Document type) within the Folder

·         Full search on DisplayName within the Folder



That is the bulk of it.  Hopefully, everyone has learned a thing or two.