Book review: Microsoft Silverlight 5 and Windows Azure Enterprise Integration

Disclaimer: I received a copy of this book from Packt Publishing.

The author, David Burela, though I didn’t hear about him before seems to be well known in the Australian community.

When you look at the contents of the book it looks like it’s covering the main integration parts with Windows Azure.

- Hosting Silverlight Applications in Azure
- Using Azure Queues with Silverlight
- Accessing Azure Blob Storage from Silverlight
- Storing Data in Azure Table Storage from Silverlight
- Relational Data with SQL Azure and Entity Framework
- RIA Services and SQL Azure
- Exposing OData to Silverlight Applications
- Application Authentication

The author expects you to already have some Silverlight knowledge and thus won’t explain the Silverlight parts in too much detail. My experience with Windows Azure is small, which makes me probably part of the target audience. The introduction helps you understand what Azure is, a good refresher for me. After that, chapter after chapter there’s an explanation on how to integrate Silverlight with the backend, running on Azure. All in all it stays very basic and a couple of times it refers to some MSDN pages for the details. Though I agree that copying information that’s already on the web is probably not a good thing, I was reading the book on the bench and this means, no details for me at the time. I would rather have a book that is complete and puts these kind of additional parts in an Appendix.

In the end I didn’t feel satisfied. Most of the integration was more like, you integrate with WCF and that WCF will integrate with Windows Azure. This doesn’t have anything to do with the book itself, the content is good. However is a book like this really needed? You have to judge that yourself. It is an engaging book that will introduce Windows Azure to Silverlight developers.

Silverlight 3 talking to a RIA Service, everything hosted on Windows Azure

This is my first tryout of Windows Azure. I wanted to know if it’s possible to run the Preview of RIA Service on the CTP of Windows Azure.

First of all you’ll need a lot of different components, and if you want to host your solution in the cloud you’ll also need to register at Windows Azure.

- Register first: http://www.microsoft.com/azure/register.mspx

I assume you’ve already a machine running Visual Studio 2008 SP1. But even then you’ll need to download and install the following components if you haven’t done yet.

- Silverlight 3 Beta Tools for Visual Studio: http://www.microsoft.com/downloads/details.aspx?FamilyId=11dc7151-dbd6-4e39-878f-5081863cbb5d&displaylang=en

- .NET RIA Service May 2009 Preview: http://www.microsoft.com/downloads/details.aspx?FamilyID=76bb3a07-3846-4564-b0c3-27972bcaabce&displaylang=en

- Windows Azure Tools for Visual Studio May 2009 CTP: http://www.microsoft.com/downloads/details.aspx?FamilyID=11b451c4-7a7b-4537-a769-e1d157bad8c6&displaylang=en

 

Everything installed? Let’s start with the general setup

I first created an empty Solution, I always do this, because this is the only to have complete control over the naming. After that I added a Web Cloud Service, just like the screen below.

Add a Web Cloud Service

My solution still basic, no coding done yet, looks like this:

Solution view with Web Project and Web Cloud Project

Add a Silverlight Application project, and ensure that this Silverlight Application is hosted in the Webproject created in the previous step. Normally we would create a Silverlight Business Application, but we are going to associate RIA manually to this Silverlight Application.

New Silverlight application dialog

Let’s add a reference to the RIA library that’s needed to run this solution. You can find this library in: C:\Program Files\Microsoft SDKs\RIA Services\v1.0\Libraries\Silverlight\ (of course this can be different, depending on your installation location).

- System.Windows.RIA

There’s also a different library containing User Interface parts, we aren’t using it in this example but this is:

- System.Windows.Ria.Controls

Enable RIA on this Web Project

Before we start our coding, let’s configure the web project to enable RIA Services. I’ve explained it before, but for Windows Azure it’s a little bit different.

Add references to the following dll’s:

- System.ComponentModel.DataAnnotations

- System.Web.DomainServices

- System.Web.Ria

We still need to add the Http Handler for RIA Services. In my previous explanation I only explained how to do this for older versions of IIS. But Windows Azure is running on IIS 7. So the handler needs to be added to the handlers section in the system.webserver element.

<add name="DataService" verb="GET,POST" path="DataService.axd" type="System.Web.Ria.DataServiceFactory, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

 

Enable RIA on the Web Cloud Project

To enable RIA on the Web Cloud Project you have to change the ServiceDefinition.csdef file. Set the enableNativeCodeExecution to true.

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="MM.SilverToGold.Web.Cloud" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="WebRole" enableNativeCodeExecution="true">
    <InputEndpoints>
      <!-- Must use port 80 for http and port 443 for https when running in the cloud -->
      <InputEndpoint name="HttpIn" protocol="http" port="80" />
    </InputEndpoints>
  </WebRole>
