With the release of ADO.NET Data Services v1.5 CTP2, you can now use the Silverlight Astoria client library to access Cross-Domain services and applications written with the new client library can go out of browser.
The new Client Http networking stack introduced in SL3 supports the standard and custom HTTP Verbs(GET/PUT/POST/DELETE/MERGE) as well as access to the response status codes required for a full fidelity REST-based client experience in Silverlight. Working with the SL networking team, we modified the Astoria client library to use the networking stack in cross-domain and out-of-browser scenarios. With this change, we are now able to support Cross-Domain calls allowed by ClientAccessPolicy.xml files and applications written with the Silverlight Astoria client library can go Out Of Browser.
1. Recompile your application with a reference to the new Silverlight client library . 2. Update the URI of the Data Service to point to the absolute URI of the Data Service in its new location. 3. Drop a ClientAccessPolicy.xml file into the root of the Webserver Hosting your Data Service. 4. Deploy the newly created application to the Webserver. 5. In your Silverlight application code, find all the places that you call EndExecute/EndSaveChanges/EndExecuteBatch and check if the call is being marshaled back to the UI thread , else Silverlight will throw an invalid Cross-Thread Access Exception. To fix this, always dispatch the call to EndExecute to the UI thread using Dispatcher.BeginInvoke. As an example:
nwContext.BeginExecute<Customers>(new Uri("Customers"), (asResult) => { Dispatcher.BeginInvoke( () =>{ CustomersGrid.ItemsSource = nwContext.EndExecute<Customers>(asResult).ToList(); } ); }, someUserState);
Now , let’s walk through a demo application that illustrates how to build a Silverlight application that accesses an ADO.NET Data Service from a different domain than the Silverlight application and can also run Out-Of-Browser.
We have a sample Silverlight application that looks like this :
1. SilverlightApplicationHost is the Web application hosting your Silverlight XAP , think of this as UI.Foo.Com. 2. DataServiceHost is the web application hosting the ADO.NET Data Service , think of this as API.Foo.Com 3. DataServicesXDomainSLClient is the Silverlight application that runs in UI.Foo.Com and consumes the Data Service from API.Foo.Com.
Since the DataServiceHost site hosts the Data Service, it also hosts the ClientAccessPolicy.xml file which allows apps from the domain hosting the Silverlight app to access resources hosted at API.Foo.com
The Silverlight application, DataServicesXDomainSLClient, has a Service Reference to the Data Service hosted at DataServiceHost. It has two buttons which download an Entity Set called “Publications” from the Data Service and looks like this.
The “Load Publications Via Uri” downloads Entities from the “Publications” entity set and the Click handler looks like this :
void btnLoadPublications_Click(object sender, RoutedEventArgs e) { object userState = null; //download the Publications and sort the Publications in descending order of Name publicationContext.BeginExecute<Publication>( new Uri("/Publications?$expand=PublishedFrom&$orderby= Name desc", UriKind.Relative), (asResult) => { //Dispatch the EndExecute call to the UI thread Dispatcher.BeginInvoke( () => { var IEnumerableOfPublications = publicationContext.EndExecute<Publication>(asResult); PublicationsGrid.ItemsSource = IEnumerableOfPublications.ToList(); } ); }, userState); }
The “Load Publications Via Linq” downloads entities via a Linq Query and the Click Handler looks like this :
void btnLoadPublicationsLinq_Click(object sender, RoutedEventArgs e) { object userState = null; //download the Publications and sort the Publications in ascending order of Name var publicationLinqQuery = (from pub in publicationContext.CreateQuery<Publication>("Publications") .Expand("PublishedFrom") orderby pub.Name ascending select pub) as DataServiceQuery<Publication>; publicationLinqQuery.BeginExecute( (asResult) => { //Dispatch the EndExecute call to the UI thread Dispatcher.BeginInvoke( () => { var IEnumerableOfPublications = publicationLinqQuery.EndExecute(asResult); PublicationsGrid.ItemsSource = IEnumerableOfPublications.ToList(); }); }, userState); }
Clicking the “Install Me” button installs the app and launches it Out Of Browser. Here is what the “Install Me” button click handler looks like :
/// <summary> /// Installs the Silverlight application as an Out Of Browser application /// </summary> void InstallApplication(object sender, RoutedEventArgs e) { //Install the app App.Current.Install(); //Hide the "Install Me" button btnInstallOOBApp.Visibility = Visibility.Collapsed; }
The buttons which do a Linq Query and a URI query still work , without any changes to the code .
To debug your Out Of Browser Silverlight apps , follow these steps.
1. Open the properties of the Silverlight application.
2. Select the Out Of Browser application which has the name of the project with the Page hosting the SL application. Which , in this case , is SilverlightApplicationHost.
3. Hit F5 and select yes when this prompt comes up. This prompt is warning you that you have a Service Reference to a Data Service. In In-Browser Silverlight apps , running the SL app directly will launch it off of the file system ( i.e c:\Projects\yourProjectPath), and you wont be able to make calls to data services as this would constitute a Cross-Scheme request and isn’t allowed.
While debugging your Out Of Browser Silverlight application, you can ignore this prompt.
No, the SL3 Client Http Stack is only used for Out-Of-Browser and Cross-domain network access. The XmlHttp based stack is still used for In Browser, Same Domain network access to preserve backward compatibility. You can customize this by setting a new property on the client library called HttpStack. HttpStack which has 3 possible values:
1. Auto: Client library decides when to switch networking stacks. 2. XmlHttp: The classic networking stack based on XmlHttpRequest 3. ClientHttp: The new SL3 Client HTTP stack
The Default value is Auto, and you should leave it as it is, unless you need to customize the networking stack we use. When the HttpStack is set to Auto, the client library automatically switches the networking stack it uses to talk to the Data Service.
Silverlight App
Data Service
Out Of Browser
Networking stack
http://foo.com
False
XmlHttp
True
ClientHttp
http://UI.foo.com
http://API.foo.com
False/True
Features VS Networking Stack
Feature
Cross Domain Data Access
No
Yes
Out Of Browser Data Access
NTLM Based Authentication
No*
Same Domain Data Access
Cookie Based Authentication
Cookie store shared with browser
*We are working over the next few releases of Silverlight to extend the ClientHttp stack such that it supports all possible scenarios.
With the new networking stack, in X-Domain and OOB scenarios, the client library is now restricted to the same options as any other application that uses the SL3 networking stack. The main concern is that NTLM based authentication schemes such as Windows Authentication or BASIC Authentication are not supported in X-Domain and Out Of Browser scenarios. The only authentication schemes that are supported are cookie-based authentication schemes such as ASP.NET Forms Authentication. An example of using the new client library with ASP.NET Forms Authentication will be shown in Part II of this blog post.
You can download the sample application shown here at the bottom of the post.
Phani Raj Engineer, ADO.NET Data Services .