New Web Services Features in Silverlight 2 RTW

Here is an overview of the new features added since Beta 2.

SOAP Headers

SOAP headers were a big customer request, so we have added headers support in this release. There are two methods to use headers, depending on the customer scenario.

The easier method is useful when you need to get/set a header while invoking a single operation on the service. You can use the OperationContext class, and specifically the IncomingMessageHeaders or OutgoingMessageHeaders property to receive or send a header. Below is a code example where the client sends the header <MyClientHeader xmlns="http://silverlight.net">...</MyClientHeader> to the service.

public Page()
{

     InitializeComponent();

     // Instantiate generated proxy
    
Service1Client proxy = new Service1Client();

     // Hook up an event handler when operation completes
    
proxy.DoWorkCompleted += new EventHandler<DoWorkCompletedEventArgs>(proxy_DoWorkCompleted);

     using (OperationContextScope ocs = new OperationContextScope(proxy.InnerChannel))
     {

     // We can add "MyClientHeader" SOAP header to the outgoing message. It is important that this comes before calling the operation.
    
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("MyClientHeader", "http://silverlight.net", "..."));

     // Call an operation on the service
     proxy.DoWorkAsync("foo");

     }
}

Now assume we want to get at a header that the service sent back. In this example, the service sent the <MyServiceHeader xmlns="http://silverlight.net">...</MyServiceHeader> header to the client. Note: The old Begin*/End* async pattern needs to be used with OperationContext if you are retrieving the headers sent in a service reply. The event-based async pattern (using *Completed event and *Async method) is currently not supported. Also, please be sure to use exact order of calls demonstrated below.

public Page()
{

     InitializeComponent();

     // Instantiate generated proxy
     Service1Client proxy = new Service1Client();

     // Call an operation on the service using Begin/End async pattern
    
((Service1)proxy).BeginDoWork("foo", doWorkCallback, proxy);

}

// Receive callback when the service responds
void doWorkCallback(IAsyncResult result)
{
     Service1 proxy = (Service1)result.AsyncState;

     using (OperationContextScope ocs = new OperationContextScope(((Service1Client)proxy).InnerChannel)) 
     {

          // Get the service response. This needs to happen before we access the headers.
          string response = proxy.EndDoWork(result);

          // Now we can access the headers of the incoming message. In this case we assume the header "MyServiceHeader" was sent by the service.
          string headerContents = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("MyServiceHeader", "http://silverlight.net");

          // Do something with response and header

     }
}

The harder method can be used when you want to get/set headers upon invoking any operation on the service. In that case you would have to use OperationContext every time you call a service operation, which is very clunky. Instead, what would be useful is functionality similar to that provided by WCF message inspectors and the IClientMessageInspector class. Using a client message inspector you can get access to the Message instance just received from or about to be sent to the service, and manipulate the headers directly on the instance. IClientMessageInspector is not part of SL 2, but this code sample demonstrates how to accomplish the same functionality. In the sample, we add a header to every message sent to the service, and the header contains the IP address of the client which is calling the service.

SOAP Faults

Eugene posted about faults just a couple of weeks back. Faults are another major request but unfortunately they are not supported out of the box in SL 2. However, using the same client message inspectors approach and some extra configuration on the WCF service side, rudimentary faults can be enabled. The same code sample linked above demonstrates how to do this. I will put together a more detailed post about the sample in the coming weeks.

Reusing existing types in "Add Service Reference"

If you use "Add Service Reference" to add a reference to the service in your client, it will by default generate a duplicate of any type used by your service operation. Frequently when developing a WCF service and a Silverlight client, you want to declare your types in only one place. Alternatively, maybe your data contract types contain internal logic that you would like to preserve and that logic is lost when "Add Service Reference" generates the duplicate types in the client.

Reusing types in Add Service Reference

To prevent duplicate types from being generated in the client, you would normally declare the data contract types in a new project, which is referenced by both your WCF service and the Silverlight client. Then when adding a reference to the service, you would select the correct option in the "Add Service Reference" dialog. This way "Add Service Reference" would find the types already referenced in the shared project, and not generate duplicates.

Note: In Silverlight the shared project that contains the data contract types has to be a "Silverlight Library", which can be referenced by both Silverlight projects and regular desktop framework projects. If the shared project is of any other type, you will not be able to reference it from within a "Silverlight Application" project.

This option was already there in the Silverlight version of "Add Service Reference", but it did not work up until this release.

Duplex Services

We have made improvements to the duplex channel shipped in Beta 2:

  • Client and server side duplex components are now ready for production use, with improved stability, security, etc. In Beta 2 the server-side duplex component was under an "evaluation" license.
  • Server-side duplex component may now be hosted in Partial Trust
  • Default timeouts and timeout behavior is “smarter” – no changes should be required for common scenarios

In addition, Eugene has developed a great sample on top of the raw duplex channel model, to simplify duplex usage. On the client side you can use the DuplexReceiver class:

public class DuplexReceiver
{

     // Opens a channel to the service to receive messages using the default PollingDuplexBinding
     public DuplexReceiver(Uri address, IEnumerable<Type> possibleTypes);

     // Opens a channel to the service to receive messages using the default PollingDuplexBinding
    
public DuplexReceiver(EndpointAddress address, IEnumerable<Type> possibleTypes);

     // Sends a message to a Duplex service. (The first time a message is sent, connection will be established to the service).
    
public void SendMessageAsync(object message);

     // Event that will be called after a message has been sent
    
public event EventHandler<AsyncCompletedEventArgs> SendMessageCompleted;

     // Event that will be called for each received message
    
public event EventHandler<ReceivedMessageEventArgs> MessageReceived;

     // Disconnects from a Duplex service (can later reconnect again). To permanently close, first call DisconnectAsync and then call Close
    
public void DisconnectAsync();

     // Closes the Duplex connection
    
public void Close();

     // Other methods and properties omitted for brevity...

}

Instead of using the channel model directly, you can use the SendMessageAsync method to send messages to the service. The MessageReceived event is fired when the service sends the client a message. Note that the DuplexReceiver contructor takes the list of types that can possibly be sent. The sample also provides a server-side DuplexService object, which keeps track of connected clients and can relay messages to the correct recipient, or broadcast messages to all clients.

Support for ChannelFactory<T>

This is an advanced use case: say you want to use a service without generating a proxy to it. Perhaps you are connecting to a complex service and you manually copied over/shared all the contracts and types that the service uses (for example in order to preserve the internal logic of these types). But you never used the "Add Service Reference" wizard so you don't have a proxy class to the service. In this case ChannelFactory<T> can be used to communicate with a service which implements the service contract <T>, as shown below. 

public Page()
{
     InitializeComponent();

     ChannelFactory<Service1Channel> factory = new ChannelFactory<Service1Channel>(
          new BasicHttpBinding(),
         
new EndpointAddress("http://localhost:49507/Service1.svc"));

     Service1Channel channel = factory.CreateChannel();

     channel.BeginDoWork(new AsyncCallback(doWorkCallback), channel);
}

void doWorkCallback(IAsyncResult result)
{
     Service1Channel channel = (Service1Channel)result.AsyncState;
     string response = channel.EndDoWork(result);

     // Do something with response
}

Note that using this approach, the event-based async pattern is not supported.

Other

  • Types generated from ADO.NET Entity Data Models (.edmx files) in WCF services intended for Silverlight consumption are now supported. Just use the type generated from a .edmx model as an argument in a service operation.
  • Internal types and internal members may now be serialized by the DataContractSerializer and the DataContractJsonSerializer (on a per-assembly opt-in basis)
  • JSON/XML Mapping is now supported (through System.Runtime.Serialization.Json.dll in the SDK), by using the JsonReaderWriterFactory class.
  • JAXB-style object references in XML are now supported by DataContractSerializer

Have fun using our new feature set!

Yavor Georgiev
Program Manager, Connected Framework Team

Posted 20 October 08 02:39 by SLWSTeam | 5 Comments   
Filed under , , , ,
Detailed Overview of Silverlight 2 Beta 2 Web Service Features

