Adoption of WCF technologies in Silverlight 2 applications on the web

If you are interested in what communication and serialization technologies are being used by others in Silverlight 2 applications, check out the post at http://tomasz.janczuk.org/2009/07/adoption-of-wcf-technologies-in.html. It is a summary of a research of over 700 actual Silverlight 2 applications conducted in February 2009. It compares the adoption numbers of several communication and serialization technologies, including WCF, in Silverlight 2 applications as well as provides basic analysis of backend service technology.

Tomasz Janczuk
Development Manager
WCF Team

Improving the performance of web services in SL3 Beta

Silverlight 3 Beta introduces a new way to improve the performance of web services. You have all probably used the Silverlight-enabled WCF Service item template in Visual Studio to create a WCF web service, and then used the Add Service Reference command in your Silverlight application project in order to access the web service. In SL3, the item template has undergone a small change that turns on the new binary message encoder, which significantly improves the performance of the WCF services you build. Note that this is the same binary encoder which has been available in .Net since the release of WCF, so all WCF developers will find the object model very familiar.

The best part is that this is done entirely in the service configuration file (Web.config) and does not affect the way you use the service. (Check out this post for a brief description of exactly what the change is.)

I wanted to share some data that shows exactly how noticeable this performance improvement is, and perhaps convince some of you to consider migrating your apps from SL2 to SL3.

When Silverlight applications use web services, XML-based messages (in the SOAP format) are being exchanged. In SL2, those messages were always encoded as plain text when being transmitted; you could open a HTTP traffic logger and you would be able to read the messages. However using plain text is far from being a compact encoding when sending across the wire, and far from being fast when decoding on the server side. When we use the binary encoder, the messages are encoded using a WCF binary encoding, which provides two main advantages: increased server throughput and decreased message size. 

Increased server throughput

Let’s examine the following graph (hat tip to Greg Leake of StockTrader fame for collecting this data). Here is the scenario we measure: the client sends a payload, the server receives it and sends it back to the client. Many clients are used to load the service up to its peak throughput. We run the test once using the text-based encoding and once using the new binary encoding and compare the peak throughput at the sever. We do this for 2 message sizes: in the smaller size the payload an array with 20 objects, and in the bigger one the payload is an array with 100 objects.

Some more details for the curious: The service is configured to ensure no throttling is happening, and a new instance of the service is created for every client call (known as PerCall instancing). There are ten physical clients driving load, each running many threads hitting service in tight loop (but with small 0.1 second think time between requests) using a shared channel to reduce client load. The graph measures peak throughput on the service at 100% CPU saturation. Note that in this test we did not use Silverlight clients but regular .Net clients. Since we are measuring server throughput it is not significant what the clients are.

When sending the smaller message we see a 24% increase in server throughput, and with the larger message size we see a 71% increase in server throughput. As the message complexity continues to grow, we should see even more significant gains from using the binary encoder.

What does that mean to you? If you run a service that is being used by Silverlight clients and you exchange non-trivial messages, you can support significantly more clients if the clients use SL3’s binary encoding. As usage of your service increases, that could mean being able to save on buying and deploying extra servers.

Decreased message size

Another feature of the binary encoder is that since messages sent on the wire are no longer plain-text, you will see a reduction in their average size. Let’s clarify this point: the main reason you would use the binary encoding is to increase the service throughput, as discussed in the previous section. The decrease in message size is a nice side-effect, but let’s face it: you can accomplish the same effect by turning on compression on the HTTP level.

This test was far less comprehensive than the previous one and we did it ad-hoc on my co-worker’s office machine. We took various objects inside a Silverlight control, and turned them into the same kind of SOAP messages that get sent to the service. We did this using the plain-text encoding and using binary encoding and then we compared the size of the messages in bytes. Here are our results:

The takeaway here is that the reduction of message size depends on the nature of the payload: sending large instances of system types (for example a long String) will result in a modest reduction, but the largest gains occur when complex object graphs are being encoded (for example objects with many members, or arrays).

What does this mean to you? If you run a web service and you pay your ISP for the traffic your service generates, using binary encoding will reduce the size of messages on the wire, and hopefully lower your bandwidth bills as traffic to your service increases.

Conclusion

We are confident that binary encoding is the right choice for most backend WCF service scenarios: you should never see a regression over text encoding when it comes to server throughput or message size; hopefully you will see performance gains in most cases. This is why the binary encoder is the new default in the Silverlight-enabled WCF Service item template in Visual Studio.

An important note: binary encoding is only supported by WCF services and clients, and so it is not the right choice if you aren’t using WCF end-to-end. If your service needs to be accessed by non-WCF clients, using binary encoding may not be possible. The binary AMF encoding used by Adobe Flex is similarly restricted to services that support it.

Posted 07 June 09 08:30 by SLWSTeam | 7 Comments   
Filed under , , ,
Check us out at TechEd North America 2009

I hope you enjoy the content we post on this blog. I’ll be giving a talk at the upcoming TechEd conference in LA, going through some Silverlight 3 content similar to what we have been posting here. If you’re attending TechEd, check out:

SOA03-INT Interacting with Web Services Using Microsoft Silverlight

Yavor Georgiev
Tue 5/12 | 4:30 PM-5:45 PM | Blue Theater 2
300 - Advanced, Middle Tier Platform and Tools, SOA and Business Processes, TLC Interactive Theater

Learn how easy it is to utilize POX, REST, RSS, ATOM, JSON, and SOAP services in your Silverlight 2 mash-up application. Hear best practices for developing and consuming secure services within and across domain boundaries. Experience new features in the upcoming Silverlight 3 release including optimized binary communication format, improved support for server- to-client "push" scenarios and new security features.

If you have not registered, you still have the opportunity to do so:

If you do attend, make sure you let me know you’re a reader of our blog… I’d love to hear any feedback you have.

Cheers,
-Yavor

Posted 20 April 09 12:32 by SLWSTeam | 1 Comments   
Filed under ,
Using WCF services from Silverlight in Azure

With all the buzz around Windows Azure, you may have wondered how to host your Silverlight application in the cloud. Since Silverlight controls are essentially static content, hosting them is as easy as uploading some files to the cloud.

When it comes to building WCF services to provide data to your Silverlight control, the story gets a little more complicated. The fact that the Azure cloud is a load-balanced environment as well as the deployment mechanism for setting up a service in Azure pose some unique challenges to hosting WCF services.

To help with this, our team has posted a Code Gallery site with 3 Silverlight-specific samples that you can run in the cloud and also on your local machine. The samples exercise the following features:

The third example hosts our chat sample in Azure for a massively-distributed free-for-all chat experience, and you can try it here. Try opening up this link across multiple machines and browsers and watch them all chat together.

Which brings me to probably the most useful thing we published: a list of known issues with hosting WCF services and Silverlight clients in Azure. Check out this page, and especially the sections “Hosting WCF Services” and “Hosting Silverlight Clients”. The page contains some workarounds we gathered from across the web, and is guaranteed to save you a bunch of head-scratching if you try WCF on Azure for yourself.

Cheers,
-Yavor

Some known issues in SL3 Beta

We've run across some issues with our web services features in the Silverlight 3 Beta and I want to share these here to hopefully save folks some time and frustration.

Issue: On Windows 7 Beta, you might encounter the following error when generating a proxy: "The element 'httpTransport' cannot contain child element 'extendedProtectionPolicy' because the parent element's content model is empty".

Workaround: On Windows 7, when you use the Silverlight-enabled WCF Service item template, an <extendedProtectionPolicy /> element may be generated in Web.config. This element is not supported by Silverlight. Simply remove the element from Web.config and try regenerating the Silverlight proxy.


Issue: If you use the Silverlight-enabled WCF Service template and you try generating a Silverlight proxy using Add Service Reference on a machine with both Silverlight 2 and Silverlight 3 Beta SDKs, you may get warnings at proxy generation time and errors at runtime. The warnings can include a variety of "Cusom tool" warnings which state that the endpoints found are "not compatible with Silverlight 2" or "No endpoints compatible with Silverlight 2 were found."

Workaround: If you are using Add Service Reference to generate proxies, side-by-side installation of the Silverlight 2 and Silverlight 3 Beta SDKs is not supported. Please uninstall the Silverlight 2 SDK to use Silverlight 3 features. After uninstalling, ensure that the assembly Microsoft.Silverlight.ServiceReference is not present in the machine GAC.


Issue: When using Add Service Reference to generate a proxy to a WCF duplex service (a service built with the System.ServiceModel.PollingDuplex.dll assembly provided in the Silverlight SDK), the generated proxy may not compile and may complain about a missing assembly reference.

Workaround: The proxy for the duplex service is generated correctly, however Add Service Reference will sometimes forget to reference th System.ServiceModel.PollingDuplex.dll assembly in the Silverlight client. Simply add a reference to the assembly (right-click in the Silverlight project, select Add Reference, find the assembly in the list on the .Net tab), and the proxy should now compile.

Hope this is helpful!
-Yavor Georgiev

Posted 05 April 09 10:21 by SLWSTeam | 1 Comments   
Filed under , , ,
What's new with web services in Silverlight 3 Beta

Silverlight 3 beta comes with a set of exciting web services features that address key customer requests.

Binary message encoding

In Silverlight 2 the only supported binding was BasicHttpBinding, which encodes outgoing messages as text and sends them over an HTTP transport. This binding is great for interoperability with SOAP 1.1 services and is also easily debuggable since messages can be viewed in plain text on the wire using HTTP debugging tools such as Fiddler.

However as Silverlight applications go into production and grow to scale, service developers start getting concerned with the cost of hosting services. Two things in particular that we are about:

  • Increased server throughput - more clients can be connected to a server, which means fewer servers need to be purchased. 
  • Decreased message size - smaller message sizes exchanged on the wire means lower bandwidth bills

Silverlight 3 introduces a binary message encoder, which produces significant improvements in both of the above indicators. A follow-up post is coming with some specific data on the improvements that can be expected.

Binary encoding is implemented as a custom binding, there is no out-of-the-box binary binding.

<bindings>
   <customBinding>
      <binding name="binaryHttpBinding">
         <binaryMessageEncoding />
         <httpTransport />
      </binding>
   </customBinding>
</bindings>

<endpoint address="" binding="customBinding" bindingConfiguration="binaryHttpBinding"  contract="Service" />

The BinaryMessageEncodingBindingElement can be used as part of any custom binding and so it composes easily to create things like a binary duplex binding.

The binary encoder offers performance gains over the text encoder, and there should never be any regressions. This is why binary is the new default in backend service scenarios, such as where the Silverlight-enabled WCF Service item template is used. Therefore the template has been modified to use binary. The interop cases is where binary should not be used (if the client is talking to a non-WCF service), since binary is a WCF-specific encoding: please continue to use BasicHttpBinding with text encoding in those scenarios (for example accessing ASMX services).

Duplex object model simplification 

Duplex is an innovative Silverlight 2 feature which allows the service to send data to the client without the client manually polling for the data ("smart" polling still occurs on the network layer, but the user does not need to know). However there were two significant limitations in the Silverlight 2 duplex object model:

  • Channel programming had to be used and
  • Serialization was not supported so a Message programming model had to be used.

Silverlight 3 lifts these restrictions and introduces Add Service Reference support for duplex services. Familiar-looking proxies are now generated, greatly reducing the amount of Silverlight code that is needed to access a duplex service. A simple stock ticker client implementation, which previously took 203 lines of code, can now be reduced to a mere 48 lines of code, a 76% reduction in code size. Not to mention that the channel-based code was complex and very error-prone due to its use of async patterns. Here is a snippet showing the crux of the new object model, in the context of the stock ticker example:

private void Button_Click(object sender, System.Windows.RoutedEventArgs e)

{

    ServiceClient proxy = new ServiceClient(binding, address);

 

    proxy.ReceiveCallbackCompleted += new EventHandler<ReceiveCallbackCompletedEventArgs>(proxy_ReceiveCallbackCompleted);

    proxy.StartAsync(symbol.Text);

}

 

void proxy_ReceiveCallbackCompleted(object sender, ReceiveCallbackCompletedEventArgs e)

{

    if (e.Error == null)

    {

        price.Text = e.price.ToString();

    }

}

Note that receiving the callback from the server is now just a matter of attaching a callback to an event. Also note the fact that we are working with CLR types and not Message objects, so serialization is now enabled. We have updated our documentation with a walkthrough of how to use the new object model. In addition, Eugene's duplex chat server implementation, which has proven very popular, has also been updated with the new OM.

Faults support

In Silverlight 2 if an unexpected exception occurred in the service, the fault would not be propagated to the Silverlight client. Instead of getting the exception propagated to the user, Silverlight would throw an unhelpful CommunicationException which carries no useful information. There were two reasons for this: (1) faults are returned with a 500 status code, and the browser networking stack prevents Silverlight from reading the body of such a response, and (2) Silverlight did not support he necessary client-side logic to convert the fault message into an exception that can be surfaced to the user. These limitation made it very difficult to debug services from Silverlight.

In Silverlight 3 Beta limitation (1) is unfortunately still present. To work around this issue our documentation provides a WCF endpoint behavior, which can be applied to your WCF service to switch the response code from 500 to 200. With this response code the message will be accessible to Silverlight and we can address limitation (2). In Silverlight 3, we have added the necessary client-side OM to surface faults to the user. Look out for helpful FaultException and FaultException<ExceptionDetail> exceptions which will help you debug your service. Also please see the documentation page linked earlier for a full description of the faults object model in Silverlight.

New security mode 

A common scheme used to secure services for use by Silverlight clients is browser-based authentication. However browser-based authetnication is not safe to use if your service is accessible from any domain via a cross-domain policy file. This would expose your service to CSRF type attacks, where cached browser credentials can be used by malicious apps to access your sercure service without the user's knowledge.

Silverlight 3 introduces a new security mode called TransportSecurityWithMessageCredential to address this configuration. In this mode, the credentials are included in every outgoing message to the service, and the service verifies those credentials on the SOAP layer. However since the credentials are in plain text inside the message the transport needs to be secure so we use HTTPS.

A more detailed walktrhough of valid Silverlight security configurations will follow.

Command-line proxy generation

In Silverlight 2 Add Service Reference as part of Visual Studio is the only way to generate proxies for Silverlight clients. In Silverlight 3 we are introducing a command-line tool called slsvcutil.exe, which allows customized command-line proxy generation. Using the tool, proxies can now be generated as part of your build process for greater robustness. The slsvcutil.exe tool is fully described in this documentation topic.

Thanks for reading through this, and please stay tuned for some in-depth posts about these new features.

Yavor Georgiev
Program Manager, Silverlight Web Services Team

Some new features for REST services

Just a quick announcement here of a release that will be interesting to SL developers who want to access REST services. The WCF REST Starter Kit Preview 2 is now out, go grab it at http://msdn.com/wcf/rest. The release gives you a polished install/uninstall experience, so don't be afraid to try it on your box, it won't muck it up like "preview" software so frequently does.

This release gives you one interesting client-side feature that you may have heard me or Eugene speak about: Paste XML as Types. It's a VS menu item which helps you use XmlSerializer with REST services. Frequently these services use human-readable documentation to describe the XML shape, and it is difficult to hand-code a type to use with XmlSerializer, especially when the XML instance is complex. For example check out this sample XML response from the Yahoo BOSS API. With this new feature it takes one click to generate the type:

Using Paste XML as Types with Yahoo BOSS API

Another interesting feature in the release is HttpClient - a sort of specialized WebClient - which can be used to programmatically access REST services using an extensible model for sending HTTP requests and processing HTTP responses. The model enables you to complete common HTTP/REST development activities required to consume an existing service in a fraction of the time you normally spend. Some convenient time-savers include query string support (build URIs as name/value pairs) and serialization support (easily plug in types generated with Paste XML as Types to read the response).

Unfortunately in this release the starter kit only contains a .Net version of HttpClient, which will not compile in Silverlight. We are considering porting this prototype to Silverilght, and if you get a chance to try it on .Net, please let us know of any feedback you have.

Stay tuned for some exciting content coming out over the next week!

Cheers,
-Yavor

 

Posted 13 March 09 10:04 by SLWSTeam | 3 Comments   
Filed under , ,
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 | 6 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 | 4 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 , ,
More Posts Next page »
Page view tracker