Restful WCF service with Silverlight4

5 Comments

I’ve spent the last couple weeks wrestling with WCF4 and Silverlight4.

Here is some code that does a GET/POST/PUT/DELETE with a Silverlight4 client.

The Restful WCF Service

    [ServiceContract]
    public interface IInvoiceService
    {
        [WebGet(UriTemplate = "/invoices")]
        [OperationContract]
        List GetAllInvoices();

        [WebGet(UriTemplate = "/invoices/{invoiceId}")]
        [OperationContract]
        Invoice GetInvoice(string invoiceId);

        [WebInvoke(UriTemplate = "/invoices/{invoiceId}", Method = "PUT")]
        [OperationContract]
        Invoice UpdateInvoice(string invoiceId, Invoice newInvoice);

        [WebInvoke(UriTemplate = "/invoices", Method = "POST")]
        [OperationContract]
        Invoice AddNewInvoice(Invoice newInvoice);

        [WebInvoke(UriTemplate = "/invoices/{invoiceId}", Method = "DELETE")]
        [OperationContract]
        void DeleteInvoice(string invoiceId);
    }

Here is the implementation:

  public class InvoiceService : IInvoiceService
    {
        protected static List<Invoice> invoices = new List<Invoice>
        {
            new Invoice(1, "reciever1"),
            new Invoice(2, "reciever2"),
            new Invoice(3, "reciever3"),
        };

        public List<Invoice> GetAllInvoices()
        {
            return invoices;
        }

        public Invoice GetInvoice(string invoiceId)
        {
            Invoice invoice = invoices.Find(x => x.Id == int.Parse(invoiceId));

            if (invoice == null)
            {
                WebOperationContext ctx = WebOperationContext.Current;
                ctx.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
            }

            return invoice;
        }

        public Invoice UpdateInvoice(string invoiceId, Invoice newInvoice)
        {
            Invoice current = invoices.Find(x => x.Id == int.Parse(invoiceId));

            if (current == null)
            {
                WebOperationContext ctx = WebOperationContext.Current;
                ctx.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
                return null;
            }

            invoices.Remove(current);
            invoices.Add(newInvoice);

            return newInvoice;
        }

        public Invoice AddNewInvoice(Invoice newInvoice)
        {
            Debug.WriteLine("AddNewInvoice");

            Invoice existingInvoice = invoices.Find(x => x.Id == newInvoice.Id);
            WebOperationContext ctx = WebOperationContext.Current;

            if (existingInvoice != null)
            {
                ctx.OutgoingResponse.StatusCode = HttpStatusCode.Conflict;
                return null;
            }

            invoices.Add(newInvoice);

            ctx.OutgoingResponse.StatusCode = HttpStatusCode.Created;
            ctx.OutgoingResponse.Location = PluginFactory.INSTANCE.InvoiceServiceUri() + newInvoice.Id;

            return new Invoice(newInvoice.Id, newInvoice.Receiver);
        }

        public void DeleteInvoice(string invoiceId)
        {
            var id = Convert.ToInt32(invoiceId);
            invoices = invoices.FindAll(invoice => invoice.Id != id);
        }
    }

The Silverlight Client

You have two options when consuming services on the client. You can use WebClient (which is easy but weak). Or you can use the more rich HttpWebRequest which you need to consume Status Codes. This example users the later. Here is the Silverlight client.

GET

        private void GetClick(object sender, RoutedEventArgs e)
        {
            var request = (HttpWebRequest)WebRequest.Create(url + IdTextBox.Text);
            request.BeginGetResponse(GetCompleted, request);
        }

        private void GetCompleted(IAsyncResult ar)
        {
            // necessary for concurrency
            Dispatcher.BeginInvoke(delegate
            {
                try
                {
                    var request = (HttpWebRequest)ar.AsyncState;
                    var response = (HttpWebResponse)request.EndGetResponse(ar);

                    using (var streamReader = new StreamReader(response.GetResponseStream()))
                    {
                        ParseComplex(response, streamReader);
                    }
                }
                catch (WebException)
                {
                    outputTextBlock.Text = "This id does not exist.";
                }
            });
        }

POST

