tom beeby blogs

July 7, 2009

UserState & knowing when you’re done in .NET RIA Services

Filed under: Development — Tags: , — tombeeby @ 10:46 am

UPDATE: I bumped into Nikhil Kothari on Twitter and he mentioned that the eventing model for DomainContext is changing in the July CTP (going to become a lot more intuitive when dealing with multiple concurrent calls)…

The more time I spend working with .NET RIA services, the more I like it. That said, it’s not without it’s frustrations. Today I spent a good part of the afternoon writing some Silverlight test cases and found myself repeating a stack of awkward, ugly code.

Most of the example code I’ve seen around the web is pretty simplistic and doesn’t deal with DomainContext classes that make multiple calls (submits and loads). I’m sure this will change as ria services mature, but at the moment rich examples are hard to come by.

The issue I was having was tracking which call was returning in two of the main events that a DomainContext raises: Loaded and Submitted. These  events are useful in the sense that they tell you when your call has completed, but if you’ve made multiple calls simultaneously then it’s not easy to tell which call is the one that has raised the event. For instance, when the Loaded event is raised, the LoadedDataEventArgs gives you access to a LoadedEntities property which holds the collection of newly loaded entities. You could then check the type of the first entity in order to see which load call has completed, but this is not a great solution as a call may have returned null (i.e. zero results)

Enter UserState. I actually couldn’t find much documentation on this one, but in a nutshell, it is a parameter of type object that you can pass into load and submit methods of your DomainContext and get back in the LoadedDataEventArgs and SubmittedChangesEventArgs.

On the most simple level you could call a method, say, LoadById() and pass in an int, say 1. When the Loaded event is raised after the call, you get back the LoadedDataEventArgs which now carries a property called UserState which is an int with a value of 1. Nice!

After reading around a bit on the Silverlight forums, I decided on the following approach to streamline things further.

Firstly, I created a delegate in the presenter of my view.

private delegate void CompletedDelegate(EventArgs args);

Secondly, I hooked up a reusable method to the Loaded and Submitted events of my DomainContext. The idea is to take the events’ EventArgs and have a look if they have a UserState property that is the delegate type we are after. Here’s the method:

private void contextEventHandler(EventArgs args)
{
    if (args is LoadedDataEventArgs)
    {
        if (((LoadedDataEventArgs)args).UserState is CompletedDelegate)
        {
            ((CompletedDelegate)((LoadedDataEventArgs)args).UserState).Invoke(args);
        }
    }
    else if (args is SubmittedChangesEventArgs)
    {
        if (((SubmittedChangesEventArgs)args).UserState is CompletedDelegate)
        {
            ((CompletedDelegate)((SubmittedChangesEventArgs)args).UserState).Invoke(args);
        }
    }
}

And here’s the constructor of the presenter where I hooked up the method and handled events generated by the view:

public HomePagePresenter(HomePage view)
{
    this.view = view;

    catCtxt = new CategoryDomainContext();
    catCtxt.Loaded += (s, e) => contextEventHandler(e);
    catCtxt.Submitted += (s, e) => contextEventHandler(e);

    view.Click += (s, e) =>
        {
            if ((s as Button).Tag.ToString() == "Save")
            {
                catCtxt.SubmitChanges(new CompletedDelegate(dataSubmitted));
            }
            else if ((s as Button).Tag.ToString() == "Reject")
            {
                catCtxt.RejectChanges();
            }
        };

    loadData();
}

The key part of the above is catCtxt.SubmitChanges(new CompletedDelegate(dataSubmitted)); which sets the UserState as the delegate. Now, when the call to submit completes, the method dataSubmitted will be called. Here is that method:

private void dataSubmitted(EventArgs e)
{
    SubmittedChangesEventArgs args = e as SubmittedChangesEventArgs;
    if (args.Error != null)
    {
        HtmlPage.Window.Alert(args.Error.Message);
    }
    else
    {
        HtmlPage.Window.Alert("Data submission complete");
    }
}

Finally, it’s worth taking a look at the loadData() method which again passes in a delegate as UserState:

private void loadData()
{
    catCtxt.LoadCategories(null, new CompletedDelegate(dataLoaded));
}

And the dataLoaded method:

private void dataLoaded(EventArgs e)
{
    notifyChange("Categories");
}

And to road off the code bits, here’s the simplistic DomainService class I used in the example:

[EnableClientAccess()]
public class CategoryDomainService : DomainService
{
    public IQueryable<Category> GetCategories()
    {
        return CategoryHelper.GetCategories().AsQueryable();
    }

    public void InsertCategory(Category cat)
    {
    }

    public void UpdateCategory(Category newCat, Category originalCat)
    {
    }

    public void DeleteCategory(Category cat)
    {
    }
}

All in all I was pretty happy with this technique. It seemed to make ria services a little more WCF-like to me, while still retaining all the major benefits of ria services. The code is still pretty rough, but hey – all my test cases are now passing and the code is a lot more readable than it was. Happy days!

NOTE: It’s probably worth pointing out that the July CTP of ria services may well render this example obsolete when it comes out. soon i hope!!!

June 30, 2009

Building a .NET RIA service project as a Silverlight class library

Filed under: Development — Tags: , — tombeeby @ 10:44 am

I’ve spent a lot of time over the past few days playing with the new .NET RIA services which can be installed alongside Silverlight 3. RIA services are great, and one thing I’m really liking is how much old code I’ll be able to throw away (like stacks of custom WCF wrappers on the Silverlight side to manage async state and batching multiple service requests).

The original pressure for my team to adopt RIA services was mainly driven by the nice end-to-end data validation framework that it ships with. We started rolling our own and it quickly became clear how much work it was going to take, and – let’s be fair – nobody likes writing that sort of code. If you haven’t checked it out already, a good place to start is over at Brad Abrams’ blog.

A key goal of RIA services is to simplify n-tier architectures, and it does this by creating a link between a ASP.NET web application project and a Silverlight application project and generating a lot of code that is magically shared between the two. I won’t go into this in any detail, because it’s not the point of this post.

One of the big issues I hit first up is this: once you install the RIA services pack, you are given the ability to link a ASP.NET web application project with a Silverlight application, but not a Silverlight class library. My particular usage scenario means I need to share a service DLL  amongst a bunch of XAPs (i.e. modules of a Prism solution) , so it’s no good for me to have a direct link between the RIA services web app and a Silverlight app (e.g. the Prism shell). I need a library I can share between all my modules.

When you create a new web application project, you get the following option:

1

Alternatively, you can go into the properties of a Silverlight application and link the server project there:

2

But strangely enough, these options don’t exist when you are dealing with a Silverlight class library.

The work around is this: create you ASP.NET web application and then create your Silverlight class library. The two aren’t linked yet. Exit visual studio and open the .csproj file of the class library project. You want to add the following:

<PropertyGroup>
	....
	<LinkedServerProject>..\SilverlightApplication1.Web\SilverlightApplication1.Web.csproj</LinkedServerProject>
	...
</PropertyGroup>

Just make sure the path points to your web application project.

Now when you re-open visual studio and build your web application project (assuming it has some domain service classes in it) you’ll see the generated code in your Silverlight class library.

I should probably note that this will all probably change by the time the July CTP comes out (Brad Abrams implied as much in a twitter response to my question).

Theme: Shocking Blue Green. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.