| Comments

Are you using SharePoint and want to know how to leverage Silverlight?  Have you seen the Blueprints project on Codeplex?  But what if those particular implementations don’t meet your needs and you want to create your own contained web part with your Silverlight 2 application?

Kirk Evans writes about a method of doing this in a recent post: Hosting Silverlight in SharePoint.  Take a look at Kirk’s post with a step-by-step guide of getting started with his method.  In looking at the method he describes, it is conceivable that you actually could make a more generic web part that serves as a XAP host and allows the user to set the property of the Source to a URI for a Silverlight 2 application.

Hmmm…I wonder if Kirk is up to modifying it ;-).

UPDATE (08 OCT 2008):

Looks like there is a similiar web part in the works already!  Thanks to a note from Andy Nogueira, he has a project (also on Codeplex) for SilverPart, which is a Silverlight wrapper web part for SharePoint.  Thanks for the pointer Andy!

| Comments

Today we released Silverlight 2 RC0This release is for a very specific purpose and although the information will likely be repeated, I wanted to try to help answer a few questions.

What is this release?

RC0 is a developer release only!  The intent of providing these bits is to provide developers with ample time to have access to the release candidate runtime/controls for Silverlight with the primary goal of making sure that developers with Silverlight 2 Beta 2 applications that are live today prepare for the release of Silverlight 2.

What should a developer do?

If you have a Silverlight 2 Beta 2 application that is out there today, you should use this RC0 build to port/stage your application in a test environment to this RC0 build and test to make any required changes based on the breaking changes from Beta 2 to RC0.

Why should I care?

Because your Silverlight 2 Beta 2 applications will not work on the release of Silverlight 2.  If you have applications today, you want to make sure that your application will work and that is why we’re providing this RC0 build for developers now.

I’ve made my changes and it works, should I deploy it now?

NO!  This is a developer release only.  What does that mean? That means that there is no end-user installable runtime that is released, only the developer runtime with the developer tools.  If you deploy an RC0 application into the wild your users will be greeted with unfriendly install messages taking them to bits for Beta 2, making them confused.  You should, however, deploy to your test environments for your test team(s) to check out your application.

So why am I doing this again then?

Sorry to be repetitive, but this is for developers.  Again, the goal is to give developers who have Beta 2 applications ample time to port/stage and test their applications.  You want to do this to be ready so that when Silverlight 2 releases, your app will be ready and you can flip the switch on your bits.

Will my end users be auto updated to RC0?

No, end users who have either Silverlight 1.0 or Silverlight 2 Beta 2 installed will not be automatically updated to RC0.  When Silverlight 2 releases, they will be notified of a new version for the release version.

So how will I know what may break?

We’ve created a breaking changes document that provides the breaking changes between Beta 2 and RC0.  It is available for you to download and we recommend you use this as your guide and first point of attack when troubleshooting porting your application.  The breaking changes document is located here.

As an example, here’s one that I think is so simple, but might have some banging their heads when their users complain they are still being asked to install Silverlight.  In the Beta 2 builds, if you use the <object> instantiation method, your code may look something like this:

   1: <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">
   2:     <param name="source" value="ClientBin/XMLFile.xap"/>
   3:     <param name="onerror" value="onSilverlightError" />
   4:     <param name="background" value="white" />
   5:     
   6:     <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
   7:         <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
   8:     </a>
   9: </object>

In RC0 (and release) you’ll want to change it to this:

   1: <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">
   2:     <param name="source" value="ClientBin/XMLFile.xap"/>
   3:     <param name="onerror" value="onSilverlightError" />
   4:     <param name="background" value="white" />
   5:     
   6:     <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
   7:         <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
   8:     </a>
   9: </object>

Notice the type attribute in the <object> tag changes from application/x-silverlight-2-b2 to application/x-silverlight-2.  Please note this is the plugin application type only and not to be confused with the server-side MIME type mapping (which should be .XAP mapping to application/x-silverlight-app).

Also notice the correct link to the “fwlink” to the runtime.  When Silverlight releases you’ll be sure in your custom install experience (please don’t use the default) you’ll want to point to the right link.

Ok, I’m convinced, what do I need to do?

