Welcome to irritatedVowel.com Sign in | Help

POKE 53280,0: Pete Brown's Blog

Silverlight, WPF, Woodworking, .NET Programming, CNC, Nature, and other topics.

Pete Brown writes on a number of topics including Silverlight, WPF, .NET, woodworking and working as a consultant in the DC area. On most forums, Pete goes by the name Psychlist1972. Pete has worked at Applied Information Sciences (AIS) since 1996 where he currently performs as a lead architect and project manager.

Applied Information Sciences - My Employer



World Domination

who's online

Networks


View Pete Brown's profile on LinkedIn

AddThis Social Bookmark Button
WCF Integration in Silverlight 2 Beta 1

In preparation for my Silverlight for Business Applications webcast today, I decided to look more deeply into how Silverlight works with services. I originally concentrated a lot on security, and had a much larger post on how to secure your services, but ran into some issues there. More on that below.

WCF Service Requirements for Silverlight

In Silverlight 2 Beta 1, WCF services must be set up to use basicHttpBinding. Basic HTTP Binding sets up a SOAP 1.1 endpoint in your service. To enable that, before setting the service reference in your Silverlight application, change the service's web.config from the default wsHttpBinding to basicHttpBinding:

<system.serviceModel>
...
    <services>
        <service behaviorConfiguration="ServiceBehavior" name="Service">
            <endpoint address="" 
              binding="basicHttpBinding" 
              contract="IService">
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>
            <endpoint address="mex" 
              binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
</system.serviceModel>

 

If you forget to do that before adding a service reference, no big deal. Just refresh your service reference in your Silverlight project. If that doesn't work, remove and re-add the reference.

Enabling Exception Information in WCF

During debugging, you may want to get exception information back from WCF. In order to enable that, change the includeExceptionDetailsInFaults setting in the service's web.config to true:

<behaviors>
    <serviceBehaviors>
        <behavior name="TestServiceBehavior">
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
    </serviceBehaviors>
</behaviors>

Adding the Silverlight Service Reference

Once your WCF service is running, you can add a reference from your Silverlight project. To do that, right click the Silverlight project and choose "Add Service Reference". Be sure to change the namespace to something useful, as this is the namespace that will be appended to the Silverlight application's namespace.

image

To avoid dealing with cross-domain configuration right at the moment, I added the service to the test web project. This ensures that the service and the Silverlight app are served from the same server and port.

image

Cross-Domain Support

If you want to enable your service to work cross-domain, there are two files you will want to concern yourself with:

crossdomain.xml

This file comes from back in the macromedia flash days. Since it has wide support on the internet, it makes sense for Silverlight to support it. You can read some documentation on this file format here.

One use supported by the specification is to specify domains which can access the service:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy 
  SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="www.yoursite.com" />
  <allow-access-from domain="yoursite.com" />
  <allow-access-from domain="*.moock.org" />
</cross-domain-policy>

However, that detailed format is not supported by Silverlight. Instead, you must opt in to all domains if you want to use the crossdomain.xml approach. Such a policy file would look like this:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy 
  SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*" />
</cross-domain-policy>

However, since this format doesn't cover all the scenarios that Silverlight developers are likely interested in (and flash developers too, most likely), Microsoft has provided another cross-domain file that is more flexible and currently Silverlight-specific: clientaccesspolicy.xml.

clientaccesspolicy.xml

lf you want finer control over your cross-domain policy, you'll want to use clientaccesspolicy.xml. This file allows you to specify both what domains have access to your service, and also what subpaths are covered by the policy. You can include both clientaccesspolicy.xml and crossdomain.xml for your services; Silverlight will check this file before looking for the crossdomain.xml

The equivalent to the "allow all domains access to all services" is below:

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

If you want to get more selective about what you enable, you can specify external domains and subfolders on your site:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from>
        <domain uri="http://contoso.com"/>
      </allow-from>
      <grant-to>
        <resource path="/public-services/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

You can find additional information about cross-domain files on msdn.

Ian Griffiths discovered a small bug with the Silverlight-specific policy file in Beta 1, and documented it here.

Calling Your Service

The proxy and default configuration generated when you add the service reference will be adequate for your initial testing. The generated .ClientConfig file has specifics about your service. If you change your service, and refresh your reference, this file will be updated to reflect those changes. If you run into any problems with that, just delete the file, remove your service references, and re-add them.

ServiceReferences.ClientConfig File
<configuration>
    <system.serviceModel>
        <client>
            <endpoint 
                address="http://localhost:47879/SilverlightApplication2_Web/Service.svc"
                binding="basicHttpBinding" 
                bindingConfiguration="BasicHttpBinding_IService"
                contract="SilverlightApplication2.ServiceReference1.IService"
                name="BasicHttpBinding_IService" />
        </client>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IService" 
                         maxBufferSize="65536"
                         maxReceivedMessageSize="65536">
                    <security mode="None" />
                </binding>
            </basicHttpBinding>
        </bindings>
    </system.serviceModel>
</configuration>

Note that the default endpoint has the address in the file. You can override this in code if you desire. However, since this is a configuration file, you'll probably want to change (and maintain) the endpoint address in the config here, prior to deploying your app to test/production.

The clientconfig file is deployed in the xap.

Calling Code
private void TestService()
{
    ServiceReference1.TestServiceClient client = 
        new ServiceReference1.TestServiceClient();
    
    client.GetTheValueCompleted += 
        new EventHandler<TempBizAppDemo1.ServiceReference1.GetTheValueCompletedEventArgs>
            (client_GetTheValueCompleted);
    
    client.GetTheValueAsync();
}