private void PostComplexClick(object sender, RoutedEventArgs e)
        {
            ClearTextBoxes();

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl);
            request.Method = "POST";
            request.ContentType = postContentType;
            request.BeginGetRequestStream(PostComplexRequestReady, request);
        }

        private void PostComplexRequestReady(IAsyncResult asyncResult)
        {
            HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
            Stream postStream = request.EndGetRequestStream(asyncResult);

            Dispatcher.BeginInvoke(delegate
            {
                Invoice newInvoice = new Invoice(int.Parse(IdTextBox.Text), RandomReceiver());
                byte[] byteData = Encoding.UTF8.GetBytes(newInvoice.AsXml());
                postStream.Write(byteData, 0, byteData.Length);
                postStream.Flush();
                postStream.Close();

                request.BeginGetResponse(PostComplexResponseReady, request);
            });
        }

        private void PostComplexResponseReady(IAsyncResult asyncResult)
        {
            Dispatcher.BeginInvoke(delegate
            {
                try
                {
                    var request = asyncResult.AsyncState as HttpWebRequest;
                    var response = (HttpWebResponse)request.EndGetResponse(asyncResult);
                    using (var streamReader = new StreamReader(response.GetResponseStream()))
                    {
                        ParseComplex(response, streamReader);
                    }
                }
                catch (WebException e)
                {
                    dynamic exceptionResponse = e.Response;
                    if (exceptionResponse.StatusCode == HttpStatusCode.Conflict)
                        outputTextBlock.Text = "This user already exists.";
                    else
                        outputTextBlock.Text = e.Message;
                }
            });

        }

PUT

  private void PutClick(object sender, RoutedEventArgs e)
        {
            ClearTextBoxes();

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + IdTextBox.Text);
            request.Method = "PUT";
            request.ContentType = postContentType;
            request.BeginGetRequestStream(PostComplexRequestReady, request);

            // Note: PUT is very similar to POST - only difference is url
        }

DELETE

   private void DeleteClick(object sender, RoutedEventArgs e)
        {
            ClearTextBoxes();

            var request = (HttpWebRequest)WebRequest.Create(url + IdTextBox.Text);
            request.Method = "DELETE";
            request.BeginGetResponse(GetCompleted, request);

            // Note: DELETE is very similar to GET
        }

Silverlight Model-View-Presenter (MVP) example

2 Comments

The Model-View-Presenter is a great pattern for breaking apart separations of concerns in your applications.

The model holds your data and services.
The view holds your user interface controls and interactions.
The the presenter coordinates things behind the scenes.

It’s nice because it keep your business logic out the UI and it makes testing a lot easier as you can focus on just one layer of the application at a time.

Having used MVP a lot in ASP.NET applications, I wanted to see what it would look like in Silverlight and coded up this quick example for reference.

Let’s now see how MVP handles someone entering new user information on a page and hitting the save button.

The View

The view is our gateway into getting and controlling what the user sees on the screen.

UserAdminView.xaml

<UserControl x:Class="MVP1.View.UserAdminView" ...  d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="White">

        <ListBox ScrollViewer.VerticalScrollBarVisibility="Disabled">

            <TextBlock Text="Username"/>
            <TextBox Name="userNameTextBox" Width="100" Height="25" />
            <TextBlock Text="Roles" />

            <StackPanel Orientation="Horizontal">
                <CheckBox Name="RequestorCheckBox"  />
                <TextBlock Text="Requestor"/>
            </StackPanel>

            <StackPanel Orientation="Horizontal">
                <CheckBox Name="ApproverCheckBox"  />
                <TextBlock Text="Approver"/>
            </StackPanel>

            <Button Name="SaveButton" Content="Save" Click="SaveButtonClicked"/>
            <TextBlock Name="Message" Foreground="Green" Text="Success" Visibility="Collapsed"/>

         </ListBox>
    </Grid>
</UserControl>

When the user hits the save button we need to know what the users name is and what roles they are going to be assigned. To do that we might define a view interface that looks like this:

IUserAdminView.cs

    public interface IUserAdminView
    {
        string ReadName();
        IList ReadRoles();
        void DisplayMessage(string userName);
    }

… and gets implemented like this:

UserAdminView.xaml.cs

    public partial class UserAdminView : IUserAdminView
    {
        private readonly UserAdminPresenter presenter;

        public UserAdminView()
        {
            InitializeComponent();
            presenter = new UserAdminPresenter(this, new UserRepository());
        }

        public string ReadName()
        {
            return userNameTextBox.Text;
        }

        public IList<string> ReadRoles()
        {
            IList<string> roles = new List<string>();
            if (RequestorCheckBox.IsChecked == true)
                roles.Add("Requestor");
            if (ApproverCheckBox.IsChecked == true)
                roles.Add("Approver");
            return roles;
        }

        public void DisplayMessage(string userName)
        {
            Message.Visibility = Visibility.Visible;
            Message.Text = string.Format("{0} was successfully added.", userName);
        }

        private void SaveButtonClicked(object sender, RoutedEventArgs e)
        {
            presenter.HandleAddUser();
        }
    }

ReadName(), ReadRoles() and DisplayMessage() interact directly with the view and do pretty much what you’d expect.

The SaveButtonClicked event hanlder however is a bit different.

       private void SaveButtonClicked(object sender, RoutedEventArgs e)
        {
            presenter.HandleAddUser();
        }

