Rants Tagged with “Silverlight 2”
After digging and some prodding by a PM at Microsoft, I realize that the relative URI story in WebClient is different that I expected. I am not sure whether this changed from previous versions but Beta 2 and the RC this is the way that Relative URI's work in WebClient:
- WebClient supports a BaseAddress property (read/write) that by default contains the path to the .xap file (though you could replace it with HtmlPage.Document.DocumentUri.ToString() to resolve to the current page).
- It uses the BaseAddress to calculate the relative URI.
- This is not the same as the Image/Media "Site of Origin" relative URI problem (see my post about that here).
- In most cases a relative URI in WebClient will do the right thing and supporting the BaseAddress will allow you to change the basis for the relative URI's pretty easily.
Note that the WebRequest classes (BrowserHttpRequest specifically) does not support relative URI's so if you want to use that class instead of WebClient, you'll have to do your own relative URI resolution.
I am happy to announce our newest partner for the Silverlight Tour: Saffron Interactive. They will be teaching the Silverlight Tour materials in the United Kingdom including their first class on December 3-5, 2008 in London, England.
For this first class I will be teaching the class so if you are in London and have been hoping to take the class from me, this is your one opportunity as Saffron will be teaching all subsequent classes.
When making web requests in Silverlight 2, its easy to start with the simple WebClient class. In fact, it supports making simple requests (DownloadStringAsync and OpenReadAsync) as well as uploading through the class. On the other hand there are some that swear by the WebRequest route. What's the big difference?
Let's start with WebRequest. The pattern for WebRequest is to call WebRequest.Create:
Uri url = new Uri("http://localhost:8889/Silverlight.js", UriKind.Absolute);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);;
Notice that we are actually using a HttpWebRequest object and casting the return value of the Create call. In reality this object is a BrowserHttpWebRequest object. This class represents a web request in Silverlight 2 (since all requests are actually routed through the browser's networking stack). The reason for this is to make sure that any requests are part of the page. This means that when you make a request in Silverlight 2 it is bringing with it the same Session ID and cookies. This also means that for large sized requests, the user may cancel the request.
To execute the request, we need to get a WebResponse object that contains our results of the request. To do this, ordinarily you would call the HttpWebRequest's BeginGetResponse method:
req.BeginGetResponse(new AsyncCallback(WebComplete), req);
This method specifies that you create an AsyncCallback object that describes the callback once the request is complete. The WebComplete object in the AsyncCallback is actually the method to call (though you could use a delegate or lambda here):
void WebComplete(IAsyncResult a)
{
HttpWebRequest req = (HttpWebRequest)a.AsyncState;
HttpWebResponse res = (HttpWebResponse)req.EndGetResponse(a);
Dispatcher.BeginInvoke(() => status.Text = "Downloading...Done.");
}
Note that we're retrieving the request from the AsyncState and then calling EndGetResponse to complete the operation. The most important thing to understand inside this callback is that it does not happen on the UI thread so any calls to update the UI will result in InvalidThreadAccessExceptions. Typically this means using the Dispatcher to call the UI thread as necessary (as shown). In addition, the response contains a stream that contains the results of the request. To retrieve the data, you need to write code to dig it out of the stream as necessary...not hard, but another step.
In contrast, the WebClient class performs this operation very differently. First, it supports two different request styles: DownloadString and OpenRead. DownloadString support the ability to retrieve a string with the contents of the request. The OpenRead style returns a Stream instead. This way you can decide if you need a simple way to retrieve just a string, otherwise you can use the tried and true way of consuming a Stream.
Another change is the WebClient class uses events not AsyncCallbacks to complete the asynchronous model. The events and execution start of each of the styles are paired up with Completed events and Async execution methods. For example, to make a request with the WebClient with the DownloadString style:
WebClient client = new WebClient();
client.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("/Silverlight.js", UriKind.Relative));
The other big difference is that the WebClient class handles the context switch for the user. What this means is that when the event is fired, it is always called on the UI thread. So your event handling code can update the UI directly as so:
void client_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
status.Text = "Downloading...Done.";
}
So what's the verdict? There is none. They both are fine to use. In fact, under the covers the WebClient class uses the BrowserHttpWebRequest class so that it does not matter. If you find the WebClient class easier to use, go ahead. But if you are already familiar with the HttpWebRequest-style classes and AsyncCallback objects, continue to do what you're comfortable with. Just understand the differences between these workhorses of Silverlight 2.
What do you use?
In case you haven't heard yet, Microsoft announced that a Release Candidate of the Silverlight 2 tools are now available. You can download it now here:
Included is the Silverlight 2 SDK, Silverlight 2 Visual Studio Tools, the Silverlight 2 Developer Runtime and Blend 2 SP1 (was called Blend 2.5 but is now a patch to Blend 2 instead). Note that the Release Candidate should give you time to get your applications ready for release, but that the runtime won't be generally available on the Internet until Silverlight 2 reaches release. Unlike when Silverlight 2 Beta 2 was released, you won't have to rush to fix your applications.
This means there is no "Go-Live" license with the Release Candidate, but you can modify your code to be compatible with the release and be ready to deploy them once the RTW (Release to Web) happens (which hopefully will happen soon).
Note: Beta 2 users will automatically be upgraded to the RTW version once its available.
Also make sure you look at the Breaking Changes document to see what's changed. The changes are not dramatic but there are a couple of surprises:
- By default all rendering is now pixel aligned. This should allow you to avoid that sub-pixel rendering issues that plagued earlier releases. You can enable sub-pixel rendering if you need it.
- Blend 2 SP1 now supports the Font Manager (so you can embed and even subset fonts automatically).
- New controls were released (ComboBox, ProgressBar and PasswordBox).
- Fonts now must be assembly resources (no more free floating fonts in the .xap file).
- Custom Control XAML files now must exist in a themes folder instead of at the root of the project.
For all the changes, please review the Breaking Changes document.
I am currently converting all my examples to RTW and they will ship when the release happens.
It has come to my attention that my current examples using ADO.NET Data Services are performing very badly. I was using that example as anecdotal evidence that Data Services performed slower than the Web Service counterparts. I don't think this is accurate. I am working on some performance comparisons that I will share on my blog once Silverlight 2 goes into a full release so I can be sure that the numbers reflect a real-world release.
The issue seems to surround a bone-headed query I was making:
var qry = from p in TheContext.Products.Expand("Supplier").Expand("Category")
orderby p.ProductName
select p;
This means for every product I was retrieving its related Category and Supplier. The problem is that I was duplicating this data (since some products shared Categories and Suppliers). Not efficient at all.
When I re-release these examples when Silverlight 2 ships, I will be hosting the examples on CodePlex. Watch here for announcements on the release of the code, new versions of the examples as well as the performance comparisons coming soon.
I was crufting up a sample LINQ to JSON example today to post in my blog but something odd happened. I couldn't find a public service that both used JSON and supports a security policy file. Let me clarify that.
In Silverlight (like Flash/Flex), in order to make calls to external domains, that domain must support a security policy file. Flash defines one format and Silverlight another, though Silverlight supports the Flash format (for the most part). So if a domain has allowed Flash to access its site, Silverlight should be able to. Great...right?
I could have crafted up an example of writing your own service that exposed JSON (pretty easy in .NET 3.5 and WCF), but that's not the point. If I was going to expose a service, why would I choose JSON if Silverlight is the only client? Its not significantly smaller than XML and the other benefits are not significant enough to bother.
What I thought was a no brainer was to use one of the public API's that support it (e.g. Yahoo Image Search, Google Base, etc.) So far none that I can find support a policy file (Flash's or Silverlight's) so I can't call them. This is similar to the problem with Amazon's S3 lack of policy file support noted by several people (Tim Heuer most notably).
I'd love to finish the example and show it because LINQ to SQL is cool, but until I find a compelling public API, I won't bother...its just not that important. If any of my readers know of one (or think one might work), let me know and I'll try it out.
Jon Galloway has a great new post on how to get the dev builds of Chrome to see new fixes for Silverlight and Flash. While this is laudable, these new builds still don't show any content (e.g. any of my examples) that use "windowless=true".
I originally thought it was the hosting (silverlight.js which I use extensively instead of object tags or the asp.net control). After looking at the differences, I settled in on the issue which is windowless=true. I expect they'll fix it eventually.
This took me a few days to get around to, but Adam Cooper sent me a link to his utility class for supporting the scroll wheel in ScrollViewers the other day. I am very impressed by it so far and wanted to share it with all my Silverlight 2 readers!
I just got back from the Silverlight 2 Firestarter in New York City. I had a great time. We have a good turn-out and great discussions about the technology. The Microsoft guys that set this up were just great, especially Peter Laudati who organized the whole thing and made my short trip up there really simple and fun.
For the attendees of the talks, here's a link to the example project I built for you:
Much has been made in the blogosphere about the recent announcement that the NBC/NFL deal. NBC announced recently that they would be showing their live NFL games over the web via Flash versus Silverlight. I've heard a lot of hyperbole on both sides about why this happened. I am deferring to something who I think actually doesn't have a horse in this race, an online video business analyst:
To quote him (if you haven't clicked over yet):
It's a shame that in our industry, some bloggers are more concerned with writing a headline just for drama sake, as opposed to actually getting the details right. In the past few days, at least half a dozen sites said that NBC was "dropping", "dumping" or "ditching" Silverlight in favor or Flash for streaming of football games on NBCSports and NFL.com....Problem is, none of this is true.
As far as I can tell, the decision was a business decision and not a technical decision. Let's try and be honest and not religious about this. Both Silverlight and Flash are great technologies. As someone who has invested a lot of time and money in Silverlight, I'd like it to do well but I could never say that it is superior in every way to Flash/Flex...because that just isn't true. Hopefully pundits on both sides can do the same.
In fact, I am of the opinion that the best thing to happen to Flash developers was Silverlight. Huh? Yeah! The reason this was so good for Flash is it forced Adobe to start paying attention again. Competition is good for everyone and Adobe is being pushed on both features and price to be competitive with Microsoft. In that ecosystem everyone wins.