void client_GetTheValueCompleted(
    object sender, 
    TempBizAppDemo1.ServiceReference1.GetTheValueCompletedEventArgs e)
{
    // act upon the information returned from the service
    // e.Result;
}

As you may already know, all service calls in Silverlight 2 Beta 1 are async calls. Getting data from a service is a two-step operation. First, you set up an event handler which will be called when the service completes. Second, you call the service async method.

There's a lot of controversy about requiring async calls in Silverlight, so it may be something that changes in the future. I'll make no value judgements on it here. However, the current async implementation has the broadest support across browsers and operating systems. It also helps to ensure that the UI thread is not blocked (the calls go through the browser network stack, which is typically on the UI thread), and the browser UI remains responsive. Since async calls are a requirement in Beta 1, we'll just take that as a given.

The nice thing is, once you are used to the async pattern, the code is nice. The event handler you get has strongly-typed event args that include the return value from your service in e.Result (there is no e.Result if your service is a void function or VB sub)

Next Steps

At this point, if you have some UI hooked up to view the results from your service, you should be all set to go ... assuming message-level security doesn't matter (and it doesn't in many many cases as proven by the proliferation of AJAX applications out there calling open services without any message-level security)

Security

When it came to dealing with security like I normally would in a WCF service-based application, I ran into a couple brick walls and ran out of time. I did learn about some other options that may work, though.

The current MSDN documentation on securing your services for Silverlight 2 Beta 1 clients can be found here. It's pretty light, though.

I'm still feeling my way around some of the security options available to us, including tokens and rolling custom encryption. Look for a follow-up post once that is all sorted out. In the mean time, continue to secure your services like you would for AJAX applications (transport-level, HTTPS, IIS-based auth for the entire application) and have your authentication happen outside of Silverlight. Developers coming from the desktop world and those currently doing service calls from ASP.NET server-side will likely not be satisfied with that, so I promise to provide some good examples in the future :)

Update: Tim Heuer also has a great post on this topic. Take a look at it when you finish up here. 

 

Share this post: Email it! | bookmark it! | digg it! | reddit!
Posted: Wednesday, March 19, 2008 10:44 AM by Pete.Brown

Comments

Sergey said:

Hi, I create a virtual directory for web project, which uses Silvelright 2.0. I use a WCF Service for get data from server. There are exeption when I view site over virtual directory in browser. Can you help me?
# March 19, 2008 2:17 PM

Pete.Brown said:

Hi Sergey

1. Is this a cross-domain issue? Is your service hosted on a machine other than what served up the Silverlight app? Are you using host headers or anything that would change the machine or domain name?

2. If you rule out the above, check to make sure your service is using basicHttpBinding, not wsHttpBinding or tcp.

3. When you generated the proxy to the service, did you get any error information then? If not, and the service interface hasn't changed, the exception might just be in the code server-side.

Pete

# March 19, 2008 3:50 PM

Andy Beaulieu said:

Hi Pete! Is there any other trick to getting at the exception details in the silverlight client? I added includeExceptionDetailInFaults=true, and if I look at the http traffic coming back, I do indeed see the exception details in an InnerException. But I don't have access to them in the CompletedEventArgs.Error class - I always get a ServiceModel.ProtocolException, with InnerException being null.
# March 19, 2008 8:09 PM

WCF Integration in Silverlight 2 Beta 1 said:

In preparation for my Silverlight for Business
# March 20, 2008 4:55 AM

Christopher Steen said:

Link Listing - March 20, 2008
# March 21, 2008 3:32 AM

Christopher Steen said:

ASP.NET ASP.NET Basics: Foundation of ASP.NET [Via: mikedopp ] Miscellaneous DotNetNuke 4.8.2 Released!...
# March 21, 2008 3:32 AM

Jonas said:

As you mentioned: The clientconfig file is deployed in the xap. How can I change the endpoint address on production server. Thanks.
# March 24, 2008 10:25 PM

Silverlight SDK said:

I've been watching the Silverlight forums since the release of Silverlight 2, and I've noticed folks
# March 25, 2008 3:43 PM

Silverlight SDK said:

I've been watching the Silverlight forums since the release of Silverlight 2, and I've noticed folks
# March 27, 2008 2:21 PM

Robert said:

I created a silverlight app and a wcf service that returns a stream. I get a partial trust error when trying to return the stream to the silverlight app. How do I properly return a stream from a WCF service to silverlight. Is there anything special I have to do. Any help on this would be great thanks!!
# April 3, 2008 11:41 AM

codism said:

In my application, it is ok to allow anonymous access to all end points. But the logic determining if a certain operation can be preformed is in code, by user information provided in a context object. Could you point me out the solution to pass user information automatically for each service call?
# April 11, 2008 12:07 PM

sheng said:

i have a wcf service,exe is can run. but it's can't run with silverlight. WCF services already set up to use basicHttpBinding 错误如下: "System.ServiceModel.CommunicationException"类型的异常在 System.ServiceModel.dll 中发生,但未在用户代码中进行处理 其他信息: Operation is not valid due to the current state of the object. Can you help me?
# May 8, 2008 12:23 PM

Jeremy Thake said:

I am using WCF services and can't see a way of setting a behavoiur on the client as you would in a config file e.g.: behavior name="XamlPrintWcfService.XamlPrintWcfIServiceBehavior" dataContractSerializer maxItemsInObjectGraph= "6553600" How can this be done in C# code within the Silverlight Project. Note I'm using Silverlight 2.0 beta 1. I noticed that is does create the ServiceReferences.ClientConfig but it simply doesn't use this and you have to set it in code using your above example for WCF (you state it works for ASMX).
# May 15, 2008 2:07 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Enter the text you see in the image:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS