| Comments

We were all jumping for joy when Silverlight 2 beta 1 was released and the ability to connect to services was more readily/easily available to us.  For discoverable services that provided a WSDL we were quickly able to implement them using the Add Service Reference capability in Visual Studio 2008.  Beta 2 brings a few changes to the world of services that you should know about.  I’ll do my best to recap some of them here.

Generating a WCF Service

In beta 1 when we created a WCF service for use in Silverlight, we used the “WCF Service” template in Visual Studio (assuming you used Visual Studio).  This was fine and created a standard WCF service for us.  There were a few changes that we had to make to ensure that our Silverlight application could consume it in an acceptable manner.  First, we had to change the binding configuration in ASP.NET web.config from wsHttpBinding to basicHttpBinding as Silverlight only supports that binding type right now.  Secondly, we might have had to add capabilities to enable ASP.NET compatibility support depending on what we were doing with the service.  In beta 2, this process gets a bit simpler for services specifically built for Silverlight.  After you install the tools for Visual Studio, you now get a new item type:

It is important to note that the WCF Service template is still a perfectly acceptable one to choose, you just have to ensure to make those changes accordingly.  The new Silverlight-enabled WCF Service basically does those for us as well as add the ASP.NET compatibility attributes for us in the code.  Additionally, the traditional interface/implementation is simplified into a single class.  Again, the other ways are still valid, but for services specifically built for Silverlight, this might be an easier route to get them done.

Cross-domain policy file updates

Cross-domain restrictions still apply within beta 2 and the same rules apply.  There is one subtle change that is required to your clientaccesspolicy.xml file that is required.  In the allow-from node of the policy file, the attribute http-request-headers is now required.  If your service is an open/public one then specifying “*” is probably acceptable (you’ll have to be the judge of that.  If you only wanted to allow specific headers (besides the blacklisted ones) you can provide those in a comma-separated list and can use wildcards as well.  For example you could use X-MyApp-* if you wanted.

Another thing to note about the support for Adobe’s crossdomain.xml policy file is one thing we found in interpretation of the policy template.  Previously Flash was a Macromedia product and as such that file is adorned with a DOCTYPE that represents a schema with macromedia in it.  Well, Adobe has changed the schema a little bit and also updated the DOCTYPE to reflect Adobe as the authority.  Right now, Silverlight still expects to validate the macromedia declaration.

ServiceReferences.ClientConfig

In beta 1, when you performed the Add Service Reference operation a file named ServiceReferences.ClientConfig was created and had some configuration information in it.  This file, however, wasn’t really used.  In beta 2, this configuration file can be shipped with your XAP and used as configuration.  It provides a subset of WCF configuration.  Refined details of those settings are in the SDK, but I thought it might be helpful to know.

Change to WebClient

In beta 1, WebClient was the easiest library to use in accessing non-discoverable services.  One challenge was that it only supported GET verb requests.  In beta 2 WebClient has changed to enable POST verb actions as well.  the UploadStringAsync function will send the request but the endpoint URI must be a URI that accepts the POST verb.

In addition, WebClient is now callable on a background thread in addition to the UI thread.  This may come in handy for some situations.

I see these as small but helpful changes.  Most are based on feedback we received from beta 1 customers and community, so thank you for that feedback.  I hope this helps!

| Comments

The first of my Silverlight videos have posted which cover some networking stuff that I’ve been blogging about already.  If you want to see a walk through of things you might have already read, please take a look at them:

There are more coming and I’m interested in hearing your comments so please give them.  If you have suggestions for things that need to be demonstrated to help others (or yourself), please let me know about them as well!

| Comments

I’ve started a dialog with a few of you about getting Silverlight and service integration working, specifically with ASP.NET web services (and even WCF ones).  A few have downloaded some of my samples, but others have started from scratch.  A few have reported getting some interesting errors, ASYNC_blahblah and NotFound errors specifically.  While this was boggling my mind (as I wasn’t getting them), a reader’s comments pointed me along the lines of something…he mentioned “maybe it is because my web service is ASP.NET 2.0 and not 3.5” – of which that shouldn’t be the case, so I went to test that.

The Situation

Most of the samples you are likely seeing (including mine) are implementing web services within the same project that the Silverlight host is implementing.  What I mean to say is probably you are doing File…New…Silverlight Project and then incorporating the web service into the web site project that comes with that template.  If you do so, you probably aren’t running into problems.  Also note that the target framework of that default web site project is .NET 3.5.  This doesn’t make a difference, but I’m just noting it here.

But what if you have an existing service, or you have an existing web site project that you are running in Visual Studio and running into problems…and l think I know why…let’s investigate by doing this step-by-step.

The Web Service

First open an instance of Visual Studio 2008 and choose to create a new ASP.NET Web Service (I’m calling mine ‘FooService’).  Be sure to select .NET Framework 2.0 for this experiment:

Do nothing more to the service.  We’re just going to use the HelloWorld stub for this experiment.  We know we’re going to simulate a cross-domain situation so create a clientaccesspolicy.xml file at the root of this project.  You can use my snippet to do the default public policy quickly if you’d like, it’s wickedly cool and awesomely awesome.  I recommend it ;-).  Moving on… We are done here.  CTRL+F5 this bad boy to start it running (or select Service.asmx and view in browser) – we just need to get the service running.  Make note of the URL, it is likely http://localhost:XXXXX/FooService/Service.asmx where “XXXXX” is the random port assigned by VS.  Just note that URL.  Obviously if you didn’t call yours FooService, then it will be different.

