Even more update on my Mix09 talk “building business applications with Silverlight 3”.  Now for some brand new content – that just could not have been done before this release. 

This demo will take the Application logic we created in my Mix09 talk and put a REST based web service head on it with ADO.NET Data Services.   

image

This might be useful if an application starts as a simple RIA Application but later you discover that you want to add a more explicit services layer to enable a wide range of clients to access your application.  Luckily all your investment in the server application logic continues to work. 

Just to show off the point, we will then consume that from a WinForms applications.  This extends your reach and headroom for using RIA Services even more! 

The demo requires (all 100% free and always free):

  1. VS2008 SP1 (Which includes Sql Express 2008)
  2. Silverlight 3 RTM
  3. .NET RIA Services July '09 Preview

Also, download the full demo files and check out the running application.

Start with the application where we left off in Part 4…  In the the server project, let’s add a REST head to the DomainService.  This will allow any arbitrary client to access the DomainService and gives us a chance to selectively control what gets exposed. 

image

Then we customize the class that was created for us.

public class SuperEmployeeService : DataService<SuperEmployeeDomainService>, IServiceProvider
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(IDataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);
        config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
    }
 

Notice here i am using the “demo” mode with “*” and “All”..  Here is where you can control what aspects of the Domain are meant to be accessed via any client and which are really part of the Silverlight app.   It is a best practice to list them explicitly. 

Now I simply right click and view in browser..  We get the standard ADO.NET Data Services (Astoria) REST head.  But rather than going directly against my database, I now have a formal way to add application logic. 

image

We can even traverse the data via the standard astoria URL formats.  

Again, notice all the calls are run through your DomainService so the application logic controls the access, shape and content of all the data here. 

http://localhost:52878/SuperEmployeeService.svc/$metadata

image

http://localhost:52878/SuperEmployeeService.svc/SuperEmployee(12)

image

Ok – that is cool… but let’s do something more useful.  How about building an WinForms client from this service.    Notice this would work with WPF, Ajax or even any Java client! 

Add a new WinForms application then add a service reference. 

image

Oh, and Shawn Wildermuth, this Add Service Reference is for you!  We talked about it at Mix and now here it is in the bits!  Enjoy. 

Now we add a little form..

image

And some simple code behind… We set up the proxy to Astoria..

SuperEmployeeDomainService context; 
public Form1()
{
    InitializeComponent();
 
    context = new SuperEmployeeDomainService(
        new Uri("http://localhost:52878/SuperEmployeeService.svc/"));
    context.MergeOption = MergeOption.AppendOnly;
}

Now we can just load the data…

private void loadButton_Click(object sender, EventArgs e){
 
    var savedCursor = Cursor.Current;
    Cursor.Current = Cursors.WaitCursor;
    var q = from emp in context.SuperEmployee
            where emp.Issues > 10
            orderby emp.Name
            select emp;
 
 
    dataGridView1.DataSource = q.ToList();
    dataGridView1.CellEndEdit += dataGridView1_CellEndEdit;
    Cursor.Current = savedCursor;
 
}
 
hit F5, press load and you get your data!  Again, through that same set of application logic. 
 
image
 
Now let’s add some code to update the server when data on the client changes..
 
void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    var row = dataGridView1.Rows[e.RowIndex].Cells;
    int empId = Convert.ToInt32(row["EmployeeId"].Value);
 
    var q = from emp in context.SuperEmployee
            where emp.EmployeeID ==empId 
            select emp;
    var employee = q.FirstOrDefault();
 
    employee.Gender = row["Gender"].Value as string;
    employee.Issues = Convert.ToInt32(row["Issues"].Value);
    employee.LastEdit = DateTime.Now;
    employee.Name = row["Name"].Value as string;
    employee.Origin = row["Origin"].Value as string;
    employee.Publishers = row["Publishers"].Value as string;
    employee.Sites = row["Sites"].Value as string;
 
    var savedCursor = Cursor.Current;
    Cursor.Current = Cursors.WaitCursor;
    context.UpdateObject(employee);
    context.SaveChanges();
    Cursor.Current = savedCursor;
}

Here we just handle the event when the cell is done being edited..  Then we find employee that is object that corresponds to this row and update its values. 

Again, this same pattern would work for any client that works with Astoria today..