</ServiceDefinition>

 

Coding

Now it’s time for coding, though I won’t explain much about the code. Please read my other RIA articles to get coding for RIA Service in your fingers.

First the RIA Service part, a very simple HelloWorldDomainService, just add the following class to your Web project.

using System.Web.DomainServices;
using System.Web.Ria;

namespace MM.HelloWorld.Web
{
	[EnableClientAccess]
	public class HelloWorldDomainService : DomainService
	{
		[ServiceOperation]
		public string HelloWorld(string name)
		{
			return string.Format("Hello {0}, from RIA Services running in the Cloud.", name);
		}
	}
}

When you now build the solution the Silverlight part will get generated.

Show the RIA Services generated file 

Coding the Silverlight part

We now have completed the RIA Services part, let’s do the Silverlight coding. First some UI, containing a button, a input field and a result field. I also added a Click event to the button.

<UserControl x:Class="MM.HelloWorld.Sui.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <StackPanel Height="45" Width="Auto" Orientation="Horizontal">
                <TextBlock FontSize="20" VerticalAlignment="Center" Width="201" Text="What's your name:"/>
                <TextBox x:Name="NameTextBox" Height="25" Width="192" Background="#FFFFFFFF" BorderThickness="2,2,2,2" FontSize="14"/>
            </StackPanel>
            <Button Content="Hello?" Click="Button_Click" Height="33" FontSize="20" Margin="5,5,5,5"/>
            <TextBlock x:Name="WorldResponse"/>
        </StackPanel>
    </Grid>
</UserControl>

Alright, in the Click event we want to call the RIA Service, and let’s hope the RIA Service running in the cloud answers us.

private void Button_Click(object sender, RoutedEventArgs e)
{
    var helloWorldDomainContext = new HelloWorldDomainContext();
    helloWorldDomainContext.HelloWorldCompleted +=
        HelloWorldDomainContextHelloWorldCompleted;
    helloWorldDomainContext.HelloWorld(NameTextBox.Text);
}

The code for the HelloWorldCompleted event is very simple, it’s just setting the text of a TextBlock. Please note the event automatically get’s you back to the UI-Thread, no manually checking for UI-Thread required.

private void HelloWorldDomainContextHelloWorldCompleted(object sender, InvokeEventArgs e)
{
    if(e.ReturnValue!=null)
        WorldResponse.Text = e.ReturnValue.ToString();
}

When you test this locally, it will run, but the interesting part of course: Will it run on Windows Azure?

Let it run on Windows Azure

To get your solution to Windows Azure you will first have to right-click the cloud-project, and choose for Publish. This will open a Windows Explorer window showing the files that are ready for publishing. In this example it looks like this.

image

We’ll now logon to the Windows Azure portal. In here you have to create a Hosted Services project. I’ve already done this before, but there are articles on the web about creating a Hosted Services project on Windows Azure. To be honest, you can even do this without an article. My portal looks like this.

Windows Azure Developer Portal

Let’s choose the Hosted Services project, this project is called “Monster Cloud” in my Azure environment. But you can have your own name. The next page looks like this.

Windows Azure Developer Portal - Hosted Services project

Let’s click the Deploy button, and see what happens.

Windows Azure Developer Portal - Deploy a new package screen

Ah we need to provide a few things. An application package, we have this already, it’s in our publish folder that was created for us: MM.HelloWorld.Web.Cloud.cspkg.

Let’s browse for this file, and also pick the Configuration Settings file, this is: ServiceConfiguration.cscfg.

All that’s left is providing a label name, and clicking the Deploy button. My screen looked like this before clicking Deploy.

Windows Azure Developer Portal - Deploy a new package screen, filled

When clicking deploy a lot of things are being done behind the scenes. First of all the files are uploaded, but also a kind of VM get’s created for us, this takes some time, might even take 5 minutes or longer. So you definitely have to have a bit of patience. After the deployment was complete my screen looked like this.

Windows Azure Developer Portal - Run the Azure package

Let’s click the Run button.

So let’s try the url that’s created for our staging environment. For a brief period of time, you can take a look at my staging environment.

It’s working as expected. We now have a Silverlight 3 application communicating with RIA Services, and everything running in the cloud.

Testing the Silverlight 3 communicating with RIA Services, all running on the cloud.

You can download the Source Files. If you have any questions or remarks please let me know.

Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.

Silverlight 3 and RIA Service – Cross Domain Proxy Enhanced

Some time ago I wrote a very small RIA Service that could be used to overcome Cross Domain issues. It’s a proxy that sits between your Silverlight application and any server where you want to get content over http.

A lot people know that not even half of the public API’s have cross domain configurations in place. The best solution that’s left is a proxy that can forward the calls to the public API and return the response back to the original caller. This article will expand the Silverlight part of the Cross Domain Proxy. Nothing needs to be changed to the RIA Service part of this Cross Domain Proxy.

What is the problem we have with the solution from my earlier article about Cross Domain Proxy?

One thing: The Cross Domain Proxy RIA Service is a generic service that can be used for all cross domain accesses. So basically we could write an application that’s performing multiple calls through the cross domain proxy at the same time. But how do we use the responses? We basically have one event “ProcessCompleted”, should we then react to this event by doing different things? Yes that could be, but we could do it differently as well.

I’m thinking about a ProxyService that’s running on Silverlight which has a little bit more knowledge compared to the RIA Services generated stub. This service would enable to do a cross domain request but provide a function to be called on completion at the same time.

The code using this service would look like this (firing multiple cross domain requests at the same time):

var domainProxyService = new DomainProxyService();
domainProxyService.Process(
    new ProxyRequest
        {
            Url = "http://www.silverlight.net/"
        },
    response => Debug.WriteLine(string.Format("1:", response.Content)));
domainProxyService.Process(
    new ProxyRequest
        {
            Url = "http://www.asp.net/"
        },
    response => Debug.WriteLine(string.Format("2:", response.Content)));

domainProxyService.Process(
    new ProxyRequest
        {
            Url = "http://www.azure.net/"
        },
    response => Debug.WriteLine(string.Format("3:", response.Content)));

The DomainProxyService needs to be intelligent enough to be able to route the reponses to the correct function pointers.

So there needs to be a key that can help associate the request with the response. In my last article I introduced the property Id in the ProxyRequest and the RequestId in the ProxyResponse. But for all purpose I don’t want to put a value in the Id, as a caller I don’t use this field, it’s just for internal usage so that association between Request and Response is possible.

My idea is to put a dictionary in the DomainProxyService to associate the request id with a function pointer. I want the function point to be of a type void that accepts one parameter of type ProxyResponse. That would make a dictionary like this:

private readonly Dictionary<Guid, Action<ProxyResponse>> m_dictionaryOfListeners =
    new Dictionary<Guid, Action<ProxyResponse>>();

The method to process a request isn’t that difficult. It will generate a new Id if it’s still empty. Besides that it will add an item to the dictionary, the key with the associated function to call on completion. And after all the most important part, we will call the original RIA Service.

public void Process(ProxyRequest proxyRequest, Action<ProxyResponse> callBack)
{
    //Generate a unique id if it doesn't contain an id yet.
    if (Guid.Empty == proxyRequest.Id)
        proxyRequest.Id = Guid.NewGuid();
    //Add the callback to list of listeners for use on completion.
    m_dictionaryOfListeners.Add(proxyRequest.Id, callBack);

    m_domainProxy.Process(proxyRequest);
}

We will still need to have one generic listener for the ProcessCompleted event. This listener will look up the appropriate function to call in the dictionary. Will invoke the function and remove the item in the dictionary.

private void DomainProxyProcessCompleted(object sender, InvokeEventArgs e)
{
    var proxyResponse = e.ReturnValue as ProxyResponse;
    if (proxyResponse != null)
    {
        //If the dictionary contains listeners for this request
        if (m_dictionaryOfListeners.ContainsKey(proxyResponse.RequestId))
        {
            m_dictionaryOfListeners[proxyResponse.RequestId].Invoke(proxyResponse);
            m_dictionaryOfListeners.Remove(proxyResponse.RequestId);
        }
    }
}

To be complete here the full source of the DomainProxyService class. Please remember this article continues on my previous article about Domain Proxy.

public class DomainProxyService
{
    private readonly Dictionary<Guid, Action<ProxyResponse>> m_dictionaryOfListeners =
        new Dictionary<Guid, Action<ProxyResponse>>();

    private readonly DomainProxy m_domainProxy = new DomainProxy();

    public DomainProxyService()
    {
        m_domainProxy.ProcessCompleted += DomainProxyProcessCompleted;
    }

    private void DomainProxyProcessCompleted(object sender, InvokeEventArgs e)
    {
        var proxyResponse = e.ReturnValue as ProxyResponse;
        if (proxyResponse != null)
        {
            //If the dictionary contains listeners for this request
            if (m_dictionaryOfListeners.ContainsKey(proxyResponse.RequestId))
            {
                m_dictionaryOfListeners[proxyResponse.RequestId].Invoke(proxyResponse);
                m_dictionaryOfListeners.Remove(proxyResponse.RequestId);
            }
        }
    }

    public void Process(ProxyRequest proxyRequest, Action<ProxyResponse> callBack)
    {
        //Generate a unique id if it doesn't contain an id yet.
        if (Guid.Empty == proxyRequest.Id)
            proxyRequest.Id = Guid.NewGuid();
        //Add the callback to list of listeners for use on completion.
        m_dictionaryOfListeners.Add(proxyRequest.Id, callBack);

        m_domainProxy.Process(proxyRequest);
    }
}


Ps. This article is cross posted on:
Mark Monster’s blog and Silverlight Help.

Silverlight 3 and RIA Service – Creating a Proxy for Cross Domain HttpRequests

One of the first things I thought about after writing my first two articles on RIA Services (Basic and Advanced) was how I could take advantage of this new technology.

The first thing I could thing of was a solution that helps overcoming the Cross Domain Issues when accessing resources on the internet. What about something like a proxy service to overcome cross domain issues? Access our known proxy server which will forward the request to the actual resource on the internet.

image

Let’s first define the interface to communicate through. A very simple ProxyRequest that contains the resource to access on the ‘Any resource’ side, and an Id to make sure we can correctly associate the Request and the Response later on.

namespace MM.Ria.CrossDomainProxy
{
    public class ProxyRequest
    {
        [Key]
        public Guid Id { get; set; }

        public string Url { get; set; }
    }
}

The ProxyResponse is very simple as well. Almost the same as the ProxyRequest a RequestId associated with the Id in the ProxyRequest, the Content and of course something to store any error that occurred.

namespace MM.Ria.CrossDomainProxy
{
    public class ProxyResponse
    {
        [Key]
        public Guid RequestId { get; set; }

        public string Content { get; set; }

        public string Error { get; set; }
    }
}

And we need an Interface with an Operation, let’s call it process.

namespace MM.Ria.CrossDomainProxy
{
    public interface IProxy
    {
        ProxyResponse Process(ProxyRequest request);
    }
}

We now create the RIA Service implementation, by just delegating everything to a RegularProxy implementation. So this one is simple as well.

namespace MM.Ria.CrossDomainProxy
{
    [EnableClientAccess]
    public class DomainProxy : DomainService, IProxy
    {
        private readonly RegularProxy m_proxy = new RegularProxy();

        [ServiceOperation]
        public ProxyResponse Process(ProxyRequest request)
        {
            return m_proxy.Process(request);
        }
    }
}

And the magic is in the RegularProxy, don’t think we should call it magic though. Just an usage of the WebClient class to download the data from the Url.

namespace MM.Ria.CrossDomainProxy
{
    public class RegularProxy : IProxy
    {
        public ProxyResponse Process(ProxyRequest request)
        {
            var response = new ProxyResponse {RequestId = request.Id};
            try
            {
                using (var client = new WebClient())
                {
                    string data = client.DownloadString(request.Url);
                    response.Content = data;
                }
            }
            catch (Exception exception)
            {
                response.Error = exception.Message;
            }

            return response;
        }
    }
}

Don’t forget this is a very basic Proxy implementation and doesn’t implement all the features we can think of. But this first basic set up can easily be enhanced with for example Credentials support, Caching and other things as well.

But how can we use it in our Silverlight application? Simple as well.

var domainProxy = new DomainProxy();
domainProxy.ProcessCompleted += (sender, e) => Debug.WriteLine((e.ReturnValue as ProxyResponse).Content);
domainProxy.Process(new ProxyRequest
                        {
                            Id = Guid.NewGuid(), 
                            Url = "http://www.silverlight.net/"
                        });

Looks like the keyword is simple when we’re creating RIA Services. I really like it.

Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.

Silverlight 3 and RIA Services – The advanced things

My last article was about the basics of RIA Services. This article goes about the more advanced things in RIA Services. This article contains a few things that make the usage of RIA Services in more advanced scenario’s possible.

  • Complex Types in RIA Services
  • RIA Services in a separate class library
  • RIA Services and Out of browser mode
  • RIA Services on a different host

Using Complex Types in RIA Services

In my other article I just made use just a string as input parameter and a string as output parameter. It’s however very well possible to use custom types instead. There’s hower one prerequisite for those custom types.

  • Each Custom Type needs to have one property decorated with a KeyAttribute. This is required for input and output types.