The Silverlight Application

Start another instance of VS2008 and choose File…New…Project…Silverlight Application.  I’m calling mine FooApp.  Now, if you don’t see any of the Silverlight templates, just change the target framework back to .NET Framework 3.5 if you haven’t done so already.  Accept the default for creating the FooApp_Web project for you, we’ll need a host here anyway under HTTP.

Modify nothing in the Page.xaml file but add a service reference to the Silverlight application by right-clicking on the app and choosing ‘Add Service Reference.’  Put the URL of the ASP.NET 2.0 service (from previous step) in the box and click GO.  You should get it discovered and have ‘ServiceReference1’ as the name:

Just keep the lame name because we’re just playing around remember?  Now, go to Page.xaml.cs and add the following code:

public Page()
{
    InitializeComponent();
    Loaded += new RoutedEventHandler(Page_Loaded);
}

void Page_Loaded(object sender, RoutedEventArgs e)
{
    ServiceReference1.ServiceSoapClient proxy = new FooApp.ServiceReference1.ServiceSoapClient();
    proxy.HelloWorldCompleted += new EventHandler<FooApp.ServiceReference1.HelloWorldCompletedEventArgs>(proxy_HelloWorldCompleted);
    proxy.HelloWorldAsync();
}

void proxy_HelloWorldCompleted(object sender, FooApp.ServiceReference1.HelloWorldCompletedEventArgs e)
{
    try
    {
        TextBlock tb = new TextBlock();
        tb.Text = e.Result;
        LayoutRoot.Children.Add(tb);
    }
    catch (Exception ex)
    {
        string wtf = ex.Message;
    }
}

What we are doing here is calling the service (asynchronously of course) and wiring up the completion event to emit a new TextBlock with the result of the web service.  The Page() constructor just adds a Loaded event so we aren’t doing anything in the constructor to the XAML before it is done loading.

Okay, so we are done.  We have our web service with an appropriate clientaccesspolicy.xml file and it is running.  We have our Silverlight application with a service reference to that and proxy code generated.  We are using that proxy code to call the service, and use the result in a new TextBlock in our root layout element.  Sweet.  Put a breakpoint on the exception catch (should be line 37) and hit F5 (choose yes to enable debugging in web.config).

WTF?

Did you get ‘Async_ExceptionOccurred’ like I did?  Sonofa…  Maybe it is because I’m accessing an ASP.NET 2.0 service? No.  Maybe it is because my app is on port YYYY and my service is on port XXXX?  Nope.  Ah, cross-domain issues?  Try again.

Investigating the Problem

Okay, on to figuring out what is going on. 

If you are a web developer and you aren’t using an HTTP sniffing tool, shame on you.  This should be one of your biggest assets when doing web client development like Flash, Silverlight, AJAX, whatever.  For Microsoft developers there are usually 2 tools (both free) that come to the top: Fiddler and Web Development Helper.  I’m a HUGE fan of WebDevHelper (which I just noticed is on CodePlex now, cool Nikhil!) for 2 reasons.  First, it doesn’t require me to change my proxy settings or anything, which is a pain when using Fiddler and the built-in web server with VS because of the dynamic ports it uses.  Second, it is IN THE BROWSER!  I turn it on and I get an explorer bar at the bottom that shows me everything.  Me likey.