Because the view isn’t really in a position to handle saving the user, it passes this request off to the presenter who can (he’s got the view for reading data and the model for saving it).

But before we get into that guy let’s take a quick look at the model.

The Model

 public interface IUserRepository
    {
        void AddUser(string username);
        void UpdateUserRoles(string username, IList<string> roles);
    }

The Model often goes by more than one name. Some call it the Service layer. My friends like Task. Here I’ve called it IUserRepository because all we’re going to do is save the user to the database.

This example doesn’t actually talk to any databases, but if it did that code would go here (or a more likely some backend webservice):

public class UserRepository: IUserRepository
    {
        public void AddUser(string username)
        {
            // add user to the database
        }

        public void UpdateUserRoles(string username, IList roles)
        {
            // update the user roles
        }
    }

That’s it for the model. It just does the actual work of whatever we want to do and is usually called from the presenter.

The Presenter

 public class UserAdminPresenter
    {
        private IUserAdminView view;
        private IUserRepository repos;

        public UserAdminPresenter(IUserAdminView view, IUserRepository repos)
        {
            this.view = view;
            this.repos = repos;
        }

        public void HandleAddUser()
        {
            string userName = view.ReadName();
            IList<string> roles = view.ReadRoles();

            if (!string.IsNullOrEmpty(userName))
            {
                repos.AddUser(userName);
                repos.UpdateUserRoles(userName, roles);
                view.DisplayMessage(userName);
            }
        }
}

The presenter is where we bring it all together. We use our view to get the data and the model to save it. It coordinates whatever is going on in your view.

In this case there’s only one thing we’re doing. Adding a user. So when the Save button gets pressed our view passes control over to the presenter and it goes about using the view and model to do just that.

        public void HandleAddUser()
        {
            string userName = view.ReadName();
            IList<string> roles = view.ReadRoles();

            if (!string.IsNullOrEmpty(userName))
            {
                repos.AddUser(userName);
                repos.UpdateUserRoles(userName, roles);
                view.DisplayMessage(userName);
            }
        }

That’s it. That’s all there is to MVP.

How is this different from any other MVP implementation?

Not much.

Any differences will usually be in platform. The stateless (request/response) nature of the web means web events come at HTTP Posts. In Silverlight they come as .NET WPF events.

Other than that they are pretty much the same.

How is this different from MVC?

It’s not really that much different. Thick client MVC implementations, in my experience, use a lot of eventing for communication. I don’t like that.

I find heavy eventing hard to follow and difficult to debug. So much happens behind the scenes it can be hard to see where you are in the program. This isn’t an MVC problem. It’s more an implementation style (see last post for an example of heavy eventing).

What I like about MVP (and MVC implementations like Rails and MVC.NET) is the simple request response enforced by statelessness of HTTP. Fire event, something happens, update controls.

If I can maintain that simplicity my Silverlight applications (less rather than more events) I will usually go for that.

What about MVVM?

That’s on my todo list next. I want to try the data binding that comes with that and see how that compares to MVC and MVP.

Stay tuned.

In the meantime, here’s an article to get you started on MVVM.

You can download the source here for this example here SilverLight-MPV.doc (rename *.doc to *.zip – wordpress limitation).

Silverlight Model-View-Controller (MVC) example

8 Comments

I recently started playing with Silverlight again, and wanted to share one way of doing MVC.

To keep things simple, I created an app that basically updates one textbox when you start typing something in the other (salary calculates taxes).

Let’s first go through the code at a high-level, and then walk through what actually happens sequentially behind the scenes.

Step 1: Define your model.

    public interface ICalculatorModel
    {
        double Salary { get; set; }
        double Taxes { get; set; }

        event EventHandler<CalculatorEventArgs> TaxesChanged;
    }

In MVC our model defines our data. Here we are saying we’ve got two pieces of information we are interested in (salary and taxes) and an event to notify people when one of these values change.

Here’s what the actual model looks like.

public class CalculatorModel : ICalculatorModel
    {
        private double salary;
        private double taxes;
        public readonly double TAX_RATE = 0.3d;

        public double Salary
        {
            get { return salary; }
            set
            {
                if (value == this.salary) return;
                salary = value;
                Taxes = salary*TAX_RATE;
            }
        }

        public double Taxes
        {
            get { return taxes; }
            set
            {
                if (value == this.taxes) return;
                taxes = value;
                OnTaxesChanged(new CalculatorEventArgs(this));
            }
        }

        public event EventHandler<CalculatorEventArgs> TaxesChanged;

        protected void OnTaxesChanged(CalculatorEventArgs e)
        {
            if (TaxesChanged != null)
                TaxesChanged(this, e); // fire event
        }
    }

It basically sets values for it’s properties, and fires off an event when someone changes the Taxes property value (this is the event our view registers for so it knows when to update it’s value on the screen).

