<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-18388564</id><updated>2026-05-26T22:31:53.712-08:00</updated><title type='text'>Oran Dennison</title><subtitle type='html'>thoughts on software development, currently in the key of C#</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://orand.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default?alt=atom&amp;redirect=false'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18388564.post-3702557082522540557</id><published>2009-04-17T17:22:00.001-08:00</published><updated>2009-04-17T17:23:10.498-08:00</updated><title type='text'>The Quest for Raw Feeds in the Live Framework</title><content type='html'>&lt;p&gt;Ever since I started playing with Live Framework, I’ve wanted to import Atom feeds from external sources such as blogs, Twitter, and various &lt;a href=&quot;http://code.google.com/apis/gdata/&quot;&gt;Google Data APIs&lt;/a&gt;.&amp;#160; Surprisingly, as we will see later, this is not easy.&lt;/p&gt;  &lt;p&gt;I am most interested in annotating Twitter feeds and synchronizing those annotations between multiple devices, apps, and users.&amp;#160; Why would I want to do this?&amp;#160; Because this can address a number of limitations with Twitter and existing Twitter clients:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Read/unread status isn’t shared between apps and devices&lt;/li&gt;    &lt;li&gt;Groups and saved searches aren’t synchronized&lt;/li&gt;    &lt;li&gt;No third option between public and protected accounts&lt;/li&gt;    &lt;li&gt;Favorites are public (no private or semi-private favorites)&lt;/li&gt;    &lt;li&gt;Availability issues due to fail whales, being offline, etc.&lt;/li&gt;    &lt;li&gt;You must be online to tweet, favorite, and follow&lt;/li&gt;    &lt;li&gt;You don’t own your data, Twitter does&lt;/li&gt;    &lt;li&gt;No good path for migrating from centralized tweets (twitter.com) to a decentralized, federated model&lt;/li&gt;    &lt;li&gt;Twitter’s crossdomain.xml doesn’t support direct access by Silverlight and Flash apps&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That last point on crossdomain.xml is particularly frustrating since you would think that between Silverlight 3 Out-of-Browser and Live Framework it would be straight-forward to build a reasonable competitor to &lt;a href=&quot;http://www.tweetdeck.com/&quot;&gt;TweetDeck&lt;/a&gt;, &lt;a href=&quot;http://www.twhirl.org/&quot;&gt;Twhirl&lt;/a&gt;, or &lt;a href=&quot;http://desktop.seesmic.com/&quot;&gt;Seesmic Desktop&lt;/a&gt; (&lt;a href=&quot;http://www.adobe.com/devnet/air/&quot;&gt;Adobe AIR&lt;/a&gt;’s killer apps), but that is not the case.&lt;/p&gt;  &lt;h3&gt;Atom in the Live Framework&lt;/h3&gt;  &lt;p&gt;Before discussing the issues with importing Atom feeds, it is useful to consider how the Live Framework uses Atom.&amp;#160; As you may know, Atom is the Live Framework’s native infoset.&amp;#160; These Atom feeds can be accessed using other representations such as RSS, JSON, and POX, but the abstract infoset is fundamentally Atom, supplemented by AtomPub for CRUD and FeedSync for sync.&lt;/p&gt;  &lt;p&gt;Live Framework then layers a resource model on top of Atom.&amp;#160; This resource model adds schemas for data such as News, Contacts, MeshDevices, MeshObjects, and more.&amp;#160; These schemas can be discovered by using the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd137144.aspx&quot;&gt;OPTIONS HTTP verb&lt;/a&gt; or by reading the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136539.aspx&quot;&gt;Resource Model documentation&lt;/a&gt;.&amp;#160; As you can see from the documentation, all schemas are based on the abstract Resource schema which includes a number of general-purpose Atom properties as well as Mesh-specific properties such as Triggers.&lt;/p&gt;  &lt;h3&gt;What’s wrong with a little schema?&lt;/h3&gt;  &lt;p&gt;The resource type closest to a raw Atom entry is the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136078.aspx&quot;&gt;DataEntryResource&lt;/a&gt;.&amp;#160; Conveniently, it supports arbitrary element and attribute extensions, so it looks like you ought to be able to shove any arbitrary Atom entry into a DataEntry.&lt;/p&gt;  &lt;p&gt;It turns out that while DataEntry’s schema provides a home for every possible Atom data element, in practice some of the elements are reserved or have special behavior.&amp;#160; Further, this behavior is inconsistent between the local LOE and the cloud LOE, although the inconsistency can be used to hack around some of the limitations, highlighting the power of the back door endpoints used by the Live Framework Client.&lt;/p&gt;  &lt;h3&gt;Reserved elements&lt;/h3&gt;  &lt;p&gt;The Live Framework doesn’t let you store your own arbitrary data in the following elements of an Atom entry:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;id&lt;/li&gt;    &lt;li&gt;published&lt;/li&gt;    &lt;li&gt;updated&lt;/li&gt;    &lt;li&gt;content&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you attempt to provide your own values for these elements, they will be overwritten with auto-generated values by the cloud Live Operating Environment.&lt;/p&gt;  &lt;p&gt;The &amp;lt;id&amp;gt; element will always be set to a random GUID such as: &lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;Consolas&quot;&gt;&amp;lt;id&amp;gt;urn:uuid:05950d5f-4815-3269-c6a6-e4620256033e&amp;lt;/id&amp;gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The &amp;lt;published&amp;gt; and &amp;lt;updated&amp;gt; elements will always be set to the cloud LOE’s DateTime.UtcNow.&amp;#160; Actually, this isn’t true for &amp;lt;published&amp;gt; on the local LOE but we’ll get to that later.&lt;/p&gt;  &lt;p&gt;Forcing &amp;lt;published&amp;gt; and &amp;lt;updated&amp;gt; to DateTime.UtcNow causes problems when bulk importing entries.&amp;#160; All of the entries will share the same time, making sorting impossible.&amp;#160; This is particularly problematic because currently you can’t sort on custom elements, so even if you store the original &amp;lt;published&amp;gt; and &amp;lt;updated&amp;gt; elements under different names, you’re out of luck when it comes to sorting and filtering.&lt;/p&gt;  &lt;p&gt;The &amp;lt;content&amp;gt; element is used as a grab bag for all sorts of LiveFX-specific content:&lt;/p&gt;  &lt;p&gt;&lt;font face=&quot;Consolas&quot;&gt;&amp;lt;content type=&amp;quot;application/xml&amp;quot;&amp;gt;     &lt;br /&gt;&amp;#160; &amp;lt;DataEntryContent xmlns:i=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot; xmlns=&amp;quot;http://user.windows.net&amp;quot; /&amp;gt;      &lt;br /&gt;&amp;lt;/content&amp;gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&amp;lt;content&amp;gt; is also where you will see &lt;a href=&quot;http://orand.blogspot.com/2009/01/exploring-live-framework-triggers.html&quot;&gt;Triggers&lt;/a&gt; if any have been attached to the resource.&lt;/p&gt;  &lt;p&gt;Clobbering the &amp;lt;content&amp;gt; element is a big problem for importing blog feeds because this is where the blog post body content lives.&lt;/p&gt;  &lt;p&gt;On a side note, it appears that the Live Framework only supports &amp;lt;title&amp;gt; and &amp;lt;subtitle&amp;gt; elements where type=“text”, but I could be wrong.&lt;/p&gt;  &lt;h3&gt;Additional elements&lt;/h3&gt;  &lt;p&gt;Live Framework preserves the original &amp;lt;author&amp;gt; element, but adds a second &amp;lt;author&amp;gt; element with the &amp;lt;name&amp;gt;, &amp;lt;uri&amp;gt;, and &amp;lt;email&amp;gt; of the LiveID user account that imported the entry.&amp;#160; The Live Framework author element appears before any external author elements.&amp;#160; It is perfectly valid for Atom entries to have more than one author, but this is something to watch out for if your app assumes only one author per entry or if author information has app-level significance.&lt;/p&gt;  &lt;p&gt;I haven’t tried importing entries with pre-existing &amp;lt;category&amp;gt; or &amp;lt;link&amp;gt; elements, but I assume they would successfully import and be supplemented by additional LiveFX-specific &amp;lt;category&amp;gt; and &amp;lt;link&amp;gt; elements.&lt;/p&gt;  &lt;h3&gt;Local LOE differences&lt;/h3&gt;  &lt;p&gt;After learning how the cloud LOE behaves, I tried importing Atom feeds from Twitter into the local LOE.&amp;#160; Unlike the cloud LOE, the local LOE preserved the original &amp;lt;published&amp;gt; element.&amp;#160; However, the &amp;lt;updated&amp;gt; element was again set to DateTime.UtcNow, just like on the cloud LOE.&amp;#160; At least I can now use LiveFX’s support for sorting, filtering, and paging imported Twitter feeds by the &amp;lt;published&amp;gt; date.&lt;/p&gt;  &lt;p&gt;After successfully preserving the &amp;lt;published&amp;gt; element by using the local LOE, I checked the same feed on the cloud LOE after it synchronized.&amp;#160; Amazingly, the cloud LOE now showed the correct original &amp;lt;published&amp;gt; date!&amp;#160; “Aha,” I thought, “I should be able to make the cloud LOE accept the original &amp;lt;published&amp;gt; date by talking to it using FeedSync instead of AtomPub.”&lt;/p&gt;  &lt;p&gt;Unfortunately, accessing the cloud LOE DataFeed’s Sync feed using FeedSync did &lt;em&gt;not&lt;/em&gt; preserve the original &amp;lt;published&amp;gt; date.&amp;#160; Very interesting!&amp;#160; Then how did the local LOE successfully sync the original &amp;lt;published&amp;gt; dates to the cloud LOE?&lt;/p&gt;  &lt;h3&gt;The parallel universe of Windows Live Core&lt;/h3&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;“This is your last chance. After this, there is no turning back. You take the blue pill - the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill - you stay in Wonderland and I show you how deep the rabbit-hole goes.”&lt;/em&gt; – Morpheus, The Matrix&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Ok, perhaps I’m being overly dramatic. :-)&amp;#160; But seriously, what you know as MeshObjects, ApplicationInstances, and so on are actually CoreObjects living in the grittier, undocumented world of the Windows Live Core (WLC).&amp;#160; The local and cloud LOEs are like the Matrix, hiding the WLC from you and letting you believe that the shiny world of Live Framework is all there is.&lt;/p&gt;  &lt;p&gt;There are three main endpoints in WLC:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;accounts.developer.mesh-ctp.com&lt;/li&gt;    &lt;li&gt;storage.developer.mesh-ctp.com&lt;/li&gt;    &lt;li&gt;enclosure.developer.mesh-ctp.com&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Accounts is responsible for managing the 3 types of identity in the mesh: users, devices, and apps.&amp;#160; Accounts is also responsible for ApplicationClaims (mapping apps to users) and DeviceClaims (mapping devices to users).&amp;#160; Storage is where CoreObjects live.&amp;#160; Enclosure is where CoreObject media resources live.&lt;/p&gt;  &lt;p&gt;The Live Framework Client synchronizes with the cloud using storage.developer.mesh-ctp.com, not user-ctp.windows.net, and instead of hitting the DataFeed’s /Sync URI, it hits the /Sse URI.&amp;#160; SSE is Simple Sharing Extensions, the old name for FeedSync.&lt;/p&gt;  &lt;p&gt;storage.developer.mesh-ctp.com’s FeedSync implementation is more tolerant of arbitrary data than user-ctp.windows.net.&amp;#160; By using this back door, the Live Framework Client is able to preserve our original &amp;lt;published&amp;gt; date.&lt;/p&gt;  &lt;p&gt;If you want to learn more about Windows Live Core, you can use &lt;a href=&quot;http://www.fiddlertool.com/&quot;&gt;Fiddler&lt;/a&gt; to inspect the Live Framework Client’s communication.&amp;#160; You can also use &lt;a href=&quot;http://www.red-gate.com/products/reflector/&quot;&gt;Reflector&lt;/a&gt; to check out the Microsoft.Live.Core.Resources namespace in Microsoft.MeshOperatingEnvironment.Runtime.Client.WlcProxies.dll located in C:\Users\[username]\AppData\Local\Microsoft\Live Framework Client\Bin\Moe2\.&lt;/p&gt;  &lt;h3&gt;DataFeed vs. DataEntries feed&lt;/h3&gt;  &lt;p&gt;So far I have focused on the issues when importing individual Atom entries within a feed.&amp;#160; There are also issues when importing metadata for the feed itself.&amp;#160; But first it is useful to discuss the differences between a DataFeed and its DataEntries feed.&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;DataFeed_vs_DataEntries_feed&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3450705759/&quot;&gt;&lt;img style=&quot;border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px&quot; border=&quot;0&quot; alt=&quot;DataFeed_vs_DataEntries_feed&quot; src=&quot;http://static.flickr.com/3380/3450705759_536a374dce.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In the picture above, green=entry and orange=feed.&amp;#160; The most obvious thing to note here is that DataFeed is an &lt;em&gt;entry&lt;/em&gt; that links to an Entries feed containing multiple DataEntries.&lt;/p&gt;  &lt;p&gt;The Entries feed’s &amp;lt;title&amp;gt; is read-only and is always “DataEntries”.&amp;#160; &amp;lt;id&amp;gt; and the rest of the elements listed above are auto-generated by the Live Operating Environment.&amp;#160; The DataEntries feed isn’t extensible, so you can’t add links to things such as the original feed’s self link or alternate link.&lt;/p&gt;  &lt;p&gt;This means that if you want to preserve any feed metadata from your original feed, you must store it somewhere else.&amp;#160; The DataFeed entry is a likely candidate.&lt;/p&gt;  &lt;p&gt;You can store the original feed’s title in the DataFeed’s title.&amp;#160; You can also add any links from the original feed that don’t conflict with LOE-managed links such as self link.&amp;#160; If you need to store the original feed’s self link, you can do this by renaming its rel and title attributes.&lt;/p&gt;  &lt;p&gt;It should now be quite clear that importing external feeds is like putting a square peg in a round hole.&amp;#160; Even if you find a way to do it, you won’t be able to take existing Twitter clients and easily tweak them to use Live Framework’s imported Twitter feeds.&lt;/p&gt;  &lt;h3&gt;Other considerations for apps&lt;/h3&gt;  &lt;p&gt;I noticed a few other interesting things as I was exploring.&amp;#160; The local LOE correctly lists imported tweets in reverse chronological order (the order in which they were imported).&amp;#160; When these tweets are synchronized with the cloud LOE, they are listed in chronological order (the exact opposite of the local LOE).&lt;/p&gt;  &lt;p&gt;You can use Resource Scripts to import external feeds, as I demonstrated in the code sample for &lt;a href=&quot;http://orand.blogspot.com/2008/12/fluent-livefx-resource-scripts.html&quot;&gt;this post&lt;/a&gt;.&amp;#160; With the new &lt;a href=&quot;http://blogs.msdn.com/benwilli/archive/2009/03/30/feeling-a-bit-loopy.aspx&quot;&gt;Loop statement&lt;/a&gt;, this becomes even easier.&amp;#160; However, Resource Scripts can only read external feeds when the script is executed locally, not in the cloud.&lt;/p&gt;  &lt;p&gt;Whether you’re importing one item at a time or using Resource Scripts for bulk imports, it is clearly preferable to import using the local LOE.&amp;#160; But what if you want to use delegated auth to import data using a 3rd-party website?&amp;#160; Unless you figure out how to hack WLC (which I doubt supports delegated auth), you’re out of luck when it comes to the &amp;lt;published&amp;gt; date because you don’t have a local LOE.&lt;/p&gt;  &lt;h3&gt;Hope for the future: Federated Storage&lt;/h3&gt;  &lt;p&gt;I don’t know much about Federated Storage Services since I didn’t have access to the pre-CTP release that supposedly exposed them, but I believe the idea is to allow third parties to create proxies to their services, similar to how Contacts and Profiles from Hotmail’s Address Book Clearing House (ABCH) are currently exposed.&amp;#160; You can see hints of Federated Services if you paste the following link into the Live Framework Resource Browser:&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;https://user-ctp.windows.net/V0.1/Mesh/SomeRandomUri&quot; href=&quot;https://user-ctp.windows.net/V0.1/Mesh/SomeRandomUri&quot;&gt;https://user-ctp.windows.net/V0.1/Mesh/SomeRandomUri&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I would imagine that this would provide a better option for “importing” 3rd-party data into the mesh.&amp;#160; You would probably have much greater control over the URIs, titles, and more.&amp;#160; Furthermore, this data wouldn’t need to be stored in Microsoft’s datacenters.&amp;#160; This is especially important if you want to “import” feeds with sizeable enclosures such as pictures and video.&lt;/p&gt;  &lt;p&gt;One possible downside of Federated Storage is that I imagine you won’t be able to arbitrarily annotate data in external feeds, reducing their potential in data mashup scenarios.&amp;#160; This limitation already manifests itself in the inability to persist Delete triggers for Contacts and Profiles.&lt;/p&gt;  &lt;h3&gt;Another request for “Yahoo Pipes for AtomPub”&lt;/h3&gt;  &lt;p&gt;At the end of &lt;a href=&quot;http://orand.blogspot.com/2009/01/meshscript-ideas-for-future.html&quot;&gt;this blog post&lt;/a&gt;, I proposed using Live Framework to enable something like &lt;a href=&quot;http://pipes.yahoo.com/pipes/&quot;&gt;Yahoo Pipes&lt;/a&gt; for AtomPub.&amp;#160; This would enable you to import and mash up arbitrary feeds, perhaps supplemented by a visual Resource Script designer.&amp;#160; I believe support for raw Atom feeds is crucial for this scenario.&amp;#160; Support for raw RSS feeds may also be desirable.&lt;/p&gt;  &lt;h3&gt;Feature request&lt;/h3&gt;  &lt;p&gt;If you want to easily build Live Framework apps that import feeds from external sources, please vote on &lt;a href=&quot;https://connect.microsoft.com/liveframework/feedback/ViewFeedback.aspx?FeedbackID=433414&quot;&gt;this feature request&lt;/a&gt; on Connect.&amp;#160; Thanks!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/3702557082522540557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/3702557082522540557' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/3702557082522540557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/3702557082522540557'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/04/quest-for-raw-feeds-in-live-framework.html' title='The Quest for Raw Feeds in the Live Framework'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-1170530125308483490</id><published>2009-04-08T01:05:00.001-08:00</published><updated>2009-04-08T18:34:24.898-08:00</updated><title type='text'>Live Mesh and Live Framework Presentation</title><content type='html'>&lt;p&gt;Yesterday I gave a presentation on Live Mesh and the Live Framework for &lt;a href=&quot;http://groups.google.com/group/software-pros-ak&quot;&gt;Software Professionals of Alaska&lt;/a&gt;.&lt;/p&gt;  &lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px&quot; id=&quot;scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:57e4d3b7-bbdc-418f-90b4-76220347c4e6&quot; class=&quot;wlWriterEditableSmartContent&quot;&gt;&lt;div&gt;&lt;object width=&quot;400&quot; height=&quot;300&quot;&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot; /&gt;&lt;param name=&quot;movie&quot; value=&quot;http://vimeo.com/moogaloop.swf?clip_id=4066353&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=00adef&amp;amp;fullscreen=1&quot; /&gt;&lt;embed src=&quot;http://vimeo.com/moogaloop.swf?clip_id=4066353&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=00adef&amp;amp;fullscreen=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; width=&quot;400&quot; height=&quot;300&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://orand.googlecode.com/files/LiveMeshLiveFxPresentation.wmv&quot;&gt;High-quality WMV download&lt;/a&gt; (78.6 MB)&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://orand.googlecode.com/files/Intro%20to%20Mesh%20and%20LiveFX.pptx&quot;&gt;Slides&lt;/a&gt; (5.6MB pptx)&lt;/p&gt;  &lt;h3&gt;What did I talk about?&lt;/h3&gt;  &lt;p&gt;&lt;a title=&quot;MeshifiedYertle&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3423579420/&quot;&gt;&lt;img style=&quot;border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; border=&quot;0&quot; alt=&quot;MeshifiedYertle&quot; src=&quot;http://static.flickr.com/3628/3423579420_6f711c42c0.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;As you can see by Yertle the Meshified Turtle, I had some fun with the presentation.&lt;/p&gt;  &lt;p&gt;Besides putting my own spin on the typical introductory material, I gave some guidance on things that tend to trip up developers coming from a background of relational databases, file systems, and app-owned data (36:42 onwards).&lt;/p&gt;  &lt;p&gt;The last part of my presentation is the most interesting part (to me anyway).&amp;#160; This is where I speculate wildly about what the future might hold.&amp;#160; There are some good scoops in there that most people probably don’t know about.&amp;#160; I might get in trouble for talking about them, but I assure you that every scoop or bit of speculation has a publicly available source to back it up.&amp;#160; I’ve got them right here in my notes.&amp;#160; Check it out starting at 42:12.&lt;/p&gt;  &lt;h3&gt;More info&lt;/h3&gt;  &lt;p&gt;As I mentioned in the presentation, the &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/threads/&quot;&gt;Live Framework Forum&lt;/a&gt; is the best one stop shop for more resources to get you started.&amp;#160; There are several sticky threads at the top that contain everything you need.&lt;/p&gt;  &lt;p&gt;There were two things I intended to demo but forgot.&amp;#160; First is mobile web access to Live Mesh at &lt;a href=&quot;http://m.mesh.com&quot;&gt;http://m.mesh.com&lt;/a&gt;.&amp;#160; It works in desktop browsers too, so check it out.&amp;#160; Make your browser window tiny and pretend it’s a phone. ;-)&lt;/p&gt;  &lt;p&gt;The second thing I forgot to demo was the Live Framework Resource Browser.&amp;#160; Fortunately, there is already a &lt;a href=&quot;http://msdn.microsoft.com/en-us/azure/dd441707.aspx&quot;&gt;video&lt;/a&gt; showing it in action.&amp;#160; Real clicky-clicky browsing action starts around the 7-minute mark.&lt;/p&gt;  &lt;p&gt;Afterward several people said they wanted to see what it’s like to develop a Mesh-Enabled Web App.&amp;#160; Check out this nice &lt;a href=&quot;http://channel9.msdn.com/posts/mtaulty/Live-Framework-MEWA-Hello-World/&quot;&gt;11-minute video&lt;/a&gt; showing how to build a Silverlight MEWA.&lt;/p&gt;  &lt;p&gt;Since we’re on a roll with videos, I’d also recommend you check out the very well done Live Mesh ad I mentioned in the “futures” part of my presentation.&amp;#160; If you have the bandwidth, &lt;a href=&quot;http://www.youtube.com/watch?v=lFpwzg-AP_Q&quot;&gt;go to the source&lt;/a&gt; and click the HD button.&amp;#160; It’s beautiful.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px&quot; id=&quot;scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:abfe89c4-00c4-4886-bdc3-714bd4b873e9&quot; class=&quot;wlWriterEditableSmartContent&quot;&gt;&lt;div id=&quot;e9766d92-7459-43d1-a660-59f515e839f1&quot; style=&quot;margin: 0px; padding: 0px; display: inline;&quot;&gt;&lt;div&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=lFpwzg-AP_Q&amp;amp;hl=en&amp;amp;fs=1&quot; target=&quot;_new&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUw_7jmlgMR5qZlwnTYDIcXgPl6YQW9kaSVYcdF0_dpvRcz_BTB2i1yrBV578tPcL5HSdsX0mgiE5ZjCyAXKXh_e_vKeYu5fZD3aAX2lMpTxXPmVBOrSqN4hlm_n-106_a17CO/?imgmax=800&quot; style=&quot;border-style: none&quot; galleryimg=&quot;no&quot; onload=&quot;var downlevelDiv = document.getElementById(&#39;e9766d92-7459-43d1-a660-59f515e839f1&#39;); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;object width=\&amp;quot;425\&amp;quot; height=\&amp;quot;355\&amp;quot;&amp;gt;&amp;lt;param name=\&amp;quot;movie\&amp;quot; value=\&amp;quot;http://www.youtube.com/v/lFpwzg-AP_Q&amp;amp;hl=en&amp;amp;fs=1&amp;amp;hl=en\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;embed src=\&amp;quot;http://www.youtube.com/v/lFpwzg-AP_Q&amp;amp;hl=en&amp;amp;fs=1&amp;amp;hl=en\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; width=\&amp;quot;425\&amp;quot; height=\&amp;quot;355\&amp;quot;&amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/object&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;&quot; alt=&quot;&quot;&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;A note on presenting&lt;/h3&gt;  &lt;p&gt;I thought I would be embarrassed to listen to a recording of myself, but it turned out better than I expected.&amp;#160; One thing I learned is that &lt;a href=&quot;http://twitter.com/akcoder&quot;&gt;Dan&lt;/a&gt; was right when he held up the “Talk louder” sign.&amp;#160; Thanks, Dan.&amp;#160; Sometimes I fade away at the end of sentences.&amp;#160; I blame it on my time in Finland (their sentences all run downhill, even questions).&amp;#160; Something to work on for next time.&lt;/p&gt;  &lt;p&gt;Listening to myself in the third person without visual cues, I noticed several times when my dry humor was so deadpan, you might be left wondering whether it was intentional.&amp;#160; So if you have “was that intentional?” moments while listening, the answer is probably “yes.” There was probably an equally subtle smile on my face as I said it. ;-)&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/1170530125308483490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/1170530125308483490' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/1170530125308483490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/1170530125308483490'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/04/live-mesh-and-live-framework.html' title='Live Mesh and Live Framework Presentation'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-5537447314232100851</id><published>2009-03-12T23:51:00.001-08:00</published><updated>2009-03-12T23:56:36.788-08:00</updated><title type='text'>RESTful UDP: a Live Framework Feature Request</title><content type='html'>&lt;p&gt;Yes, I admit, “RESTful UDP” sounds unnatural, maybe even unethical.&amp;#160; I also admit that I’m getting ahead of myself, talking about design before requirements.&amp;#160; So what motivates me to ask for such a feature?&lt;/p&gt;  &lt;p&gt;I want real-time P2P messaging between users, apps, and devices.&amp;#160; &lt;a href=&quot;http://orand.blogspot.com/2009/03/exploring-live-framework-notifications.html&quot;&gt;Notifications&lt;/a&gt; get us most of the way there, but they aren’t enough.&amp;#160; Before I discuss the issues with notifications, let’s talk about scenarios that motivate this.&lt;/p&gt;  &lt;h3&gt;Scenarios&lt;/h3&gt;  &lt;p&gt;Imagine walking up to a large-screen Mesh-enabled device such as an XBox, Microsoft Surface, or public kiosk.&amp;#160; You pair your Mesh-enabled smartphone and project its apps and data onto the big screen, with your smartphone acting as the data entry device.&lt;/p&gt;  &lt;p&gt;Expanding on this scenario, imagine a game that takes advantage of the smartphone’s accelerometer and camera, turning your phone into a high-powered Wiimote with the entire touch screen used for control surface.&amp;#160; You might want to attach a wrist strap…&lt;/p&gt;  &lt;p&gt;Imagine the cool apps you could write if a group of people shares real-time GPS data from smartphones and carputers.&lt;/p&gt;  &lt;p&gt;This feature would be useful for more than just extending the capabilities of smartphones.&amp;#160; You could remotely control media playback, chat with people, push real-time financial data, and build a variety of interesting distributed apps that are designed to run in real-time across a mesh of devices, aggregating specialized device capabilities into a single composite experience.&lt;/p&gt;  &lt;p&gt;Cross-platform support exponentially increases the possibilities and relevance of the mesh.&amp;#160; You can imagine special-purpose devices whose entire reason for existence is to be plugged into the mesh to supplement apps and user experiences.&amp;#160; This is true even without real-time messaging, but this capability is crucial for enabling the most seamless composite device experiences.&lt;/p&gt;  &lt;h3&gt;Who else wants this?&lt;/h3&gt;  &lt;p&gt;Back in December, Kevin Hoffman kicked off an &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/8648ff55-9348-40f2-a0d0-b50272d2d012/&quot;&gt;extended discussion&lt;/a&gt; on this feature request.&amp;#160; Here’s a brief excerpt:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Low Latency: Other actions that people take within the application need to happen quickly. I need very low latency between when the action takes place and when the other client(s) are notified about the action. Think of these as instant messages, though with a domain-specific purpose. Some can be directed at an individual MEWAs, others can be broadcasts. I do not currently have a solution for the low latency.&lt;/p&gt;    &lt;p&gt;I know that Silverlight applications cannot receive push messages because of their highly restricted network Sandbox. However, I&#39;m wondering if they would be able to create an HTTP WCF service via .NET Services and host the proxy in the cloud that would allow near-real-time HTTP message posting between MEWAs... Is this possible?&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Strages has a &lt;a href=&quot;http://social.microsoft.com/Forums/en-US/LiveMesh/thread/b6fb5d7b-c69a-405f-9e0d-bcf0052a3174#page:2&quot;&gt;big wish list&lt;/a&gt; in the Mesh forum that includes:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;as mobile phones and laptops will get close and closer together.. there will get a time that you just plug your phone to a local monitor and keyboard.. or even better bring your own flexible seized monitor etc etc.. you get it&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;John Macintyre’s &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB34/&quot;&gt;PDC session&lt;/a&gt; had a demo of remotely controlling a Media Center.&amp;#160; Sync delays in the demo made for a not so seamless experience.&lt;/p&gt;  &lt;h3&gt;Warning: detailed discussion ahead&lt;/h3&gt;  &lt;p&gt;I could probably end the feature request here.&amp;#160; Please take everything that follows as optional food for thought.&amp;#160; If you like what you’ve heard so far and just want to vote for this, please visit this &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/31470d46-71d8-4805-9729-3e2e2ada4e72&quot;&gt;feature request on the Live Framework forum&lt;/a&gt; and vote it up.&amp;#160; If you have comments, please post them on the forum rather than here.&lt;/p&gt;  &lt;h3&gt;Why UDP?&lt;/h3&gt;  &lt;p&gt;First, I don’t intend UDP to be taken literally (well maybe I do, but that’s an implementation detail).&amp;#160; Specifically, I’m interested in the following UDP characteristics:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;One-way messaging &lt;/li&gt;    &lt;li&gt;Low latency &lt;/li&gt;    &lt;li&gt;Stateless (lossy, no sessions, unordered, etc.) &lt;/li&gt;    &lt;li&gt;Multicasting &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It shouldn’t be necessary to expose the concept of P2P session initiation, even if that is ultimately an implementation detail.&lt;/p&gt;  &lt;h3&gt;Why REST?&lt;/h3&gt;  &lt;p&gt;I &lt;em&gt;do&lt;/em&gt; intend REST to be taken literally.&amp;#160; I’m interested in the following REST characteristics:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;URI-addressable resources &lt;/li&gt;    &lt;li&gt;Hyperlinks to other resources &lt;/li&gt;    &lt;li&gt;Arbitrary user content &lt;/li&gt;    &lt;li&gt;Transport-agnostic (yes, I think that’s RESTful) &lt;/li&gt;    &lt;li&gt;POST and GET (PUT and DELETE don’t make sense here) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Links to arbitrary resources are an important tool for keeping message size small.&lt;/p&gt;  &lt;p&gt;Being transport-agnostic is important, for performance and for constrained network environments.&amp;#160; Of course HTTP should be supported, but it should also be possible to use TCP, UDP, the Messenger Relay, or even use &lt;a href=&quot;http://edjez.instedd.org/2008/06/mesh4x-sms-adapter-sync-data-without.html&quot;&gt;SMS like Mesh4x does&lt;/a&gt;.&amp;#160; Just like with Notifications, there should be no need for senders and receivers to use the same transport or representation.&lt;/p&gt;  &lt;p&gt;Making this feature available to plain old DHTML Mesh apps would be pretty amazing.&lt;/p&gt;  &lt;h3&gt;Meshisms&lt;/h3&gt;  &lt;p&gt;I would also like support for some Mesh-specific features:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;AtomPub feed-based model &lt;/li&gt;    &lt;li&gt;Multiple representations (ATOM, POX, JSON, Binary XML) &lt;/li&gt;    &lt;li&gt;Expansions &lt;/li&gt;    &lt;li&gt;“LINQ to REST” &lt;/li&gt;    &lt;li&gt;Send messages from triggers (a fine-grained alternative to subscriptions) &lt;/li&gt;    &lt;li&gt;Local LOE support &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Why aren’t Notifications enough?&lt;/h3&gt;  &lt;p&gt;In my &lt;a href=&quot;http://orand.blogspot.com/2009/03/exploring-live-framework-notifications.html&quot;&gt;Notifications post&lt;/a&gt; I covered some of the issues that make Notifications less than ideal for real-time messaging, even when paired with &lt;a href=&quot;http://orand.blogspot.com/2009/02/exploring-live-framework-activities.html&quot;&gt;Activities&lt;/a&gt;.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Three round-trips per notification cycle (can be reduced to two using expansions) &lt;/li&gt;    &lt;li&gt;Watermarks are destructive &lt;/li&gt;    &lt;li&gt;You can’t directly publish your own notifications &lt;/li&gt;    &lt;li&gt;Notification queues are per-user and designed for single-threaded use (one per client) &lt;/li&gt;    &lt;li&gt;Each app does its own polling rather than sharing one connection, unlike iPhone’s push notifications &lt;/li&gt;    &lt;li&gt;Notifications are one-way from cloud to client (no client-to-cloud or P2P) &lt;/li&gt;    &lt;li&gt;Notification polls don’t chain from local LOE to cloud LOE&lt;/li&gt;    &lt;li&gt;While Notifications are usually instantaneous, they can become backlogged and delayed by several minutes &lt;/li&gt;    &lt;li&gt;The local LOE doesn’t currently implement Activities&lt;/li&gt;    &lt;li&gt;There is no way for multiple clients to efficiently receive only unseen Activities in a single round trip&lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;A proposed solution&lt;/h3&gt;  &lt;p&gt;There may be better solutions, but I visualize this problem being solved by a REST front-end to a “transport-agnostic UDP” messaging system.&amp;#160; Under the hood, the system prefers direct UDP communication but can use Messenger Relay or HTTP if necessary.&amp;#160; The front-end seen by developers is an AtomPub interface very much like the Notifications interface.&amp;#160; When using HTTP, push messaging is enabled by parking requests for up to 30 seconds if no messages are waiting.&lt;/p&gt;  &lt;p&gt;It is preferable to program against the local LOE.&amp;#160; Polling the local LOE for messages causes the local LOE to poll the cloud LOE, and if any participating devices are reachable, they are also polled if another push mechanism can’t be established.&amp;#160; It is important to be able to establish local P2P connections even if the cloud LOE isn’t reachable.&amp;#160; Care is needed to avoid round-robin message loops.&lt;/p&gt;  &lt;p&gt;Messages would auto-generate a short MaxAge upon receipt by each LOE, similar to Activities.&amp;#160; It is probably most efficient to simply let Messages expire instead of explicitly deleting them.&lt;/p&gt;  &lt;p&gt;In order to support multiple recipients of the same message, clients should be able to poll the queue with a nondestructive query string watermark.&amp;#160; An alternative might be to let each client create its own destructive NotificationQueue that receives full copies from the main message queue, but this assumes the 3-round-trips issue is solved.&lt;/p&gt;  &lt;p&gt;This can be a soft state service with no need for additional infrastructure recovery features.&lt;/p&gt;  &lt;p&gt;If it is necessary to impose the UDP equivalent of Twitter’s 140-character limit, that’s fine.&amp;#160; 65,507 bytes seems like plenty.&amp;#160; Users can always just send links to large resources.&amp;#160; If expansions are supported, the receiver can optionally inline the large data on demand without necessarily transmitting it across the network if it already exists in the local LOE.&lt;/p&gt;  &lt;h3&gt;Addressability&lt;/h3&gt;  &lt;p&gt;Messages should be able to target one or more users and devices, and scope a broadcast by MeshObject/AppInstance.&amp;#160; This could be solved in a variety of ways.&lt;/p&gt;  &lt;p&gt;You could scope all messages by MeshObject (MeshObjects/{id}/MessageQueue), with the option to subscope them further with links to Members and Mappings.&amp;#160; This is the option I prefer.&amp;#160; It doesn’t require directly addressing users and devices, it doesn’t require any changes to enable the “cloud device” to be addressed, and it should provide decent partitioning.&amp;#160; A downside is that it requires separate requests for separate MeshObjects.&amp;#160; However, if you program against a local LOE which multiplexes everything under the hood, this shouldn’t be a problem.&lt;/p&gt;  &lt;p&gt;Or you could have one queue to rule them all at Mesh/MessageQueue.&amp;#160; Messages would have one or more links to users, devices, and/or MeshObjects.&amp;#160; Subscribers would poll the queue with the option of filtering on these links by query string.&lt;/p&gt;  &lt;p&gt;Or you could add /MessageQueue to various scoping contexts such as Devices/{id} and {id}/Profiles.&amp;#160; This would require exposing the cloud LOE as a device entry.&lt;/p&gt;  &lt;p&gt;I’m not sure if devices or mappings from other users are currently discoverable.&amp;#160; This would need to be addressed.&lt;/p&gt;  &lt;h3&gt;Device connectivity&lt;/h3&gt;  &lt;p&gt;I suspect there may already be a way to access existing device connectivity information, but if not, it would be very helpful to see which devices (including the cloud device) are reachable for real-time messaging.&lt;/p&gt;  &lt;h3&gt;Issues with just exposing Mesh’s P2P support&lt;/h3&gt;  &lt;p&gt;At the PDC I heard talk of exposing Mesh’s peer-to-peer channel to enable developers to establish connections between devices for streaming data.&amp;#160; Although this is a great solution for some scenarios (and I would like to have such a feature), it’s not so great for other scenarios.&lt;/p&gt;  &lt;p&gt;Streaming in this context is a reliable, sessionful feature.&amp;#160; In order to get the lowest latency possible, I want unreliable, sessionless communication.&lt;/p&gt;  &lt;p&gt;You can optimize for latency or for throughput, but not both.&amp;#160; Streaming is optimized for high throughput.&amp;#160; I want low latency (UDP, or disable TCP’s &lt;a href=&quot;http://en.wikipedia.org/wiki/Nagle&#39;s_algorithm&quot;&gt;Nagle algorithm&lt;/a&gt;).&lt;/p&gt;  &lt;h3&gt;Bonus points: ad-hoc device discovery&lt;/h3&gt;  &lt;p&gt;This is a tangentially related issue that can be addressed independently.&amp;#160; Although apps can be written to select from a known list for pairing with other users and devices, I would love to have ad-hoc user/device pairing.&lt;/p&gt;  &lt;p&gt;There are many, many ways to accomplish this.&amp;#160; I would like to use &lt;a href=&quot;http://www.microsoft.com/tag/&quot;&gt;Microsoft Tag&lt;/a&gt; for pairing devices from unknown users and meshes.&amp;#160; One device displays a tag containing its mesh address, and the other device scans the tag.&amp;#160; The tag could be a printed tag, or displayed on a screen.&amp;#160; The tag exchange could be two-way for greater security.&amp;#160; For public kiosks, the tag could be changed every minute or generated on demand.&lt;/p&gt;  &lt;p&gt;There are a whole host of additional issues raised by ad-hoc device pairing, but it sure sounds like the future to me.&amp;#160; Someone’s going to solve this problem in a generic way, please don’t let Apple get there first. ;-)&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;Hopefully the additional detail is a helpful starting point for discussion.&amp;#160; I am quite open to alternate solutions that can provide real-time P2P messaging.&amp;#160; As I noted earlier, if you like this idea, please visit this &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/31470d46-71d8-4805-9729-3e2e2ada4e72&quot;&gt;feature request on the Live Framework forum&lt;/a&gt; and vote it up.&amp;#160; If you have any comments, please post them on the forum thread.&amp;#160; Thanks!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/5537447314232100851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/5537447314232100851' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/5537447314232100851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/5537447314232100851'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/03/restful-udp-live-framework-feature.html' title='RESTful UDP: a Live Framework Feature Request'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-4624006039762088753</id><published>2009-03-08T14:31:00.001-08:00</published><updated>2009-03-08T14:31:27.674-08:00</updated><title type='text'>Exploring Live Framework Notifications</title><content type='html'>&lt;p&gt;In order to tune in to the data that matters to you, Live Framework lets you receive near-real-time notifications of changes by subscribing to objects and feeds.&amp;#160; Although the SDK documentation is fairly sparse at the moment, &lt;a href=&quot;http://crazyviraj.blogspot.com/&quot;&gt;Viraj Mody&lt;/a&gt; wrote an &lt;a href=&quot;http://blogs.msdn.com/livemesh/archive/2008/10/08/behind-live-mesh-the-pub-sub-system.aspx&quot;&gt;excellent blog post&lt;/a&gt; describing how the notification system works, and John Macintyre also gave a great &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB34/&quot;&gt;PDC session on notifications&lt;/a&gt;.&amp;#160; Being the curious sort, I still had many questions, so I dug in further and this blog post and ResourceClient library are the result.&lt;/p&gt;  &lt;h3&gt;Overview&lt;/h3&gt;  &lt;p&gt;Notifications are exposed in the high-level programming model through the ChangeNotificationReceived event.&amp;#160; Under the hood, this is made possible by queues, subscriptions, and notifications working together.&amp;#160; These three building blocks can be accessed through the resource-oriented programming model, enabling even more interesting scenarios.&amp;#160; Even if you have no desire to program at this level, understanding how notifications work can help you take fuller advantage of the high-level model.&lt;/p&gt;  &lt;p&gt;Slide 9 from John Macintyre’s presentation shows how the pieces tie together.&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;SubscriptionsAndNotificationsSlide&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3334327516/&quot;&gt;&lt;img border=&quot;0&quot; alt=&quot;SubscriptionsAndNotificationsSlide&quot; src=&quot;http://static.flickr.com/3381/3334327516_d578da8659.jpg&quot; width=&quot;400&quot; height=&quot;302&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The typical usage pattern looks like this:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Client creates a queue &lt;/li&gt;    &lt;li&gt;Client subscribes its queue to one or more resources or feeds &lt;/li&gt;    &lt;li&gt;Client polls the queue’s Notifications feed &lt;/li&gt;    &lt;li&gt;A resource or feed changes &lt;/li&gt;    &lt;li&gt;Subscription Service posts a notification to each of the queues that are subscribed to the resource or feed &lt;/li&gt;    &lt;li&gt;Client’s poll returns with one or more notifications &lt;/li&gt;    &lt;li&gt;Client takes the watermark of the most recent notification and posts it to the queue &lt;/li&gt;    &lt;li&gt;Client takes some action based on the notifications such as requesting the newest version of the changed resource or feed &lt;/li&gt;    &lt;li&gt;Client polls the queue’s Notifications feed… &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;After the initial queue creation, a minimum of three round-trips are necessary to complete each cycle.&amp;#160; Later we will see a trick for doing this in two round-trips.&lt;/p&gt;  &lt;p&gt;Although the client has to poll the queue, this is actually more of a push than a pull.&amp;#160; The HTTP request stays “parked” at the server until a notification arrives or a timeout expires (just like relay binding’s &lt;a href=&quot;http://vasters.com/clemensv/CommentView,guid,9dcf76ad-b6e6-47c7-aa81-60970dc6a166.aspx&quot;&gt;HTTP “parked requests” in &lt;strike&gt;BizTalk Services&lt;/strike&gt; .NET Service Bus&lt;/a&gt;).&amp;#160; This means that when a notification arrives, the server can immediately push it to the client on the HTTP response of the parked request, saving half a round-trip of latency.&amp;#160; Jeremy Mazner has more to say on the subject in &lt;a href=&quot;http://channel9.msdn.com/posts/Dan/David-Steere-and-Trevor-Robinson-How-Live-Mesh-P2P-Syncing-Works/?Page=3&quot;&gt;this Channel9 thread&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;So far I have described the behavior of the cloud LOE.&amp;#160; We will cover the client LOE’s slightly different behavior later.&lt;/p&gt;  &lt;h3&gt;Recovery from failures&lt;/h3&gt;  &lt;p&gt;In John’s diagram above, the Queue Service and Subscription Service are both in-memory soft state services.&amp;#160; This means it is possible for a Queue Service instance to go down resulting in queue loss (including all its notifications).&amp;#160; A Subscription Service instance can also go down, resulting in loss of subscriptions.&amp;#160; In both cases, the client will receive a specific error notification the next time it tries to poll the queue.&lt;/p&gt;  &lt;p&gt;In the case of queue loss, it is the responsibility of the client to create a new queue and resubscribe to each resource.&amp;#160; In the case of subscription loss, the client is told “resources from these addresses lost subscriptions” and it just needs to resubscribe to each one using its existing queue.&lt;/p&gt;  &lt;p&gt;As Viraj notes in &lt;a href=&quot;http://blogs.msdn.com/livemesh/archive/2008/10/08/behind-live-mesh-the-pub-sub-system.aspx&quot;&gt;his blog post&lt;/a&gt;, &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;A short summary of the solution is that in cases where one or several Queue and/or PubSub Servers go down, the system is able to detect exactly what happened and take remedial action to restore state in the cloud in cooperation with clients (because clients were the original source for all the transient data that was resident on those servers before they lost state).&lt;/p&gt; &lt;/blockquote&gt;  &lt;h3&gt;What can you subscribe to?&lt;/h3&gt;  &lt;p&gt;From the high-level object model, only the following types are subscribable via ChangeNotificationReceived:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;MeshObject &lt;/li&gt;    &lt;li&gt;MeshDevice &lt;/li&gt;    &lt;li&gt;LiveItemCollection (feeds)     &lt;ul&gt;       &lt;li&gt;Mesh.Devices &lt;/li&gt;        &lt;li&gt;Mesh.MeshObjects &lt;/li&gt;        &lt;li&gt;Mesh.News &lt;/li&gt;        &lt;li&gt;MeshObject.DataFeeds &lt;/li&gt;        &lt;li&gt;MeshObject.Mappings &lt;/li&gt;        &lt;li&gt;MeshObject.Members &lt;/li&gt;        &lt;li&gt;MeshObject.News &lt;/li&gt;        &lt;li&gt;These may not work yet:         &lt;ul&gt;           &lt;li&gt;Contact.Profiles &lt;/li&gt;            &lt;li&gt;LOE.Contacts &lt;/li&gt;            &lt;li&gt;LOE.Profiles &lt;/li&gt;            &lt;li&gt;Member.Profiles &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If you use the resource-oriented programming model, you can subscribe to all of the resources behind the high-level objects as well as:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ApplicationResource &lt;/li&gt;    &lt;li&gt;ApplicationInstanceResource &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In addition to the high-level feeds, you can also subscribe to feeds for:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;MeshObject.Activities &lt;/li&gt;    &lt;li&gt;Applications &lt;/li&gt;    &lt;li&gt;InstalledApplications &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;One quirk is that MeshObject isn’t subscribable from the local LOE, although you can still subscribe to the local MeshObjects feed.&lt;/p&gt;  &lt;p&gt;It is useful to consider the MeshObject-&amp;gt;DataFeed-&amp;gt;DataEntry hierarchy in terms of what is and isn’t subscribable.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Mesh/MeshObjects/Subscriptions &lt;/li&gt;    &lt;li&gt;Mesh/MeshObjects/{id}/Subscriptions &lt;/li&gt;    &lt;li&gt;Mesh/MeshObjects/{id}/DataFeeds/Subscriptions     &lt;ul&gt;       &lt;li&gt;this is a “feed of feeds” &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strike&gt;Mesh/MeshObjects/{id}/DataFeeds/{id}/Subscriptions&lt;/strike&gt;     &lt;ul&gt;       &lt;li&gt;this doesn’t exist &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Mesh/MeshObjects/{id}/DataFeeds/{id}/Entries/Subscriptions &lt;/li&gt;    &lt;li&gt;&lt;strike&gt;Mesh/MeshObjects/{id}/DataFeeds/{id}/Entries/{id}/Subscriptions&lt;/strike&gt;     &lt;ul&gt;       &lt;li&gt;this doesn’t exist &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;What notifications do you receive?&lt;/h3&gt;  &lt;p&gt;You would expect all resources and feeds to notify you when resources are created, updated, or deleted, but that isn’t the case.&amp;#160; Some resources and feeds don’t notify you when entries are updated, some aren’t subscribable, and some are read-only.&amp;#160; This varies between the cloud LOE and the local LOE and between various objects.&amp;#160; Here’s an incomplete listing of which notification triggers work based on my experimentation:&lt;/p&gt;  &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;399&quot;&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;&amp;#160;&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Local&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;130&quot;&gt;Cloud&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;MeshObject&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Not subscribable&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;130&quot;&gt;Update, Delete&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;MeshDevice&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Not subscribable&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;131&quot;&gt;Nothing? at least not Update&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;MeshObjects feed&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Create, Update, Delete&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;131&quot;&gt;Create, Delete (no Update)&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;Devices feed&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Can’t update locally&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;131&quot;&gt;Update, maybe others&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;DataFeeds&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Create, Update, Delete&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;131&quot;&gt;Create, Update, Delete&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;135&quot;&gt;DataEntries&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;Create, Update, Delete (with double notifications for each)&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;131&quot;&gt;Create, Update, Delete&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;I’m not sure why, but a subscription to DataEntries creates two notifications for each change on the local LOE.&lt;/p&gt;  &lt;h3&gt;How subscriptions work&lt;/h3&gt;  &lt;p&gt;As you have seen, you can subscribe to any resource or feed that has a Subscriptions URL (ex: Mesh/MeshObjects/{id}/Subscriptions).&amp;#160; This Subscriptions feed only supports HTTP POST (no GET).&amp;#160; Individual subscriptions only support PUT (no DELETE).&lt;/p&gt;  &lt;p&gt;Subscriptions have the following interesting properties:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;NotificationQueueLink &lt;/li&gt;    &lt;li&gt;ExpirationDuration &lt;/li&gt;    &lt;li&gt;ResourceEntityTag &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;NotificationQueueLink is the only thing you need to include when you create your subscription.&amp;#160; This link should point to the SelfLink of the NotificationQueue you have created, &lt;em&gt;not&lt;/em&gt; its NotificationsLink.&lt;/p&gt;  &lt;p&gt;ExpirationDuration is expressed in seconds and is assigned a random number between 2700 and 4500 (45 min to 75 min) from the cloud LOE and a fixed value of 3600 (60 min) from the local LOE.&amp;#160; The internal class NotificationManager that is used to implement ChangeNotificationReceived has a hard-coded subscriptionRenewalInterval of 60 minutes, so it seems there’s a chance of cloud subscriptions being in an unrenewed state for up to 15 minutes, but I could be wrong.&lt;/p&gt;  &lt;p&gt;ResourceEntityTag is the ETag of the resource when the subscription was created.&amp;#160; I believe a notification is sent each time the resource’s ETag changes.&lt;/p&gt;  &lt;p&gt;Note that the subscription doesn’t have a link to the resource or feed you subscribed to.&amp;#160; It is important for you to maintain your own copy of the URI to the resource you subscribed to.&amp;#160; First, if you want to imitate ChangeNotificationReceived and execute different event handlers for different subscriptions, you will need this URI to demux from notifications to event handlers.&amp;#160; Second, you will need this URI to create new subscriptions when you receive an AllSubscriptionsLost notification.&lt;/p&gt;  &lt;p&gt;Clients should track their subscriptions for a variety of reasons:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;You can’t GET the subscription feed &lt;/li&gt;    &lt;li&gt;You can’t GET a subscription via its SelfLink &lt;/li&gt;    &lt;li&gt;For subscription renewal &lt;/li&gt;    &lt;li&gt;To recover from queue or subscription loss &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;How notification queues work&lt;/h3&gt;  &lt;p&gt;Notification queues are created by posting to Mesh/NotificationQueues.&amp;#160; If using AtomPub, you can simply post an empty entry:&lt;/p&gt;  &lt;p&gt;&amp;lt;entry xmlns=&amp;quot;http://www.w3.org/2005/Atom&amp;quot;/&amp;gt;&lt;/p&gt;  &lt;p&gt;You can’t GET Mesh/NotificationQueues to see which queues exist, so you will need to maintain a reference to the queue you get back.&lt;/p&gt;  &lt;p&gt;Queues are intended to only have a single consumer (one queue per client), and that consumer’s queue usage should effectively be single-threaded.&lt;/p&gt;  &lt;p&gt;There are a few important properties on queues:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ExpirationDuration &lt;/li&gt;    &lt;li&gt;Watermark &lt;/li&gt;    &lt;li&gt;SelfLink &lt;/li&gt;    &lt;li&gt;NotificationsLink &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;ExpirationDuration is expressed in seconds and is 300 (5 min) from the cloud LOE and 600 (10 min) from the local LOE.&amp;#160; ExpirationDuration is the duration after which the notification queue expires if its Notifications feed isn’t polled.&lt;/p&gt;  &lt;p&gt;Watermark is used together with PUT to remove all notifications in the queue with watermarks less than or equal to the watermark you sent.&amp;#160; Updating a watermark is destructive.&amp;#160; You can’t PUT an earlier watermark to roll back the queue, and that’s fine with me.&lt;/p&gt;  &lt;p&gt;SelfLink is the URI you use for a new subscription’s NotificationQueueLink.&amp;#160; You also PUT to the SelfLink URI when updating the queue’s watermark.&amp;#160; SelfLink is PUT only.&amp;#160; You can’t GET or DELETE a queue.&lt;/p&gt;  &lt;p&gt;NotificationsLink is the feed where new notifications appear.&amp;#160; This feed is not your typical feed.&amp;#160; As I mentioned earlier, polling the NotificationsLink “parks” the HTTP request on the server until a notification appears or a timeout expires.&amp;#160; This timeout varies between 25 and 30 seconds for the cloud LOE and is hopefully low enough so that intermediary proxies don’t prematurely close the connection.&amp;#160; Requests will return immediately if the queue already contains notifications.&amp;#160; Unfortunately, requests to the NotificationsLink on the local LOE always return immediately whether or not the queue is empty.&amp;#160; This is a significant problem not only because the programming model is inconsistent, but because it means that in order to get the same low latency as the cloud LOE you have to hammer the snot out of the local LOE, pegging the CPU in the process.&amp;#160; Hopefully this gets fixed.&amp;#160; The SDK sidesteps this issue by only polling every 5 seconds, but that loses much of the benefit of push notifications.&lt;/p&gt;  &lt;p&gt;The notifications feed behaves strangely when it contains more than one notification.&amp;#160; Sometimes it displays all of the notifications (up to 10), and sometimes it only displays the first one.&amp;#160; For example, you can poll the queue and see 4 notifications.&amp;#160; You can poll it again and perhaps only see one.&amp;#160; Polling a third time might show all 4 again.&amp;#160; At least it always displays notifications in order (oldest first).&amp;#160; This means you shouldn’t count on seeing more than one notification at once, but be aware that it is possible.&amp;#160; Simply act on all of the notifications you receive, PUT the watermark of the last one, and poll the queue again.&amp;#160; Using this technique you will eventually see all of the notifications in the queue, even if it appears there is only one or if the queue appears to be clipping the results at 10 notifications.&lt;/p&gt;  &lt;p&gt;Queues are semi-private.&amp;#160; They can’t be seen by other user accounts and can’t be shared.&amp;#160; Since you can’t enumerate queues with GET and their URLs are randomly generated, the only way another app or client within the same user account can see your queue is if you choose to share the queue’s URI, although I can’t think of any good reason to do that other than for testing.&lt;/p&gt;  &lt;h3&gt;Queue loss&lt;/h3&gt;  &lt;p&gt;Queues can be lost either by failing to poll them within their ExpirationDuration or by the unexpected death of a queue manager in the LOE.&amp;#160; You will find out the queue is gone when you poll the queue’s notifications feed and receive an AllSubscriptionsLost notification.&lt;/p&gt;  &lt;p&gt;You might be wondering, if the queue is gone, then how can I poll its notifications feed?&amp;#160; It turns out that if a queue doesn’t exist at a particular URI, a new “dead” queue will be automatically created at that URI.&amp;#160; You can see this by connecting to the cloud LOE with the LiveFX Resource Browser and visiting the following URI:&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;https://user-ctp.windows.net/V0.1/Mesh/NotificationQueues/1234-1234-1234/Notifications&quot;&gt;Mesh/NotificationQueues/1234-1234-1234/Notifications&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Note that this only works on the cloud LOE.&amp;#160; The local LOE will return an error.&amp;#160; Apparently you shouldn’t expect to lose a queue on the local LOE.&lt;/p&gt;  &lt;p&gt;A weird bit of trivia is that you can create two different queues with identical URIs in two different user accounts.&amp;#160; I’m guessing this is because queue managers are allocated per-user.&lt;/p&gt;  &lt;p&gt;Another weird bit of trivia is that the AllSubscriptionsLost notification has a watermark that increments each time a subscription attempts (and fails) to post a notification to the queue.&amp;#160; This is one reason why the name AllSubscriptions lost is misleading and ought to be renamed to something like QueueLost.&amp;#160; The subscriptions are most certainly still alive.&lt;/p&gt;  &lt;h3&gt;How notifications work&lt;/h3&gt;  &lt;p&gt;You can’t create notifications directly.&amp;#160; In other words, you can’t POST a new notification to a queue’s Notifications feed.&amp;#160; Notifications are only created by subscriptions (and queue or subscription loss).&lt;/p&gt;  &lt;p&gt;Notifications have the following interesting properties:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;NotificationType &lt;/li&gt;    &lt;li&gt;ResourceLink &lt;/li&gt;    &lt;li&gt;Watermark &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;NotificationType can be one of the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ResourceChanged &lt;/li&gt;    &lt;li&gt;SubscriptionLost &lt;/li&gt;    &lt;li&gt;AllSubscriptionsLost &lt;/li&gt;    &lt;li&gt;System &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;ResourceChanged is what you will see as the result of subscribing to a resource.&amp;#160; SubscriptionLost is received when a Subscription Service unexpectedly dies on the cloud LOE.&amp;#160; SubscriptionLost is &lt;em&gt;not&lt;/em&gt; received when a subscription expires due to its ExpirationDuration reaching zero.&amp;#160; As mentioned earlier, AllSubscriptionsLost would probably be better named QueueLost.&amp;#160; I’m not sure if System is used anywhere in the public API.&amp;#160; Perhaps it’s used for device connectivity.&lt;/p&gt;  &lt;p&gt;ResourceLink points to the feed or object that changed, or in the case or SubscriptionLost, I believe it points to the resource whose subscription was lost.&lt;/p&gt;  &lt;p&gt;Watermark is a counter string that increases with each new entry.&amp;#160; On the cloud LOE these look like “1.248.0”, “2.248.0”, “3.248.0”.&amp;#160; On the client LOE they are simply “1”, “2”, “3”.&lt;/p&gt;  &lt;p&gt;Notification SelfLinks are incrementing integers on the cloud LOE and GUID-like strings on the local LOE.&amp;#160; You can’t GET a notification using its SelfLink.&amp;#160; You can only see notifications by polling the notifications feed.&amp;#160; You also can’t do queries on notification feeds.&amp;#160; If you try to use something like $skip or $top, you will get an AllSubscriptionsLost notification and every notification in the queue gets discarded without you ever seeing them.&amp;#160; However, the subscriptions still work and the queue continues to function normally afterward (other than the data loss).&lt;/p&gt;  &lt;h3&gt;Notifications and expansions&lt;/h3&gt;  &lt;p&gt;A cool trick for saving a round-trip is to use &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136803.aspx&quot;&gt;expansions&lt;/a&gt; to return changed resources and feeds inline in the notification results.&amp;#160; A not-so-cool potential side-effect is that if the notifications feed returns more than one notification for the same resource or feed, the expansion will result in duplicate expanded data, wasting bandwidth.&lt;/p&gt;  &lt;p&gt;If you could combine watermark updates with the next poll request, you could get the poll-watermark-update cycle from 3 round-trips down to just 1 round-trip.&lt;/p&gt;  &lt;h3&gt;Notifications and activities&lt;/h3&gt;  &lt;p&gt;When you combine notifications, expansions, &lt;a href=&quot;http://orand.blogspot.com/2009/02/exploring-live-framework-activities.html&quot;&gt;activities&lt;/a&gt;, and the cloud LOE, this enables near-real-time messaging between clients.&amp;#160; By subscribing to an Activities feed, clients can poll the Notifications feed using $expand and receive complete activity entries as soon as someone posts a new activity.&amp;#160; The latency in this scenario is half a round-trip to post the activity plus half a round-trip to receive the activity through your parked HTTP request to the notifications feed.&amp;#160; Since notifications, subscriptions, and activities all use in-memory stores, this should have quite good performance.&amp;#160; There are a number of issues with this technique that I’ll cover in a future blog post, but it is promising for near-real-time communications.&lt;/p&gt;  &lt;h3&gt;Sync bypasses update notifications&lt;/h3&gt;  &lt;p&gt;Sync appears to bypass notification of updated feed entries.&amp;#160; Specifically, if I subscribe to the MeshObjects feed on the local LOE, I am notified when sync from the cloud causes a MeshObject to be added or removed from the feed, but I am not notified if sync causes a MeshObject to be updated.&amp;#160; I haven’t experimented with other feed types, but the same issue might exist with feeds such as DataEntries.&lt;/p&gt;  &lt;h3&gt;Trigger support&lt;/h3&gt;  &lt;p&gt;You can use Create and Update &lt;a href=&quot;http://orand.blogspot.com/2009/01/exploring-live-framework-triggers.html&quot;&gt;triggers&lt;/a&gt; on subscriptions and queues.&amp;#160; Delete triggers aren’t persisted and therefore won’t work.&amp;#160; You might use this to POST a queue and create subscriptions for it in its PostCreateTrigger, saving a round trip.&amp;#160; Of course these subscriptions wouldn’t be tracked and managed by the SDK.&amp;#160; You could also create a MeshObject and add a subscription to it in the MeshObject’s PostCreateTrigger.&lt;/p&gt;  &lt;p&gt;Updating resources and feeds through Resource Scripts or triggers doesn’t bypass notifications.&lt;/p&gt;  &lt;h3&gt;Client vs. Cloud&lt;/h3&gt;  &lt;p&gt;The client LOE waits for data to sync to it from the cloud before notifying you of any changes.&amp;#160; This can take a while, so if you want quick notifications, be sure to subscribe to the cloud LOE, not the local LOE.&amp;#160; It would sure be nice if local subscriptions caused the local LOE to subscribe to the same resource in the cloud (if connected), taking advantage of push notifications to achieve the same latency for local subscriptions as if you were subscribed directly to the cloud LOE.&lt;/p&gt;  &lt;p&gt;It is probably stating the obvious at this point, but I think it’s worth noting that queues are one-way from cloud to client.&lt;/p&gt;  &lt;h3&gt;Notification delays&lt;/h3&gt;  &lt;p&gt;Although notifications are normally posted to queues immediately, it is possible for notifications to be delayed if there is a large backlog generated by lots of rapid updates to a subscribed resource or feed.&amp;#160; You might see a few updates trickle in, then 15 seconds later another batch of updates appears, and so on, for several minutes.&lt;/p&gt;  &lt;h3&gt;Device connectivity&lt;/h3&gt;  &lt;p&gt;Supposedly device connectivity uses the subscription and notification services under the hood as a signal channel for P2P session establishment.&amp;#160; It may be possible to see this in action and even participate in the process, but I haven’t explored this.&amp;#160; There must be a reason you can subscribe directly to individual MeshDevices, but I haven’t seen anything interesting pop up yet.&amp;#160; Check out George Moore’s description of &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/ee15fffc-e5b1-4033-94d6-1fa6e117913c&quot;&gt;P2P notifications and file sync&lt;/a&gt; for a fascinating scenario that I’m not sure is possible with the current CTP.&lt;/p&gt;  &lt;h3&gt;Other transports&lt;/h3&gt;  &lt;p&gt;Supposedly there is a TCP transport for receiving push notifications, but it doesn’t appear to be used or available at the moment.&amp;#160; This could be useful for chaining subscriptions from the local LOE to the cloud LOE (or other clients) while preserving an HTTP programming experience for developers.&lt;/p&gt;  &lt;h3&gt;The high-level programming model&lt;/h3&gt;  &lt;p&gt;If you have managed to read this far, you should now have a healthy appreciation for the services provided by the high-level programming model.&amp;#160; At this level, all we see is the ChangeNotificationReceived event on feeds, MeshObject, and MeshDevice.&amp;#160; You simply subscribe to this event on the appropriate object and your event handler will be called when entries are created (on feeds only of course), updated, and deleted.&lt;/p&gt;  &lt;p&gt;Here are some of the gory details it takes care of for you:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Queue creation &lt;/li&gt;    &lt;li&gt;Queue polling &lt;/li&gt;    &lt;li&gt;Updating the watermark &lt;/li&gt;    &lt;li&gt;Subscription creation &lt;/li&gt;    &lt;li&gt;Subscription renewal &lt;/li&gt;    &lt;li&gt;Recovering from queue loss &lt;/li&gt;    &lt;li&gt;Recovering from subscription loss &lt;/li&gt;    &lt;li&gt;Demuxing from notifications to event handlers &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Let’s dig into that last one a bit deeper.&amp;#160; If you use Reflector to examine how ChangeNotificationReceived works, you will see that each object subscribes to receive any and all notifications that arrive on the queue.&amp;#160; When these notifications are received, each object iterates through all notification entries, checking to see if the notification’s ResourceLink matches its own SelfLink.&amp;#160; If there is a match, the object raises the ChangeNotificationReceived event and stops iterating the notification list, effectively filtering out multiple notifications for itself that might have been received in a single response.&amp;#160; It appears that if the client’s LiveOperatingEnvironment is configured with AutoLoadRelationships, the object will then be reloaded, &lt;em&gt;after&lt;/em&gt; the event is raised, meaning that if you examine the object in your event handler, it may not contain the latest changes.&amp;#160; This is reported in the forums &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/c13dd892-c86e-4c2f-ad18-5eb894978c72&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/f8add781-7629-4b73-b93b-cdec3859a599&quot;&gt;here&lt;/a&gt; and is supposed to be fixed in the next release.&amp;#160; Those threads also mention a performance issue with notifications when using the Silverlight library that will be fixed in the next release.&lt;/p&gt;  &lt;h3&gt;Programming at the Resource level&lt;/h3&gt;  &lt;p&gt;As part of my explorations, I wrote a library called ResourceClient that makes it easier to work directly with Resources such as queues, subscriptions, and notifications.&amp;#160; Here’s a brief example of the syntax it enables.&lt;/p&gt;  &lt;div style=&quot;font-family: consolas; background: white; color: black; font-size: 10pt&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: blue&quot;&gt;using&lt;/span&gt; (&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt;&amp;#160;&lt;span style=&quot;color: #2b91af&quot;&gt;ResourceClientContext&lt;/span&gt;(username, password))&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;{&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; queue = &lt;span style=&quot;color: #2b91af&quot;&gt;Uris&lt;/span&gt;.&lt;span style=&quot;color: #2b91af&quot;&gt;Cloud&lt;/span&gt;.NotificationQueues.Post(&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;NotificationQueueResource&lt;/span&gt;());&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; queue.StartAutoPoll((notifications, context) =&amp;gt;&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;if&lt;/span&gt; (notifications.Entries.Count() &amp;gt; 0)&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;Console&lt;/span&gt;.WriteLine(notifications.ToAtomString());&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; });&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;Uris&lt;/span&gt;.&lt;span style=&quot;color: #2b91af&quot;&gt;Cloud&lt;/span&gt;.MeshObjects.Subscribe(queue);&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; mo = &lt;span style=&quot;color: #2b91af&quot;&gt;Uris&lt;/span&gt;.&lt;span style=&quot;color: #2b91af&quot;&gt;Cloud&lt;/span&gt;.MeshObjects.Post(&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;My Object&amp;quot;&lt;/span&gt;));&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeedsLink.Subscribe(queue);&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed = mo.DataFeedsLink.Post(&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;DataFeedResource&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;My Feed&amp;quot;&lt;/span&gt;));&lt;/pre&gt;    &lt;pre style=&quot;margin: 0px&quot;&gt;}&lt;/pre&gt; &lt;/div&gt;  &lt;p&gt;This code writes to the console Atom-formatted notifications for the new MeshObject and the new DataFeed.&amp;#160; I will cover the details of this library in another blog post.&amp;#160; For now I will just mention that in addition to being a generic resource-oriented API, it contains notification-specific helpers for automatic queue polling, manual polling, sending watermarks, subscribing, and dispatching to different event handlers for each subscription.&lt;/p&gt;  &lt;h3&gt;MeshNotificationPlayground sample app&lt;/h3&gt;  &lt;p&gt;I have written a little WPF app that demonstrates queues, subscriptions, notifications, and activities in action.&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;MeshNotificationPlayground&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3337539536/&quot;&gt;&lt;img border=&quot;0&quot; alt=&quot;MeshNotificationPlayground&quot; src=&quot;http://static.flickr.com/1032/3337539536_27a7bc0871.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;You can create a queue, poll it, copy the queue’s URL to the clipboard for pasting into Resource Browser, select a notification and send its watermark, select a MeshObject and subscribe to its Activities feed, and create new Activities for the selected object.&lt;/p&gt;  &lt;p&gt;Here are some things to try:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Poll an empty queue and see that the request returns after 25 to 30 seconds&lt;/li&gt;    &lt;li&gt;Poll the queue with the WPF app and Resource Browser at the same time, notice that they both wait, then cause a new notification and see that both requests return immediately&lt;/li&gt;    &lt;li&gt;Subscribe to multiple Activities feeds, create activities in each of them, and notice the resulting notifications have different ResourceLinks&lt;/li&gt;    &lt;li&gt;Send a watermark that isn’t the last watermark and see that the queue only empties up to the watermark you sent&lt;/li&gt;    &lt;li&gt;Wait 5 minutes and poll the queue to see an AllSubscriptionsLost notification&lt;/li&gt;    &lt;li&gt;After receiving AllSubscriptionsLost, create more activities for subscribed feeds and see that AllSubscriptionsLost’s watermark increases each time&lt;/li&gt;    &lt;li&gt;Click Refresh Activities List and watch MaxAge count down for each activity. Notice the random MaxAges.&amp;#160; When a maxAge reaches zero, the activity disappears.&amp;#160; See that this causes a new notification.&lt;/li&gt;    &lt;li&gt;Create more than 10 notifications and see that no more than 10 are returned.&amp;#160; Send the latest watermark, poll again, and see that the remaining notifications appear.&lt;/li&gt;    &lt;li&gt;Poll the queue repeatedly when it has multiple notifications and see that sometimes only 1 notification appears.&lt;/li&gt;    &lt;li&gt;Click Create Activity many times in a row and see that notifications for that Activities feed continue to trickle in several minutes later.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can download the code &lt;a href=&quot;http://orand.googlecode.com/files/MeshNotificationPlayground.zip&quot;&gt;here&lt;/a&gt;.&amp;#160; It includes and uses the ResourceClient library.&lt;/p&gt;  &lt;h3&gt;Comparison to iPhone’s Push Notifications&lt;/h3&gt;  &lt;p&gt;If for some reason your eyes haven’t glazed over yet, check out Viraj’s &lt;a href=&quot;http://crazyviraj.blogspot.com/2008/07/some-thoughts-on-apples-push.html&quot;&gt;analysis of the iPhone Push Notification Service&lt;/a&gt;.&amp;#160; If you read between the lines, this is a fascinating compare-and-contrast to Live Mesh’s notification solution, with Live Mesh being better in many ways.&amp;#160; It hints that Microsoft might imitate Apple and use notifications to mine usage metrics for apps.&lt;/p&gt;  &lt;p&gt;Apple’s solution is slightly more efficient in that it creates a single channel from the cloud to each device, whereas Live Framework currently requires each app to establish its own channel.&amp;#160; This could be solved by having apps subscribe to the local LOE using local queues which would then transparently chain the subscriptions and queues through a single channel to the cloud LOE.&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;Hopefully this helps clarify how you should expect notifications to behave in your apps, as well as providing ideas for more creative uses of the building block features of queues, notifications, and subscriptions.&amp;#160; I plan to follow up with more details on my ResourceClient library, and write up a feature request that combines the best parts of notifications and activities to enable better real-time communication between clients.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/4624006039762088753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/4624006039762088753' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/4624006039762088753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/4624006039762088753'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/03/exploring-live-framework-notifications.html' title='Exploring Live Framework Notifications'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-8951296151739270707</id><published>2009-02-21T23:44:00.001-09:00</published><updated>2009-03-08T15:08:38.222-08:00</updated><title type='text'>Exploring Live Framework Activities</title><content type='html'>&lt;p&gt;Live Framework has an interesting undocumented feature called Activities.&amp;#160; You can think of Activities as a more general-purpose, transient alternative to &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd199277.aspx&quot;&gt;News&lt;/a&gt; in the Mesh.&amp;#160; Currently the only resource for learning more about Activities is John Macintyre’s PDC session &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB34/&quot;&gt;Live Services: Notifications, Awareness, and Communications&lt;/a&gt;.&amp;#160; Some of the information in this post is from John’s presentation, but much of it comes from my own exploration.&lt;/p&gt;  &lt;h3&gt;What are Activities good for?&lt;/h3&gt;  &lt;p&gt;Unlike News, Activities aren’t necessarily meant to be displayed or used in a predefined way.&amp;#160; Live Mesh uses Activities to track transient state such as which users are online, which users are currently in a folder, and which users are currently using a particular app (more details on this later).&amp;#160; You can use Activities in your own apps to build features such as chat, remote control of apps, and near-real-time transmission of small messages (when used with notifications).&lt;/p&gt;  &lt;h3&gt;Where can you use Activities?&lt;/h3&gt;  &lt;p&gt;Only cloud LOE MeshObjects expose Activities feeds.&amp;#160; There is no Activities link from client LOE MeshObjects.&amp;#160; Technically ApplicationInstance also has an Activities feed, but in practice the ApplicationInstance Activities feed points to the Activities feed of the app’s MeshObject.&lt;/p&gt;  &lt;p&gt;An interesting side note is that ApplicationInstance is essentially the same resource as its MeshObject.&amp;#160; It shares the same entry id and contains a copy of all the MeshObject’s elements, plus a few more app-specific elements.&amp;#160; I assume these entries map to a single CoreObject under the hood.&lt;/p&gt;  &lt;h3&gt;What do Activities look like?&lt;/h3&gt;  &lt;p&gt;An Activity has the following interesting data elements:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;MemberLink (Uri) &lt;/li&gt;    &lt;li&gt;ActivityTime (DateTimeOffset) &lt;/li&gt;    &lt;li&gt;MaxAge (short int) &lt;/li&gt;    &lt;li&gt;Type (string) &lt;/li&gt;    &lt;li&gt;UserData (serialized object) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;MemberLink is created for you automatically and points to the parent MeshObject’s Member entry corresponding to the user who created the Activity.&amp;#160; You can’t create a MemberLink that points to a different user’s Member entry.&lt;/p&gt;  &lt;p&gt;ActivityTime is optional and is separate from the entry’s published and updated times.&amp;#160; You can specify any ActivityTime you want in the past or in the future, although you would typically set it to something like DateTimeOffset.UtcNow.&lt;/p&gt;  &lt;p&gt;MaxAge is the number of seconds until the Activity expires.&amp;#160; MaxAge is automatically generated for you.&lt;/p&gt;  &lt;p&gt;Type can contain anything you want.&amp;#160; Later we’ll see an example of how Live Mesh encodes user presence in Type.&lt;/p&gt;  &lt;p&gt;UserData is the same GetUserData/SetUserData extensibility point you find on MeshObject and DataEntry.&lt;/p&gt;  &lt;p&gt;The Title of an Activity is always blank, even if you try to supply one.&lt;/p&gt;  &lt;h3&gt;How do Activities behave?&lt;/h3&gt;  &lt;p&gt;The most interesting Activity behavior is the automatic expiration based on MaxAge.&amp;#160; When an Activity is created, a random MaxAge between 600 and 900 (between 10 and 15 minutes) is assigned.&amp;#160; This randomness is intended to smooth out the server load in the datacenter.&amp;#160; The same technique is used for Subscriptions.&amp;#160; See slide 11 of John’s presentation for an illustration of what happened before they started using random TTLs:&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;PatchTuesdayTtlBadness&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3298933046/&quot;&gt;&lt;img border=&quot;0&quot; alt=&quot;PatchTuesdayTtlBadness&quot; src=&quot;http://static.flickr.com/3367/3298933046_1bcc8fdbef.jpg&quot; width=&quot;399&quot; height=&quot;301&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Once an Activity has been created, its MaxAge value counts down to zero.&amp;#160; You can see the countdown happen as you poll the Activity or its feed.&amp;#160; When MaxAge reaches zero, the Activity entry automatically disappears from the feed.&amp;#160; The Activity actually hangs around for a few seconds while MaxAge is zero, and during this time the MaxAge element is missing from the entry.&lt;/p&gt;  &lt;p&gt;You can update an Activity entry which will reset its MaxAge to a new random value between 10 and 15 minutes.&amp;#160; Later we will see how Live Mesh user presence uses this technique.&lt;/p&gt;  &lt;p&gt;You can also delete an Activity immediately without waiting for MaxAge to expire if you so choose.&lt;/p&gt;  &lt;p&gt;Activity feeds are subscribable, so you can register to receive notifications as entries are added or removed.&amp;#160; Entries that are removed due to MaxAge reaching zero also trigger a notification.&amp;#160; I’m not sure if you will receive a notification if Activity state is lost due to unexpected server state loss (remember, Activities are in-memory only).&lt;/p&gt;  &lt;p&gt;Activity feeds are not extensible, meaning you can’t use ElementExtensions and AttributeExtensions.&amp;#160; As mentioned earlier they do support UserData which is hopefully sufficient for most scenarios.&lt;/p&gt;  &lt;p&gt;Activities support Create and Update triggers but not Delete triggers.&amp;#160; This is the same &lt;a href=&quot;http://orand.blogspot.com/2009/01/exploring-live-framework-triggers.html&quot;&gt;partial trigger support&lt;/a&gt; exhibited by Contacts.&lt;/p&gt;  &lt;p&gt;Earlier I mentioned you can’t create a MemberLink that points to a different user’s Member entry.&amp;#160; It turns out that you also can’t delete an Activity created by another user, even though you can delete your own Activities in the same feed.&amp;#160; That’s right, in this case it is possible to have different permissions on each item within a single feed!&amp;#160; So much for MeshObject being the most granular unit of permissioning… ;-)&lt;/p&gt;  &lt;p&gt;The OPTIONS verb and $metadata do not work for Activities.&lt;/p&gt;  &lt;h3&gt;What is the programming model?&lt;/h3&gt;  &lt;p&gt;Today, Activities are only exposed through the resource model as &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd157009.aspx&quot;&gt;MeshObjectActivityResource&lt;/a&gt;.&amp;#160; There is only an ActivitiesLink property on MeshObject, not an Activities collection, and there is no LiveItem-based Activity object.&lt;/p&gt;  &lt;p&gt;Actually, that’s only true for the .NET and Silverlight SDKs.&amp;#160; The JavaScript SDK has a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd138755.aspx&quot;&gt;MeshObjectActivity&lt;/a&gt; class and MeshObject has an &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd138805.aspx&quot;&gt;Activities property&lt;/a&gt;, but I haven’t used the JavaScript SDK.&lt;/p&gt;  &lt;p&gt;For now, using Activities from .NET or Silverlight requires using AtomPubClient, Resource Scripts, or raw HTTP.&lt;/p&gt;  &lt;p&gt;I’m guessing Activities aren’t yet exposed through the high-level programming model because of the additional complexity of MaxAge expiration, automatically handling MaxAge resets, and the possibility of wrapping Activities in a scenario-specific programming model for user presence.&lt;/p&gt;  &lt;h3&gt;Behind the scenes&lt;/h3&gt;  &lt;p&gt;The Mesh is composed of a variety of services spread across many servers in the data center.&amp;#160; Some of these services use reliable state stores and others use soft state stores.&lt;/p&gt;  &lt;p&gt;Reliable state includes the Accounts store (accounts.developer.mesh-ctp.com), user-data structured storage (storage.developer.mesh-ctp.com), and user-data blob storage (enclosure.developer.mesh-ctp.com).&lt;/p&gt;  &lt;p&gt;Soft state includes storage for device presence, notification queues, subscriptions, activities, and dictionary state for the Live Desktop.&amp;#160; You can see most of these on slide 21 from &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB06/&quot;&gt;Abolade’s PDC session&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;MeshServicesDeployment&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3297604729/&quot;&gt;&lt;img border=&quot;0&quot; alt=&quot;MeshServicesDeployment&quot; src=&quot;http://static.flickr.com/3303/3297604729_93ff28b34a.jpg&quot; width=&quot;397&quot; height=&quot;304&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The design of the Activity Service is similar to the notification and subscription services.&amp;#160; This means the Activity Service uses only in-memory tables for high performance, so state loss is a possibility.&amp;#160; Therefore you shouldn’t use Activities for any state that you can’t afford to lose.&amp;#160; On the bright side, the high performance in-memory design of Activities fits together quite nicely with notifications and subscriptions.&lt;/p&gt;  &lt;p&gt;&lt;s&gt;The client LOE doesn’t appear to implement any of the soft state stores at this time.&amp;#160; This is probably why client LOE MeshObjects don’t have an Activities link.&lt;/s&gt; &lt;b&gt;Update:&lt;/b&gt; The client LOE implements Notifications and Subscriptions, although they behave slightly differently from the cloud LOE.  However, the client LOE still doesn&#39;t implement Activities.&lt;/p&gt;  &lt;h3&gt;How does Live Mesh use Activities?&lt;/h3&gt;  &lt;p&gt;One way Live Mesh uses Activities is to track which users are currently in a Live Folder.&amp;#160; Here’s an example of such an activity:&lt;/p&gt;  &lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;...&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;2009-02-21T08:27:15Z&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;updated&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;2009-02-21T08:27:15Z&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;updated&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;strong&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;LiveFX/Member&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;LiveFX/Member&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Mesh/MeshObjects/.../Members/...&amp;quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;self&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;self&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Mesh/MeshObjects/.../Activities/...-...&amp;quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;edit&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;edit&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Mesh/MeshObjects/.../Activities/...-...&amp;quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;term&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Activity&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Activity&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;scheme&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;http://user.windows.net/Resource&amp;quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;application/xml&amp;quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ActivityContent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;UserDataBuffer&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;UserDataBuffer&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;strong&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ActivityTime&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;2009-02-21T08:27:13Z&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ActivityTime&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;MaxAge&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;539&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;MaxAge&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;strong&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;UserActivity:Type[Presence];LiveFolderId[::{4ba12b8a-865f-4f52-99a4-12901be64d54}];&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ActivityContent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt; &lt;p&gt;The important pieces of information are the link to the user who is in the folder, the ActivityTime when they opened the folder, and UserActivity encoded in the Type field.&amp;#160; LiveFolderId is the entry id of the folder’s MeshObject.&amp;#160; Type[Presence] implies that other user activity types are probably tracked using the same format.&lt;/p&gt;  &lt;p&gt;If you open a folder on the Live Desktop and watch the corresponding Activity entry, you will see that the Live Desktop does a PUT to reset the MaxAge when 15 seconds are left.&amp;#160; All of the other entry details such as ActivityTime remain unchanged.&lt;/p&gt;  &lt;p&gt;If you close the folder, the Activity entry is deleted immediately without waiting for MaxAge to expire.&lt;/p&gt;  &lt;p&gt;It turns out that anything that has a Mesh companion bar tracks user presence activity.&amp;#160; This means that Mesh-Enabled Web Applications also get this same behavior for free.&amp;#160; In this case the UserActivity’s LiveFolderId is the entry id of the app’s MeshObject.&lt;/p&gt;  &lt;p&gt;The Activity’s Member link is used by the Mesh companion bar to display an orange box next to users who are currently in the folder or app.&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;MeshBarPresence&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3299750312/&quot;&gt;&lt;img border=&quot;0&quot; alt=&quot;MeshBarPresence&quot; src=&quot;http://static.flickr.com/3434/3299750312_cf1de64b33.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In this case you can see that I am playing Collaborative Crossword all by myself.&amp;#160; Apparently Ray doesn’t have time for me anymore. ;-)&lt;/p&gt;  &lt;p&gt;There is nothing stopping you from creating an Activity that makes another user believe you are in a folder or app when you’re not, although you would have to periodically update the Activity to continue to appear present.&amp;#160; So if you must be present to spoof your presence, how much are you really spoofing?&amp;#160; Hmm…&amp;#160; It may also be possible to delete Activities to hide the fact that you’re in a folder or app, although I assume the Activity will eventually be recreated.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;You would think that user presence should be determined by the combination of the Member link &lt;em&gt;and &lt;/em&gt;the specially formatted Type field’s Presence and LiveFolderId, but it turns out that all you need to do to appear present is create any Activity whatsoever in a MeshObject’s Activities feed.&lt;/p&gt;  &lt;h3&gt;Source Code&lt;/h3&gt;  &lt;p&gt;I have source code that demonstrates much of what I’ve described, but it is part of a larger project that also demonstrates notifications and subscriptions, so I will publish the source with my &lt;a href=&quot;http://orand.blogspot.com/2009/03/exploring-live-framework-notifications.html&quot;&gt;notifications and subscriptions blog post&lt;/a&gt;.&amp;#160; If you were surprised by how much there is to know about activities, just wait until you see notifications and subscriptions!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/8951296151739270707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/8951296151739270707' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/8951296151739270707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/8951296151739270707'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/02/exploring-live-framework-activities.html' title='Exploring Live Framework Activities'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-6135202084190288332</id><published>2009-02-16T14:33:00.001-09:00</published><updated>2009-02-28T14:05:58.728-09:00</updated><title type='text'>Mesh4Linux</title><content type='html'>&lt;p&gt;Last week my eyes lit up when I saw the following tweet from Miguel de Icaza, leader of the Mono project.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href=&quot;http://twitter.com/migueldeicaza&quot;&gt;&lt;img style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px&quot; border=&quot;0&quot; alt=&quot;Avatar_bigger&quot; align=&quot;left&quot; src=&quot;http://s3.amazonaws.com/twitter_production/profile_images/26491162/avatar_bigger.jpg&quot; width=&quot;64&quot; height=&quot;64&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://twitter.com/migueldeicaza&quot;&gt;migueldeicaza&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;Miguel de Icaza&lt;/p&gt;    &lt;p&gt;RT: @&lt;a href=&quot;http://twitter.com/bradyanderson&quot;&gt;bradyanderson&lt;/a&gt;:is trying to authenticate my Linux Live Operating Environment using Windows Live Delegated authentication (Mesh4Linux) &lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/migueldeicaza/status/1200964093&quot;&gt;4:21 PM Feb 11th&lt;/a&gt; from web&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I immediately tried to find out more, but this is the only mention of “Mesh4Linux” I could find on the web.&amp;#160; &lt;a href=&quot;http://bradynerdona.blogspot.com/&quot;&gt;Brady&lt;/a&gt; is a &lt;a href=&quot;http://www.novell.com/company/bios/des.html&quot;&gt;distinguished engineer&lt;/a&gt; at Novell who works on the Mono project.&amp;#160; I checked out his tweets, and he’s been talking about building a Live Mesh / Live Framework implementation for Linux ever since PDC.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson&quot;&gt;&lt;img style=&quot;border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; border=&quot;0&quot; alt=&quot;Photo_16_bigger&quot; src=&quot;http://s3.amazonaws.com/twitter_production/profile_images/56629183/Photo_16_bigger.jpg&quot; width=&quot;65&quot; height=&quot;65&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://twitter.com/bradyanderson&quot;&gt;bradyanderson&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;is attending the &amp;quot;What I learned building My first live mesh app&amp;quot; session at #pdc2008&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/979412436&quot;&gt;11:35 AM Oct 28th, 2008&lt;/a&gt; from &lt;a href=&quot;http://iconfactory.com/software/twitterrific&quot;&gt;twitterrific&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;is excited to start hacking on a Live Operating Environment for the Linux Desktop. Opens the door for some amazing applications&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/981226348&quot;&gt;2:04 PM Oct 29th, 2008&lt;/a&gt; from &lt;a href=&quot;http://iconfactory.com/software/twitterrific&quot;&gt;twitterrific&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;created his first MeshObject on Linux! Now DataFeed, DataEntry, Membership.... bows his head and goes away quietly&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1050042409&quot;&gt;1:02 PM Dec 10th, 2008&lt;/a&gt; from &lt;a href=&quot;http://iconfactory.com/software/twitterrific&quot;&gt;twitterrific&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;just implemented DataFeed creation and Mesh/MeshObject enumeration&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1052457719&quot;&gt;4:06 PM Dec 11th, 2008&lt;/a&gt; from &lt;a href=&quot;http://iconfactory.com/software/twitterrific&quot;&gt;twitterrific&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;&amp;quot;is hoping this is the first twitter message pushed from the sync framework (2)&amp;quot;&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1153600212&quot;&gt;2:18 PM Jan 27th&lt;/a&gt; from web&lt;/p&gt;    &lt;p&gt;is researching Differential Synchronization algorithms&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1156119736&quot;&gt;10:04 AM Jan 28th&lt;/a&gt; from &lt;a href=&quot;http://iconfactory.com/software/twitterrific&quot;&gt;twitterrific&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;is catching up on the latest Live Mesh developments. I can&#39;t seem to find the January tools update :-(&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1199594564&quot;&gt;8:11 AM Feb 11th&lt;/a&gt; from web&lt;/p&gt;    &lt;p&gt;is trying to authenticate my Linux Live Operating Environment using Windows Live Delegated authentication - getting closer.&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1200894633&quot;&gt;2:55 PM Feb 11th&lt;/a&gt; from web&lt;/p&gt;    &lt;p&gt;the CTP versions of Live Mesh and Azure Services are so slow they&#39;re barely usable. *screams profanities*&lt;/p&gt;    &lt;p&gt;&lt;a href=&quot;http://twitter.com/bradyanderson/status/1200934107&quot;&gt;3:10 PM Feb 11th&lt;/a&gt; from web&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I’m guessing Brady is the guy Ori Amiga is referring to in the following quote from &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB19/&quot;&gt;this PDC session&lt;/a&gt; (15:50 onwards):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;The whole point I wanted to make, it&#39;s just plain good old HTTP, and if you can talk that, every device, programming language, stack is welcome to the party. &lt;/p&gt;    &lt;p&gt;&lt;strong&gt;Some guy walked up to me after the stage yesterday, if you&#39;re here I&#39;d love to keep chatting with you, said man I want to write Live Operating Environment for Linux. Can I do that?&amp;#160; I was like, hell yeah, we&#39;ll hire you, come write it even in-house if you want to. &lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;But really the idea is the Mesh will never be, I can&#39;t imagine we&#39;ll be successful in making people&#39;s lives better if we only stick to a Microsoft stack.&amp;#160; That makes no sense.&amp;#160; let&#39;s say, I&#39;d admit, most of my devices at home and my receivers, my TVs, all the media stuff we have, the car, they don&#39;t run Windows, and that&#39;s ok, there&#39;s nothing wrong with that. It&#39;s great that my Windows devices are gonna behave really well in the Mesh, but I&#39;d love for everything else that&#39;s sort of net connected to behave that way as well.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;It is worth noting that Ori Amiga, a Principal Group Program Manager on the Live Mesh team, has &lt;a href=&quot;http://channel9.msdn.com/posts/Charles/Ori-Amiga-Mesh-Mobile/&quot;&gt;built multiple carputers&lt;/a&gt;, one using Linux and another using Live Mesh.&lt;/p&gt;  &lt;p&gt;I pinged Brady and Miguel for details on Mesh4Linux but haven’t heard back yet.&amp;#160; There appears to be no connection to &lt;a href=&quot;http://code.google.com/p/mesh4x/&quot;&gt;Mesh4x&lt;/a&gt;, another open source project with many similarities to Live Mesh, including FeedSync support.&lt;/p&gt;  &lt;p&gt;Mesh4Linux is in the early stages at this point, but I’m already dreaming of the possibilities it will enable not just on Linux desktops but on the &lt;a href=&quot;http://www.mono-project.com/Mono:Iphone&quot;&gt;iPhone&lt;/a&gt;, &lt;a href=&quot;http://tirania.org/blog/archive/2009/Feb-16.html&quot;&gt;Google Android phones&lt;/a&gt;, and embedded devices such as carputers.&amp;#160; Go Brady!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2/28/09 Update:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://www.hanselman.com/blog/&quot;&gt;Scott Hanselman&lt;/a&gt; used &lt;a href=&quot;http://www.kyte.tv&quot;&gt;kyte&lt;/a&gt; to live stream Miguel’s &lt;a href=&quot;http://www.kyte.tv/ch/240253-shanselman/361163-mono-on-iphone&quot;&gt;Mono on iPhone session&lt;/a&gt; at the Alt.NET conference in Seattle.&amp;#160; Via the online comments, I asked about Mesh4Linux (as well as Miguel’s &lt;strike&gt;communist C#&lt;/strike&gt; &lt;a href=&quot;http://www.zazzle.com/turkey_crescent_tshirt-235665137990346334&quot;&gt;Turkish flag t-shirt&lt;/a&gt;).&amp;#160; Scott got a chance to ask Miguel about Mesh4Linux at the end (50:08) right after Miguel mentioned the benefits of sync for disconnected scenarios:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;SH: What about Mesh4Linux?&lt;/p&gt;    &lt;p&gt;MdI: There is no Mesh4Linux as far as I know.&amp;#160; I know there is an engineer at Novell who &lt;em&gt;wants&lt;/em&gt; Mesh4Linux.&lt;/p&gt;    &lt;p&gt;SH: So it’s a dream, not a project.&lt;/p&gt;    &lt;p&gt;MdI: Yes.&lt;/p&gt;&lt;/blockquote&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/6135202084190288332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/6135202084190288332' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/6135202084190288332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/6135202084190288332'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/02/mesh4linux.html' title='Mesh4Linux'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-951109570692916186</id><published>2009-01-15T16:53:00.001-09:00</published><updated>2009-02-14T09:24:14.236-09:00</updated><title type='text'>Exploring Live Framework Triggers</title><content type='html'>&lt;p&gt;The &lt;a href=&quot;http://dev.live.com/liveframework/&quot;&gt;Live Framework&lt;/a&gt; has the ability to add triggers to resources.&amp;#160; There is some documentation on triggers &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd217759.aspx&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://dev.live.com/liveframework/liveframeworkresourcescripts.pdf&quot;&gt;here&lt;/a&gt; (pgs. 14-15), but after reading it I was left with more questions than answers.&amp;#160; So I took a deep dive exploring the nooks and crannies of triggers and this blog post is the result.&lt;/p&gt; &lt;h3&gt;Overview of triggers&lt;/h3&gt; &lt;p&gt;Triggers are scripts that can be executed before and after resources are created, updated, and deleted.&amp;#160; The scripts are written using Resource Scripts (AKA MeshScripts), a tiny DSL for working with AtomPub and FeedSync in Live Mesh.&amp;#160; Think of it as the T-SQL of Live Mesh.&amp;#160; MeshScripts be used as sprocs as well as triggers, but I’ll be focusing on triggers in this post.&amp;#160; See my &lt;a href=&quot;http://orand.blogspot.com/2008/12/fluent-livefx-resource-scripts.html&quot;&gt;previous&lt;/a&gt; &lt;a href=&quot;http://orand.blogspot.com/2009/01/meshscript-queries-liveitems-and-magic.html&quot;&gt;posts&lt;/a&gt; for examples of sproc-style usage.&lt;/p&gt; &lt;p&gt;There are six triggers that can be attached to each resource:&lt;/p&gt; &lt;ul&gt;   &lt;li&gt;PreCreateTrigger &lt;/li&gt;   &lt;li&gt;PostCreateTrigger &lt;/li&gt;   &lt;li&gt;PreUpdateTrigger &lt;/li&gt;   &lt;li&gt;PostUpdateTrigger &lt;/li&gt;   &lt;li&gt;PreDeleteTrigger &lt;/li&gt;   &lt;li&gt;PostDeleteTrigger &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;The Create triggers run before and after each HTTP POST of a resource, the Update triggers run before and after each HTTP PUT of a resource, and the Delete triggers run before and after each HTTP DELETE of a resource.&amp;#160; This enables you to pack quite a bit of custom business logic inside a single call to the server.&lt;/p&gt; &lt;h3&gt;Trigger parameters&lt;/h3&gt; &lt;p&gt;The resource that you’re creating, updating, or deleting is accessible from inside each trigger as a script parameter.&amp;#160; For Create and Update triggers, the parameter is the actual resource sent from the client to the server in the POST or PUT request.&amp;#160; For Delete triggers, the parameter is the server’s version of the resource being deleted since a resource isn’t sent from the client to the server for delete requests (the client simply specifies the URL of the resource to delete).&lt;/p&gt; &lt;p&gt;Three steps are necessary to use a script parameter:&lt;/p&gt; &lt;ol&gt;   &lt;li&gt;Define the parameter &lt;/li&gt;   &lt;li&gt;Bind to the parameter from one or more statements &lt;/li&gt;   &lt;li&gt;Add the parameter to the script’s root statement &lt;/li&gt; &lt;/ol&gt; &lt;p&gt;Here’s what this looks like using the syntax I created in my &lt;a href=&quot;http://orand.blogspot.com/2008/12/fluent-livefx-resource-scripts.html&quot;&gt;helper library&lt;/a&gt;.&amp;#160; I’ve bolded the three steps.&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; param = &lt;/strong&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;strong&gt;    &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.ResourceParameter&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;();&lt;/strong&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;mo.Resource.Triggers.PostCreateTrigger = &lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.Sequence(&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource(news)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .Bind(s =&amp;gt; s.CollectionUrl, &lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; param, p =&amp;gt; p.NewsFeedLink)&lt;/strong&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .Bind(s =&amp;gt; s.Request.Title, &lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; param, p =&amp;gt; p.Title)&lt;/strong&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; )&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160; .AddParameters(param)&lt;/strong&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Compile();&lt;/pre&gt; &lt;/div&gt; &lt;p&gt;&lt;br/&gt;The script snippet above adds a news entry to the news feed of the MeshObject you are creating (after it has been created, of course).&amp;#160; You can see this code in the context of a working sample in the download at the end of this post.&amp;#160; The sample also shows the equivalent “classic” syntax for the same trigger script.&lt;/p&gt; &lt;p&gt;Parameters are optional.&amp;#160; If you don’t need to access the original resource from your trigger script then you can safely omit all three steps and simply create a trigger script without any parameters.&lt;/p&gt; &lt;p&gt;There is only one actual resource parameter per script.&amp;#160; If you add more than one to the script, they are all treated as the same parameter.&amp;#160; This makes sense since all resource parameters are named “$Resource” under the hood.&lt;/p&gt; &lt;p&gt;There is another kind of script parameter called the ConstantParameter that lets you specify a name for the parameter, thus letting you to have more than one of them per script, but I have been unable to get ConstantParameters to work so we’ll ignore them for now.&amp;#160; I’m guessing they are used for looping statements which aren’t available in the current CTP.&lt;/p&gt; &lt;h3&gt;Create/Update triggers&lt;/h3&gt; &lt;p&gt;Create and Update triggers share many similarities, so I will cover them together.&lt;/p&gt; &lt;p&gt;Create and Update triggers are a one-shot deal.&amp;#160; You must attach new Create or Update triggers each time you Add() or Update() the resource.&amp;#160; Only the triggers appropriate for the HTTP verb are used.&amp;#160; So for POST, the Create triggers are executed but the Update triggers are silently tossed, and for PUT, the Update triggers are executed and the Create triggers are tossed.&amp;#160; By “tossed” I mean they aren’t executed, and the trigger is set to null in the response you get back.&lt;/p&gt; &lt;p&gt;In case it’s not clear, Create and Update triggers are not persisted on the server.&amp;#160; They only exist for the duration of the HTTP request/response.&lt;/p&gt; &lt;p&gt;Unlike sproc-style MeshScripts, the trigger script’s Source property becomes null after the script has executed.&amp;#160; At first I thought this was a bug, but then I realized that this was necessary so that if you then proceeded to call Update() on the item it wouldn’t re-run the same trigger again.&lt;/p&gt; &lt;p&gt;Just like sproc-style scripts, Create and Update triggers return the results of script execution in the Result property of the trigger script which you can inspect for details.&amp;#160; Use them immediately or lose them because they won’t stick around for subsequent requests.&lt;/p&gt; &lt;h3&gt;Original vs. updated values&lt;/h3&gt; &lt;p&gt;The script parameter for Update triggers contains the updated resource being PUT by the client.&amp;#160; If you need access to the original value that will be replaced by the PUT, you can access it in the PreUpdateTrigger using the following code, replacing MeshObjectResource with the appropriate resource type:&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;originalValue = &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.ReadResource&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;()&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Bind(s =&amp;gt; s.EntryUrl, param, p =&amp;gt; p.SelfLink)&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;You can then bind to originalValue in subsequent statements.&amp;#160; Note that “param” in the sample is the trigger script’s resource parameter.&lt;/p&gt; &lt;h3&gt;Delete triggers&lt;/h3&gt; &lt;p&gt;Only Delete triggers have a non-null Source property after a POST or a PUT.&amp;#160; This is because only Delete triggers are persisted along with the resource on the server.&amp;#160; Delete triggers can be added to a resource using either POST or PUT.&amp;#160; Since Delete triggers are round-tripped (the Source doesn’t become null in the response), you don’t need to remember to re-add them on subsequent updates, unlike Update triggers.&amp;#160; However, they &lt;em&gt;are &lt;/em&gt;re-persisted each time you do an update.&amp;#160; This means that you can remove a Delete trigger by setting it to null and calling Update().&lt;/p&gt; &lt;p&gt;Delete triggers are executed when you perform an HTTP DELETE on the URL of a resource that already has a Delete trigger added to it by a previous operation.&amp;#160; Since no actual resource is posted or returned by the DELETE operation, there is no way to examine the script results or learn about errors.&lt;/p&gt; &lt;h3&gt;How triggers deal with errors&lt;/h3&gt; &lt;p&gt;They don’t. :-)&amp;#160; To be more precise, errors are simply ignored.&amp;#160; They don’t cancel the POST/PUT/DELETE operation.&amp;#160; Similar to sproc-style scripts, no script Result is returned to the client if an error occurs.&amp;#160; Unlike sproc-style scripts, the error is &lt;em&gt;not&lt;/em&gt; returned to the client.&lt;/p&gt; &lt;h3&gt;Transactions&lt;/h3&gt; &lt;p&gt;While we’re on the subject of sproc-style scripts, it should be noted that sproc-style scripts are not transactional, and trigger-style scripts aren’t transactional either.&amp;#160; Sure, they may execute within the scope of a single HTTP request/response “transaction” but there is no rollback on failure.&amp;#160; Future releases are expected to include compensation/undo support.&lt;/p&gt; &lt;h3&gt;Comparison to SQL triggers&lt;/h3&gt; &lt;p&gt;Various databases support statement-level triggers and row-level triggers.&amp;#160; Statement-level triggers are executed once for a batch of rows resulting from a single statement, while row-level triggers are executed once for each row.&amp;#160; Statement-level triggers and row-level triggers attached to each table in the database.&lt;/p&gt; &lt;p&gt;While Live Framework triggers can inspect data “per row,” the triggers are actually attached &lt;em&gt;to&lt;/em&gt; each “row,” not to each “table.”&amp;#160; And as you already know, only Delete triggers actually &lt;em&gt;remain &lt;/em&gt;attached to the “row.”&lt;/p&gt; &lt;p&gt;This means that it isn’t possible to put triggers on feeds (the equivalent of tables) that fire when entries are added, updated, or removed from the feed.&lt;/p&gt; &lt;p&gt;And as I explain in the next section, you can’t currently modify the incoming data before it is added or updated, unlike with SQL triggers.&lt;/p&gt; &lt;h3&gt;Parameters are read-only (I think…)&lt;/h3&gt; &lt;p&gt;At first I was under the impression that the incoming POST/PUT data exposed in the parameter to the PreCreate and PreUpdate triggers could be modified and the modified values would be passed along to the actual POST or PUT operation.&amp;#160; I made this assumption based on the following quote from page 15 of &lt;a href=&quot;http://dev.live.com/liveframework/liveframeworkresourcescripts.pdf&quot;&gt;this document&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt;   &lt;p&gt;&amp;quot;The output of the PreCreateTrigger can be data-bound to the actual POST request entity and the data is propagated dynamically in the request pipeline. Similarly, the response entity of the POST operation can be data bound to the PostCreateTrigger. A similar binding can be done using the PreUpdateTrigger to the request entity of the PUT operation and the response of the PUT operation and the PostUpdateTrigger. Note that such a model to flow the data dynamically between the PostDeleteTrigger script and the response entity is not applicable to the DELETE operation since we do not return response entity in the DELETE operation.&amp;quot;&lt;/p&gt; &lt;/blockquote&gt; &lt;p&gt;This sounds promising, but unfortunately I have been unable to find a way to update the script parameter.&lt;/p&gt; &lt;p&gt;The problem is that I can’t find a way to bind &lt;em&gt;to&lt;/em&gt; the resource parameter.&amp;#160; The resource parameter is exposed as a StatementParameter, not as a Statement.&amp;#160; All of the Bind() methods that take a StatementParameter have the parameter on the right-hand-side.&amp;#160; This means that you can assign &lt;em&gt;from&lt;/em&gt; a resource parameter, but you can’t assign &lt;em&gt;to&lt;/em&gt; it.&lt;/p&gt; &lt;p&gt;So I tried binding to “Parameters[0].Value” on the root statement of the script, but that didn’t work.&amp;#160; Then I tried binding to the parameter using its secret “$Resource” name, but that didn’t work either.&lt;/p&gt; &lt;p&gt;Perhaps someone forgot to add the appropriate Bind() overload, or perhaps there’s another way to get at the parameter that I’m not thinking of.&amp;#160; But until this is sorted out, parameters are read-only, at least on my box.&lt;/p&gt; &lt;p&gt;Once parameters can be modified, it will be interesting to see if you can completely replace the parameter (even set it to null?), or only update properties on it.&amp;#160; It will also be interesting to see if you can delete the resource in the PostCreate trigger and return a completely different resource to the client.&amp;#160; This could be a useful technique for creating &lt;a href=&quot;http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2009/01/02/live-framework-sdk-having-a-single-meshobject.aspx&quot;&gt;singleton Mesh objects&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Triggers and the local LOE&lt;/h3&gt; &lt;p&gt;Triggers don’t work at all if you’re connecting to the local client LOE.&amp;#160; If you add triggers to a resource and then Add() or Update() it, the resource comes back with all its triggers set to null.&amp;#160; This makes sense because the ability to execute scripts inside the client LOE is expected to be added in a later release.&lt;/p&gt; &lt;p&gt;But not even the Delete triggers are persisted and propagated up to the server.&amp;#160; It turns out that Delete triggers also don’t propagate from the server down to the client.&amp;#160; This made me nervous, wondering what will happen if I update a client-side resource that has a server-side Delete trigger.&amp;#160; Will the absence of a client-side trigger clobber the server-side trigger?&amp;#160; Thankfully the server properly merges the client-side update with the server-side resource’s Delete triggers.&amp;#160; Must be some FeedSync magic.&lt;/p&gt; &lt;p&gt;Then I tried deleting a resource on the client that had server-side Delete triggers.&amp;#160; The resource was successfully removed on the server, but the server-side triggers failed to execute!&amp;#160; So synchronization bypasses triggers.&lt;/p&gt; &lt;h3&gt;Speculation regarding client script execution&lt;/h3&gt; &lt;p&gt;Once client script execution is added in a future release, how will this probably change the situation?&lt;/p&gt; &lt;p&gt;Create/Update triggers will run on the client if you connect via ConnectLocal().&lt;/p&gt; &lt;p&gt;Assuming synchronization of Delete triggers is fixed, you will be able to add Delete triggers on either the client or the server.&amp;#160; If you delete the resource via Connect(), the trigger will run on the server.&amp;#160; If you delete via ConnectLocal(), the trigger will run on the client.&lt;/p&gt; &lt;p&gt;But what if you want a trigger to always run on the server?&amp;#160; Perhaps the trigger accesses external resources that you are unable to access while the client is offline.&amp;#160; Or perhaps the trigger accesses resources that aren’t synced to the client such as Contacts, Profiles, or MeshObjects that aren’t mapped to that particular device.&amp;#160; Perhaps there could be a client-side queue of pending triggers that are synchronized up to the server?&lt;/p&gt; &lt;h3&gt;Creating triggers inside of scripts&lt;/h3&gt; &lt;p&gt;Officially, you can’t add triggers to resources from inside of scripts.&amp;#160; If you try, you will get the following error message: “Trigger can not be associated with a resource which is being modified using meshscripts.”&amp;#160; Hey, look!&amp;#160; They said MeshScripts!&amp;#160; Personally, I think that’s a far better name than Live Framework Resource Scripts, as you can tell from the titles of my previous blog posts. :-)&lt;/p&gt; &lt;p&gt;Anyway, it &lt;em&gt;is&lt;/em&gt; possible to add Delete triggers to resources from inside of a script.&amp;#160; The trick is that you must copy them from a pre-existing resource, like so:&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.Sequence(&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; originalCollection = &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.ReadResourceCollection&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;(&lt;span style=&quot;color: #2b91af&quot;&gt;ScriptHelper&lt;/span&gt;.MeshObjectsUrl)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .WithQuery&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;, &lt;span style=&quot;color: #2b91af&quot;&gt;MeshObject&lt;/span&gt;&amp;gt;(&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; q =&amp;gt; q.Where(o =&amp;gt; o.Resource.Title.StartsWith(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;Original&amp;quot;&lt;/span&gt;))),&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource(&lt;span style=&quot;color: #2b91af&quot;&gt;ScriptHelper&lt;/span&gt;.MeshObjectsUrl, &lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;I have delete triggers&amp;quot;&lt;/span&gt;))&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Bind(s =&amp;gt; s.Request.Triggers.PreDeleteTrigger, &lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; originalCollection, c =&amp;gt; c.Response.Entries[0].Triggers.PreDeleteTrigger)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Bind(s =&amp;gt; s.Request.Triggers.PostDeleteTrigger, &lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; originalCollection, c =&amp;gt; c.Response.Entries[0].Triggers.PostDeleteTrigger)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;).Compile().RunAtServer();&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;Technically, you can use this technique to add Create and Update triggers too.&amp;#160; This can be verified by inspecting the the script result and seeing that the resource was returned with Create and Update triggers containing the Source script that you specified.&amp;#160; However, these triggers don’t run.&amp;#160; Why not?&lt;/p&gt; &lt;h3&gt;Scripts bypass trigger execution&lt;/h3&gt; &lt;p&gt;Just as synchronization bypasses trigger execution, scripts also bypass trigger execution.&amp;#160; This is why our Create and Update triggers were added but didn’t run.&lt;/p&gt; &lt;p&gt;What happens if we use a script to delete a resource with Delete triggers on the server?&amp;#160; The script deletes the resource without running its triggers.&lt;/p&gt; &lt;h3&gt;Consequences of bypassing triggers&lt;/h3&gt; &lt;p&gt;If you choose to use Delete triggers, you must be careful to do all of your Delete operations through direct HTTP DELETE calls to the server.&amp;#160; Don’t use ConnectLocal(), and don’t use MeshScripts to delete resources.&lt;/p&gt; &lt;p&gt;This loophole could be useful in “oops” situations where you don’t want the triggers to run.&lt;/p&gt; &lt;p&gt;The bigger issue here is that you can’t reliably enforce server-side business logic.&amp;#160; I spoke with Abolade about this after &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB06/&quot;&gt;his PDC session&lt;/a&gt; and he mentioned that perhaps the content screening hook points (used to block enclosures containing viruses and other inappropriate content) could be exposed to users for running custom business logic that is capable of rejecting content.&amp;#160; This could also be used to implement table-style triggers that are guaranteed to always run.&amp;#160; At first I thought this would be cool to have, but now I’m starting to think that such a server-centric feature isn’t an appropriate fit with the design philosophy of Mesh.&amp;#160; I may elaborate why in a future post.&lt;/p&gt; &lt;h3&gt;Triggers on non-Mesh objects&lt;/h3&gt; &lt;p&gt;Currently the root ServiceDocument at &lt;a title=&quot;https://user-ctp.windows.net/&quot; href=&quot;https://user-ctp.windows.net/&quot;&gt;https://user-ctp.windows.net/&lt;/a&gt; exposes Profiles and Contacts in addition to Mesh.&amp;#160; I think these are known as Federated Storage Services, but I’m not sure.&amp;#160; Contacts map out of the Mesh to your actual Hotmail contacts.&amp;#160; Anyway, you access /Profiles and /Contacts using the same resource-based programming model as the rest of /Mesh.&amp;#160; Anything that is a Resource can have triggers, so what happens if we add triggers to a Contact?&lt;/p&gt; &lt;p&gt;I added a new Contact containing Create and Delete triggers.&amp;#160; The Create triggers worked, but the Delete triggers weren’t persisted and therefore didn’t run when I deleted the Contact.&lt;/p&gt; &lt;p&gt;I’m guessing there’s a service integration layer that translates back and forth between Mesh’s resource-based programming model and external services.&amp;#160; The Contacts service probably doesn’t have a place to store arbitrary data such as triggers, so they get lost in translation.&amp;#160; But the Create and Update triggers can still run because they don’t need to be persisted anywhere, so they can live entirely in the world of Mesh’s resource-oriented request/response pipeline that wraps the calls to the Contacts service.&amp;#160; Hmm, maybe there are benefits to not having to persist triggers…&amp;#160; But it would also be nice to have a consistent programming model for Create, Update, &lt;em&gt;and &lt;/em&gt;Delete.&lt;/p&gt; &lt;h3&gt;Summary of limitations&lt;/h3&gt; &lt;p&gt;There are a number of limitations scattered throughout this blog post, so here’s a more concise list:&lt;/p&gt; &lt;ul&gt;   &lt;li&gt;Create and Update triggers aren’t persisted&lt;/li&gt;   &lt;li&gt;No row-level/statement-level triggers on feeds&lt;/li&gt;   &lt;li&gt;Trigger parameters are read-only (I think)&lt;/li&gt;   &lt;li&gt;Can’t add triggers from scripts&lt;/li&gt;   &lt;li&gt;Synchronization bypasses triggers&lt;/li&gt;   &lt;li&gt;Scripts bypass triggers&lt;/li&gt;   &lt;li&gt;Delete triggers don’t work on non-Mesh objects&lt;/li&gt;   &lt;li&gt;Local LOE doesn’t support triggers&lt;/li&gt;   &lt;li&gt;Triggers can’t reliably enforce business logic&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;Download&lt;/h3&gt; &lt;p&gt;You can download the sample code &lt;a href=&quot;http://orand.googlecode.com/files/FluentResourceScriptsV3.zip&quot;&gt;here&lt;/a&gt;.&amp;#160; The samples use my Fluent MeshScripts library with a few minor updates.&lt;/p&gt; &lt;p&gt;While writing this I discovered and fixed a bug in my library’s expression-to-string code when it encounters expressions such as “c =&amp;gt; c.Response.Entries[0].Triggers.PreDeleteTrigger”.&amp;#160;&amp;#160; I also created an AddParameters overload that takes an SResourceParameter&amp;lt;TResource&amp;gt;.&lt;/p&gt; &lt;p&gt;The code includes examples of using all the trigger types, creating a resource with triggers from a script, bypassing delete triggers with a script, triggers on Contacts, and the “can’t add triggers from meshscripts” error.&lt;/p&gt; &lt;h3&gt;Wrap-up&lt;/h3&gt; &lt;p&gt;Besides providing some detailed documentation and code samples for Live Framework triggers, hopefully this post has helped you think about scenarios where you might want to use them, as well as provided some pointers on when to avoid them or use them with care.&amp;#160; I also hope this can be used to improve the usability and functionality of this powerful feature of the Live Framework.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; it appears that triggers don&#39;t work on DataFeeds and DataEntries.  See Raviraj&#39;s post in &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/4a94b33c-5f05-4acb-a156-835353a9078c&quot;&gt;this forum thread&lt;/a&gt; for details.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/951109570692916186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/951109570692916186' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/951109570692916186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/951109570692916186'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/01/exploring-live-framework-triggers.html' title='Exploring Live Framework Triggers'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-425229986990485956</id><published>2009-01-07T16:32:00.001-09:00</published><updated>2009-01-07T16:32:01.139-09:00</updated><title type='text'>MeshScript Ideas for the Future</title><content type='html'>&lt;p&gt;In my &lt;a href=&quot;http://orand.blogspot.com/2009/01/meshscript-queries-liveitems-and-magic.html&quot;&gt;last post&lt;/a&gt; where I added LiveItem syntax to MeshScripts, I said I had some more ideas for MeshScripts.&amp;#160; Some of these ideas are very small, some are very big, and some are in between.&amp;#160; The reason I’m listing them here is that there’s no way I could get to even a fraction of them (I’d like to move on and explore other areas of Live Mesh), so hopefully they spark your imagination.&lt;/p&gt;  &lt;h3&gt;Enhancements for existing MeshScripts&lt;/h3&gt;  &lt;p&gt;These enhancements could be applied to MeshScripts without taking a dependency on the library I wrote.&lt;/p&gt;  &lt;h4&gt;Chunking and chaining&lt;/h4&gt;  &lt;p&gt;There is an upper limit on the number of statements the server will process in a single script.&amp;#160; It would be nice to implement automatic script chunking and chaining based on a configurable statement batch size.&amp;#160; For cross-batch bindings, outputs from one batch can be fed into inputs for the next batch.&amp;#160; Special care needs to be taken at CompoundStatement boundaries, especially with ConditionalStatement.&amp;#160; This could also be used to implement a progress indicator for large jobs while still preserving most of the performance benefits of batching.&lt;/p&gt;  &lt;h4&gt;Automatic parallelization option&lt;/h4&gt;  &lt;p&gt;I’m guessing most people are going to write their scripts using SequenceStatement as their CompoundStatement of choice.&amp;#160; It would be cool to have the option of automatically transforming and optimizing scripts by wrapping sections in InterleaveStatements where possible based on analysis of binding dependencies and URLs.&amp;#160; This ought to be a feature the user explicitly opts into.&lt;/p&gt;  &lt;h3&gt;Enhancements to Fluent MeshScripts library&lt;/h3&gt;  &lt;p&gt;These enhancements are specific to my Fluent MeshScripts library.&lt;/p&gt;  &lt;h4&gt;Use control flow MeshScript features&lt;/h4&gt;  &lt;p&gt;Note that ScriptContext’s record-replay model doesn’t need any “programmatic” script control flow features such as ConditionalStatement or the coming-soon LoopStatement.&amp;#160; Perhaps there’s an opportunity to add If/Else logic to the SLiveItem syntax.&amp;#160; This would require an expression tree visitor to touch up references to script statements since currently you must hard-code the statement ID/Name in the condition.&lt;/p&gt;  &lt;p&gt;A switch statement could be added that uses multiple ConditionalStatements under the hood.&lt;/p&gt;  &lt;p&gt;A similar sub-ScriptContext scoping solution could be used for generating InterleaveStatement sections.&lt;/p&gt;  &lt;p&gt;Until we get a real LoopStatement, a fake Loop statement could be created that unwraps the loop a specified number of times.&amp;#160; This could be used for scenarios such as copying the last 10 items from a Twitter feed into a Mesh feed.&lt;/p&gt;  &lt;h4&gt;Miscellaneous enhancements&lt;/h4&gt;  &lt;p&gt;Create a helper method that enables single-round-trip Live Folder creation that returns LiveItems.&lt;/p&gt;  &lt;p&gt;I haven’t investigated &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136803.aspx&quot;&gt;expansions&lt;/a&gt; yet, but it seems like there’s an opportunity to take advantage of them in MeshScripts, preferably with helper methods to simplify common scenarios, whatever those might be.&lt;/p&gt;  &lt;h3&gt;Taking MeshScripts in bold new directions&lt;/h3&gt;  &lt;p&gt;Here are some wild and crazy ideas that probably won’t come to pass, but wouldn’t they be cool?&lt;/p&gt;  &lt;h4&gt;Add batching to LiveItems&lt;/h4&gt;  &lt;p&gt;It would be nice if LiveItems had the option of operating either in batched mode (like my SLiveItem implementation) or real-time mode (as they currently do).&amp;#160; Perhaps this could be enabled through a new Batched property on LiveItemAccessOptions.&amp;#160; This means LiveItems would be able to speak both AtomPub/FeedSync and MeshScripts.&lt;/p&gt;  &lt;h4&gt;Escaping the MEWA sandbox&lt;/h4&gt;  &lt;p&gt;This next one is more of a “see if it’s possible” item than a new thing to implement, but it could open up some interesting new scenarios that would be ripe for additional library development.&amp;#160; It would be interesting to see if MEWAs can use MeshScripts to escape the MEWA sandbox, either by calling them as sprocs or as triggers.&amp;#160; Of course if this is possible, it’s likely it will be quickly disabled, but who knows, perhaps it’s acceptable.&amp;#160; I tried running a simple ReadCollection script from a Silverlight MEWA and got an exception trying to deserialize the result (no public default constructor), so I haven’t pursued it further.&lt;/p&gt;  &lt;h4&gt;Yahoo Pipes for AtomPub&lt;/h4&gt;  &lt;p&gt;Yes, building &lt;a href=&quot;http://pipes.yahoo.com/pipes/&quot;&gt;Yahoo Pipes&lt;/a&gt; for AtomPub and FeedSync would involve much more than just MeshScripts, but I think MeshScripts could play an important role in its implementation, especially with the forthcoming visual script designer.&lt;/p&gt;  &lt;p&gt;This idea first came to me as I was experimenting with pulling in external Atom feeds using MeshScripts (it’s also possible using LiveItems).&amp;#160; Most feeds had formatting that broke the script, but a few external Atom feeds magically worked.&amp;#160; I thought, wouldn’t it be nice if there were a MeshAtomTidy service that touched up external feeds with the appropriate data to ensure they load nicely into the Mesh?&lt;/p&gt;  &lt;p&gt;That would be great for read-only feeds.&amp;#160; Wouldn’t it be even nicer if you could map LiveID credentials to external credentials and access other AtomPub APIs such as Google Calendar, Google Spreadsheets, Picasa, and more?&amp;#160; It would also be cool if you could write a little bit of glue code or script to wrap an AtomPub API around non-AtomPub APIs such as Twitter.&amp;#160; Or even better, just select from a list of pre-existing AtomPub wrappers for popular services.&lt;/p&gt;  &lt;p&gt;Next, I’d like to enable automatic synchronization between Mesh feeds and external feeds.&amp;#160; It’s not very exciting to send tweets while you’re offline, but offline access to the Google APIs is more compelling.&amp;#160; There may be a need for additional transformations and business logic in between which is where the full-featured suite of Yahoo Pipes modules comes in handy.&lt;/p&gt;  &lt;h4&gt;Popfly integration&lt;/h4&gt;  &lt;p&gt;The closest Microsoft equivalent to Yahoo Pipes is &lt;a href=&quot;http://www.popfly.com&quot;&gt;Popfly&lt;/a&gt;.&amp;#160; It has a similar set of modules and a drag-and-drop design experience.&amp;#160; Perhaps there is an opportunity to integrate Popfly mashups with Mesh feeds.&amp;#160; It would also be cool if you could package Popfly games as MEWAs that can run on your desktop or on your phone and maybe even sell them through a Live Mesh App Store, but that’s probably enough crazy talk for one blog post. :-)&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/425229986990485956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/425229986990485956' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/425229986990485956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/425229986990485956'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/01/meshscript-ideas-for-future.html' title='MeshScript Ideas for the Future'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-7675267787324206719</id><published>2009-01-07T16:27:00.001-09:00</published><updated>2009-01-07T16:36:39.768-09:00</updated><title type='text'>MeshScript Queries, LiveItems, and Magic</title><content type='html'>&lt;p&gt;I’ve continued to extend my &lt;a href=&quot;http://orand.blogspot.com/2008/12/fluent-livefx-resource-scripts.html&quot;&gt;Fluent Resource Scripts library&lt;/a&gt; in several interesting new ways.&amp;#160; I’ve added:&lt;/p&gt; &lt;ul&gt;   &lt;li&gt;Strongly typed LINQ queries &lt;/li&gt;   &lt;li&gt;Turning script results into LiveItems (MeshObject, DataFeed, DataEntry, etc.) &lt;/li&gt;   &lt;li&gt;LiveItem syntax for scripts &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;I’ve had to resort to more significant hacks to implement these, and I don’t feel that these features are as solid or as complete as the features in my original Fluent MeshScripts post.&amp;#160; But I think these ones are far more interesting, so I hope you will look past the rough edges and imagine the potential if these features were done properly.&amp;#160; The LiveItem syntax for scripts is especially cool, if I do say so myself.&lt;/p&gt; &lt;h3&gt;Queries&lt;/h3&gt; &lt;p&gt;Both &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd157126.aspx&quot;&gt;LiveQuery&lt;/a&gt; and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd138874.aspx&quot;&gt;ResourceQuery&lt;/a&gt; let you generate query strings from strongly-typed LINQ queries.&amp;#160; ResourceQuery &lt;a href=&quot;https://connect.microsoft.com/liveframework/feedback/ViewFeedback.aspx?FeedbackID=389531&quot;&gt;is broken&lt;/a&gt;, which is unfortunate because its only generic parameter is of type Resource, which also happens to be the only generic parameter for most script statements.&amp;#160; This would have allowed us to implicitly pass along the statement’s generic parameter to our helper method without having to write any generic angle brackets.&lt;/p&gt; &lt;p&gt;So we have to use LiveQuery instead, which takes a generic parameter of type LiveItem (the non-generic LiveItem, not LiveItem&amp;lt;TResource&amp;gt;).&amp;#160; This makes it so that instead of calling my helper method like this:&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.ReadResourceCollection&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;(&lt;span style=&quot;color: #2b91af&quot;&gt;ScriptHelper&lt;/span&gt;.MeshObjectsUrl)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .WithQuery(&lt;br/&gt;&amp;#160;&amp;#160;&amp;#160;q =&amp;gt; q.Where(o =&amp;gt; o.Resource.Title.StartsWith(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;my&amp;quot;&lt;/span&gt;)))&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;You must instead call it like this, specifying both the Resource type and the LiveItem type:&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.ReadResourceCollection&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;(&lt;span style=&quot;color: #2b91af&quot;&gt;ScriptHelper&lt;/span&gt;.MeshObjectsUrl)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .WithQuery&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;, &lt;span style=&quot;color: #2b91af&quot;&gt;MeshObject&lt;/span&gt;&amp;gt;(&lt;br/&gt;&amp;#160;&amp;#160;&amp;#160;q =&amp;gt; q.Where(o =&amp;gt; o.Resource.Title.StartsWith(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;my&amp;quot;&lt;/span&gt;)))&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;Oh well, it’s still useful, and once ResourceQuery is fixed we can switch to the shorter syntax.&lt;/p&gt; &lt;p&gt;I should note that these queries are immediately turned into query strings under the hood.&amp;#160; In other words, they are evaluated at script design-time, not at script runtime.&amp;#160; I have put in a &lt;a href=&quot;https://connect.microsoft.com/liveframework/feedback/ViewFeedback.aspx?FeedbackID=391272&quot;&gt;feature request&lt;/a&gt; to support query generation at runtime.&lt;/p&gt; &lt;h3&gt;Turning script results into LiveItems&lt;/h3&gt; &lt;p&gt;So you’ve written a resource script, you run it, and you get some results back.&amp;#160; Then you think, “I’d like to do further work with the results I’ve gotten back.”&amp;#160; You dig into the individual statements in the script’s Result property, cast them to the appropriate statement type so you can then dig into the Resource property and examine the actual data that was returned.&lt;/p&gt; &lt;p&gt;But what if instead of working with results MeshScript-style, you wanted to work with them LiveItem-style, without having to do a bunch of tedious digging and casting?&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;DataFeed&lt;/span&gt; outFeed = &lt;span style=&quot;color: blue&quot;&gt;null&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: blue&quot;&gt;using&lt;/span&gt; (&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;ScriptContext&lt;/span&gt;(loe))&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;{&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.Sequence(&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ..., &lt;span style=&quot;color: green&quot;&gt;// create moStatement&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource(scriptFeed)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .AtUrl(moStatement, mo =&amp;gt; mo.Response.DataFeedsLink)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .SaveResult(&lt;span style=&quot;color: blue&quot;&gt;ref&lt;/span&gt; outFeed)&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; ).Compile().Run();&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;}&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;DataEntry&lt;/span&gt; de = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;DataEntry&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;new entry&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;outFeed.DataEntries.Add(&lt;span style=&quot;color: blue&quot;&gt;ref&lt;/span&gt; de);&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;I’m not quite sure what programming idiom to compare SaveResult() to since the result isn’t actually saved until the script is run.&amp;#160; The closest thing I can think of is a &lt;a href=&quot;http://www.ps.uni-sb.de/alice/manual/futures.html&quot;&gt;future&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;SaveResult() creates a new LiveItem of the appropriate type, and after the script is run, this LiveItem is filled in with all of the necessary response information to give you a “live” LiveItem that you can start partying on right away without requiring another server round-trip to flesh it out.&amp;#160; This required a fair bit of reflection magic because by default LiveItems are essentially “DeadItems” until they’re associated with a LOE and Reloaded.&lt;/p&gt; &lt;p&gt;Notice I’ve added the use of a ScriptContext to enable the generated LiveItems to be automatically associated with an existing LiveOperatingEnvironment.&lt;/p&gt; &lt;p&gt;SaveResult() has been implemented for CreateResourceStatement, ReadResourceStatement, and ReadResourceCollectionStatement.&amp;#160; I have also added Statement extension methods ToMeshObject(), ToDataFeed(), and ToDataEntry() if you prefer to work that way.&lt;/p&gt; &lt;p&gt;When you combine ReadResourceCollection with SaveResult() and the query support above, you can now batch multiple LiveItem queries.&lt;/p&gt; &lt;h3&gt;LiveItem syntax for MeshScripts&lt;/h3&gt; &lt;p&gt;So we’re starting to get a decent bridge between the world of MeshScripts and the world of LiveItems.&amp;#160; But man, that MeshScript syntax is still pretty nasty, even with the fluent stuff I’ve added.&amp;#160; Wouldn’t it be nice if you could write a MeshScript the same way you write LiveItem code?&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: blue&quot;&gt;using&lt;/span&gt; (&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;ScriptContext&lt;/span&gt;(loe))&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;{&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; mo = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SMeshObject&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;original title&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataFeed&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;first feed&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed2 = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataFeed&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;second feed&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed3 = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataFeed&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;third feed&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.Resource.Title = &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;script-generated title&amp;quot;&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.Resource.Type = &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;LiveMeshFolder&amp;quot;&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed.Resource.Type = &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;LiveMeshFiles&amp;quot;&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed2.Resource.Title = feed.Resource.Title;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed3.Resource = feed.Resource;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeeds.Add(feed);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeeds.Add(feed2);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeeds.Add(feed3);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; entry = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataEntry&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;my entry&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed.DataEntries.Add(entry);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;}&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;The only syntactic differences in the code above are the S-prefixes on the various SLiveItems, the absence of ref parameters, and there are no explicit calls to loe.Mesh.MeshObjects.Add() for the SMeshObject, although that extra syntactic hoop could easily be enabled.&lt;/p&gt; &lt;p&gt;Yes, that code results in just one round-trip to the server.&amp;#160; “You’re kidding,” you say?&amp;#160; “Where’s the man behind the curtain?”&amp;#160; Let’s see that again, annotated with comments.&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: blue&quot;&gt;using&lt;/span&gt; (&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;ScriptContext&lt;/span&gt;(loe))&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;{&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// CreateResourceStatements&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; mo = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SMeshObject&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;original title&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataFeed&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;first feed&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed2 = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataFeed&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;second feed&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; feed3 = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataFeed&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;third feed&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// set properties at runtime using ExpressionBindings&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.Resource.Title = &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;script-generated title&amp;quot;&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.Resource.Type = &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;LiveMeshFolder&amp;quot;&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed.Resource.Type = &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;LiveMeshFiles&amp;quot;&lt;/span&gt;;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// bind sFeed&#39;s Response.Title to sFeed2&#39;s Request.Title&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed2.Resource.Title = feed.Resource.Title;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// bind sFeed&#39;s Response to sFeed3&#39;s Request&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed3.Resource = feed.Resource;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// bind DataFeedsLinks to CollectionUrls&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeeds.Add(feed);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeeds.Add(feed2);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; mo.DataFeeds.Add(feed3);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// CreateResourceStatement&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; entry = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SDataEntry&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;my entry&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: green&quot;&gt;// bind DataEntriesLink to CollectionUrl&lt;/span&gt;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; feed.DataEntries.Add(entry);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;} &lt;span style=&quot;color: green&quot;&gt;// automatically run the script&lt;/span&gt;&lt;/pre&gt; &lt;/div&gt;&lt;p&gt;&lt;br/&gt;In ORM terms, the ScriptContext now functions as a UnitOfWork that automatically saves all items created or modified within its scope.&amp;#160; You can think of it as a script recorder that replays what it has recorded when it’s done.&amp;#160; In addition to the LOE parameter, ScriptContext also takes an optional RunLocality parameter that determines whether the script is executed by the client or by the server.&amp;#160; It defaults to running at the server.&lt;/p&gt; &lt;p&gt;The CreateResourceStatements were surprisingly straight-forward to implement.&amp;#160; So were the Add() methods.&lt;/p&gt; &lt;p&gt;The property getters and setters required a bit more magic.&amp;#160; String-based property getters all return a magic string that specifies the binding.&amp;#160; String-based property setters generate a PropertyBinding if they are passed a magic string, otherwise they generate a constant ExpressionBinding with the string they are given.&amp;#160; SResource-based setters generate a PropertyBinding.&amp;#160; The magic string approach could also be used for Uri-based properties, although I didn’t implement those in this prototype.&lt;/p&gt; &lt;p&gt;At first I generated script statements in the order that the SLiveItems were created, but later I added dependency-tracking so that property assignments and Add() calls re-order the statements if necessary.&lt;/p&gt; &lt;p&gt;Another advantage of late SLiveItem statement execution is that you won’t &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/6389baed-61bb-4efa-a5b6-06b6693ed34c&quot;&gt;run into NullReferenceExceptions&lt;/a&gt; if you Add() SLiveItems to other SLiveItems in the “wrong” order.&amp;#160; That forum thread was actually part of the inspiration for imitating LiveItem syntax.&lt;/p&gt; &lt;p&gt;In that same forum thread I also detailed how LiveItems lead a dual life as a request and as a response.&amp;#160; A similar duality exists with SLiveItems.&amp;#160; When assigning properties, the object on the left-hand-side sets properties on its request, while the object on the right-hand-side gets properties on its response.&lt;/p&gt; &lt;p&gt;Each SLiveItem has a Result property that returns a “live” LiveItem once the script has been run by explicitly calling ScriptContext.Current.CreateScript().Run().&amp;#160; This uses the SaveResult() technique described earlier.&lt;/p&gt; &lt;p&gt;Each SLiveItem exposes a WrappedStatement property that lets you make changes to the underlying Statement if you need that escape hatch into script-land to touch things like the request resource.&lt;/p&gt; &lt;h3&gt;Using SLiveItem syntax with triggers&lt;/h3&gt; &lt;p&gt;With these tools in our bag, we are now ready to make triggers more accessible.&lt;/p&gt; &lt;p&gt;First, I created a new type, SResourceParameter&amp;lt;TResource&amp;gt; and a factory method, S.ResourceParameter&amp;lt;TResource&amp;gt;().&amp;#160; This enables a more strongly-typed Bind() call than what I had in V1.&lt;/p&gt; &lt;p&gt;Then I updated the Bind() methods to tell the ScriptContext about any ParameterBindings so they can be automatically added to the auto-generated root script statement.&lt;/p&gt; &lt;p&gt;Finally, I decided to try out yet another syntax for Bind() that looks like Set().EqualTo().&amp;#160; It exists as a method on SLiveItem instead of as an extension method for Statements and I only implemented it for Resource ParameterBindings, but it could just as easily be applied to all of the other binding types.&lt;/p&gt; &lt;p&gt;This lets us write:&lt;/p&gt; &lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: blue&quot;&gt;using&lt;/span&gt; (&lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;ScriptContext&lt;/span&gt;(loe))&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;{&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; originalObject = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;MeshObject&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;Original object&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; triggerParam = &lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.ResourceParameter&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;();&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: blue&quot;&gt;var&lt;/span&gt; triggerCreatedObject = &lt;span style=&quot;color: blue&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #2b91af&quot;&gt;SMeshObject&lt;/span&gt;(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;trigger-created object&amp;quot;&lt;/span&gt;);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; triggerCreatedObject.Set(s =&amp;gt; s.Request.Title).EqualTo(triggerParam, p =&amp;gt; p.Title);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; originalObject.Resource.Triggers.PostCreateTrigger = &lt;span style=&quot;color: #2b91af&quot;&gt;ScriptContext&lt;/span&gt;.Current.CreateScript();&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; loe.Mesh.MeshObjects.Add(&lt;span style=&quot;color: blue&quot;&gt;ref&lt;/span&gt; originalObject);&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;}&lt;/pre&gt;   &lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&lt;/pre&gt; &lt;/div&gt; &lt;p&gt;The Set().EqualTo() syntax isn’t as nice as the LiveItem property getter/setter syntax, but Set().EqualTo() was quick to write and I didn’t feel like taking more time to write the wrapper that would enable plain old property support.&amp;#160; I’m sure it could be done.&lt;/p&gt; &lt;h3&gt;What remains to be done?&lt;/h3&gt; &lt;p&gt;The LiveItem syntax turned out to be quite a bit more work than I was expecting, and it’s still nowhere near being done.&amp;#160; In fact it may have some major flaws that necessitate a rewrite, I’m not quite sure yet.&amp;#160; One major issue is that it currently only supports CreateResourceStatements.&amp;#160; Adding support for other statement types could have a huge ripple effect.&amp;#160; The use of magic strings is another design decision that may cause headaches down the road, but so far I’m getting away with it, and the alternatives aren’t nearly as nice to use.&lt;/p&gt; &lt;p&gt;I started out without any generics in the SLiveItem and SResource base classes but later introduced the rather insane explosion of generics to consolidate repetitive functionality from the derived classes.&amp;#160; It may be desirable to first undo the base class generics to create some mental breathing room and then add more functionality.&lt;/p&gt; &lt;p&gt;SLiveItem wrappers need to be created for Contact, Mapping, Member, Device, News, and Profile.&amp;#160; This may require creating additional wrapper classes for the helper classes they depend on such as NewsItemContext.&lt;/p&gt; &lt;p&gt;As mentioned in the previous section, Uri properties need magic string support, and ParameterBindings need LiveItem-style property assignment support.&lt;/p&gt; &lt;p&gt;Once the &lt;a href=&quot;https://connect.microsoft.com/liveframework/feedback/ViewFeedback.aspx?FeedbackID=389531&quot;&gt;ResourceQuery bug&lt;/a&gt; is fixed, WithQuery should use it instead of LiveQuery.&amp;#160; If the &lt;a href=&quot;https://connect.microsoft.com/liveframework/feedback/ViewFeedback.aspx?FeedbackID=391272&quot;&gt;runtime query feature&lt;/a&gt; is implemented, this should also be supported.&lt;/p&gt; &lt;p&gt;SLiveItem needs to implement Update() and CreateQuery().&lt;/p&gt; &lt;p&gt;The current implementation freely reorders statements.&amp;#160; It also assumes that when you’re doing property assignments, everything on the left-hand-side is a request and everything on the right-hand-side is a response.&amp;#160; If you set the same property more than once, only the last set sticks, and getting the same property at different points always returns the same value.&amp;#160; This may result in unexpected behavior if the user is depending on the same property having different values at different points in the script.&amp;#160; This could be dealt with by generating more than one statement per SLiveItem and/or by generating AssignStatements.&lt;/p&gt; &lt;p&gt;Per the comments in the code, my usage of ETags when generating LiveItems from script results may not be correct.&amp;#160; There are also a number of other TODOs in the code comments.&lt;/p&gt; &lt;p&gt;Last but not least, this needs unit tests.&amp;#160; More interfaces such as IScriptContext probably need to be created to enhance testability.&lt;/p&gt; &lt;p&gt;I’m sure there’s more I’m forgetting.&amp;#160; I told you, it’s a lot of work! :-)&lt;/p&gt; &lt;h3&gt;Download&lt;/h3&gt; &lt;p&gt;You can download V2 of the Fluent MeshScripts library &lt;a href=&quot;http://orand.googlecode.com/files/FluentResourceScriptsV2.zip&quot;&gt;here&lt;/a&gt;.&amp;#160; I have enhanced the console app with additional examples that demonstrate most of the new features in this post.&lt;/p&gt; &lt;p&gt;To run the sample you will need to change the username and password.&amp;#160; If the project references to Microsoft.LiveFX.Client.dll, Microsoft.LiveFX.ResourceModel.dll, and Microsoft.Web.dll are broken, you will need to remove and recreate them in both projects.&lt;/p&gt; &lt;h3&gt;Wrap-up&lt;/h3&gt; &lt;p&gt;I was going to discuss future directions for this library and for MeshScripts in general but this post has gone on for long enough so I’ll save that for my &lt;a href=&quot;http://orand.blogspot.com/2009/01/meshscript-ideas-for-future.html&quot;&gt;next post&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Hopefully my enhancements help you visualize more possibilities for MeshScripts.&amp;#160; At the very least, they should make MeshScripts much easier for you to write and work with.&lt;/p&gt; &lt;p&gt;As always, I’d love to hear any feedback.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/7675267787324206719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/7675267787324206719' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/7675267787324206719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/7675267787324206719'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2009/01/meshscript-queries-liveitems-and-magic.html' title='MeshScript Queries, LiveItems, and Magic'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-5284032093970970334</id><published>2008-12-20T23:22:00.001-09:00</published><updated>2008-12-20T23:45:27.235-09:00</updated><title type='text'>Fluent LiveFX Resource Scripts</title><content type='html'>&lt;p&gt;After writing my &lt;a href=&quot;http://orand.blogspot.com/2008/11/live-mesh-resource-script-demo.html&quot;&gt;Resource Script demo post&lt;/a&gt;, I’ve been digging deeper into &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136476.aspx&quot;&gt;Live Framework Resource Scripts&lt;/a&gt;.&amp;#160;&amp;#160; Along the way I’ve written a &lt;a href=&quot;http://orand.googlecode.com/files/FluentResourceScripts.zip&quot;&gt;helper library&lt;/a&gt; to make them easier to work with.&amp;#160; My enhancements focus primarily on keeping your scripts strongly typed and enabling a more concise &lt;a href=&quot;http://en.wikipedia.org/wiki/Fluent_interface&quot;&gt;fluent interface&lt;/a&gt; syntax.&amp;#160; These enhancements let Intellisense help you out quite a bit more, resulting in greater discoverability and productivity.&lt;/p&gt; &lt;p&gt;I must warn you that the following discussion won’t make much sense unless you’re already somewhat familiar with Resource Scripts.&amp;#160; I apologize and promise to follow up in future posts with material that’s more suitable as an introduction, using my library of course. :-)&lt;/p&gt; &lt;h3&gt;Strongly typed bindings&lt;/h3&gt; &lt;p&gt;If you’ve played with Resource Scripts at all, you’ve almost certainly run into Bindings.&amp;#160; These creatures consume magic strings such as “EntryUrl”, “CollectionUrl”, “Request.Title”, “Response.SelfLink”, “Response.DataFeedsLink”, and “Response.DataEntriesLink” to name a few.&amp;#160; Yuck!&amp;#160; To make matters worse, the types of Request and Response are usually (but not always!) generic parameters to a statement, meaning that their available sub-properties will vary based on the generic type.&amp;#160; Also, some statement types don’t have Request, and others don’t have either Request &lt;em&gt;or &lt;/em&gt;Response.&amp;#160; It would sure be nice if I don’t have to consult MSDN documentation or Reflector each time I write a binding statement.&amp;#160; Bindings are strongly-typed at runtime, so why not at design-time too?&lt;/p&gt; &lt;p&gt;Then &lt;a href=&quot;http://www.codethinked.com/post/2008/11/29/Taking-the-Magic-out-of-Expression.aspx&quot;&gt;this post&lt;/a&gt; popped up in Google Reader and reminded me that I can generate those icky dirty strings from nice shiny expression trees, just like LINQ to SQL generates SQL from strongly-typed C# statements.&amp;#160; So my Bindings can go from this:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;Statement&lt;/span&gt;.CreateResource(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;feedStatement&amp;quot;&lt;/span&gt;, &lt;span style=&quot;color: blue&quot;&gt;null&lt;/span&gt;, dataFeed,&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style=&quot;color: #2b91af&quot;&gt;Statement&lt;/span&gt;.Bind(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;CollectionUrl&amp;quot;&lt;/span&gt;, &lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;        &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;folderStatement&amp;quot;&lt;/span&gt;, &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;Response.DataFeedsLink&amp;quot;&lt;/span&gt;));&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;to this:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource(dataFeed)&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Bind(df =&amp;gt; df.CollectionUrl,&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;        folderStatement, fs =&amp;gt; fs.Response.DataFeedsLink);&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;Due to the way I’ve defined the generic parameters on the lambda expressions, the types of the source property and the target property have to match.&amp;#160; If they don’t, you get immediate red squiggly feedback in Visual Studio.&amp;#160; I’m not sure if that’s a Visual Studio thing or a &lt;a href=&quot;http://www.jetbrains.com/resharper/&quot;&gt;Resharper&lt;/a&gt; thing, but that’s how it works on my box.&amp;#160; At the very least you will find out at compile-time instead of at runtime.&lt;/p&gt;&lt;p&gt;Besides the lambda expressions and the ability to call Bind() on the statement after it has been created, it’s worth noting that the Statement.Name “folderStatement” string has been replaced with a reference to the source Statement itself.&amp;#160; No more remembering statement names (until we get to ConditionalStatements that is…).&lt;/p&gt;&lt;h3&gt;Simpler statement construction&lt;/h3&gt;&lt;p&gt;So what was that “S” thing in the previous example?&amp;#160; That’s my static utility class that offers methods equivalent to most of the static factory methods on the Statement class.&amp;#160; Methods in “S” have the same names, but they typically have fewer parameters, resulting in a more concise syntax when you’re data binding.&amp;#160; They also give you the option of using strings instead of Uri objects.&lt;/p&gt;&lt;p&gt;Yes I know, it’s not fair that my utility class gets the short, easy to type name while “Statement” makes you type twice as much before Intellisense kicks in and wastes a bunch of horizontal space.&amp;#160; So put “using S = Microsoft.LiveFX.ResourceModel.Scripting.Statement;” at the top of your code if that makes you feel better. :-)&lt;/p&gt;&lt;p&gt;You may also have noticed that I didn’t supply a name for the statement.&amp;#160; All of the factory methods in “S” automatically generate a random statement name so that every statement is inherently bindable.&amp;#160; If you need a well-known name for inspecting script results or for use in a ConditionalStatement, you can use the NameStatement() extension method:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource(dataFeed).NameStatement(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;myName&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;NameStatement() also checks for valid statement names so you find out at design-time rather than at runtime that statements can’t start with a number and can’t contain spaces.&lt;/p&gt;&lt;h3&gt;Functional statement construction&lt;/h3&gt;&lt;p&gt;Once you start writing utility methods to generate groups of statements that you string together into a script, you quickly run into the issue that you’re always having to write little bits of shim code to repackage your statements into a single Statement[] before feeding them into your CompoundStatement of choice (Sequence, Interleave, or Conditional).&amp;#160; Wouldn’t it be nice if you could throw anything you wanted into a CompoundStatement and it would all be taken care of, similar to the XElement constructor in LINQ to XML?&lt;/p&gt;&lt;p&gt;If you’re not familiar with the XElement constructor, it looks like this:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: blue&quot;&gt;public&lt;/span&gt; XElement(&lt;span style=&quot;color: #2b91af&quot;&gt;XName&lt;/span&gt; name, &lt;span style=&quot;color: blue&quot;&gt;params&lt;/span&gt; &lt;span style=&quot;color: blue&quot;&gt;object&lt;/span&gt;[] content)&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;It’s a bit loosey-goosey with the object[] parameter, but according to &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb943882.aspx&quot;&gt;the documentation&lt;/a&gt; it allows you to pass in objects that are (or can be converted to) XML nodes, as well as IEnumerable&amp;lt;T&amp;gt; of such objects.&amp;#160; Null content is silently ignored.&amp;#160; Anything else results in an exception at runtime.&lt;/p&gt;&lt;p&gt;When this style is applied to CompoundStatement construction, it enables the following code:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.Sequence(&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; readMeshObjects,&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; conditionallyCreateFolders,&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; createAnotherFolder,&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; createFiles)&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;That doesn’t look very interesting without the type declarations, but imagine the first two parameters are different types of Statements, the third parameter is a custom object that implements IEnumerable&amp;lt;Statement&amp;gt;, and the last parameter is a Statement array.&amp;#160; You can see this code in action in the IfElseSample in the download.&lt;/p&gt;&lt;h3&gt;Binding to URLs and Requests&lt;/h3&gt;&lt;p&gt;One of the most common uses of bindings is to perform CRUD operations on a URL that comes from the result of a previous statement.&amp;#160; Specifying the target URL in the binding can become quite repetitive.&amp;#160; The property name for the target URL also varies by statement type.&amp;#160; Sometimes it’s EntryUrl, sometimes it’s CollectionUrl, and sometimes it’s MediaResourceUrl.&lt;/p&gt;&lt;p&gt;I address this with the AtUrl() extension method which eliminates the need to specify the target property and lets you write:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource(dataFeed)&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .AtUrl(folderStatement, fs =&amp;gt; fs.Response.DataFeedsLink);&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;A similar WithRequest() extension method exists for binding to the Request property on CreateResource, UpdateResource, and SynchronizeResourceCollection.&lt;/p&gt;&lt;h3&gt;Conditional statements&lt;/h3&gt;&lt;p&gt;The ConditionalStatement is worth an entire blog post.&amp;#160; Until then, here’s an example of the syntax I’ve enabled:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.If(statement =&amp;gt;&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; (((&lt;span style=&quot;color: #2b91af&quot;&gt;ReadResourceCollectionStatement&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;MeshObjectResource&lt;/span&gt;&amp;gt;)&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; statement.FindStatement(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;ReadObjects&amp;quot;&lt;/span&gt;)).Response.Entries&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; .Where(mo =&amp;gt; mo.Title == &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;My Folder&amp;quot;&lt;/span&gt;).Count() == 0))&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Then(&lt;span style=&quot;color: #2b91af&quot;&gt;ScriptHelper&lt;/span&gt;.CreateFolder(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;Folder didn&#39;t exist&amp;quot;&lt;/span&gt;))&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .Else(&lt;span style=&quot;color: #2b91af&quot;&gt;ScriptHelper&lt;/span&gt;.CreateFolder(&lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;Folder DID exist&amp;quot;&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;I should note that ConditionalStatement already exposed the ability to use lambda expressions.&amp;#160; All I did was enable the If().Then().Else() syntax.&amp;#160; The Else() is optional.&lt;/p&gt;&lt;h3&gt;Strongly typed statement groups&lt;/h3&gt;&lt;p&gt;Notice the CreateFolder() helper method in the previous example?&amp;#160; Originally this method returned a Statement[] containing two statements.&amp;#160; The first statement created the MeshObject that represents the folder and the second statement created a DataFeed at the DataFeedsLink of the folder.&amp;#160; This Statement[] was sufficient for creating a folder with a given name, but if I wanted to do something interesting with it such as put files in the folder or use a binding to change its title, it quickly became a pain to grab the appropriate entry from the array and cast it to the correct type.&lt;/p&gt;&lt;p&gt;So I created a helper class named CreateFolderStatementPair that exposes strongly typed properties named FolderStatement and FilesFeedStatement.&amp;#160; This lets you write:&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&lt;span style=&quot;color: #2b91af&quot;&gt;S&lt;/span&gt;.CreateResource&amp;lt;&lt;span style=&quot;color: #2b91af&quot;&gt;DataEntryResource&lt;/span&gt;&amp;gt;()&lt;/pre&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;&amp;#160;&amp;#160;&amp;#160; .AtUrl(folder.FilesFeedStatement, f =&amp;gt; f.Response.DataEntriesLink)&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;and&lt;/p&gt;&lt;div style=&quot;font-size: 10pt; background: white; color: black; font-family: consolas&quot;&gt;&lt;pre style=&quot;margin: 0px&quot;&gt;folder.FolderStatement.Bind(mo =&amp;gt; mo.Request.Title, &lt;span style=&quot;color: #a31515&quot;&gt;&amp;quot;new title&amp;quot;&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;br/&gt;CreateFolderStatementPair inherits from an abstract class named StatementGroup which implements IEnumerable&amp;lt;Statement&amp;gt; and also has an implicit operator conversion to Statement[].&amp;#160; Implementing IEnumerable&amp;lt;Statement&amp;gt; means you can pass a StatementGroup into S.Sequence(), S.Interleave(), and the Then()/Else() methods.&amp;#160; The implicit conversion to Statement[] means you can pass a StatementGroup into methods that expect a Statement[] such as the original Statement.Sequence() method.&amp;#160; You can use StatementGroup to create your own strongly typed group of statements that play well with bindings and with the S.*/Statement.* factory methods.&lt;/p&gt;&lt;h3&gt;Miscellaneous helpers&lt;/h3&gt;&lt;p&gt;Besides CreateFolder(), The ScriptHelper static class has a few other useful methods.&amp;#160; CreateMedia() takes a CreateResourceStatement&amp;lt;DataFeedResource&amp;gt; and an external media URL and does a CreateMedia at the MediaResourcesLink of the CreateResourceStatement.&amp;#160; There is also a CreateMedias() method that takes multiple media URLs.&amp;#160; ScriptHelper has a few other convenience properties and methods, but nothing noteworthy.&lt;/p&gt;&lt;p&gt;There are a few other extension methods I haven’t mentioned yet.&lt;/p&gt;&lt;p&gt;ToSequence() and ToInterleave() turn a Statement array into a SequenceStatement or an InterleaveStatement respectively.&lt;/p&gt;&lt;p&gt;AddBindings() and AddParameters() let you add bindings and parameters to statements after they have been created.&lt;/p&gt;&lt;p&gt;FindStatement&amp;lt;TStatement&amp;gt;() recursively finds the first statement of the specified type in an IEnumerable&amp;lt;Statement&amp;gt;.&lt;/p&gt;&lt;p&gt;A Compile() method has been added to all statement types, not just CompoundStatements.&amp;#160; Run() and RunAtServer() with an implicit Compile() have also been added to any Statement type.&lt;/p&gt;&lt;p&gt;Run() and RunAtServer() no longer require any parameters if you first call ScriptHelper.SetCredential(username, password).&lt;/p&gt;&lt;h3&gt;Download&lt;/h3&gt;&lt;p&gt;You can download the code &lt;a href=&quot;http://orand.googlecode.com/files/FluentResourceScripts.zip&quot;&gt;here&lt;/a&gt;.&amp;#160; The solution contains a console app that demonstrates some of the features with a few sample scripts.&lt;/p&gt;&lt;p&gt;To run the sample you will of course need to change the username and password.&amp;#160; If the project references to Microsoft.LiveFX.Client.dll, Microsoft.LiveFX.ResourceModel.dll, and Microsoft.Web.dll are broken, you will need to remove and recreate them in both projects.&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;If you’re wondering why Resource Scripts didn’t have these features already, you need to remember that Resource Scripts were designed to be written using a visual designer tool similar to the Windows Workflow designer.&amp;#160; The team was also under intense pressure to make the CTP available in time for PDC.&lt;/p&gt;&lt;p&gt;Think of this library as an experiment to see what a more code-centric API might look like and whether it could co-exist with a visual designer tool.&amp;#160; Who knows, maybe some of the concepts such as strongly-typed StatementGroups might find their way into such a visual designer.&lt;/p&gt;&lt;p&gt;Hopefully this library enables and encourages more people to play with Resource Scripts.&amp;#160; If you have any feedback, I’d love to hear it.&amp;#160; Have fun scripting your Mesh!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/5284032093970970334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/5284032093970970334' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/5284032093970970334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/5284032093970970334'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2008/12/fluent-livefx-resource-scripts.html' title='Fluent LiveFX Resource Scripts'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-3450442187630840797</id><published>2008-11-06T18:33:00.001-09:00</published><updated>2008-11-06T18:36:58.955-09:00</updated><title type='text'>L1v3 M35H L337 H4x0rZ</title><content type='html'>&lt;p&gt;In case you aren’t already persuaded that the Live Mesh team are a bunch of L337 H4x0rZ, check out the ids of entries in the Profiles feed.&lt;/p&gt;  &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;250&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;117&quot;&gt;&lt;strong&gt;id&lt;/strong&gt;&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;131&quot;&gt;&lt;strong&gt;title&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;116&quot;&gt;G3N3RaL&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;GeneralProfile&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;116&quot;&gt;480u7Y0U&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;AboutYouProfile&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;116&quot;&gt;k0n74C7Inf0&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;ContactProfile&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;116&quot;&gt;wORK1nfo&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;132&quot;&gt;WorkProfile&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;116&quot;&gt;1n7eRE572&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;133&quot;&gt;InterestsProfile&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;I believe this also demonstrates their far-reaching commitment to open web standards and the new generation of social apps.&amp;#160; Or perhaps the hidden message is “so easy, even script kiddies can hack it!”&lt;/p&gt;  &lt;p&gt;You can see this for yourself by firing up the Live Framework Resource Browser (LivefxResourceBrowser.exe from the SDK tools) and drilling down into Cloud LOE &amp;gt; Profiles.&lt;/p&gt;  &lt;p&gt;On a slightly related note, as I was digging around with the Resource Browser I discovered that the following two URL styles appear to be interchangeable.&lt;/p&gt;  &lt;p&gt;https://user-ctp.windows.net/V0.1/&lt;strong&gt;cid-1234567890123456789&lt;/strong&gt;/Profiles&lt;/p&gt;  &lt;p&gt;https://user-ctp.windows.net/V0.1/&lt;strong&gt;email-abc@live.com&lt;/strong&gt;/Profiles&lt;/p&gt;  &lt;p&gt;I’m not sure if the email identifier format is stable enough to bank on, but it’s convenient for typing or tweaking URLs by hand.&amp;#160; Does anyone know of other equivalent identifier types in Mesh resources?&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/3450442187630840797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/3450442187630840797' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/3450442187630840797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/3450442187630840797'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2008/11/l1v3-m35h-l337-h4x0rz.html' title='L1v3 M35H L337 H4x0rZ'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-4790159402703934249</id><published>2008-11-05T12:51:00.001-09:00</published><updated>2008-11-05T12:51:56.964-09:00</updated><title type='text'>Live Mesh Resource Script Demo</title><content type='html'>&lt;p&gt;In the &lt;a href=&quot;http://channel9.msdn.com/pdc2008/BB19/&quot;&gt;Live Framework Programming Model Architecture and Insights&lt;/a&gt; session, Ori Amiga (standing in for Dharma Shukla, previously a WF architect) demos a Live Mesh resource script that runs in the cloud.&amp;#160; The script creates a folder on the Live Mesh desktop and downloads two images from external resources, placing them in the newly created folder.&lt;/p&gt;  &lt;p&gt;I couldn’t find this sample on the web, so I recreated it from the session video.&amp;#160; You can download the demo project &lt;a href=&quot;http://orand.googlecode.com/files/MeshResourceScriptDemo.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;You may need to touch up the references to Microsoft.LiveFX.Client.dll, Microsoft.LiveFX.ResourceModel.dll, and Microsoft.Web.dll since they live under C:\Program Files (x86)\ on my 64-bit box and are probably under C:\Program Files\ if you’re running 32-bit.&lt;/p&gt;  &lt;p&gt;At first, my demo threw an error trying to run the following line:&lt;/p&gt;  &lt;p&gt;script.RunAtServer(creds);&lt;/p&gt;  &lt;p&gt;After investigating with Reflector, I discovered that RunAtServer() hard-codes a default script URL of https://&lt;strong&gt;user&lt;/strong&gt;.windows.net/V0.1/Script/ which needs to be changed to https://&lt;strong&gt;user-ctp&lt;/strong&gt;.windows.net/V0.1/Script/ .&amp;#160; You can override this either by calling an overload of RunAtServer() that takes a URI, or by creating an App.config file and adding the following line in the &amp;lt;appSettings&amp;gt; section.&lt;/p&gt;  &lt;p&gt;&amp;lt;add key=&amp;quot;ScriptUrl&amp;quot; value=&amp;quot;https://user-ctp.windows.net/V0.1/Script/&amp;quot;/&amp;gt;&lt;/p&gt;  &lt;p&gt;I chose to use the appSettings solution since that is what Ori must have used in the demo.&lt;/p&gt;  &lt;p&gt;I really would prefer ScriptUrl to be exposed as a property on ResourceScript&amp;lt;&amp;gt; that appSettings/ScriptUrl maps into rather than having to specify the URL either in config or in each method call.&amp;#160; My philosophy is that you should always be able to do in code what you can do in config.&lt;/p&gt;  &lt;p&gt;I’m looking forward to playing more with Live Mesh resource scripts, &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136476.aspx&quot;&gt;documented here&lt;/a&gt;.&amp;#160; Right now they feel a bit convoluted to create programmatically, but they appear to be designed to put a friendlier layer on top such as an Oslo DSL or a “resource workflow designer”.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/4790159402703934249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/4790159402703934249' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/4790159402703934249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/4790159402703934249'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2008/11/live-mesh-resource-script-demo.html' title='Live Mesh Resource Script Demo'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-3801748822504635933</id><published>2008-11-04T23:03:00.001-09:00</published><updated>2008-11-05T14:07:07.214-09:00</updated><title type='text'>Dissecting Live Mesh App Packages</title><content type='html'>&lt;p&gt;After &lt;a href=&quot;http://orand.blogspot.com/2008/10/live-mesh-flash-adobe-air.html&quot;&gt;bundling Flash inside a Mesh app&lt;/a&gt;, I took a closer look at what Visual Studio is doing behind the scenes.&amp;#160; The Mesh-enabled Web Application template creates a project with a .meshproj extension.&amp;#160; A .meshproj file has several important properties.&amp;#160; &amp;lt;OutputName&amp;gt; is the prefix used to name the resulting zip file.&amp;#160; &amp;lt;DebuggerCodeType&amp;gt; is set to either JavaScript or Silverlight, depending on whether you create an HTML/JavaScript or a Silverlight Mesh app.&amp;#160; &amp;lt;ApplicationUri&amp;gt; is the Application Self-Link that you are supposed to copy-and-paste from the Developer Portal after you upload the zip file, as instructed below:&lt;/p&gt;  &lt;p&gt;&lt;a title=&quot;MeshAppSelfLinkPrompt&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/3004110533/&quot;&gt;&lt;img height=&quot;186&quot; alt=&quot;MeshAppSelfLinkPrompt&quot; src=&quot;http://static.flickr.com/3149/3004110533_6c16983d28.jpg&quot; width=&quot;424&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;A .meshproj file also imports $(MSBuildExtensionsPath)\Microsoft\Live Framework\v1.0\Microsoft.LiveFramework.targets which first ensures that your project has an index.html and then zips up the output directory, naming the zip file using the OutputName you specified.&lt;/p&gt;  &lt;p&gt;You don’t need to use Visual Studio to do this.&amp;#160; You can easily create your own Mesh app package by hand.&amp;#160; At a minimum, your zip file must contain:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;index.html &lt;/li&gt;    &lt;li&gt;Manifest.xml &lt;/li&gt;    &lt;li&gt;Logo.png &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Index.html is the entry point for your app.&amp;#160; Logo.png is the icon that will be displayed on your desktop and should be a 32-bit 256 x 256 png.&amp;#160; Manifest.xml is your app manifest. A detailed description of the manifest configuration options is &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd179561.aspx&quot;&gt;documented here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I believe you can bundle anything you want in the zip file, although Microsoft supposedly runs an antivirus scan on the contents, and there may be additional checks for inappropriate content.&amp;#160; Anything in the zip file gets downloaded to your computer when the app is installed on your local desktop.&amp;#160; This is why my Flash app was able to run offline.&lt;/p&gt;  &lt;p&gt;You might be able to use this to “install” an &lt;a href=&quot;http://www.xbap.org/&quot;&gt;XBAP&lt;/a&gt; application that can run offline.&amp;#160; To make it cross-platform, you could bundle the XBAP together with a &lt;a href=&quot;http://msdn.microsoft.com/en-us/magazine/cc895632.aspx&quot;&gt;“down-level” Silverlight version&lt;/a&gt; and choose which one to display based on what the client supports.&amp;#160; If download size is a concern, it might be possible to put the executables in a DataFeed instead of in the app zip file and selectively sync only the version you want to display, but I haven’t dug into DataFeeds enough yet to see if this kind of per-client sync filtering is possible.&amp;#160; Of course you would be working against the built-in versioning management if you did this (updates should only occur when the user closes and re-opens the app).&lt;/p&gt;  &lt;p&gt;Ok, so uploading a zip file sounds nice and simple, right?&amp;#160; Then why does Visual Studio want me to copy-and-paste the Application Self-Link URI?&amp;#160; It turns out that if you use Visual Studio you only upload the zip file once per app.&amp;#160; Once you’ve uploaded the zip and told Visual Studio about the Self-Link URI, Visual Studio will use that URI for subsequent deployments to upload the individual files directly.&lt;/p&gt;  &lt;p&gt;If you watch Visual Studio using &lt;a href=&quot;http://www.fiddlertool.com/fiddler/&quot;&gt;Fiddler&lt;/a&gt; (you’ll need to &lt;a href=&quot;http://www.fiddler2.com/Fiddler/help/httpsdecryption.asp&quot;&gt;configure HTTPS support&lt;/a&gt;) you will see it query the Mesh for the resource feeds of your app, do HTTP DELETEs for each resource that was inside your zip file, and then do a bunch of POSTs to upload each item in your project.&amp;#160; That seems a bit risky.&amp;#160; What if Visual Studio dies before reposting all the resources it deleted?&amp;#160; It seems like updating an app by manually uploading a zip file is a safer, slightly more atomic operation.&amp;#160; It’s no big deal right now, but once real production apps are being upgraded, something more robust would be nice.&amp;#160; I’m guessing we will see more explicit versioning, giving the user the choice of whether or not to upgrade.&amp;#160; If such a feature is added, the direct app resource update trick might be useful for bypassing an explicit upgrade prompt.&lt;/p&gt;  &lt;p&gt;The next time your Live Mesh client (MOE.exe) talks to the cloud, it will download the new versions of the files into your local app cache (AppData\Local\Microsoft\Live Framework Client\Bin\Moe2\MR\).&amp;#160; For some reason I was unable to pinpoint the download traffic with Fiddler, so I can’t say for certain whether individual files are downloaded or if they are zipped up first.&amp;#160; It appears older versions of files aren’t removed.&amp;#160; This is probably to support the explicit user upgrade scenario in the future, but it seems like they could still be doing more cleanup.&lt;/p&gt;  &lt;p&gt;I’m really curious why Visual Studio updates individual app resources rather than following the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd136857.aspx&quot;&gt;documented workflow&lt;/a&gt; of uploading a zip file with the updates.&amp;#160; Anyone know?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I posed this question in the comments &lt;a href=&quot;http://dannythorpe.com/2008/11/04/fixing-default-permissions-in-apps-created-with-live-framework-tools-for-microsoft-visual-studio/&quot;&gt;on Danny Thorpe’s blog&lt;/a&gt; and he responded:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;On your second question, the reason we upload files individually instead of uploading the zip file is because the REST API we’re uploading to doesn’t handle zip files. The dev portal that you manually upload your zip file to unzips the file and uploads the individual bits to the production storage. The Live Services REST APIs that the VS tools use to upload files goes (as far as I know) straight into the production storage.&lt;/p&gt;    &lt;p&gt;In a nutshell, the dev portal that you see in your web browser is just a front end to the actual cloud service. VS doesn’t upload to the dev portal UI, it uploads to the cloud itself.&lt;/p&gt;    &lt;p&gt;Keep in mind that the long side trip of manual steps that you currently have to go through to get a new app created and uploaded to the cloud will all be going away as soon as the cloud APIs to create and provision a new application are implemented.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;He also explains the debugging versioning scheme in the comments, and I suggest you &lt;a href=&quot;http://dannythorpe.com/2008/11/04/fixing-default-permissions-in-apps-created-with-live-framework-tools-for-microsoft-visual-studio/&quot;&gt;go read it&lt;/a&gt; for more great details.&lt;/p&gt;  &lt;p&gt;One other related insight from Danny comes from &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/liveframework/thread/1c9e35f4-0ed4-4463-9f9c-67f9e69b8d38&quot;&gt;this forum thread&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Our goal for the VS tools is to do all development against the local LOE and let the local LOE deal with sync&#39;ing things back to the cloud.&amp;#160; All the parts needed to do that aren&#39;t ready yet, so for the PDC CTP we redirected the VS tools to upload and debug mesh apps in the cloud.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This makes the current chattiness (and the “glue” dialog box) much more acceptable to me since the end goal is to use the local REST API rather than the cloud API.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; Danny has &lt;a href=&quot;http://dannythorpe.com/2008/11/05/inside-live-framework-tools-for-visual-studio-ctp1/&quot;&gt;posted a thorough response&lt;/a&gt; to this post.&amp;#160; There’s lots of great information there, so I won’t quote it all here.&amp;#160; One “aha” moment for me was the concept of separate debug application resources.&amp;#160; He also confirms that the “glue” dialog will be going away soon.&amp;#160; Go read it for details.&amp;#160; Thanks, Danny!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/3801748822504635933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/3801748822504635933' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/3801748822504635933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/3801748822504635933'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2008/11/dissecting-live-mesh-app-packages.html' title='Dissecting Live Mesh App Packages'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-4555482638051495644</id><published>2008-10-31T17:23:00.001-08:00</published><updated>2008-12-03T07:40:51.380-09:00</updated><title type='text'>Live Mesh + Flash == Adobe AIR</title><content type='html'>&lt;p&gt;&lt;a title=&quot;MeshFlashPacman&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/2990627960/&quot;&gt;&lt;img height=&quot;329&quot; alt=&quot;MeshFlashPacman&quot; src=&quot;http://static.flickr.com/3135/2990627960_37d8880891.jpg&quot; width=&quot;412&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Yes, that’s an Adobe Flash app running as a Live Mesh app, and it was &lt;em&gt;easy&lt;/em&gt;.&amp;#160; Feel free to &lt;a href=&quot;https://developer.mesh-ctp.com/Web/Apps/AppConsent.aspx?AppUrl=Mesh%2fApplications%2fBX5J4LJDV35EXAY3AYJKYVF3EM&quot;&gt;install the app&lt;/a&gt; and try it out for yourself.&lt;/p&gt;  &lt;p&gt;First I &lt;a href=&quot;http://www.lancelhoff.com/2008/03/20/how-to-download-embedded-swf-files-using-firefox/&quot;&gt;snagged a pre-existing .swf file&lt;/a&gt; since I am not a Flash developer.&amp;#160; Then I created a new Visual Studio project using the Mesh-enabled Web Application template that comes with the &lt;a href=&quot;https://developer.mesh-ctp.com/developers/developers.aspx&quot;&gt;Live Framework Tools for Visual Studio&lt;/a&gt;.&amp;#160; I added the .swf file to the project with the default build action of Content and copied-and-pasted the object embed tag into the body of index.html.&amp;#160; Then I ran through the usual Ctrl-F5 steps to upload and deploy the resulting zip package and boom, it just worked!&amp;#160; I was able to use the app in the browser in my Live Desktop, and an icon for the app magically appeared on my Windows desktop that let me run the app offline, “outside the browser” (I believe MeshAppHost.exe actually hosts a chromeless IE browser control).&amp;#160; I’m guessing you would also get the same desktop experience using the Mac Tech Preview.&lt;/p&gt;  &lt;p&gt;If I were an actual Flash developer, I would take it to the next step and call the Mesh APIs using the Microsoft.LiveFramework.js library.&amp;#160; That should “just work” as ActionScript, right?&lt;/p&gt;  &lt;p&gt;If &lt;a href=&quot;http://blogs.zdnet.com/microsoft/?p=1273&quot;&gt;Flash for Windows Mobile&lt;/a&gt; appears before &lt;a href=&quot;http://silverlight.net/learn/mobile.aspx&quot;&gt;Silverlight for Windows Mobile&lt;/a&gt;, this could make for a very interesting deployment option when combined with the &lt;a href=&quot;http://blogs.msdn.com/livemesh/archive/2008/10/30/service-update-beta-and-required-client-upgrade.aspx&quot;&gt;Live Mesh client for Windows Mobile&lt;/a&gt; once it supports Mesh apps.&amp;#160; Three days ago Amit Chopra &lt;a href=&quot;http://channel9.msdn.com/pdc2008/PC10/&quot;&gt;announced&lt;/a&gt; that a public CTP of Silverlight 2 for Mobile will be available in Q1 of 2009.&amp;#160; I’m guessing this will coincide with &lt;a href=&quot;http://visitmix.com/2009/&quot;&gt;MIX09&lt;/a&gt; which starts March 18.&lt;/p&gt;  &lt;p&gt;The skeptics might say hosting Flash in a Live Mesh app is an unsupported hack that Microsoft will quickly disable, but I don’t think so.&amp;#160; David Chappell’s whitepaper &lt;a href=&quot;http://download.microsoft.com/download/e/4/3/e43bb484-3b52-4fa8-a9f9-ec60a32954bc/Azure_Services_Platform.docx&quot;&gt;Introducing the Azure Services Platform&lt;/a&gt; specifically states:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“A mesh-enabled Web application must be implemented using a multi-platform technology, such as Microsoft Silverlight, DHTML, or &lt;strong&gt;Adobe Flash&lt;/strong&gt;. These technologies are supported on all of the operating systems that can run the Live Framework: Windows Vista/XP, Macintosh OS X, and Windows Mobile 6.”&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I think this is a very cool option that highlights the fact that Microsoft designed Mesh to be an open platform with the broadest possible reach.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A &lt;a href=&quot;http://blogs.msdn.com/liveframework/archive/2008/12/02/what-problems-are-we-trying-to-solve.aspx&quot;&gt;whitepaper&lt;/a&gt; just published by a Program Manager and an Architect on the Live Framework team contains the following quote that confirms Flash support:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;What application types are supported by the Live Framework? &lt;/p&gt;    &lt;p&gt;The Live Framework supports client side applications of all types including the following application      &lt;br /&gt;types on Windows to interact with Client or Cloud versions of Live Operating Environment: &lt;/p&gt;    &lt;ol&gt;     &lt;li&gt;Browser based apps (Javascript, &lt;strong&gt;Flash&lt;/strong&gt; and Silverlight) on IE, Firefox and Safari &lt;/li&gt;      &lt;li&gt;Managed desktop applications written using WPF, WinForms, or other languages like Python,        &lt;br /&gt;Ruby, or Perl. All you need is an HTTP Client stack in your programming environment of choice. &lt;/li&gt;      &lt;li&gt;Traditional native Win32 applications (all you need is WinInet/IXmlHttpRequest and MSXML) &lt;/li&gt;   &lt;/ol&gt;    &lt;p&gt;Additionally, on the server side, you can use PHP, WCF, ASP.Net or any other server-side language or      &lt;br /&gt;technology to interact with the cloud version of the Live Operating Environment. &lt;/p&gt;&lt;/blockquote&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/4555482638051495644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/4555482638051495644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/4555482638051495644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/4555482638051495644'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2008/10/live-mesh-flash-adobe-air.html' title='Live Mesh + Flash == Adobe AIR'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-5603389440427354956</id><published>2008-04-18T10:39:00.002-08:00</published><updated>2008-07-21T21:17:22.635-08:00</updated><title type='text'>LINQ to NHibernate in LINQPad</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://www.linqpad.net/&quot;&gt;LINQPad&lt;/a&gt; is like Query Analyzer for LINQ queries.  Out of the box it does LINQ to SQL, LINQ to Objects, and LINQ to XML.  Wouldn&#39;t it be nice if it did &lt;a href=&quot;http://www.ayende.com/Blog/archive/2007/03/17/Implementing-Linq-for-NHibernate-A-How-To-Guide--Part.aspx&quot;&gt;LINQ to NHibernate&lt;/a&gt; as well?  Here&#39;s how.  The setup process is a bit tedious, but you only need to do it once.&lt;/p&gt;&lt;h2&gt;Get a working copy of LINQ to NHibernate&lt;/h2&gt;&lt;p&gt;If you haven&#39;t done so already, use Subversion to check out LINQ to NHibernate from &lt;a href=&quot;https://nhcontrib.svn.sourceforge.net/svnroot/nhcontrib/trunk/src/NHibernate.Linq&quot;&gt;https://nhcontrib.svn.sourceforge.net/svnroot/nhcontrib/trunk/src/NHibernate.Linq&lt;/a&gt; and build it.  If you run NHibernate.Linq.Tests.exe, the MbUnit AutoRunner will run through all the tests and display an HTML report of the test results.  I get 134 passing tests and 31 failing tests which is to be expected since not all of the LINQ features have been implemented yet, but if you check the commit logs you will see this is actively being worked on.  Note that you will need a standard Northwind database (get it &lt;a href=&quot;http://www.microsoft.com/downloads/details.aspx?familyid=06616212-0356-46A0-8DA2-EEBC53A68034&amp;amp;displaylang=en&quot;&gt;here&lt;/a&gt; if you don&#39;t already have it), you will need to create a new database named Test, and you may need to modify the connection strings in App.config to match your setup.&lt;/p&gt;&lt;h2&gt;Add assembly references&lt;/h2&gt;&lt;p&gt;Once you&#39;ve got LINQ to NHibernate working, open LINQPad and press F4 to bring up Advanced Query Properties.  Add references to NHibernate.dll, NHibernate.Linq.dll, and the assemblies containing your entities and your data context.  In this example, those would be Northwind.Entities.dll and NHibernate.Linq.Tests.exe respectively.  Note that when you click Browse to add an assembly reference, you will need to enter *.* in the File Name textbox and press enter to change the file type filter from *.dll to all file types so you can add the Tests.exe reference.&lt;/p&gt;&lt;h2&gt;Import namespaces&lt;/h2&gt;&lt;p&gt;While you&#39;re in the Advanced Query Properties dialog, go to the Additional Namespace Imports tab and enter namespace imports for NHibernate.Cfg and NHibernate.Linq.Tests.Entities.  You may want to click the &quot;Set as default for new queries&quot; button in the lower left so you don&#39;t need to set up these assembly and namespace references the next time you start LINQPad.  Alternatively, when you save a LINQPad .linq query file it will save these references and reload them the next time you open the .linq query file.  This can be handy for switching between different databases and data contexts.&lt;/p&gt;&lt;h2&gt;Resolve connection string config issues&lt;/h2&gt;&lt;p&gt;If you provide NHibernate with connection strings from App.config, LINQPad will not be able to automatically pick these up so you will need to tweak your hibernate.cfg.xml file to contain the actual connection string instead of a named connection string reference.  This involves renaming &quot;connection.connection_string_name&quot; to &quot;connection.connection_string&quot; and changing the value to the connection string found in your App.config.  If you don&#39;t want to mess up your real hibernate.cfg.xml file, make a copy and modify the copy.&lt;/p&gt;&lt;h2&gt;Bootstrap the NHibernate data context&lt;/h2&gt;&lt;p&gt;In LINQPad, change the query type to &quot;C# Statement(s)&quot; and paste the following code, modifying the path and name of your hibernate.cfg.xml file as necessary:&lt;/p&gt;&lt;a href=&quot;http://11011.net/software/vspaste&quot;&gt;&lt;/a&gt;&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;span style=&quot;color:blue;&quot;&gt;var &lt;/span&gt;cfg = &lt;span style=&quot;color:blue;&quot;&gt;new &lt;/span&gt;Configuration().Configure(&lt;span style=&quot;color:#a31515;&quot;&gt;@&quot;C:\NHibernate.Linq\NHibernate.Linq.Tests\bin\Debug\hibernate.cfg.xml&quot;&lt;/span&gt;);&lt;br /&gt;&lt;span style=&quot;color:blue;&quot;&gt;var &lt;/span&gt;factory = cfg.BuildSessionFactory();&lt;br /&gt;&lt;span style=&quot;color:blue;&quot;&gt;var &lt;/span&gt;db = &lt;span style=&quot;color:blue;&quot;&gt;new &lt;/span&gt;NorthwindContext(factory.OpenSession());&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:blue;&quot;&gt;var &lt;/span&gt;q =&lt;br /&gt;    &lt;span style=&quot;color:blue;&quot;&gt;from &lt;/span&gt;c &lt;span style=&quot;color:blue;&quot;&gt;in &lt;/span&gt;db.Customers&lt;br /&gt;    &lt;span style=&quot;color:blue;&quot;&gt;where &lt;/span&gt;c.City == &lt;/span&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;span style=&quot;color:#a31515;&quot;&gt;&quot;London&quot;&lt;br /&gt;    &lt;/span&gt;&lt;span style=&quot;color:blue;&quot;&gt;orderby &lt;/span&gt;c.CustomerID&lt;br /&gt;    &lt;span style=&quot;color:blue;&quot;&gt;select new &lt;/span&gt;{ c.CustomerID, c.CompanyName };&lt;br /&gt;q.Dump();&lt;/span&gt;&lt;/pre&gt;&lt;a href=&quot;http://11011.net/software/vspaste&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Press F5 or Ctrl+E to run this and you should see the following result:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a title=&quot;NHibernateLINQPad&quot; href=&quot;http://www.flickr.com/photos/58933838@N00/2422323683/&quot;&gt;&lt;img alt=&quot;NHibernateLINQPad&quot; src=&quot;http://static.flickr.com/2386/2422323683_99c03ebc5d.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The SQL generated by NHibernate is displayed above the results due to the show_sql=true line in hibernate.cfg.xml.  Be sure to save this &quot;query template&quot; as a LINQPad .linq file so you don&#39;t have to go through this process again!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/5603389440427354956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/5603389440427354956' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/5603389440427354956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/5603389440427354956'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2008/04/linq-to-nhibernate-in-linqpad.html' title='LINQ to NHibernate in LINQPad'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-6638165506889862931</id><published>2007-12-25T15:13:00.001-09:00</published><updated>2007-12-25T15:13:34.260-09:00</updated><title type='text'>WCF Message Size Tester</title><content type='html'>&lt;p&gt;Recently on the &lt;a href=&quot;http://forums.microsoft.com/msdn/showforum.aspx?forumid=118&amp;amp;siteid=1&quot;&gt;WCF Forum&lt;/a&gt; someone suggested that WCF wasn&#39;t able to send messages larger than 2 GB, so I wrote up a little &lt;a href=&quot;http://orand.googlecode.com/files/WcfMessageSizeTest.zip&quot;&gt;example&lt;/a&gt; to disprove this theory.&amp;nbsp; I was able to send a 500 GB message with no problems, and I&#39;m guessing that if I let it run long enough, there will be no problem sending up to 8 million terabytes, the maximum size of a WCF message (Int64.MaxValue).&lt;/p&gt; &lt;p&gt;The main &quot;trick&quot; to sending messages larger than 2 GB is to change the binding&#39;s &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.servicemodel.transfermode.aspx&quot;&gt;TransferMode&lt;/a&gt; from its default of TransferMode.Buffered to TransferMode.Streamed.&amp;nbsp; Besides enabling you to send messages with minimal in-memory overhead, this also allows you to set &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.servicemodel.channels.transportbindingelement.maxreceivedmessagesize.aspx&quot;&gt;MaxReceivedMessageSize&lt;/a&gt; larger than 2 GB without WCF throwing an exception when it tries to build the channel stack.&lt;/p&gt; &lt;p&gt;It&#39;s worth noting that MaxReceivedMessageSize is enforced by WCF regardless of whether the TransferMode is Buffered or Streamed.&amp;nbsp; The same is true for &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.servicemodel.channels.binding.sendtimeout.aspx&quot;&gt;SendTimeout&lt;/a&gt; and &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/system.servicemodel.channels.binding.receivetimeout.aspx&quot;&gt;ReceiveTimeout&lt;/a&gt;, so these still need to be adjusted accordingly.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms731913.aspx&quot;&gt;Stream-based messaging in WCF&lt;/a&gt; is typically accomplished by using service operations that take a Stream as the only parameter, return a Stream, or both.&amp;nbsp; So what kind of Stream should I ask WCF to send for me?&amp;nbsp; I wanted my example to run as fast as possible, which means I didn&#39;t want it to be touching the disk in order to send or receive messages.&amp;nbsp; And I don&#39;t have enough memory or address space to buffer a 500 GB MemoryStream.&amp;nbsp; So I created a little hack stream implementation whose Read method leaves the byte buffer untouched and simply returns the appropriate number of bytes &quot;read&quot;.&amp;nbsp; This results in sending 500 GB of zeros. :-)&lt;/p&gt; &lt;p&gt;Download the example code &lt;a href=&quot;http://orand.googlecode.com/files/WcfMessageSizeTest.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/6638165506889862931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/6638165506889862931' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/6638165506889862931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/6638165506889862931'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2007/12/wcf-message-size-tester.html' title='WCF Message Size Tester'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-6417287542619530779</id><published>2007-12-11T15:51:00.001-09:00</published><updated>2007-12-11T15:51:45.162-09:00</updated><title type='text'>Rhino Mocks Quick Reference</title><content type='html'>&lt;p&gt;Last week I gave a presentation on mock objects for &lt;a href=&quot;http://groups.google.com/group/software-pros-ak&quot;&gt;Software Professionals of Alaska&lt;/a&gt;.&amp;nbsp; Once the PowerPointy hand-waving was out of the way, I illustrated the concepts with code examples using &lt;a href=&quot;http://www.ayende.com/projects/rhino-mocks.aspx&quot;&gt;Rhino Mocks&lt;/a&gt;.&amp;nbsp; I thought I was well-versed in Rhino Mocks before I started, but in the process of preparing the presentation I realized there was a lot that I didn&#39;t know or had forgotten.&amp;nbsp; So I distilled all the main facts and features down into a 3-page quick reference of tables and example usage.&amp;nbsp; You might argue that 3 pages makes it a &quot;slow reference,&quot; but regardless I still think it&#39;s useful to see all the basics stripped down to the bare minimum.&amp;nbsp; Much of the content came from the &lt;a href=&quot;http://www.ayende.com/Wiki/(S(rw1wpp55ybvm4e45nyies155))/Default.aspx?Page=Rhino+Mocks+Documentation&quot;&gt;Rhino Mocks Documentation Wiki&lt;/a&gt;, so look there first if you need more details on a particular feature.&lt;/p&gt; &lt;p&gt;So without further ado, I present the &lt;a href=&quot;http://orand.googlecode.com/files/Rhino%20Mocks%203.3%20Quick%20Reference.pdf&quot;&gt;Rhino Mocks 3.3 Quick Reference&lt;/a&gt;.&amp;nbsp; It includes:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;the 3 different record/replay syntax styles&lt;/li&gt; &lt;li&gt;4 types of mocks, 7 if you include MultiMocks&lt;/li&gt; &lt;li&gt;expectations and setup&lt;/li&gt; &lt;li&gt;methods&lt;/li&gt; &lt;li&gt;properties&lt;/li&gt; &lt;li&gt;events&lt;/li&gt; &lt;li&gt;exceptions&lt;/li&gt; &lt;li&gt;delegates&lt;/li&gt; &lt;li&gt;custom behavior&lt;/li&gt; &lt;li&gt;assert messages&lt;/li&gt; &lt;li&gt;ordered and unordered&lt;/li&gt; &lt;li&gt;repetition&lt;/li&gt; &lt;li&gt;the full set of argument constraints&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Feedback is quite welcome.&amp;nbsp; Enjoy!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/6417287542619530779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/6417287542619530779' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/6417287542619530779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/6417287542619530779'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2007/12/rhino-mocks-quick-reference.html' title='Rhino Mocks Quick Reference'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-8523264103764913692</id><published>2007-09-26T09:46:00.001-08:00</published><updated>2007-09-26T09:46:00.888-08:00</updated><title type='text'>Google Street View in Anchorage</title><content type='html'>&lt;p&gt;Yesterday as &lt;a href=&quot;http://spu.facebook.com/profile.php?id=42901503&quot;&gt;Garret&lt;/a&gt; and I were on our way to the &lt;a href=&quot;http://groups.google.com/group/software-pros-ak/about&quot;&gt;Software Professionals of Alaska&lt;/a&gt; meeting where &lt;a href=&quot;http://www.milkcarton.com/blog/&quot;&gt;Dan&lt;/a&gt; and I&amp;nbsp;presented on &lt;a href=&quot;http://www.mbunit.com/&quot;&gt;MbUnit&lt;/a&gt;, we spotted &lt;a href=&quot;http://gizmodo.com/gadgets/eye-on-you/google-streetview-camera-car-fleet-set-to-invade-america-279222.php&quot;&gt;one of these&lt;/a&gt;&amp;nbsp;on 36th Avenue!&amp;nbsp; So I&amp;nbsp;grabbed my cell phone and snapped a few shots.&amp;nbsp; Too bad the camera was covered due to the rain, otherwise we might be famous!&amp;nbsp; The Starbucks-sipping driver frowned at us as we enthusiastically pointed, waved, and took pictures.&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://farm2.static.flickr.com/1387/1443007197_4edd5de0a0_o_d.jpg&quot;&gt; &lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://farm2.static.flickr.com/1154/1443007099_be6ae04b53_o_d.jpg&quot;&gt;&lt;/p&gt; &lt;p&gt;&lt;img src=&quot;http://farm2.static.flickr.com/1181/1443869856_4ba04b0ab1_o_d.jpg&quot;&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/8523264103764913692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/8523264103764913692' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/8523264103764913692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/8523264103764913692'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2007/09/google-street-view-in-anchorage.html' title='Google Street View in Anchorage'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-116658401877033860</id><published>2006-12-19T18:06:00.000-09:00</published><updated>2009-05-08T14:49:12.541-08:00</updated><title type='text'>Generic NHibernate Enum String Mapping</title><content type='html'>&lt;p&gt;Today one of my coworkers mentioned all the little NHibernate enum mapping turd classes that were accumulating in our data access layer.&amp;#160; See &lt;a href=&quot;http://codebetter.com/blogs/jeffrey.palermo/archive/2006/03/14/140949.aspx&quot;&gt;this post&lt;/a&gt; for more details on how it works and why you would want to do this.&amp;#160; I wondered aloud if generics could be used to eliminate this waste of disk space.&amp;#160; A few minutes later, this is what we came up with.&lt;/p&gt; &lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; GenericEnumMapper&amp;lt;TEnum&amp;gt; : EnumStringType&lt;br /&gt;{&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; GenericEnumMapper() : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(TEnum))&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt; &lt;br /&gt; &lt;p&gt;To use this class in your NHibernate mapping file, just use the following lovely .NET 2.0 generics syntax in your &amp;quot;type&amp;quot; attribute:&lt;/p&gt; &lt;pre class=&quot;csharpcode&quot;&gt;MyNamespaceB.GenericEnumMapper`1[[MyNamespaceA.MyEnum,&lt;br /&gt; MyAssemblyA]], MyAssemblyB&lt;/pre&gt; &lt;br /&gt; &lt;p&gt;No, that ` is not an apostrophe, it&#39;s a backtick.&amp;#160; It lives on the same key as ~ on my keyboard.&lt;/p&gt; &lt;br /&gt; &lt;p&gt;Here it is in a sample hbm.xml mapping file:&lt;/p&gt; &lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt; ?&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;hibernate-mapping&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;urn:nhibernate-mapping-2.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;MyNamespaceA.UserCredential, MyAssemblyA&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;attr&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;UserCredential&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;lazy&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Id&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;ID&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;Guid&amp;quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;generator&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;guid.comb&amp;quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;UserId&amp;quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;CredentialType&amp;quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;CredentialTypeID&amp;quot;&lt;/span&gt; &lt;br /&gt;&lt;strong&gt;&lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&amp;quot;MyNamespaceB.GenericEnumMapper`1[[MyNamespaceA.CredentialType,&lt;br /&gt;MyAssemblyA]], MyAssemblyB&amp;quot;&lt;/span&gt;&lt;/strong&gt;&lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    ...&lt;br /&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;hibernate-mapping&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt; &lt;br /&gt; &lt;p&gt;Copy, paste, and replace CredentialType with your own enum type, and you&#39;re good to go!&lt;/p&gt;  </content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/116658401877033860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/116658401877033860' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/116658401877033860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/116658401877033860'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2006/12/generic-nhibernate-enum-string-mapping.html' title='Generic NHibernate Enum String Mapping'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-116190409010716373</id><published>2006-10-26T15:08:00.000-08:00</published><updated>2007-12-12T13:56:33.696-09:00</updated><title type='text'>Debugging with Reflector and Visual Studio</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/default.aspx&quot;&gt;Mike Taulty&lt;/a&gt; recently &lt;a href=&quot;http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2006/10/25/8930.aspx&quot;&gt;posted&lt;/a&gt; about how he debugs using Visual Studio, &lt;a href=&quot;http://www.aisto.com/roeder/dotnet/&quot;&gt;Reflector&lt;/a&gt;, and &lt;a href=&quot;http://msdn.microsoft.com/msdnmag/issues/03/06/Bugslayer/&quot;&gt;SOS&lt;/a&gt;.  I&#39;ve been doing a similar style of debugging lately that I think is a bit more efficient, and here&#39;s how I do it.  You may want to first &lt;a href=&quot;http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2006/10/25/8930.aspx&quot;&gt;take a look&lt;/a&gt; at what Mike&#39;s doing to put this in context.&lt;/p&gt;&lt;p&gt;First I use &lt;a href=&quot;http://weblogs.asp.net/nunitaddin/default.aspx&quot;&gt;Jamie Cansdale&lt;/a&gt;&#39;s awesome &lt;a href=&quot;http://www.testdriven.net/&quot;&gt;TestDriven.NET&lt;/a&gt; which has the very cool &lt;a href=&quot;http://weblogs.asp.net/nunitaddin/archive/2006/08/29/Go-To-Reflector.aspx&quot;&gt;Go To Reflector&lt;/a&gt; feature.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.flickr.com/104/280170004_3cc8396d22_o.png&quot; /&gt; &lt;/p&gt;&lt;p&gt;You can also Go To Reflector from any frame in a call stack:&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.flickr.com/110/280170012_ef4d949e89_o.png&quot; /&gt; &lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.flickr.com/117/280170007_92781ca41c_o.png&quot; /&gt; &lt;/p&gt;&lt;p&gt;One cool thing about this is that your Reflector instance stays open the whole time, and as you bounce around your call stack using Go To Reflector, the Reflector instance synchronizes to the new location that you specified using Go To Reflector.&lt;/p&gt;&lt;p&gt;You can also &lt;a href=&quot;http://weblogs.asp.net/nunitaddin/archive/2006/08/30/TestDriven.NET-2.0.1761-_2D00_-RC1.aspx&quot;&gt;set breakpoints on code from within Reflector&lt;/a&gt;, which is a bit friendlier than setting breakpoints from the Disassembly window.  Yes, you can set breakpoints on assemblies that you don&#39;t even have the source for.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.flickr.com/122/280170010_caa8196e11_o_d.png&quot; /&gt; &lt;/p&gt;&lt;p&gt;Instead of dropping into SOS mode to look at local variables and the value of &lt;span style=&quot;font-family:Courier New;&quot;&gt;this&lt;/span&gt;, I simply pull up the Locals debug window.  The Locals window shows values from the current stack frame as you double-click each frame in the Call Stack pane.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://static.flickr.com/88/280170006_8360bd81c3_o_d.png&quot; /&gt; &lt;/p&gt;&lt;p&gt;Sometimes the Autos window will show additional relevant variables that the Locals window doesn&#39;t and vice versa, so you may want to check both if you don&#39;t find what you&#39;re looking for.&lt;/p&gt;&lt;p&gt;Unfortunately I haven&#39;t found a way to get Visual Studio to do the equivalent of SOS&#39;s !dumpheap or !dumpobj for browsing and searching the heap, so you&#39;ll still need to drop down to SOS/WinDbg if you want to find all in-memory instances of particular objects or if you&#39;re analyzing a dump file.  Supposedly you can load WinDbg/AdPlus dumps in Visual Studio, but I haven&#39;t gotten that to work very well with dumps of managed code.  If anyone knows the secret to getting Visual Studio to analyze dumps of managed code in the same level of detail as it analyzes managed processes, I&#39;d love to find out.&lt;/p&gt;&lt;p&gt;For more commentary on Mike&#39;s original goal of being able to debug the .NET Framework using its actual source code, see &lt;a href=&quot;http://weblogs.asp.net/astopford/archive/2006/10/26/Debugging-with-source.aspx&quot;&gt;this post&lt;/a&gt; by &lt;a href=&quot;http://weblogs.asp.net/astopford/default.aspx&quot;&gt;Andrew Stopford&lt;/a&gt; about using &lt;a href=&quot;http://www.microsoft.com/downloads/details.aspx?FamilyId=8C09FD61-3F26-4555-AE17-3121B4F51D4D&amp;amp;displaylang=en&quot;&gt;Rotor&lt;/a&gt; to debug with source, and check out the comments regarding &lt;a href=&quot;http://www.codeplex.com/deblector&quot;&gt;Deblector&lt;/a&gt;.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/116190409010716373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/116190409010716373' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/116190409010716373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/116190409010716373'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2006/10/debugging-with-reflector-and-visual.html' title='Debugging with Reflector and Visual Studio'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-116175151020582592</id><published>2006-10-24T20:45:00.000-08:00</published><updated>2006-10-24T20:46:20.516-08:00</updated><title type='text'>WCF Service Dependency Injection</title><content type='html'>&lt;p&gt;Whoops, I accidentally got some &lt;a href=&quot;http://haacked.com/archive/2006/10/24/Integrate_Your_Custom_Search_Engine_With_The_Browser.aspx&quot;&gt;link love&lt;/a&gt; from &lt;a href=&quot;http://haacked.com/&quot;&gt;Phil Haack&lt;/a&gt;, but my blog has been dormant for 8 months!&amp;nbsp; Time to start posting all those half-finished Windows Live Writer drafts!&amp;nbsp; Here goes...&lt;/p&gt; &lt;p&gt;Say you&#39;ve implemented a WCF service that uses a business logic layer which in turn uses a data access layer.&amp;nbsp; Rather than hard-code these dependencies into your service&#39;s constructor, you would like to use &lt;a href=&quot;http://www.martinfowler.com/articles/injection.html&quot;&gt;dependency injection&lt;/a&gt; to enable unit testing of each layer using a&amp;nbsp;&lt;a href=&quot;http://en.wikipedia.org/wiki/Mock_object&quot;&gt;mock object&lt;/a&gt;&amp;nbsp;framework such as &lt;a href=&quot;http://www.ayende.com/projects/rhino-mocks.aspx&quot;&gt;Rhino Mocks&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;For our purposes we&#39;ll do constructor injection using &lt;a href=&quot;http://www.springframework.net/&quot;&gt;Spring.NET&lt;/a&gt;, although I&#39;ve also heard good things about the &lt;a href=&quot;http://www.castleproject.org/index.php/Main_Page&quot;&gt;Castle&lt;/a&gt; containers, and &lt;a href=&quot;http://www.codeplex.com/wiki/view.aspx?ProjectName=ObjectBuilder&quot;&gt;ObjectBuilder&lt;/a&gt; from Microsoft patterns &amp;amp; practices looks promising.&lt;/p&gt; &lt;p&gt;So we have a few simple classes and interfaces that we&#39;d like to automagically hook up:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    [ServiceContract]&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IServiceContract&lt;br /&gt;    {&lt;br /&gt;        [OperationContract]&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ServiceLayer : IServiceContract&lt;br /&gt;    {&lt;br /&gt;        IBusinessLogic _businessLogic;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ServiceLayer(IBusinessLogic businessLogic)&lt;br /&gt;        {&lt;br /&gt;            _businessLogic = businessLogic;&lt;br /&gt;        }&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IBusinessLogic&lt;br /&gt;    {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; BusinessLogic : IBusinessLogic&lt;br /&gt;    {&lt;br /&gt;        IDataAccess _dataAccess;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; BusinessLogic(IDataAccess dataAccess)&lt;br /&gt;        {&lt;br /&gt;            _dataAccess = dataAccess;&lt;br /&gt;        }&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IDataAccess&lt;br /&gt;    {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; DataAccess : IDataAccess&lt;br /&gt;    {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;We&#39;d like to accomplish the equivalent of the following code whenever our service is created:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ServiceLayer(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; BusinessLogic(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DataAccess()));&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;What does the Spring.NET equivalent look like?&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    IApplicationContext ctx = ContextRegistry.GetContext();&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; (ServiceLayer)ctx.GetObject(&lt;span class=&quot;str&quot;&gt;&quot;ServiceLayer&quot;&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;How does Spring.NET know how to wire up the dependencies?&amp;nbsp; It uses reflection and config hints to determine who depends on whom:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;configSections&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;sectionGroup&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;spring&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;section&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;context&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Spring.Context.Support.ContextHandler, Spring.Core&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;section&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;objects&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Spring.Context.Support.DefaultSectionHandler, Spring.Core&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;sectionGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;configSections&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;resource&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;config://spring/objects&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;objects&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;http://www.springframework.net&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;DataAccess&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;NamespaceA.DataAccess, AssemblyA&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;BusinessLogic&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;NamespaceB.BusinessLogic, AssemblyB&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;autowire&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;constructor&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;ServiceLayer&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;NamespaceC.ServiceLayer, AssemblyC&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;autowire&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;constructor&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;That&#39;s great, but how do we get WCF to do this for us at the right place at the right time?&amp;nbsp; By using WCF&#39;s &quot;behavior injection&quot; functionality of course!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;We&#39;ll need to implement an &lt;a href=&quot;http://windowssdk.msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iinstanceprovider.aspx&quot;&gt;IInstanceProvider&lt;/a&gt; that allows us to serve up instances of our service each time WCF needs a new instance.&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; DependencyInjectionInstanceProvider : IInstanceProvider&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Type _serviceType;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; DependencyInjectionInstanceProvider(Type serviceType)&lt;br /&gt;        {&lt;br /&gt;            _serviceType = serviceType;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; GetInstance(InstanceContext instanceContext)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; GetInstance(instanceContext, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; GetInstance(InstanceContext instanceContext, Message message)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; result = &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;            IApplicationContext context = ContextRegistry.GetContext();&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;[] objectNames = context.GetObjectNamesForType(_serviceType);&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (objectNames.Length != 1)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; YourOwnException(&lt;br /&gt;                    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(&lt;br /&gt;                    CultureInfo.InvariantCulture,&lt;br /&gt;                    &lt;span class=&quot;str&quot;&gt;&quot;There must exist exactly one &amp;lt;object&amp;gt; definition for the {0} service in the Spring configuration&quot;&lt;/span&gt;,&lt;br /&gt;                    _serviceType.Name)&lt;br /&gt;                    );&lt;br /&gt;            }&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; context.GetObject(objectNames[0]);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; instance) { }&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Then we&#39;ll need an &lt;a href=&quot;http://windowssdk.msdn.microsoft.com/en-us/library/system.servicemodel.description.iservicebehavior.aspx&quot;&gt;IServiceBehavior&lt;/a&gt; that plugs in our IInstanceProvider at the right place at&amp;nbsp;the right time.&amp;nbsp; Remember,&amp;nbsp;WCF could&amp;nbsp;choose to activate our service per call, per private session, per shared session, or as a singleton.&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;&lt;p&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; DependencyInjectionServiceBehavior : IServiceBehavior&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (ChannelDispatcherBase cdb &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; serviceHostBase.ChannelDispatchers)&lt;br /&gt;            {&lt;br /&gt;                ChannelDispatcher cd = cdb &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; ChannelDispatcher;&lt;br /&gt;                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (cd != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (EndpointDispatcher ed &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; cd.Endpoints)&lt;br /&gt;                    {&lt;br /&gt;                        ed.DispatchRuntime.InstanceProvider = &lt;br /&gt;                            &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DependencyInjectionInstanceProvider(serviceDescription.ServiceType);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,  &lt;br /&gt;                Collection&amp;lt;ServiceEndpoint&amp;gt; endpoints, BindingParameterCollection bindingParameters) {}&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {}&lt;br /&gt;    }&lt;/p&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Now we want to actually use this behavior.&amp;nbsp; You could implement classes to apply this behavior using custom attributes, via config, or programmatically via a custom ServiceHost.&amp;nbsp; I chose to go the ServiceHost route.&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MyServiceHost : ServiceHost&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; MyServiceHost() : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;() { }&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; MyServiceHost(Type serviceType, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; Uri[] baseAddresses) : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(serviceType, baseAddresses) { }&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; OnOpening()&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.Description.Behaviors.Add(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DependencyInjectionServiceBehavior());&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;.OnOpening();&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;And of course a custom ServiceHost needs a custom ServiceHostFactory if you want IIS to host it (you can use your custom ServiceHost directly when self-hosting):&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MyServiceHostFactory : ServiceHostFactory&lt;br /&gt;    {&lt;br /&gt;        &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; MyServiceHost(serviceType, baseAddresses);&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;This factory can then be referenced from your .svc files:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;&amp;lt;%@ ServiceHost&lt;br /&gt;Service=&lt;span class=&quot;str&quot;&gt;&quot;NamespaceC.ServiceLayer, AssemblyC&quot;&lt;/span&gt;&lt;br /&gt;Factory=&lt;span class=&quot;str&quot;&gt;&quot;NamespaceD.MyServiceHostFactory, AssemblyD&quot;&lt;/span&gt;&lt;br /&gt;%&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;a href=&quot;http://hyperthink.net/blog/default.aspx&quot;&gt;Steve Maine&lt;/a&gt; has a great series of posts with more details on how service activation and hosting work:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://hyperthink.net/blog/2006/04/13/A+Brief+Tour+Of+Service+Activation.aspx&quot;&gt;A brief tour of service activation&lt;/a&gt; &lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://hyperthink.net/blog/2006/06/23/The+ServiceHost+Directive.aspx&quot;&gt;The @ServiceHost Directive&lt;/a&gt; &lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://hyperthink.net/blog/2006/07/08/Of+Hosts+And+Factories.aspx&quot;&gt;Of Hosts and Factories&lt;/a&gt; &lt;br /&gt;&lt;li&gt;&lt;a href=&quot;http://hyperthink.net/blog/2006/07/15/ServiceHostFactory+Vs+ServiceHostFactoryBase.aspx&quot;&gt;ServiceHostFactory vs ServiceHostFactoryBase&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/116175151020582592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/116175151020582592' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/116175151020582592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/116175151020582592'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2006/10/wcf-service-dependency-injection.html' title='WCF Service Dependency Injection'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-114023151977198732</id><published>2006-02-17T17:07:00.000-09:00</published><updated>2024-05-26T06:54:53.351-08:00</updated><title type='text'>FogBugz  browser search integration</title><content type='html'>&lt;a href=&quot;http://www.fogcreek.com/FogBugz/&quot;&gt;FogBugz 4.0&lt;/a&gt; has a handy new search URL that lets you enter a bug number to go directly to a bug, or search text to find all open cases matching your query.  Wouldn&#39;t it be nice to hook this into your browser&#39;s search box?  Fortunately, &lt;a href=&quot;http://www.microsoft.com/windows/IE/ie7/default.mspx&quot;&gt;IE7&lt;/a&gt; uses A9&#39;s &lt;a href=&quot;http://opensearch.a9.com/&quot;&gt;OpenSearch&lt;/a&gt; for its search providers, and Firefox uses &lt;a href=&quot;http://mycroft.mozdev.org/deepdocs/quickstart.html#standard&quot;&gt;Mycroft&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;font-size:130%;&quot; &gt;Creating the OpenSearch provider&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Create an XML file with the following text:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;OpenSearchDescription xmlns=&quot;http://a9.com/-/spec/opensearch/1.1/&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  &amp;lt;ShortName&amp;gt;FogBugz&amp;lt;/ShortName&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  &amp;lt;Description&amp;gt;Search FogBugz&amp;lt;/Description&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  &amp;lt;Url type=&quot;text/html&quot; template=&quot;http://[your-ip-goes-here]/fogbugz/default.asp?pre=preMultiSearch&amp;amp;amp;pg=pgList&amp;amp;amp;pgBack=pgSearch&amp;amp;amp;search=2&amp;amp;amp;searchFor={searchTerms}&quot; /&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;/OpenSearchDescription&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Replace [your-ip-goes-here] with the appropriate address.&lt;br /&gt;&lt;br /&gt;Put the XML file on your web server and put the following link somewhere that&#39;s publicly accessible:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;a href=&quot;#&quot; onClick=&quot;window.external.AddSearchProvider(&amp;amp;quot;http://[url-to-your-directory]/FogBugzOpenSearch.xml&amp;amp;quot;);&quot;&amp;gt;Add FogBugz search provider to IE7&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Replace [url-to-your-directory] with the appropriate URL.&lt;br /&gt;&lt;br /&gt;Now, when you click on the link from IE7, you&#39;ll be prompted to add a new search provider.  This will make a FogBugz option available in the dropdown list of your search box:&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://photos1.blogger.com/blogger/7828/1515/1600/IE7-FogBugz.jpg&quot;&gt;&lt;img style=&quot;margin: 0pt 10px 10px 0pt; cursor: pointer;&quot; src=&quot;http://photos1.blogger.com/blogger/7828/1515/320/IE7-FogBugz.jpg&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;font-size:130%;&quot; &gt;&lt;br /&gt;Creating the Firefox provider&lt;br /&gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Create a file named FogBugzSearch.src in a public directory on your web server with the following text:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;search&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;version=&quot;7.1&quot;&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;name=&quot;FogBugz&quot;&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;description=&quot;Search FogBugz&quot;&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;action=&quot;http://[your-ip-goes-here]/fogbugz/default.asp&quot;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;searchForm=&quot;http://[your-ip-goes-here]/fogbugz/&quot;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;method=&quot;GET&quot;&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;gt;&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;input name=&quot;pre=preMultiSearch&amp;amp;amp;pg=pgList&amp;pgBack=pgSearch&amp;amp;search=2&amp;searchFor&quot; user=&quot;&quot;&amp;gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;/search&amp;gt;&lt;br /&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;browser&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;update=&quot;http://[url-to-your-directory]/FogBugzSearch.src&quot;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;   &lt;br /&gt;updateIcon=&quot;http://[url-to-your-directory]/FogBugzSearch.png&quot;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;br /&gt;        updateCheckDays=&quot;360&quot;&lt;/span&gt; &lt;/pre&gt;&lt;/span&gt; &lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;p&gt;&amp;gt;&lt;/p&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fill in the blanks with the appropriate addresses and URLs.&lt;br /&gt;&lt;br /&gt;Put the following image in the same directory:&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://photos1.blogger.com/blogger/7828/1515/1600/FogBugzSearch.png&quot;&gt;&lt;img style=&quot;cursor: pointer;&quot; src=&quot;http://photos1.blogger.com/blogger/7828/1515/320/FogBugzSearch.png&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;font-size:130%;&quot; &gt;&lt;span style=&quot;font-size:100%;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Now to create the link.  Put the following in your head element:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;&lt;br /&gt;function addEngine(name,ext,cat,type)&lt;br /&gt;{&lt;br /&gt; if ((typeof window.sidebar == &quot;object&quot;) &amp;&amp;amp; (typeof window.sidebar.addSearchEngine == &quot;function&quot;)) { &lt;pre&gt;&lt;br /&gt;     window.sidebar.addSearchEngine(&lt;br /&gt;       &quot;http://[url-to-your-directory]&quot;+name+&quot;.src&quot;,&lt;br /&gt;       &quot;http://[url-to-your-directory]&quot;+name+&quot;.&quot;+ext, name, cat );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and the following link in your page:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&amp;lt;a href=&quot;javascript:addEngine(&#39;FogBugzSearch&#39;,&#39;png&#39;,&#39;General&#39;,&#39;0&#39;)&quot;&amp;gt;Add FogBugz search provider to Firefox&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now, when you click on the link from Firefox, you&#39;ll be prompted to add a new search provider. This will make a FogBugz option available in the dropdown list of your search box:&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://photos1.blogger.com/blogger/7828/1515/1600/Firefox-FogBugz.jpg&quot;&gt;&lt;img style=&quot;cursor: pointer;&quot; src=&quot;http://photos1.blogger.com/blogger/7828/1515/320/Firefox-FogBugz.jpg&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/114023151977198732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/114023151977198732' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/114023151977198732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/114023151977198732'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2006/02/fogbugz-browser-search-integration.html' title='FogBugz  browser search integration'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-113056856321047548</id><published>2005-10-29T17:43:00.000-08:00</published><updated>2005-10-29T17:43:35.103-08:00</updated><title type='text'>Private offices: what do they really compensate for?</title><content type='html'>Recently someone on the team forwarded a link to Joel&#39;s mini-essay &lt;a href=&quot;http://joelonsoftware.com/items/2005/10/16.html&quot;&gt;Multitasking in the Workplace&lt;/a&gt;, a small rant against the problem of coworker interruptions with private offices as the solution. In case you haven&#39;t read many Joel articles yet, he &lt;i&gt;&lt;a href=&quot;http://www.joelonsoftware.com/articles/BionicOffice.html&quot;&gt;really&lt;/a&gt;&lt;/i&gt; &lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000068.html&quot;&gt;likes&lt;/a&gt; &lt;a href=&quot;http://www.joelonsoftware.com/news/20020430.html&quot;&gt;private&lt;/a&gt; &lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000332.html&quot;&gt;offices&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I think Joel&#39;s focus on private offices is a result of his belief that superstar programmers create the best software, described in &lt;a href=&quot;http://www.joelonsoftware.com/articles/HighNotes.html&quot;&gt;Hitting the High Notes&lt;/a&gt; (&lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000074.html&quot;&gt;and&lt;/a&gt; &lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000073.html&quot;&gt;other&lt;/a&gt; &lt;a href=&quot;http://www.joelonsoftware.com/articles/fog0000000072.html&quot;&gt;places&lt;/a&gt;). Superstars are most productive if they don&#39;t have to work directly with each other. In the &lt;a href=&quot;http://www.joelonsoftware.com/articles/HighNotes.html&quot;&gt;High Notes&lt;/a&gt; article, Joel says, &quot;A single good programmer working on a single task has no coordination or communication overhead. Five programmers working on the same task must coordinate and communicate.&quot; As if communication is an evil that should be avoided if at all possible, especially where it involves his superstar programmers (perhaps he&#39;s on to something).&lt;br /&gt;&lt;br /&gt;Notice the diagram at the top of the article:&lt;br /&gt;&lt;br /&gt;&lt;table style=&quot;FONT: 12px Helvetica,Arial,sans-serif; TEXT-ALIGN: center&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Best Working Conditions&lt;/td&gt;&lt;td style=&quot;FONT-SIZE: 200%&quot;&gt;→&lt;/td&gt;&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Best Programmers&lt;/td&gt;&lt;td style=&quot;FONT-SIZE: 200%&quot;&gt;→&lt;/td&gt;&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Best Software&lt;/td&gt;&lt;td style=&quot;FONT-SIZE: 200%&quot;&gt;→&lt;/td&gt;&lt;td style=&quot;BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; BORDER-LEFT: black 1px solid; WIDTH: 65px; BORDER-BOTTOM: black 1px solid&quot;&gt;Profit!&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Where is Best Team in this picture?&lt;br /&gt;&lt;br /&gt;A number of people have commented on this, filling in the team side of the equation:&lt;br /&gt;&lt;br /&gt;Scott Berkun discusses the relationship between &lt;a href=&quot;http://www.scottberkun.com/essays/essay47.htm&quot;&gt;teams and stars&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Eric Sink replies with a &lt;a href=&quot;http://www.ericsink.com/articles/Choir.html&quot;&gt;choir analogy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.amazon.com/exec/obidos/redirect?link_code=ur2&amp;amp;amp;camp=1789&amp;tag=orand-20&amp;amp;creative=9325&amp;path=tg/detail/-/0787960756/qid=1130566289/sr=8-1/ref=pd_bbs_1?v=glance%26s=books%26n=507846&quot;&gt;The Five Dysfunctions of a Team&lt;/a&gt; says the fifth dysfunction, inattention to results, happens when team members put their individual needs (ego, career development, recognition) above the success of the team. This is a big risk when you&#39;ve got a bunch of superstars working in isolated silos.&lt;br /&gt;&lt;br /&gt;I think the most telling statement in &lt;a href=&quot;http://joelonsoftware.com/items/2005/10/16.html&quot;&gt;Multitasking in the Workplace&lt;/a&gt; is &quot;She does mention that open-spacers do frequently decide to &#39;interrupt themselves&#39; to participate in another conversation that they overheard, something which is probably net beneficial for the team&#39;s productivity but which drives me crazy.&quot; This implies that he&#39;s not going to encourage behavior that boosts the net productivity of the group! How can individual productivity possibly matter more than the net productivity of the group? I don&#39;t get it.&lt;br /&gt;&lt;br /&gt;This isn&#39;t the first time Joel has heard stuff like this. Several years ago he &lt;a href=&quot;http://www.joelonsoftware.com/news/20020430.html&quot;&gt;asked&lt;/a&gt; Tom DeMarco what he thought of pair programming contrasted with private offices. Tom replied that &quot;groups of people who work in the same style on the same kinds of tasks will &lt;i&gt;not&lt;/i&gt; distract each other.&quot; It&#39;s worth noting that Tom is the author of the excellent &lt;a href=&quot;http://www.amazon.com/exec/obidos/redirect?link_code=ur2&amp;amp;amp;amp;amp;amp;amp;camp=1789&amp;tag=orand-20&amp;amp;creative=9325&amp;amp;path=tg/detail/-/0932633439/qid=1130565979/sr=8-1/ref=pd_bbs_1?v=glance%26s=books%26n=507846&quot;&gt;Peopleware&lt;/a&gt;, the book Joel often refers to when speaking of private offices.&lt;br /&gt;&lt;br /&gt;I do agree that removing distractions is important for productivity. I&#39;m just not sure I agree with Joel that those distractions are always necessarily my coworkers.&lt;br /&gt;&lt;br /&gt;From observing our team&#39;s development cycles, I&#39;ve found it most helpful to be &quot;distracted&quot; by on-topic conversations when we&#39;re in our analysis and design phases, and least helpful when we&#39;re in the coding phase. Joel&#39;s right… when your head is full of all the variables necessary for writing code, it&#39;s very expensive to re-load after an interruption. I guess my &quot;it depends&quot; answer means I also disagree with Joel that a developer is always working on code.  Of course Joel is 45% more likely to say &lt;a href=&quot;http://www.google.com/search?hl=en&amp;lr=&amp;c2coff=1&amp;q=site%3Awww.joelonsoftware.com+programmer+OR+programmers&quot;&gt;programmer&lt;/a&gt; than &lt;a href=&quot;http://www.google.com/search?hl=en&amp;lr=&amp;c2coff=1&amp;q=site%3Awww.joelonsoftware.com+developer+OR+developers&quot;&gt;developer&lt;/a&gt;...&lt;br /&gt;&lt;br /&gt;I think it&#39;s up to each person to determine when they need to be in &quot;flow&quot; mode and put on headphones, hang a do-not-disturb sign, or disappear for a while when they need uninterrupted focus. Telecommuting can be awesome for getting lots done when you know exactly what needs to be done and can do it all on your own.&lt;br /&gt;&lt;br /&gt;I must admit that I have been strongly on both sides of the fence on this issue at various points in the past, so I reserve the right to change my mind depending on the circumstances.  In the here and now, the benefits of sacrificing my personal productivity for the productivity of the team are quite clear.&lt;br /&gt;&lt;br /&gt;That&#39;s enough for now… I really do enjoy Joel&#39;s articles, even the ones I disagree with.</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/113056856321047548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/113056856321047548' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/113056856321047548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/113056856321047548'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2005/10/private-offices-what-do-they-really.html' title='Private offices: what do they really compensate for?'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-113061868511270761</id><published>2005-10-29T12:10:00.000-08:00</published><updated>2005-10-29T12:44:45.896-08:00</updated><title type='text'>Fixing my VS2005 RTM install</title><content type='html'>After downloading Visual Studio 2005 Professional Edition RTM from MSDN I debated whether or not to install it since I would have to go without all the cool WinFX goodies like Avalon, Linq, and Windows Workflow Foundation. In the end I broke down and decided to move to the RTM.&lt;br /&gt;&lt;br /&gt;In addition to the 24-step &lt;a href=&quot;http://lab.msdn.microsoft.com/vs2005/uninstall/preRTMuninstall/default.aspx&quot;&gt;pre-RTM uninstall instructions&lt;/a&gt; you will need to uninstall a bunch of other things like the Linq Visual Studio extensions (pull up the local documentation HTML file and click the link that pulls up the folder with the Linq VS uninstall bat file), Linq, Visual Studio 2005 Extensions for Windows Workflow Foundation, Windows Workflow Foundation, WinFS, WinFX, and I think I&#39;m forgetting some more of them.  Make sure you pass through your entire Add/Remove Programs list, because some of them aren&#39;t grouped under Microsoft.&lt;br /&gt;&lt;br /&gt;In my case, I overlooked Visual Studio 2005 Extensions for Windows Workflow Foundation until after VS 2005 Beta 2 was uninstalled.  Oops!  But it appeared to uninstall just fine once I discovered that.&lt;br /&gt;&lt;br /&gt;So I went through the Visual Studio 2005 Professional Edition RTM install and everything went smoothly until right towards the end when a dialog popped up telling me that Visual Studio 2005 encountered an error, and would I like to send it to Microsoft?  This error occured while the installer was on the &quot;Executing action:HxMerge_VSCC_v80&quot; step.  I continued with the installation, and it appeared to complete successfully.&lt;br /&gt;&lt;br /&gt;But when I tried to start Visual Studio 2005, the splash screen appeared and then the devenv process went away!  I noticed the splash screen showed Microsoft Workflow Tools on the list of loaded modules...  I Googled the HxMerge installer step above and found someone else with the &lt;a href=&quot;http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=115359&quot;&gt;same problem&lt;/a&gt; with an earlier version.  So I tried starting devenv with the /safemode switch, and sure enough it started!  I went to Tools -&gt; Options and saw a configuration section for the Windows Workflow Designer, which threw an error when I tried to expand it.&lt;br /&gt;&lt;br /&gt;So, I installed Windows Workflow Foundation and Visual Studio 2005 Extensions for Windows Workflow Foundation on top of my VS2005 RTM installation, uninstalled both of the WWF items in Add/Remove Programs, and now VS2005 is happy again!&lt;br /&gt;&lt;br /&gt;And no, VS2005 RTM doesn&#39;t work with the WWF designer.  It reports an error and gives you an option to not load the module in the future.&lt;br /&gt;&lt;br /&gt;Hopefully RTM-friendly versions of Avalon, WWF, and all the other WinFX goodies show up soon!  If an RTM-friendly Linq update is possible without destabilizing the C# compiler, that would also be cool.</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/113061868511270761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/113061868511270761' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/113061868511270761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/113061868511270761'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2005/10/fixing-my-vs2005-rtm-install.html' title='Fixing my VS2005 RTM install'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18388564.post-113048956918264842</id><published>2005-10-28T00:52:00.000-08:00</published><updated>2005-10-28T00:52:49.183-08:00</updated><title type='text'>Hello world!</title><content type='html'>That is all.</content><link rel='replies' type='application/atom+xml' href='http://orand.blogspot.com/feeds/113048956918264842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/18388564/113048956918264842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/113048956918264842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18388564/posts/default/113048956918264842'/><link rel='alternate' type='text/html' href='http://orand.blogspot.com/2005/10/hello-world_28.html' title='Hello world!'/><author><name>Oran Dennison</name><uri>http://www.blogger.com/profile/18170789721507988932</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1027/862050814_7b5c261d5c.jpg'/></author><thr:total>0</thr:total></entry></feed>