views:

6738

answers:

5

I've seen a lot of links to MSDN and "works on my machine!" answers so I'd like to ask my question with the exact steps to duplicate what I'm doing. Because we are using an already existing webservice, I'm asking with the context of having a webservice hosted outside of my project, unlike many of the tutorials and videos online. So here goes:

*** Create a new ASP.NET webservice project.

It will come with an existing Service.asmx file exposing a "HelloWorld" web method.

View in browser, hit the "Invoke" button. It should work returning the "Hello World" string.

On my machine, the URL is: "http://localhost:15511/WebSite5/Service.asmx"

*** Start a new instance of Visual Studio, create a Silverlight Web Application Project.

*** Stick a single button on there with an event handler to call the web service. I personally nuke the Grid and use a simple StackPanel. eg.

<UserControl x:Class="SilverlightApplication1.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <StackPanel>
     <Button Click="Button_Click">
      <Button.Content>
       <TextBlock Text="Test"/>
      </Button.Content>
     </Button>
    </StackPanel>
</UserControl>

Add the web reference, using statement and event handler for the Button_Click:

 private void Button_Click(object sender, RoutedEventArgs e)
 {
  ServiceSoapClient client = new ServiceSoapClient();
  client.HelloWorldCompleted += (object s, HelloWorldCompletedEventArgs ea) => { 
   MessageBox.Show(ea.Result); 
  };
  client.HelloWorldAsync();
 }

Run and of course it blows up because of crossdomain issues. So next add the clientaccesspolicy.xml file with the following to the root of your web application hosting the service:

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource include-subpaths="true" path="/"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

This should open things up since it's got a wildcard for headers, uris, and resources, right?

  • Run again and you get an error:

An error occurred while trying to make a request to URI 'http://localhost:15511/WebSite5/Service.asmx'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent.

So question: is there a secret to the clientaccesspolicy file? One could alternately try with the crossdomain.xml but it gives a similar result.

A: 

Client Configuration

Maybe your ServiceReferences.ClientConfig for your Silverlight client is pointing to the wrong URL?

Also, check the location of your cross-domain policy file. This MSDN article has more information.

Locally Running Silverlight

Additional note for running Silverlight locally (Vista Sidebar, for example). As reported in this blog entry, "Silverlight cannot use any network provider, when running locally." The workaround is to use javascript to interface to the web service in this situation.

Jeff Yates
I just double checked - not only does the ClientConfig contain the correct reference, but the error message indicates the correct URL for the asmx file.
David in Dakota
I found some more information, so I've updated the answer. I hope it helps.
Jeff Yates
A: 

I ran into something like this and adding a ServiceHostFactory fixed my issue. The cross-domain policy file alone did not fix it.

class MyHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        MyHost customServiceHost =
          new MyHost(serviceType, new Uri("[Your URL goes here]",UriKind.Absolute));

        return customServiceHost;
    }
}

class MyHost : ServiceHost
{
    public MyHost(Type serviceType, params Uri[] baseAddresses)   base(serviceType, baseAddresses)
    { }

    protected override void ApplyConfiguration()
    {
        base.ApplyConfiguration();
    }
}

You also have to add Factory="MyHostFactory" in the tag that defines your service

Scott
+1  A: 

Have you tried fiddler when using this through IE, you might be able to see the traffic silverlight is causing, such as which cross policy files it is looking for?

meandmycode
+2  A: 

I've had this same problem a couple of times. In the past I've solved this by using the Web App as start up, but it looks like you've already done that. My post on the subject: http://blog.donnfelker.com/post/Silverlight-Cross-Domain-Issue.aspx

Donn Felker
Here's a working URL to that blog post: http://blog.donnfelker.com/2008/11/12/silverlight-cross-domain-issue/
Lone Coder
A: 

The problem could be that your development server is not able to serve the xml file, try this - explicitly make it available through WebGet

[ServiceContract]
    public interface ICrossDomainService
    {
        [OperationContract]
        [WebGet(UriTemplate = "ClientAccessPolicy.xml")]
        Message ProvidePolicyFile();
    }

and then the ProvidePolicyFile() can be

public System.ServiceModel.Channels.Message ProvidePolicyFile()
        {
            FileStream filestream = File.Open(@"ClientAcessPolicy.xml", FileMode.Open);
            // Either specify ClientAcessPolicy.xml file path properly
            // or put that in \Bin folder of the console application
            XmlReader reader = XmlReader.Create(filestream);
            System.ServiceModel.Channels.Message result = Message.CreateMessage(MessageVersion.None, "", reader);
            return result;
        }
Nitin Chaudhari