As you have probably read already (in Scott or Tim's posts), Silverlight 2 Beta 2 provides a set of new and improved web service features. This post will go over our Beta 2 scenarions in more detail, and we intend to follow up over the next couple of weeks and drill down into particualr features.

Duplex Communication (Server Push)

This has been the most requested feature from our customers since the release of Beta 1, and it enables some useful scenarios like building chat and monitoring apps. Duplex allows the client to expose a set of operations that the server can call to send (push) information to the client. Previously addressing the browser-based client was not possible using the web service stack, so we are very excited to ship this feature in Beta 2.

Duplex support is delivered in two assemblies: one that plugs into your WCF service, and the other one which plugs in to the Silverlight client. Once you install the Beta 2 SDK, you will get the following assemblies:

  • C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Server\Evaluation\System.ServiceModel.PollingDuplex.dll

    This is the server-side assembly. For details on it usage and how to build a duplex WCF service, see this topic in the documentation. The assembly provides you with the server-side PollingDuplexBindingElement, which allows you to build a custom binding, You can then build a custom ServiceHost, which uses the custom binding to host your service contract. A service contract hosted this way will support ServiceContractAttribute.CallbackContract, which is how you specify the client operations that the service can call. The topic referenced above goes through all these details and shows you a finished duplex WCF service.

    You may have noticed the "Evaluation" folder name in the path. This assembly is provided on a different license than the rest of the Beta 2 product, and is not meant for production apps. We intend to put some more work into the API and tune the performance before this component is ready for production environments.

  • C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client\System.ServiceModel.PollingDuplex.dll

    This is the client-side duplex assembly. For details on its usage and how to build a Silverilght client for a WCF duplex service, see this topic in the documentation. The assembly provides you with the client-side PollingDuplexHttpBinding, which can be used to create a channel to talk to the WCF duplex service. This is covered by the above topic.

You might remember Eugene's blog post, which talks about a typed "receiver" experience, which also takes care of deserialization. We are working on this and will likely release it as a code sample on silverlight.net in the coming weeks.

LINQ over JSON

Many web services provide APIs which return JSON data instead of POX or SOAP, and we want to make sure Silverlight provides great support for these types of services. So far the only way to interact with JSON in Silverlight has been to deserialize it into a type, which we have defined already to match the structure of the JSON. However this becomes impractical for APIs that return a lot of JSON data. Take Facebook for example: just asking for a user's information returns almost a page of JSON, and it would be impractical for a Silverilght developer to have to construct a type to match this JSON, especially if the Silverlight app is a mashup and interacts with multiple complex JSON APIs. In situations like this, we would prefer to "dot into" the JSON object and treat it as more of a dictionary, as opposed through the deserialization mechanism.

Beta 2 introduces a brand new feature called JsonObject, which is also new to the .Net platform. JsonObject allows you to "parse" a JSON string and then use it as a dictionary in Silverlight, as shown in this documentation topic. Using the following JSON string as an example,

[{"IsMember" : true, "Name" : "John", "Age" : 24},
{"IsMember" : false, "Name" : "Paul", "Age" : 44},
{"IsMember" : true, "Name" : "George", "Age" : 12}]

we can parse it into the JsonObject users, and then access its members this way: users[0]["Name"], users[1]["Age"], etc. We can then construct LINQ expressions such as

var members = from member in users
              
where member["IsMember"]
             
select member;

The FoodFinder sample on silverlight.net provides a real usage example of the Yahoo! Local JSON API (download the source code). The following LINQ query is used by the sample to dynamically filter the results returned by the service based on two sliders that the user controls.

var members = from restaurant in (JsonArray)results["ResultSet"]["Result"]
             
where float.Parse(restaurant["Rating"]["AverageRating"]) >= rating.Value
              where float.Parse(restaurant["Distance"]) < distance.Value
             
select restaurant;

Configuration Support

In Beta 1, the binding and endpoint address had to be specified in code and passed as parameters to the proxy constructor.

BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(http://localhost/service.svc);
ServiceClient proxy =
new ServiceClient(binding, address);

In Beta 2 the "Add Service Reference" feature in Visual Studio will generate a ServiceReference.clientConfig file, which will contain the binding and address configuration informaton, and the proxy can be constructed with its default constructor.

ServiceClient proxy = new ServiceClient();

This allows us to change the binding/address without needing to recompile the Silverlight control. In addition configuration exposes some knobs on the binding, which can be tweaked for security or performance reasons:

<binding name="BasicHttpBinding_IService" closeTimeout="00:59:00" openTimeout="00:53:00"
        
receiveTimeout="00:15:00" sendTimeout="00:21:00" maxBufferSize="65530"
        
maxReceivedMessageSize="65531" textEncoding="utf-8" />

This documentation topic explains the different settings available.

Tooling Improvements

We have added the "Silverlight-enalbled WCF Service" Item template. When a WCF service is added using this template, the binding in the service configuration is automatically switched to basicHttpBinding.

Silverlight-enabled WCF Service Item Template

IntelliSense over .clientConfig files is now supported. As you start editing the file you will get useful popups with the supported schema.

IntelliSense over .clientConfig

SOAP Improvements

We have made some general SOAP improvements in Beta 2:

  • Custom SOAP headers and faults in service - ignored and don't generate uncompilable code
  • “Wildcard” schema in service (like xsd:any or xsd:anyattribute) - now works and doesn't generate uncompilable code

And specifically if your service is a WCF (or in some cases .ASMX) service:

  • XML types like XmlElement/XElement/XmlNode[]/XmlAttribute/etc in service - now work and don't generate uncompilable code
  • Types that implement ISerializable in your service (except for collections) - now work and don't generate uncompilable code
  • Stream type in service - now works and doesn't generate uncompilable code
  • MessageHeaderAttribute in Message Contracts - ignored and doesn't generate uncompilable code

Please keep an eye on this blog for more specifics in the next couple of weeks.

Cheers,
-Yavor Georgiev
Program Manager, Connected Framework Team

Posted 10 June 08 01:21 by SLWSTeam | 10 Comments   
Filed under , , ,
Databinding and the SyndicationFeed class

I found a couple of nice databinding tricks with the SyndicationFeed class, while putting together a code sample. The sample has been posted on silverlight.net for some time now (click here and then look for "Syndication - RSS/Atom Feed Reader").

For those not familiar with it: databinding is the association of an instance of a type or collection with a WPF control. One-way bindings are useful if you update the type or collection programmatically, then the control will reflect the change automatically. Think about an app that gets search results from a web service and adds them to a collection. As the new search results get added to the collection, a list in the app's UI gets updated automatically. Two-way bindings are nice if you want to be able to keep the UI and underlying instance in sync, regardless of which one is being changed. Think about an app that maintains the user's information (name, address) in an instance of an object. You want to allow the user to update their data, so you populate the object instance properties and the UI updates automatically. Then the user types changes in the UI, and the object instance gets updated automatically.

With SyndicationFeed, our main databinding scenario involves one-way binding: you parse a feed into a SyndicationFeed instance, and you want to bind that to a UI list to display all the entries in the feed.

The first step is easy - bind the IEnumerable<SyndicationItem> collection SyndicationFeed.Items to a ListBox, by adding this in the XAML:

<ListBox x:Name="itemsList" ItemsSource="{Binding}" />

and this in the code-behind, assuming feed is an instance of SyndicationFeed:

// Set up databinding for list of items
itemsList.DataContext = feed.Items;

Now every item in the ListBox has an associated SyndicationItem. We create a DataTemplate to define the shape of each item in the ListBox.

<ListBox x:Name="itemsList" ItemsSource="{Binding}">
   <ListBox.ItemTemplate>
      <DataTemplate>
         <HyperlinkButton Content="{Binding Title.Text}}"
                         
NavigateUri="{Binding Links, Converter={StaticResource linkFormatter}}" />
         <TextBlock Text="{Binding Summary.Text, Converter={StaticResource htmlSanitizer}}" />
      </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

There are three uses of databinding to explore here. One thing to keep in mind that by default all bindings are one-way.

HyperlinkButton.Content to SyndicationItem.Title.Text

Both properties are of type string so setting up the binding is simple.

HyperlinkButton.NavigateUri to SyndicationItem.Links

The first property is a string and the second is Collection<SyndicationLink>. This binding won't work and we're not allowed to index into Links in a binding: only "dotting down" is supported. 

Bindings support "converters", which allow us to map between the two properties in the binding. Here we define the linkFormatter converter, which simply takes the first link in the collection and returns that.

public class LinkFormatter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
      // Get the first link - that's the link to the post
     
return ((Collection<SyndicationLink>)value)[0].Uri; 
   }

   public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

To use the converter in XAML, we declare it as a resource in the page, which causes it to be instantiated at runtime. Notice that we name the instance of the LinkFormatter class "linkFormatter", which is what we use in the binding itself.

<UserControl x:Class="SyndicationFeedReader.Page"
            
xmlns="http://schemas.microsoft.com/client/2007"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:SyndicationFeedReader"
>
  
<UserControl.Resources>
     
<local:HtmlSanitizer x:Key="htmlSanitizer"/>
     
<local:LinkFormatter x:Key="linkFormatter"/>
  
</UserControl.Resources>

TextBlock.Text to SyndicationItem.Summary.Text

In this case both properties are of type string, so the converter trick is not really needed. However, here we use the converter to strip out HTML markup and clean up the text to display. Again, the converter class needs to be declared as a resource, as shown above.

public class HtmlSanitizer : IValueConverter
{
  
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
     
// Remove HTML tags and empty newlines and spaces
     
string returnString = Regex.Replace(value as string, "<.*?>", "");
      returnString =
Regex.Replace(returnString, @"\n+\s+", "\n\n");

      // Decode HTML entities
     
returnString = HttpUtility.HtmlDecode(returnString);

      return returnString;
   }

   public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
     
throw new NotImplementedException();
   }
}