Ok, so using WebDevHelper I turn it on and spot the problem:

Spot it?  Remember our service was created on http://localhost:XXXX/FooService/Service.asmx?  If you read my previous post on cross-domain access (and soon a how-do-I video will be posted on this topic), you’ll note that the client access policy file must be at the ROOT of the service site. 

But Tim, it is!

Well, it is according to the file system, but look at the request Silverlight is making.  The problem here is the web development server in VS.  By default it not only grabs a random port, but also serves things up under a virtual directory (i.e., /FooService/Service.asmx instead of /Service.asmx).  So even though we have our policy file in the root, the web server isn’t treating our app like a root.  Notice the web service project properties:

The core problem was that it couldn’t find the clientaccesspolicy.xml file and thus denying the request to the service.

The Solution

For *this* scenario, the solution (or one of them, easiest in my opinion) is to change the service properties and just change the /FooService to “/” only.  This will restart the server for that project (browser to Service.asmx again just to make sure) and will then be operating under http://localhost:XXXX/Service.asmx

The next thing we need to do is go back to our Silverlight application and remove the service reference (as it is now invalid because the endpoint is no longer there).  Just select it and delete.  Choose ‘Add Service Reference’ again and point to the newly updated URL.  No need to change/delete the actual code in Page.xaml.cs because it will stay the same as long as you keep the SericeReference1 default name for this example.

Once you have that, F5 your Silverlight application again and you should see:

If we turn on WebDevHelper again we can see the policy file being requested and found, then the service call allowed through:

Again for this scenario (if you are playing around with Silverlight and just messing with services), this may be one of the issues you are running into.  A lot of the time cross-domain policy files may be the issue and that is why an HTTP sniffer is going to be your best friend to see what request is failing and why.  Even though this is an ASMX sample, if you were testing with a WCF service hosted in an ASPNET web site and running under VS2008 web development server, you'd likely run into the same issue.

Hope this helps!

| Comments

In my previous post about cross-domain policy files I received some comments about whether or not cross-domain access is allowed on Silverlight Streaming.  I think really this is two questions that I'll try to clarify here.

What is Silverlight Streaming?

For those who don't know, Microsoft provides anyone with an account to "stream" Silverlight applications for free.  We'll give you 10GB of space to put your Silverlight applications.  There are some limitations, which you can read about in the service.  The "streaming" name has confused some.  It isn't only a "where can I put media files" location, but is a service to "stream" your entire Silverlight application.  You can have a media player, or a hello world textbox...no matter.  If you haven't checked it out, sign up.

Does Silverlight Streaming support cross domain calls from Silverlight?

This really has to do with the Silverlight Streaming API.  Silverlight Streaming provides an API to manage your applications.  You can perform various activities on your Silverlight Streaming account through this API such as managing your applications, requesting files, etc.

Now I'm not sure why you would want to access the API from a Silverlight application, but I will say that the in order for this to happen (as noted in my post about cross domain access), the service would have to host a policy file at the end point.  Silverlight Streaming currently does not have that policy file.

Can my application hosted in Silverlight Streaming access cross domain services?

This is what I think the question really is in the comments.  Yes.  Provided that the service you are accessing has a clientaccesspolicy.xml file at the root of the site, then yes it could.  I whipped up a quick DataGrid sample and put it on my Silverlight Streaming account.  This is a Silverlight 2 application (xap) that calls the MSN Video POX service via a WebClient call.  I take the information and bind it to a DataGrid.  So this application below is hosted in Silverlight Streaming, calling a 3rd party service (which has a policy file enabled) and embedded within my blog post here.

I hope that makes it a little clear that yes you can do this with your apps.

How did you get a Silverlight 2 application on Silverlight Streaming?

Very easily.  Just a bit after MIX08, the SLS team added support for Silverlight 2 Beta 1 applications.  You can read about it here, but here is the manifest I used for the application you see above:

<SilverlightApp>
   <version>2.0</version>
   <source>StreamingCrossDomain.xap</source>
</SilverlightApp>

I added that manifest.xml and my StreamingCrossDomain.xap file to a zip, uploaded it to my account and done.

Hope this helps!

| Comments

If you are starting to get into integrating web services with Silverlight, you'll notice that you have to have a cross domain policy file in place on the target server, that is to say, the server hosting the service you want to implement.  There are some public web services (Flickr, YouTube, Digg, etc.) that already have these files in place for Flash, but implement in a slightly different way.

