Calling an ASMX webservice from Silverlight? Use a static port.

The setup

Rob Conery recently posted on Creating a Web Service-Enabled Login Silverlight Control, which is probably a more important topic than many people realize right now. Since Silverlight code runs client side in the user's browser, many tasks like database access and user authentication require what is by definition a "web service" (even if it uses REST or some other, non-ASMX approach).

Along the way, Rob ran into an interesting issue. Being the wise man that he is, Rob knew that he faced a choice:

  1. Figure out an odd brain teaser dealing with undocumented alpha technologies
  2. Mention the odd brain teaser to Jon, who would likely get hooked and stay up all night figuring it out

Rob's a smart guy, you guess what he chose...

The problem

Microsoft Silverlight Tools Alpha for Visual Studio codename “Orcas” Beta 1 adds a new project type to Orcas - you guessed it, the Silverlight project. It does a few things - it adds the necessary references, adds an "Add Silverlight Link" context menu icon to other projects in your solution, does some sort of magic to make sure the the client side code compiles to ClientBin rather than Bin, and probably a lot of other important stuff.

The idea is that you create a solution with a Silverlight project, then create a separate web project, and then select "Add Silverlight Link..." to your web project.

Great, so here's the plan:

  1. We set up a Silverlight project and a Web (site or application) project
  2. We create a service in the web project
  3. We add a Silverlight link from the Web project to the Silverlight project
  4. We add a web reference to the Silverlight project, pointing to our webservice

Do all those intermingled references cause a problem? They can, if you don't set a static port for your web project (more on that later).

The main problem is that the ASP.NET Development Server (nee. Cassini) uses a random port by default, so when you add the webreference to your Silverlight project it adds via the dynamic port which has been assigned to that web project. The problem there, of course, is that since the port is randomly selected the webreference quickly gets out of sync with the webservice.

As I worked through the problem, I became convinced that the solution was to split the solution out into three projects - a main website, a Silverlight project, and a webservice website. I ran into a very interesting problem there. The problem is that the Silverlight control runs under the website's Cassini port, and the Webservice runs under a different Cassini port, and Silverlight's security model prevents it from accessing another port.

I'll try to say that again, this time in English. Let's say the main website is running on http://localhost:1000/Login.aspx and the webservice we want the Silverlight control to call is running on port 2000, as http://localhost:2000/LoginService.asmx.

The Silverlight BrowserHttpWebRequest sees different ports and throws the following exception:

"Cross domain calls are not supported by BrowserHttpWebRequest"

Really? I'm calling from localhost to localhost and I'm crossing domains? Yep. Reflector shows that pretty clearly - the IsCrossDomainRequest method compares on UriComponents.SchemeAndServer:

internal static bool IsCrossDomainRequest(Uri uri)
{
    string components = uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped);
    string text2 = HtmlPage.DocumentUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped);
    if (components.Equals(text2, StringComparison.OrdinalIgnoreCase))
    {
        return false;
    }
    return true;
}

And UriComponents.SchemeAndServer includes port.

Hmm...

Rob and I discussed several options:

  1. Use IIS rather than Cassini. This isn't ideal, since it requires manual setup and clutters up your IIS installation on your local machine, but since IIS provides a distinct URL for your project without requiring a port, your reference won't change.
  2. Proxy requests by using the browser's XmlHttpRequest object, which can (probably) make cross-domain calls.
  3. Don't use a webservice, and call back to an ASPX page using a simple REST interface. In this case, there's no webreference to manage.
  4. Some other crazy rubbish involving hosts file entries which made sense at 3 AM, but sounds ridiculous right now.

None of those seemed right to me, which is why it took me so long to finish this post. The simple solution is to use one website project and set a static port number:

 Webservice with static port

In this case, the Silverlight webreference has a set port and doesn't get out of whack. More important, by using one site running under one static port, both the page and webservice run under the same port and there's no cross-domain problem.

Published Thursday, June 14, 2007 11:59 PM by Jon Galloway
Filed under: ,

Comments

# re: Calling an ASMX webservice from Silverlight? Use a static port.

I was facing the same issue with a WCF service hosted in casini and a client, and solved the same way. Great minds think alike :)

Friday, June 15, 2007 5:33 AM by lkempe

# University Update-Microsoft Silverlight-Calling an ASMX webservice from Silverlight? Use a static port.

Pingback from  University Update-Microsoft Silverlight-Calling an ASMX webservice from Silverlight? Use a static port.

# Silverlight Cream for June 15, 2007

My daily Silverlight 'Pick of the Litter' from the web, I will add on as I come across others

Friday, June 15, 2007 10:10 AM by Community Blogs

# re: Calling an ASMX webservice from Silverlight? Use a static port.

Hi,

When I am going to debug my silverlight project it says that the projet you are trying to debug is consuming web services. Calls to the Web Service will fail unless the project is executed in the context of the web which contains the web services.

Can you help me to know what does this mean?

I am using IIS as the web server. The web service works fine separately but the call from from the silverlight project just hangs indefinitely.

Thanks

Friday, June 22, 2007 8:06 AM by Peeyush

# Silverlight 1.1 (Alpha) cross domain webservice access makes mashups tricky

Any web mashups, by definition, require cross-domain calls. Those cross-domain calls may happen on the

Wednesday, July 04, 2007 2:59 AM by Jon Galloway

# Silverlight Learning Links

Presentation Download will be available Soon... Getting Started Microsoft Silverlight 1.0 Beta Runtime

Thursday, July 05, 2007 4:40 AM by Technical Bits

# July 4th Links: ASP.NET, ASP.NET AJAX, Visual Studio, Silverlight and IIS7

I've fallen behind on my weekly link-listing series - apologies for the delay. ASP.NET ASP.NET RSSToolkit

Friday, July 06, 2007 3:02 PM by Blogs

# Jeff On Games » Blog Archive » Firefox, Silverlight, Services and ASP.NET Debugging

Pingback from  Jeff On Games  » Blog Archive   » Firefox, Silverlight, Services and ASP.NET Debugging

# re: Calling an ASMX webservice from Silverlight? Use a static port.

Hi when i start my webservice and website on same port (4000) at that time visual studio gives me error.

---------------------------

Microsoft Visual Studio

---------------------------

Unable to launch Visual Studio's Localhost Web Server, port '4000' in use

---------------------------

OK  

---------------------------

Saturday, November 24, 2007 1:57 AM by Meet

# re: Calling an ASMX webservice from Silverlight? Use a static port.

Yeah. I think we can't set the same port for both web service and website... Instead, we can put everything in one project.. but I don't think this is good idea...  

Monday, December 17, 2007 9:07 AM by Michael Sync

# Silverlight Crossdomain Access Workarounds

I was testing out some typography with Silverlight and figured I’d try grab some text from Wikipedia

Friday, December 12, 2008 5:42 PM by Jon Galloway

# re: Calling an ASMX webservice from Silverlight? Use a static port.

What i did to get around this problem is to at a crossdomain.xml to my webservice application with the following code:

<div style="background-color: #cde">

<p>

<?xml version="1.0"?>

<!DOCTYPE cross-domain-policy SYSTEM "www.macromedia.com/.../cross-domain-policy.dtd">

<cross-domain-policy>

 <allow-http-request-headers-from domain="*" headers="*"/>

</cross-domain-policy>

</p>

</div>

Thursday, March 19, 2009 4:17 AM by Marius van Belkum

Leave a Comment

(required) 
(required) 
(optional)
(required)