I created a WorldRequest and a WorldResponse which fits nicely in the example for HelloWorld.

public class WorldRequest
{
    [Key]
    public string Name { get; set; }
}

public class WorldResponse
{
    [Key]
    public string Greeting { get; set; }
}

This can be used in the HelloWorldDomainService just like you would do in a normal class.

[EnableClientAccess]
public class HelloWorldDomainService : DomainService
{
    [ServiceOperation]
    public WorldResponse HelloWorld(WorldRequest worldRequest)
    {
        return new WorldResponse { Greeting = string.Format("Hello {0}.", worldRequest.Name) };
    }
}

After compilation those custom types get generated in the Silverlight project as well as we saw in my previous article. The Custom Type is now overloaded from Entity. And has a specific method called GetIdentity. This has something to do with the KeyAttribute that’s required to add to one property inside a custom types. Although this is probably necessary for integration with the Entity Framework it doesn’t make sense in my example.

[DataContract(Namespace="http://schemas.datacontract.org/2004/07/MM.Ria")]
public sealed partial class WorldRequest : Entity
{
    
    private string _name;
    
    [DataMember()]
    [Key()]
    public string Name
    {
        get
        {
            return this._name;
        }
        set
        {
            if ((this._name != value))
            {
                this.ValidateProperty("Name", value);
                this.RaiseDataMemberChanging("Name");
                this._name = value;
                this.RaiseDataMemberChanged("Name");
            }
        }
    }
    
    public override object GetIdentity()
    {
        return this._name;
    }
}

We can now easily use this generated class as we would have done in different scenario’s.

var helloWorld = new HelloWorldDomainContext();
helloWorld.HelloWorldCompleted += HelloWorldHelloWorldCompleted;
helloWorld.HelloWorld(new WorldRequest{Name = "Mark Monster"});

And in the EventHandler we have to cast the ReturnValue property to the WorldResponse type. Again I hope they make InvokeEventArgs a generic type so that we don’t have to cast this ReturnValue and have it return the correct type.

private void HelloWorldHelloWorldCompleted(object sender, InvokeEventArgs e)
{
    Debug.WriteLine((e.ReturnValue as WorldResponse).Greeting);
}

Move code for the RIA Service to a class library

Next thing that came in my mind was the fact what if I want to share my RIA Services with other people? Do they need to have the source or is a different approach possible?

Luckily it’s possible to create class library (standard .NET) add references to a few dlls.

image

After that just move your RIA Service code in there. This library can now be used in any Web project that’s linked to a Silverlight application. Just add a reference to the new library containing your RIA Service and while building code will get generated in your Silverlight application.

image

What about using RIA Services in the Out of browser mode?

It just works. I didn’t have to do anything to make the Out of browser version communicate with the RIA Services.

When the host running the RIA Services is different from the url hosting the Silverlight application?

Of course in some scenario’s the RIA Services are hosted on a different location than the Silverlight application itself. Of course you have to remind yourself about cross domain issues, so make sure the host has a clientaccesspolicy.xml or crossdomain.xml file in place.

When we take a closer look into the generated code we’ll find a default constructor and a constructor where you can specify the service URI.

/// <summary>
/// Default constructor.
/// </summary>
public HelloWorldDomainContext() : 
        base(new HttpDomainClient(new Uri("DataService.axd/MM-Ria-HelloWorldDomainService/", System.UriKind.Relative)))
{
}

/// <summary>
/// Constructor used to specify a data service URI.
/// </summary>
/// <param name="serviceUri">
/// The HelloWorldDomainService data service URI.
/// </param>
public HelloWorldDomainContext(Uri serviceUri) : 
        base(new HttpDomainClient(serviceUri))
{
}

We can now make use of the constructor which accepts a serviceUri to connect to the RIA Service that’s running at a different location. The tricky part however is the DataService.axd/MM-Ria-HelloWorldDomainService/ part. Besides DataService.axd it contains also the namespace and type name for the RIA Service, but instead of using dots to separate the namespace parts and the type name dashes are used. But for the easy parts, just copy it from the generated code I would say.

var helloWorld = new HelloWorldDomainContext(new Uri("http://myhostruningsomewhere.com/DataService.axd/MM-Ria-HelloWorldDomainService/", UriKind.Absolute));
helloWorld.HelloWorldCompleted += HelloWorldHelloWorldCompleted;
helloWorld.HelloWorld(new WorldRequest {Name = "Mark Monster"});

Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.