When calling a cross-domain service, Silverlight will check for the existence of clientaccesspolicy.xml first.  This is the format defined by Silverlight and provides a pretty flexible way to define who can access what services.  If not found, it will then default to look for crossdomain.xml, which is the file format implemented for Adobe Flash.  It is important to note that this file will also still work for most public web services.

But now perhaps you are the author of the service that your application is going to consume and/or the public will consume.  There are a few things you want to consider.  First, it would be a best practice to put your service layer on a separate domain other than your site (i.e., api.mysite.com).  In fact, this is how most are doing it these days.  These helps separate more distinctly the services from the web site and also separates the cross-domain security concerns away from the content site versus API access.  Once you have done that you'll want to implement your specific clientaccesspolicy.xml file.

When Silverlight 2 was released to beta, I created some quick helper files to assist me with creating this simple policy file (it is simple, but can get complex depending on how granular you want to define your access).  I figured it might be helpful to some who are implementing services as well.  Sure, they aren't going to save the world, but might save you some quick typing.

Visual Studio Code Snippet

The slcap.vsi file is a Visual Studio Community Installer package which contains "slcap.snippet," which is a Visual Studio code snippet format.  This is an XML snippet, so would be used only in the context of an XML file.  Just double-click on the .vsi file to install and it will walk you through the steps.  I recommend just keeping the defaults.  After it is complete, you now have an Intellisense snippet.  To use it and create a new clientaccesspolicy.xml add a new XML file to your web service site/project named clientaccesspolicy.xml.  It will open a blank XML file by default.  Select all text (CTRL+A).  Then hit the keyboard shortcut for launching XML snippets, CTRL+K,X.

NOTE: For some reason XML snippets don't operate like C#/VB ones do where you type the shortcut, then TAB, TAB.  If anyone knows why, let me know :-)

This will bring up the navigator, then simply navigate to the My XML Snippets, then locate the one you just installed:

Once you select it, there are three literal areas to override the defaults if you wanted. 

UPDATE: As Sean probably ran into below (in comments), the above screenshot does not show the required http-request-headers attribute required on the allow-from node of the policy file.  This is, however, updated in the Intellisense files and the code snippet template.  Thanks Sean for pointing out the screenshot is wrong here.

If you are implementing a completely public web service (open to anyone for cross-domain access), then the defaults will suffice.  When done changing the values, hit enter and you are done.  For those who are not keyboard shortcut masters and would be using a mouse to do all this, it might not be terribly faster to be honest (if the TAB,TAB implementation was there for XML snippets, it would eliminate the arrow up/down to navigate to the snippet).

Get the slcap.snippet here.

Visual Studio Intellisense Files

This next step is a super hack that I originally did and decided it might not be a good idea, but I'll include it here anyway :-).  This involves adding Intellisense files to your VS2008 installation and if you aren't comfortable with that, then move along.

First, you'll want to get the XSD I created, which is very simple and I'm sure doesn't fully conform to the final spec, but lacking that spec, it maps to the format well enough.  Copy the clientaccess.xsd file to the C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas location (or wherever VS2008 is installed for you).  Once you've done that you have to add an entry into the catalog.xml file to add the mapping.  Again, not this is my little hack so I created some namespace because there wasn't one defined yet.

Once you have those two files you have Intellisense for your clientaccesspolicy.xml file if you want it.  Following similar steps as above, create the new file.  This time, however, type the root node of <access-policy> but adding the 'xmlns' attribute pointing to the new namespace you just added to the catalog file (note: Intellisense should give you a list to choose from:

Once you have that, then you'll get the rest of the Intellisense for the basic format of the client access policy format.  If you have multiple allow-from/grant-to needs, this Intellisense will support it.

The only lame thing is you have my namespace in there :-).  That is what drives the Intellisense.  Right now you'll want to remove that before deploying the actual file.  Yeah, I know.  But I said this was an early hack of mine didn't I?

Get the Intellisense files here.

What do to with the completed policy file?

Either way, when you are done with the file, it needs to go in the ROOT of the domain.  This is important as it is not the application root, but the root web.  Even if your app is at foo.com/myapp, the policy file needs to be at foo.com/clientaccesspolicy.xml.

Anyhow, maybe these files will help you.  Ideally you won't be using/messing with an access policy file much, but this might save you some clicks and having the docs open next to you :-).