Step 2: Define your view.

  public partial class CalculatorView : Page
    {
        private ICalculatorModel model;
        private ICalculatorController controller;

        public CalculatorView()
        {
            InitializeComponent();
        }

        public void SetModel(ICalculatorModel calculatorModel)
        {
            model = calculatorModel;
            SalaryTextBox.TextChanged += SalaryTextBoxChanged;
            model.TaxesChanged += ModelTaxesChanged;
        }

        private void ModelTaxesChanged(object sender, CalculatorEventArgs e)
        {
            TaxesTextBox.Text = e.Taxes.ToString();
        }

        private void SalaryTextBoxChanged(object sender, TextChangedEventArgs e)
        {
            controller.SetSalary(Double.Parse(SalaryTextBox.Text));
        }

        public void SetController(ICalculatorController calculatorController)
        {
            controller = calculatorController;
        }
    }

The view fires events off (letting models and controllers know when something interesting has happened). And it registers for events it is interested in (so it knows when to update itself).

In this example we are interested in two events:

  1. When does the SalaryTextBox text change.
  2. SalaryTextBox.TextChanged += SalaryTextBoxChanged;
    
  3. When does our model Taxes value change.
  4. model.TaxesChanged += ModelTaxesChanged;
    

Let’s now take a look at the controller.

Step 3: Hooking up the controller.

    public class CalculatorController : ICalculatorController
    {
        private CalculatorView view;
        private ICalculatorModel model;

        public CalculatorController(CalculatorView view, ICalculatorModel model)
        {
            this.view = view;
            this.model = model;

            view.SetModel(model);
            view.SetController(this);
        }

        public void SetSalary(double salary)
        {
            model.Salary = salary;
        }

        public void SetTaxes(double taxes)
        {
            model.Taxes = taxes;
        }
    }

The controller basically just coordinates things between the model and the view.
Here it passes on the setting of model values to the model itself (which then fires events telling people the model is changed).

But actual hookup for the controller occurs in the MainPage.xaml.cs code behind.

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            ICalculatorModel model = new CalculatorModel();
            ICalculatorController controller = new CalculatorController(view, model);
        }
    }

That’s it for setup. Now let’s see how this all actually works.

Step 4: Let the events fly.

Because we have registered for the SalaryTextBox.TextChanged and model.TaxesChanged events in our view …

 public partial class CalculatorView : Page
    {
        public void SetModel(ICalculatorModel calculatorModel)
        {
            ...
            SalaryTextBox.TextChanged += SalaryTextBoxChanged;
            model.TaxesChanged += ModelTaxesChanged;
            ...
        }
}

when someone starts typing in the salary textbox

 public partial class CalculatorView : Page
    {
        private void SalaryTextBoxChanged(object sender, TextChangedEventArgs e)
        {
            controller.SetSalary(Double.Parse(SalaryTextBox.Text));
        }
}

our controller gets notified which passes the message onto our model

    public class CalculatorModel : ICalculatorModel
    {
        public double Salary
        {
             ...
            set
            {
                if (value == this.salary) return;
                salary = value;
                Taxes = salary*TAX_RATE;
            }
        }

        public double Taxes
        {
            ...
            set
            {
                if (value == this.taxes) return;
                taxes = value;
                OnTaxesChanged(new CalculatorEventArgs(this));
            }
        }
}

Now when the model sets it’s salary, it’s actually doing two things. First it sets the value of the salary if it’s changed, secondly it sets the Taxes property down below which in turn fires the OnTaxesChanged changed event:

    public class CalculatorModel : ICalculatorModel
    {
        protected void OnTaxesChanged(CalculatorEventArgs e)
        {
            if (TaxesChanged != null)
                TaxesChanged(this, e);
        }

This is how our Taxes textbox gets update. Because we registered for this event way back in our view, when it gets fired our Taxes textbox gets updated.

    public partial class CalculatorView : Page
    {
        private void ModelTaxesChanged(object sender, CalculatorEventArgs e)
        {
            TaxesTextBox.Text = e.Taxes.ToString();
        }

Phew!

That’s a lot of work to update one textbox based on the contents of another, but you could see how if you had a complicated UI, the benefits of separating the model from the view would start to pay off.

It jury is still out for me on how best to use MVC in Silverlight. Coming from a web background, all this eventing can get pretty confusing (the statelessness of the HTTP is nice).

But this is a start. I’ll post more when I get a chance to play with some other models like Model-View-Presenter.

You can download and play with source SilverLight-MVC here.

Note: WordPress doesn’t allow *.zip files so rename the *.doc to *.zip when you download.

You’ll need Visual Studios 2010 with Silverlight4.

In the mean time, here are some others Silverlight model view examples:

  1. Another MVC example.
  2. Model-View-Presenter example.
  3. Model-View-ViewModel example.

%d bloggers like this: