Pass-Through RSS Calls for Silverlight

I have only recently started using Silverlight, but immediately found the much talked-about issues related to cross-domain network calls.  The security layer baked into the Silverlight runtime prevents calls from the client to any remote server that is different from the one where the XAP file came from in the first place.  Calls to other servers WILL succeed only if there is a clientaccesspolicy.xml or crossdomain.xml file on the remote server.  (Either of these files establish a policy for that server to allow calls from a set of configurable domains.)

For my first stab at a Silverlight client, I started writing an RSS reader – with WPF/Silverlight standard binding to XML, should be pretty easy right?  That is – if you can get the RSS/Atom XML in the first place.

Popular sites that serve RSS or Atom seem to have the cross-domain XML files in place, but I found a handful that did not, so I didn’t want to bank on it.  Code like the line below throw a "Security Error" exception.

client.DownloadStringAsync( new Uri( rssUrl ) );

Enter:  the "pass through" service layer.

Conceptually, I need a service method residing in the same web site that my Silverlight pages come from.  I want to call a service method, passing it the "real" url that I want to go to for the RSS/Atom, and have this custom service go get the requested XML for me, and return it.  I’d like this to be transparent to the Silverlight client – it should get the exact same response data that it would if it could call the remote server directly (i.e. if it had a cross domain policy file).  This can turn out to be a generic pass-through service for any content the Silverlight client needs from the web (ASP(x) pages, XML, REST calls, etc).

I started with thoughts about using WCF, then REST which allows me to use url parameters and would make for an easy WebClient call from the Silverlight client code.  However, even the REST idea is still using WCF, which always returns serialized DataContract objects to the client.

Even the simple WCF REST method below:

[OperationContract]
[WebGet( UriTemplate = "PassThru?url={url}" )]
public string SilverlightPassThrough( string url )
{
    WebClient client = new WebClient();
    var bytes = client.DownloadData( url );
    string response = Encoding.ASCII.GetString( bytes );
    
    return response;
}
 

…will return the XML from the requested URL, but it will be wrapped in a <string> element since WCF will serialize the string result.

<string xmlns=...>
    <rss version="2.0" ...><channel><title> ...
</string>

Finally, I went way back to the ASP.NET roots, and decided to use a simple .ASPX page, where I can squirt the XML I get from the remote server, directly into the response stream, and the client won’t have any idea.

I created a basic .ASPX page in the same web site as my Silverlight page, cleared out all HTML markup in the ASPX file,

<%@ Page Language="C#" AutoEventWireup="true" 
    CodeBehind="GetRssFeed.aspx.cs"
    Inherits="PodSync.Web.GetRssFeed" %>

<!-- no more markup here (would start the Response stream before we have a chance to -->

and then added the following code:

 

protected void Page_Load( object sender, EventArgs e )
{
    WebClient client = new WebClient();
    var bytes = client.DownloadData( url );
    string response = Encoding.ASCII.GetString( bytes );

    // if remote server gave us a Content-Type, return it to our client
    string contentType = client.ResponseHeaders["Content-Type"];
    if ( !String.IsNullOrEmpty( contentType ) )
    {
    Response.ContentType = contentType;
    }

    Response.Write( response );
}
 

Now my Silverlight client just makes a call like this:

string origUrl = Feeds.SelectedItem.ToString();
string escapedUrl = origUrl.Replace( "&", "%26" );
string url = String.Format( "/GetRssFeed.aspx?url={0}", escapedUrl );
_client.DownloadStringAsync( new Uri( url, UriKind.Relative ) );

//TODO: parse the response XML in the DownloadStringCompleted handler
  ...

(Notice the escaping of & in the URL we send to our Pass-Through page. If we dont escape those characters, they are viewed by first class parameters to the GetRssFeed.aspx page, and not part of the requested URL.

Like I said, I can use this same page for any "content" based pages that my reader needs – including the plain content pages for a given RSS item.

Super simple solution I know, and uses "old school" technology, but seems to satisfy my requirement of feeding back the same exact page as you would get if you could call the remote server directly from the Silverlight client.

Hope that helps.

Leave a Reply

Your email address will not be published. Required fields are marked *