Hope this trick is useful!

Yavor Georgiev
Program Manager
Connected Framework

Debugging Web Service Usage in Silverlight 2

(Cross-posted from http://eugeneos.blogspot.com/2008/04/debugging-web-service-usage-in.html

Silverlight 2 Beta1 makes it easy to use Web Services based on either the WCF technology (Windows Communication Foundation), the “.asmx” technology (ASP.NET Web Services), or practically any other SOAP platform.

Unfortunately, when something goes wrong with service consumption, you often run into cryptic and incomprehensible error messages that don’t help you much. We are looking into various ways to make this better by the time we fully ship Silverlight 2, but for now I hope that this post will be useful in helping you debug common problems. Here are the things you can try:

Does your proxy compile?

After you use the “Add Service Reference” dialog to add a reference to a service, try building your project. If you get compilation issues in the generated proxy code, you are probably using a service that uses some feature that is not supported in Beta1. We are trying to fix all or most of these by the time we ship, but for now the easiest thing to do is to find the offending code in the generated proxy and just remove it – naturally this workaround does not work in all cases :) Some common things that will cause non-compilable proxies in Beta1:

- Using custom SOAP headers in your service
- Using custom SOAP faults
- Using “wildcard” schema in your service like xsd:any or xsd:anyattribute

And specifically if your service is a WCF (or in some cases .ASMX) service:

- Using XML types like XmlElement/XElement/XmlNode[]/XmlAttribute/etc. in your service
- Using Datasets in your service
- Using types that implement ISerializable in your service (except for collections)
- Using WCF Transactions features
- Using the Stream type in your service
- Using MessageHeaderAttribute in Message Contracts

Check the Configuration

The next step is to check whether the service is configured correctly. You should have a file called ServiceReferences.ClientConfig generated by Add Service Reference. It actually doesn’t do anything at all in Beta1! This (understandably) confuses a lot of people. Starting with Beta2, we will actually start using this file, but for now any changes that you’ll make in it won’t actually affect anything.

However, the file is still useful for debugging. Look in the file – it should look something like this:

<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:5678/TestService.svc" binding="basicHttpBinding" contract="MyProject.ITestService" name="default" />
</client>
</system.serviceModel>
</configuration>

Notice that it has exactly one endpoint element for the service you just added a reference to, and the binding is basicHttpBinding.

If you don’t see an endpoint element for your service, chances are your service wasn’t actually configured correctly for Silverlight consumption. Silverlight can only talk to simple SOAP services at this point – only SOAP 1.1, without any advanced WS-* protocols like WS-Addressing or WS-Security. If you are using “.ASMX” web services, they should just default to this simple configuration. If you are using WCF services, you need to check the configuration on the service side. Open web.config in your service-side project and find a place that looks like the following (usually towards the end):

<system.serviceModel>
...
<services>
<service name="MyProject.TestService">
<endpoint address="" binding="basicHttpBinding" contract="MyProject.ITestService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
...
</service>
</services>
</system.serviceModel>

Find the endpoint whose “contract” attribute refers to your service. Make sure that the “binding” attribute is set to “basicHttpBinding”. Unfortunately the default for WCF is “wsHttpBinding”, but it doesn’t work with Silverlight. We are hoping to ship a Visual Studio item template in the future (“Add New Item… Silverlight-enabled WCF Service”) that will have a number of Silverlight-friendly defaults, including the correct binding.

It is ok to have other endpoint elements for other contracts with other bindings - for example, do not change the "mexHttpBinding" in the second endpoint element above.

You should check your service-side configuration even if the client-side ServiceReferences.ClientConfig appears to be correct.

If ServiceReferences.ClientConfig contains more than one endpoint for your service, you may need to use a more complicated constructor to new up your service proxy – the one that takes a Binding and an EndpointAddress. Not to worry – just pass a new BasicHttpBinding() and a new EndpointAddress built from the URL of your service.

By the way, our long-term (post-Beta1) plans for the config file are described here: http://blogs.msdn.com/suwatch/archive/2008/04/07/tutorial-using-silverlight-web-service-client-configuration.aspx

Check if the Service is Running

Before looking for problems on the Silverlight side, it is useful to first check whether the service itself is working. A quick-and-dirty way to check is to just type the service address into a web browser (not the address you typed into the “Add Service Reference” dialog, but the address you can find in ServiceReferences.ClientConfig). In many cases, the “service help page” feature will be turned on and you will see either a page indicating that the service is running, or an error page which you can use as a starting point for debugging.

A more reliable way to test whether the service is working is to use a test tool such as the WCF Test Client (http://msdn2.microsoft.com/en-us/library/bb552364.aspx) to try and talk to the service.

Finally, an almost sure-fire but sometimes lengthy way of finding out whether the problem is with the Silverlight code or with the service code is to try using the service without Silverlight :) Just create a new project of type “Console Application”, do an Add Service Reference to that project just like in Silverlight, and write service consumption code inside Main() – again, just like in Silverlight. Use Console.WriteLine to show the results.  

Check for Cross-Domain Issues

Start your Silverlight application. Note the URL that appears in the browser (e.g. http://localhost:1111/something/MyGraphicalApp.aspx) – this is your “Application URL”. (Actually, what matters here is the URL of the XAP file, e.g. http://localhost:1111/somethingelse/MyGraphicalApp.xap, but in most simple cases this URL would be in the same domain as the hosting web page, so I’m ignoring the difference for now). Then, look at the URL in the ServiceReferences.ClientConfig file – e.g. http://localhost:5678/foo/TestService.svc or local.live.com/SearchService/LocalSearch.asmx - this is your “Service URL”.

In Beta1, both the “Application URL” and the “Service URL” must be HTTP URLs (not HTTPS) for service consumption to work. This is the first thing to check.

Also, a common mistake is to run your Silverlight application from a file:// Application URL, resulting in cross-domain issues. Sometimes, you run into this if you just hit F5 to run your Silverlight app – instead, right-click on the .aspx page in your project and choose “View in Browser”.

Now you need to figure out the domains for these URLs. The domain is just the basically everything between http:// and the first slash / after that, including the port number (assumed to be 80 if not present). If the domain of the Application URL is different in any way from the domain of the Service URL in any way (even if it’s just a port number difference, or just one part of the domain name is different), you have a cross-domain situation. For example, if your app is at http://localhost:1111/something/MyGraphicalApp.aspx and it is trying to call into http://localhost:5678/foo/TestService.svc, you have a cross-domain situation because localhost:1111 is different from localhost:5678.

Silverlight documentation tells you that if you are in a cross-domain situation, you need to have a “cross-domain policy file” (clientaccesspolicy.xml or crossdomain.xml) present if you want services to work. There is an easy way to check if you have everything set up correctly: Just open a browser and browse to http://service_domain/clientaccesspolicy.xml and http://service_domain/crossdomain.xml. If at least one of these is present, valid and allows cross-domain access – you’re fine. If not, you need to make sure at least one of these files is present.

A common mistake is to put the cross-domain policy file not directly at the root of the domain – for example, at http://localhost:5678/foo/clientaccesspolicy.xml instead of at http://localhost:5678/clientaccesspolicy.xml. It is easy to run into this situation when working with older (.NET 2.0) projects – see http://timheuer.com/blog/archive/2008/04/09/silverlight-cannot-access-web-service.aspx.

Also, make sure to check the syntax of these files – an error in parsing will be treated essentially the same way as if the file was not there. Also note that clientaccesspolicy.xml and crossdomain.xml have different syntax – make sure you use the appropriate content for the file you choose.

A neat trick for adding cross-domain policy files to WCF services that are not hosted in IIS is described here: http://blogs.msdn.com/carlosfigueira/archive/2008/03/07/enabling-cross-domain-calls-for-silverlight-apps-on-self-hosted-web-services.aspx

Enable Exceptions

Normally, Silverlight does not give you much information in exception messages. This decision was made to make the Silverlight download size smaller (exceptions take up a lot of space, especially once they’re translated into all of the languages Silverlight supports). You can read more about this, and find out how to turn on full exceptions for debugging, here: http://blogs.msdn.com/silverlightws/archive/2008/04/06/getting-full-exceptions-in-silverlight-2-beta-1.aspx

Also, if you are using a WCF service, WCF does not normally return much information about server-side exceptions. This is a security measure: you normally don’t want to expose internal information about your service to the outside world. However, during debugging, you can change this by following the steps here: http://blogs.devdeo.com/carlos.medina/PermaLink,guid,b3bff742-0ec9-4f5c-a178-625220a46652.aspx. Make sure to turn it off once you’re done debugging!

Finally, this seems obvious but a lot of people forget about it for some reason - when you get an exception, don’t just look at the exception itself - look at its innerException, and the innerException inside it, etc. Especially in web service scenarios, the truly useful exceptions are often “wrapped” in several layers.

Unfortunately, even with all of the steps above, you often still won’t see much useful information when a web service call fails. This is due to a pretty fundamental limitation of Silverlight Beta1 (that unfortunately may stay around even after the Beta) – the lack of support for SOAP Faults. So, to truly debug, you need to see what is actually going on – this is what the next section is about.

Getting Down to the Wire

The ultimate way to debug Silverlight service consumption issues is by using an “HTTP spying” tool such as http://www.fiddlertool.com/fiddler/ or http://projects.nikhilk.net/webdevhelper/ that shows you the actual HTTP traffic as it happens. Before using it, make sure to enable server-side exceptions (see above). Start your Silverlight app and your tool side-by-side, and make your app do a web service call. Here are some common patterns you will see:

1.Nothing
- Your HTTP spying tool may be misconfigured (try running another, non-Silverlight app, like a regular web browser, to make sure it works)
- Your app may be broken – put a breakpoint where you invoke the service, make sure it’s hit
- You may have a configuration issue – see Configuration section above
- You may be trying to host your application from a file:// or https:// URL, or trying to call an https:// service

2. Just a service request
- Congratulations – you’ve avoided a cross-domain situation if you see the actual request to the service on the wire.
- Is the address what you expected it to be?
- Look at what’s coming back. Is it timing out or are you getting a 404? Your service or even WCF itself may not be set up correctly.
- Are you getting a SOAP fault back? If so, read carefully what’s in the fault – it will usually have enough information to debug the issue.
- In general, look very carefully at both the request and the reply (including the body and HTTP headers)
- Did you remove anything to get the proxy to compile? The service may actually require some items that you removed (e.g. may require certain SOAP headers)

3. A request to clientaccesspolicy.xml (and possibly crossdomain.xml afterwards), followed by a request to the service
- Congratulations – you have a cross-domain situation but you have successfully set up your cross-domain policy files
- This is now equivalent to situation #2 above

4. Just a request to clientaccesspolicy.xml and nothing else
- Most likely a malformed clientaccesspolicy.xml, or one that contains a policy that forbids cross-domain access

5. A request to clientaccesspolicy.xml, then crossdomain.xml, then nothing else
- Basically, something went wrong with cross-domain policy files.
- Are you getting 404s back? Check if you’re hosting the files correctly and at the correct locations
- Are you getting the actual files back? They may be malformed or may forbid cross-domain access

 -- Eugene Osovetsky, Program Manager, Silverlight Web Services team

Nice overview of Silverlight HTTP stack

Karen Corby, PM working on the Silverlight 2 HTTP stack, posts an awesome overview. Her first post covers the site-of-origin policy (also known as the cross-domain restriction) and the two APIs used for HTTP communication: WebClient and HttpWebRequest/HttpWebResponse.

http://scorbs.com/2008/04/05/silverlight-http-networking-stack-part-1-site-of-origin-communication/

Yavor Georgiev
Program Manager
Connected Framework

Posted 09 April 08 06:09 by SLWSTeam | 1 Comments   
Filed under ,
Getting full exceptions in Silverlight 2 Beta 1

When debugging Silverlight 2 Beta 1 apps in Visual Studio, you might see exceptions show up like this:

An exception of type 'System.ServiceModel.ProtocolException' occurred in System.ServiceModel.dll but was not handled in user code

Additional information: [UnexpectedHttpResponseCode]
Arguments:Not Found
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=2.0.30226.2&File=System.ServiceModel.dll&Key=UnexpectedHttpResponseCode

By default Silverlight does not include the full exception strings. They are stripped out of assemblies in order to realize cost savings in the Silverlight runtime download package.

This post talks about how to configure your machine to get the full exception strings back in Visual Studio debugging sessions.

Runtime (Core) Assemblies

The Silverlight runtime assemblies are installed on every user's machine when they download and install the Silverlight runtime. These assemblies live in the C:\Program Files\Microsoft Silverlight\2.0.30226.2 folder on the user's hard drive. To keep the Silverlight runtime download package small, these assembles do not contain any exception strings. When an exception is thrown and not caught, a barebones message is shown to the user, like the one shown above.

The size savings from removing the full exceptions make sense for the end user, but when developing apps the full exception strings are needed. They are included in the Silverlight SDK install. For each runtime assembly the SDK will install an additional .debug.resources.dll assembly (which contains the full exception string) in a "en-us" folder alongside the original assembly. The shows System.ServiceModel.dll as an example:

Silverlight runtime with debug resources installed

The only manual step needed to enable full exceptions is to modify the Silverlight manifest file - C:\Program Files\Microsoft Silverlight\2.0.30226.2\slr.dll.managed_manifest. This is shown in the Silverlight 2 SDK Beta 1 release notes, under the "slr.dll.managed_manifest needs to be manually edited ..." topic. For every runtime assembly you need to add something like:

<localizedassembly>
   <
name>System.ServiceModel.debug.resources</name>
   <
version>2.0.5.0</version>
   <
publickeytoken>31bf3856ad364e35</publickeytoken>
   <
relfolder>.</relfolder>
   <
file>System.ServiceModel.debug.resources.dll</file>
</
localizedassembly>

After this modification, Visual Studio will show the full exception text:

An exception of type 'System.ServiceModel.ProtocolException' occurred in System.ServiceModel.dll but was not handled in user code

Additional information: The remote server returned an unexpected response: (404) Not Found.

Extension Assemblies

These assemblies contain specialized functionality and are not installed with the Silverlight runtime. If a Silverlight app references one of these assemblies, the assembly gets packaged together with the app's own assemblies, inside the .xap package (something Visual Studio does automatically). Developers get these assemblies by installing the Silverlight SDK, which places them in the C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client folder. Again, the Silverlight runtime does not look inside this folder, and the only way the end user can get these assemblies is if they are in the app's .xap file.

Since the extension assemblies are included with apps on-demand, and are not part of the Silverlight runtime download, the full exception strings are included in the assemblies themselves. You will automatically get full exceptions, like so:

An exception of type 'System.NotSupportedException' occurred in System.ServiceModel.Syndication but was not handled in user code

Additional information: Error in line 2 position 2. The Rss20Serializer does not support RSS version '4.0'.

Hope this is helpful!

Yavor Georgiev
Program Manager
Connected Framework

Posted 06 April 08 07:29 by SLWSTeam | 6 Comments   
Filed under
Some tips on cross-domain calls

Recently I have been seeing forum questions on silverlight.net, where people are having trouble with the Silverlight's treatment of cross-domain calls. I wanted go over the cross-domain restriction and share two tips that might help when using cross-domain web services in Visual Studio.

What is this cross-domain thing?

Modern web browsers have restrictions in place to guard against Cross-Site Scripting (XSS) and Cross-Site Request Forgery (XSRF) vulnerabilities. Exploits of these vulnerabilities can (a) send confidential user data to malicious third-parties or (b) access websites on behalf of the user without the user ever knowing. The example we like to give goes something like this: Sally has an account with Bank XYZ and she uses online banking at http://bankxyz.com/. The http://bankxyz.com/ website stores Sally's credentials in a cookie on her machine as a convenience, so Sally doesn't have to authenticate every time. Tom finds out that Sally uses Bank XYZ, and creates http://maliciousgame.com/, which he sends to Sally. When Sally opens up http://maliciousgame.com/ in her browser, a script hosted at the site secretly accesses http://bankxyz.com/ and transfers money to Tom's account, without Sally finding out. Sally is already authenticated at http://bankxyz.com/, so the script can carry out the transaction without Sally's permission. The domain names above are meant to be fictitious... I'm happy to change them if a real "Bank XYZ" or a legitimate "malicious game" come around :)

The most common way to request data is by using JavaScript's XMLHttpRequest object. To prevent the exploits listed above, browsers implement a site-of-origin restriction, which doesn't allow websites to make requests outside their own domain.

As a browser plug-in Silverlight also needs to be mindful of these vulnerabilities. We maintain consistent behavior with the browser when it comes to cross-domain calls, and we enforce the site-of-origin restriction across all Silverlight HTTP calls. This applies to WebClient, HttpWebRequest, and the calls made by web service proxies (which use HttpWebRequest internally).

Now this is a bummer for mashups, which are all about pulling data from different web services (Flickr, Yahoo!, Ebay, Facebook, etc) hosted on different domains. So similarly to Adobe Flash, we provide a mechanism to allow cross-domain calls, as described in our docs. By placing a clientaccesspolicy.xml or crossdomain.xml file at the root of its domain, a web service owner declares "the service is safe to be called by any and all Silverlight controls, and no matter who makes the call, the service won't release or mess up the user's private data". For example, Flickr just serves up images, so it is safe and allows cross-domain calls by having a http://api.flickr.com/crossdomain.xml file. A bank's website should probably not have a cross-domain policy file at its root.

There are at least two places when working with web services in Silverlight where you might hit the cross-domain restriction without even knowing it. For the following to make sense, you must have Visual Studio 2008, the Silverlight 2 Beta 1 SDK, and the Silverlight 2 Beta 1 VS tools installed on your machine.

Don't try network calls from TestPage.html on your hard drive 

When you create a Silverlight project, Visual Studio gives you the choice of hosting the control (i) in the built-in Visual Studio web server or (ii) on your local file system.

Use the VS webserver if you want to do network calls

The second choice is good if you are just playing with graphics and layout, but it is definitely the wrong choice if you want to use network calls. All HTTP requests (WebClient, HttpWebRequest, web service proxies) are bound to fail. The exact exception when trying to invoke an operation on a web service is shown below. The exception text itself is not that clear, partly because the Silverlight runtime does not contain the full exception strings. How to get the full exception text when debugging is the subject of a whole different post.

An exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll but was not handled in user code Additional information: [CrossDomainError]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=2.0.30226.2&File=System.ServiceModel.dll&Key=CrossDomainError

To be fair, we do show you a warning when you try to debug a project on your local file system that uses a web service proxy: 

VS warns not to use network calls when hosted on file system

This is why we have the first choice, which will host your Silverlight control in the Visual Studio web server at a domain like http://localhost:1234/ (the port number is randomly assigned). Which brings us to the second tip.

Don't try to call services that don't have a cross-domain policy file

Once you set up your Silverlight app in Visual Studio, it will be hosted by the built-in web server on a domain similar to http://localhost:1234/. So here the cross-domain restriction will kick in and only allow you to access web services at the http://localhost:1234/ domain. If you add a web service to your solution, you will be able to access that, since it will also live on http://localhost:1234/, and the cross-domain restriction is avoided.

Add a web service project to your Silverlight solution

Selecting WCF service project

Once you add the WCF service to your solution, you can generate a proxy by right-clicking the Silverlight project and selecting "Add Service Reference" and then using the "Discover" button.

Of course you don't always want to use a local web service. Say you want to pull some weather data from Weatherbug (you can read the details of their API usage here). You can still use "Add Service Reference", but you will end up with the situation where your Silverlight control is hosted at http://localhost:1234/ and the weather web service is hosted at http://yourApiCode.api.wxbug.net. This would fail due to the cross-domain restriction, unless Weatherbug specifically opted in by placing a policy file at the root of their domain. Fortunately they do :)

It is interesting to see Silverlight checking for the policy file, I used Fiddler to capture it.

Fiddler shows Silverlight looking for policy file

Before it does anything, Silverlight searches for a policy file. First it looks for clientaccesspolicy.xml, doesn't find it, and then it looks for crossdomain.xml, and finds it. The crossdomain.xml policy file content says that Silverlight is allowed to use the service at that domain, so Silverlight proceeds to call the .asmx web service. For details on the policy file format, see this article.

Hope this was helpful!

Yavor Georgiev
Program Manager
Connected Framework

Posted 30 March 08 05:45 by SLWSTeam | 3 Comments   
Filed under
Silverlight 2.0 - Rundown of WebServices related functionality in Beta1

 

Technorati Tags: ,

 

Hope everyone had a chance to download and play with the Silverlight 2.0 Beta1 bits. I wanted to put up a quick post detailing the features we have shipped in this Beta. We have shipped total of 5 features split across 5 assemblies.

Core Assembly:

  • System.Runtime.Serialization.dll - Data Contract OM and Data Contract Serializer
  • System.ServiceModel.Web.dll - Data Contract JSON Serializer
  • System.ServiceModel.dll - WCF Client side proxy OM and runtime.

Extension/SDK Assembly:

  • System.ServiceModel.Syndication.dll - RSS/ATOM OM
  • System.Xml.Serialization.dll - Xml Serializer

Core assemblies are the assemblies that gets installed on to your box when you install Silverlight 2.0 and SDK assemblies are installed with the SDK. When your app uses SDK assemblies its treated like any other third party dll and gets bundled with user app in the XAP file. All references to core assemblies are loaded from the users Silverlight installation directory. All WebServices components have API/wire parity with recently released Orcas version. We have strived very hard to ensure that the wire representation of Silverlight serialized types are compatible with Orcas serializer.

System.Runtime.Serialization.dll

This contains the DataContract public OM and the DataContractSerializer (DCS) class. The Silverlight DCS serializer supports the following public properties:

  1. Supports DataContractAttributes, CollectionDataContractAttribute, EnumMemberAttribute, DataMemberAttribute and KnownTypeAttributes on types.
  2. XmlDictionaryReader and XmlDictionaryWriters
  3. Ability to serialize Plain Old Clr Objects (POCO or non data contract types)

We are waiting to hear from users to decide on supporting features like IExtensibleDataObject, IDataContractSurrogate and PreserveObjectReferences. Type ISerializable is no longer available in Silverlight and so DCS can no longer serialize pure ISerializable types (it was fallback to serializing it as a POCO type provided the type has a public no argument constructor).

 

System.ServiceModel.Web.dll

We have completely rewritten DataContractJsonSerializer (DCJS) to ensure that the assembly fits in the reduced size requirements of Silverlight. This type is semi-compatible with the Orcas runtime. It maintains a subset of the public method but no longer derives from XmlObjectSerializer. Its a stand alone type and supports serializing any DataContract/POCO type to JSON. JSON produced by the Silverlight serializer is wire compatible with Orcas and so Orcas serializer should be able to deserialize that JSON just fine. Support for working with JXML (XmlJsonReader and XmlJsonWriter classes) is not available in the core and we have shipped it as a standalone sample. We believe the scenarios for JXML on the client is very limited but are open to feedback.

 

System.Xml.Serialization.dll

We have shipped an almost full featured port of the desktop XmlSerializer. Again we have strived very hard to ensure wire compat with existing Orcas serializer. One big implementation difference is the fact that the Silverlight Xml Serializer uses Lightweight Code Gen (LCG) to generate (de)serialize types on the fly. The Orcas serializer used Code Dom to generate the code required to read/write types. This implies that users will not be able to see the generate code. This behavior is actually pretty good as executing IL is way faster than executing raw code. Silverlight doesnt support features like XElement/XNode yet and hence the XmlSerializer doesnt support serializing them yet.

 

Note:

As you can see, I have stressed the "wire" compat nature of Silverlight serializers and did not talk about "Type" compat. Type compat between the serializers would mean that a desktop DataContract/XmlSeriailzable types can be reused in Silverlight. Silverlight being a subset of Orcas, certain serialization features/classes are not available. For example, a ISerializable type in desktop will obliviously will not be serializable in Silverlight. THe only supported way of porting types to Silverlight is "Schema" based. By Schema based I mean, users would need to create type on one side, export the schema for that type and then reimport it on the other side. For Beta1, the only way for importing schema is via the "Add Service Reference" option on a Silverlight project. We will ship the silverlight verison of SvcUtil, SlSvcUtil.exe, in Beta2.

 

System.ServiceModel.Syndication.dll

This is the only assembly that is complete feature port from Orcas. All Orcas RSS/Atom scenarios are fully supported in Silverlight.

Cross posted from http://blogs.msdn.com/mahjayar/archive/2008/03/11/silverlight-2-0-rundown-of-webservices-related-functionality-in-beta1.aspx

System.ServiceModel.dll

WCF client side proxy deserves a separate post of its own and I will post one shortly.

Maheshwar Jayaraman.

Software Design Engineer

Connected Framework

Posted 11 March 08 08:51 by SLWSTeam | 2 Comments   
Filed under , ,
Cross domain policy files in self-hosted services

One interesting question from the WCF forums: how to enable the cross-domain calls to self-hosted services, if there isn't an "easy" place to put the clientaccesspolicy.xml (or crossdomain.xml) as there is on IIS? The post at http://blogs.msdn.com/carlosfigueira/archive/2008/03/07/enabling-cross-domain-calls-for-silverlight-apps-on-self-hosted-web-services.aspx explains how to use the web programming model capabilities of WCF (.NetFX 3.5) to do that.

Carlos Figueira
Software Design Engineer in Test
Connected Framework Team

Posted 07 March 08 10:31 by SLWSTeam | 1 Comments   
Filed under ,
Silverlight Web Services MIX 08 Talk

Here's a link to Eugene's MIX 08 talk called "Working with Data and Web Services in Microsoft Silverlight 2". Great overview of the Web Services support in SL 2 Beta 1.

Yavor Georgiev
Program Manager
Connected Framework

Posted 06 March 08 01:03 by SLWSTeam | 1 Comments   
Filed under ,
POX Proxy Prototype Walkthrough

Update: Mahesh wrote a detailed step-by-step walkthrough of how he built the Ebay POX Proxy Example.

This post discusses the design of a POX Proxy prototype.

Current POX/JSON Support

SL 2 Beta 1 comes with support for consuming POX/JSON services.

The user experience is manual: the client has to use WebClient or HttpWebRequest (see How to: Make Requests to HTTP-Based Services) and then parse the response differently, depending on whether it contains XML or JSON.

XML can be deserialized in three different ways (see Working with XML Data in Silverlight), with XmlSerializer being the strongly-typed deserialization option. JSON can only be deserialized using DataContractJsonSerializer (see Working with JSON Data in Silverlight), which is also strongly-typed.

The code would look something like this (assuming we're working with XML, and the User type has already been defined so that XmlSerilalizer can deserialize the XML returned into it).

public void HowToMakeRequestsToHttpBasedServices()
{

     Uri serviceUri = new Uri("http://fabrikam.com/service/getUser");

     // Append any parameters to serviceUri, if necessary

     HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(serviceUri);
     request.BeginGetResponse(
new AsyncCallback(responseHandler), request);

}

void responseHandler(IAsyncResult asyncResult)
{

     HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
    
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);

     Stream responseStream = response.GetResponseStream();
    
XmlSerializer serializer = new XmlSerializer(typeof(User));

     User user = (User)serializer.Deserialize(responseStream);

     // Use user instance...

}

POX Proxy Prototype

Mahesh prototyped a POX Proxy (available here), which creates a very clean object model to access both POX and JSON, and hides some of the implementation details the current solution relies on.

private void TestPoxProxy()
{

     // Instantiate POX proxy with base service address
    
POXProxyRequest request = new POXProxyRequest(new Uri("http://fabrikam.com/service/"));

     // Set HTTP request verb
    
request.WebMethod = "POST";

     // Use RelativeUri to specify operation on service. This allows
     // us 
to reuse the same proxy instance to call different
     // operations on 
the service
    
r