Here’s what I’d do if I had a beta 2 application:

    • Re-read the above to make sure I understand the intent of this release fully.
    • Download the Silverlight Tools for Visual Studio 2008 (RC0) – this will give you the VS project templates, the VS updates required, the RC0 developer runtime and the SDk documents.
    • Download the Expression Blend 2 Service Pack 1 Preview – this build of Blend is targeted against the release bits of Silverlight and will help you in porting your application.
    • Make sure you have a backup of your project (or set a version/tag/branch in your source control) so you can rollback if needed.
    • Open your Silverlight project using the updated tools.  You’ll see a note about the project needing to be upgraded.
    • Compile/run your application and pay attention to any warnings/errors that the compiler/Visual Studio spit out.
    • Compare/contrast any warnings/errors with the breaking changes document and modify if needed.
    • Put your application in a test environment only for your developers/internal testers to mess around with.  Do not deploy your application to your customers yet!
    • Rinse.  Repeat.  The testing/changing cycle that is.

This should get you going rather quickly.  If you experience issues, use the appropriate feedback channels that you’ve already established (i.e., if you are working with someone at Microsoft or have a contact).  Please be sure to consult the breaking changes document first though.

Allow me to comment about breaking changes.  I know that as a developer this can add work for you…ah the joys of being an early adopter!  Breaking changes in beta to release products can be a good thing if it helps bring compatibility in frameworks and if it makes for an easier or more logical API.

Okay, so we do all this prep work, when is Silverlight 2 releasing?

Ah, the magic question.  While we aren’t providing any dates right now, we are still committing to shipping Silverlight this year.  We are providing this release now to ensure you as a developer can stage/test your Beta 2 applications and be ready!  If you don’t have any applications that are running now (live) on Beta 2 but have been working on one, then you’ll want to start with RC0 as well so that you minimize the work you have to do when you go live.

Other goodness

The ADO.NET Data Services (the artist formerly known as “Astoria”) bits are also updated in RC0 SDK/Tools.  The bits that were provided as a stop gap are now a part of the RC0 bits.

Need the Mac developer runtime for testing?  You can get that here.  Also keep in mind this is a developer build as well.

What’s new you say?  Well not a ton (as we’ve been saying) but you should see a ProgressBar, PasswordBox and ComboBox in there now!  In addition to the new controls, all the controls were updated with new skin templates.  Also the RC0 bits allow you to enable HTTP hosted applications to call secure services (policy file required), which I know people have been wanting.  Wondering about stuff that Shawn mentioned?  Well you shouldn’t have expected them here for 2 reasons.  First, they aren’t going to be a part of the core runtime.  Second he mentioned that they are working toward a preview release for PDC (end of October).  So be on the lookout for that work!

I hope this helps!  Again, this information is also linked here and you can see some more notes from ScottGu here.

| Comments

Someone posed this question (“Can you use IsolatedStorage in Silverlight as a more reliable browser caching technique?”) to me and I answered with my usual optimistic “in theory, yes” answer.  Of course I had never tried it which is horrible to answer that to someone without trying it.  In working on creating some Silverlight business application samples, I figured I should probably look at this scenario to see if a) it would work and b) it makes sense.  I’ll at least try to answer “a” here.

The Setup

Let’s look at the setup.  The goal here is to have a lean startup application and only request additional components/controls/applications when needed, thus producing the best startup experience for the end user.  I decided to use an existing simple sample I already had which does dynamic XAP loading for an application.  Basically the application loads a simple interface of a search box and button.  Since the user hasn’t interacted with data yet, we didn’t want to add the payload of DataGrid into the initial application.  Once the button is clicked the application is requested, loaded into memory and displayed.  The relevant code from that sample is shown here:

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     panel1.Children.Clear();
   4:  
   5:     WebClient c = new WebClient();
   6:     c.OpenReadCompleted += new OpenReadCompletedEventHandler(c_OpenReadCompleted);
   7:     c.OpenReadAsync(new Uri("DynamicXapDataGrid_CS.xap", UriKind.Relative));
   8: }
   9:  
  10: void c_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
  11: {
  12:     string appManifest = new StreamReader(Application.GetResourceStream(new StreamResourceInfo(e.Result, null), new Uri("AppManifest.xaml", UriKind.Relative)).Stream).ReadToEnd();
  13:  
  14:     Deployment deploy = XamlReader.Load(appManifest) as Deployment;
  15:  
  16:     Assembly asm = null;
  17:  
  18:     foreach (AssemblyPart asmPart in deploy.Parts)
  19:     {
  20:         string source = asmPart.Source;
  21:         StreamResourceInfo streamInfo = Application.GetResourceStream(new StreamResourceInfo(e.Result, "application/binary"), new Uri(source, UriKind.Relative));
  22:  
  23:         if (source == "DynamicXapDataGrid_CS.dll")
  24:         {
  25:             asm = asmPart.Load(streamInfo.Stream);
  26:         }
  27:         else
  28:         {
  29:             asmPart.Load(streamInfo.Stream);
  30:         }
  31:     }
  32:  
  33:     panel1.DataContext = FakeData.GetCustomers(LastNameSearch.Text);
  34:  
  35:     UIElement myData = asm.CreateInstance("DynamicXapDataGrid_CS.Page") as UIElement;
  36:  
  37:     panel1.Children.Add(myData);
  38:     panel1.UpdateLayout();
  39:  
  40: }

You can see that in line 7 above we are using OpenRead to request our satellite XAP which contains our control/logic for our DataGrid, and then starting in line 18 we look for the relevant assembly to load and instantiate (line 35) and put into the visual tree (line 37).

Browser Caching The Request

If we would execute the app (clicking the button) several times, we’d expect that the first time the browser would request the satellite XAP and deliver it.  We would also generally expect the browser to cache that request for later.  So that if we click the button again, it would retrieve from cache and operate faster.

But what about corporate policies and other types of things that may prevent the browser from caching that request?  What if we want a different mechanism for caching our object requests and satellite assemblies?

An alternate method, use IsolatedStorage

So how can we refactor the above to use Silverlight’s IsolatedStorage area as a cache for our satellite assemblies?  let’s take a look.  First if you follow similar techniques as you might in ASP.NET for caching, you’d first check the cache before you load something.  If it isn’t there, you’d load it, add it to the cache and then use it for later as well.  Let’s do that here.

Instead of making the OpenRead request on the button click, we should first check to see if the satellite XAP has been loaded into IsoStore:

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     panel1.Children.Clear();
   4:  
   5:     using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
   6:     {
   7:         if (!store.FileExists("DynamicXapDataGrid_CS.xap"))
   8:         {
   9:             WebClient c = new WebClient();
  10:             c.OpenReadCompleted += new OpenReadCompletedEventHandler(c_OpenReadCompleted);
  11:             c.OpenReadAsync(new Uri("DynamicXapDataGrid_CS.xap", UriKind.Relative));
  12:         }
  13:         else
  14:         {
  15:             LoadData();
  16:         }
  17:     }
  18: }

Line 5 shows us initating the IsolatedStorage area.  (For more information on IsolatedStorage usage, see this video.)  We first look to see if the file exists in the store.  If it is not in there, then we use our OpenRead functionality to start the request.  If the file is there, then we call our refactored LoadData() function, which we’ll look at in a moment.  The completed event for our OpenReadAsync call looks like this:

   1: void c_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
   2: {
   3:     using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
   4:     {
   5:         System.IO.IsolatedStorage.IsolatedStorageFileStream fileStream;
   6:  
   7:         // create the file
   8:         fileStream = store.CreateFile("DynamicXapDataGrid_CS.xap");
   9:  
  10:         // write out the stream to isostore
  11:         WriteStream(e.Result, fileStream);
  12:  
  13:         fileStream.Close();
  14:     }
  15:     LoadData();
  16: }
  17:  
  18: private void WriteStream(Stream stream, System.IO.IsolatedStorage.IsolatedStorageFileStream fileStream)
  19: {
  20:     byte[] buffer = new byte[4096];
  21:     int bytesRead;
  22:  
  23:     while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
  24:     {
  25:         fileStream.Write(buffer, 0, bytesRead);
  26:     }
  27: }

What we see here is that in our completed event is where we actually create the file and put it in our IsoStore location using a little helper method to write the stream data out.  Now we have a satellite assembly in our IsolatedStorage for our application.

You can see that in the completed event we also call LoadData().  This is really the same core code we previously had that we refactored into a common method:

   1: private void LoadData()
   2: {
   3:     using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
   4:     {
   5:         IsolatedStorageFileStream fileStream = store.OpenFile("DynamicXapDataGrid_CS.xap", FileMode.Open, FileAccess.Read);
   6:  
   7:         #region Original Code
   8:         StreamResourceInfo sri = new StreamResourceInfo(fileStream, "application/binary");
   9:  
  10:         Stream manifestStream = Application.GetResourceStream(sri, new Uri("AppManifest.xaml", UriKind.Relative)).Stream;
  11:         string appManifest = new StreamReader(manifestStream).ReadToEnd();
  12:  
  13:         Deployment deploy = XamlReader.Load(appManifest) as Deployment;
  14:  
  15:         Assembly asm = null;
  16:         
  17:         foreach (AssemblyPart asmPart in deploy.Parts)
  18:         {
  19:             string source = asmPart.Source;
  20:  
  21:             // next line is a hack for Beta 2 and is not needed in Silverlight 2 release
  22:             fileStream = store.OpenFile("DynamicXapDataGrid_CS.xap", FileMode.Open, FileAccess.Read);
  23:  
  24:             StreamResourceInfo streamInfo = Application.GetResourceStream(new StreamResourceInfo(fileStream, "application/binary"), new Uri(source, UriKind.Relative));
  25:  
  26:             if (source == "DynamicXapDataGrid_CS.dll")
  27:             {
  28:                 asm = asmPart.Load(streamInfo.Stream);
  29:             }
  30:             else
  31:             {
  32:                 asmPart.Load(streamInfo.Stream);
  33:             }
  34:         }
  35:  
  36:         panel1.DataContext = FakeData.GetCustomers(LastNameSearch.Text);
  37:  
  38:         UIElement myData = asm.CreateInstance("DynamicXapDataGrid_CS.Page") as UIElement;
  39:  
  40:         panel1.Children.Add(myData);
  41:         panel1.UpdateLayout();
  42:         #endregion
  43:  
  44:     }
  45: }

You’ll note that we pull the file out of IsoStore and do our same loading from there.  Please note the comment for line 22.  This is a bug in Silverlight 2 Beta 2 where the Stream is closed too early and thus you’d get an exception on line 24 because the Stream was already closed in line 10.  The code above is a hack for sure (and inefficient).  We could have subclassed Stream and modified the Close functionality, but since I know it works in the release code I wasn’t going to bother you with some unnecessary huge workaround at this point, but line 22 can be removed at release time.

The Results

So putting it all together let’s look at how the requests look.  Let’s wipe out our IsolatedStorage so that nothing is in there:

Now when we click on our button in our application, we can see that since there is nothing in our IsoStore, the HTTP traffic goes through:

and we now have something in our IsoStore as evident by the preferences dialog:

or more specifically by spelunking to the actual location for IsolatedStorage, we can see our XAP located there:

Sweet.  Now future button clicks show no more HTTP traffic because it is pulling it out of IsolatedStorage.  If we clear our browser cache, it is still there.  If we delete our cookies, the XAP is still there.  Now when our app users return, they’ll have the satellite assemblies/XAPs we need for our apps already on their machine.

Caution and Thoughts

Okay, while this “works” there are definitely some cautionary decisions you’d have to make from an application architecture point of view.  Here are some thoughts…

    • What about versioning of your satellite assemblies and controls?  If you use the exact method here, any update would never be retrieved.  Some mechanism of adding data to the IsoStore information should be considered so you know your users have what your application expects.
    • What about the size of the XAP and the available storage space in IsoStore?  You should know the sizes of things you are going to place into IsoStore, and in the code above before placing anything in there, you should look at the available space and request a quota increase if needed.  Information on how this can be done is explained here.
    • What about new browser functionality like InPrivate and In Cognito windows from browsers?  Since both of these functions are in browsers that are beta, it is hard to say how their final implementations will effect the use of IsolatedStorage, but it is something to consider and test.

At any rate, an interesting pattern that you may want to consider for your application if it makes sense.  Is it more reliable than the browser cache?  I don’t think you can universally answer that because almost all client configurations for stuff like that seem to vary…but it is an alternative!  Here’s the code for the completed solution I modified.

| Comments

Some new videos just got posted to the Silverlight community site.  Topics included:

As always, feedback and ideas are welcome.  Ben’s been leaving some great comments here on suggested topics and I’d love to see more.  I’ll be starting a new ‘series’ soon…more to come on that in a week’s time.

As a reminder, these videos are meant to help jump start some learning.  We try to keep them intermediate initially so they aren’t incredibly simple and aren’t incredibly difficult.  If we are missing the mark, I expect that you’ll leave comments on those videos that do so!

Related topics:

| Comments

The Silverlight Streaming service has been upgraded to support Silverlight 2 beta 2 applications.

As a note to customers who were previously hosting Beta 1 applications for test purposes, as beta 1 is no longer a supported test platform for SLS.  Authors should update/upload their applications using the latest Silverlight 2 bits.  These are available (with the tools) from the Silverlight community site.

Silverlight 1 applications hosted on SLS are not affected by this upgrade and still supported of course.

Remember that you can also now directly upload a XAP file to SLS using the Manage Applications functionality and then it will dynamically create a manifest file for you – so you don’t have to even worry about packaging up things in some scenarios!