Jun
1
2010

WCF RIA Services Speculation: EntityCollectionView

Disclaimer:
I am not a Microsoft employee, I have not even played a Microsoft employee on television. What follows is my own ideas on a what part of a future version of WCF RIA Services could look like.

What we know


As of this writing, MVVM friendly DomainDataSource is the fifth most requested feature for the next version of WCF RIA Services. According to Jeff Handley, this is what he envisions for this feature:

    What I have been imagining is taking the existing DomainDataSource feature and splitting it up into a set of components that can be used selectively from a ViewModel, or used all together as the DomainDataSource control that you know.
    The PagedEntityCollectionView class would likely become public, as well as the EntityCollectionView. I'd also like to break the data loading functions out so that the logic used to submit the requests for loads and the response handling could be utilized from a ViewModel. The DomainDataSource manages situations such as hierarchical data and there's a lot of code involved to replicate that in a ViewModel--I'd love to see those functions exposed for easy consumption without using the DomainDataSource control in the UI.
    So I really see this item as a way to get the features of the DomainDataSource out of the DomainDataSource, and available to developers to use how they wish."

Why this matters

Over the last two posts, I have been discussing ways that a ViewModel could present collection of Entities to the View. Of the options I presented only the PagedCollectionView is acceptable to me in the short term but in the long term there clearly has to be a better way. The other option which I hadn't previously mentioned is to build something new from scratch, an option that I have contemplated myself. The reason that I haven't is that I do not like duplicating logic that already exists and the fact that the PagedCollectionView and the EntityCollectionView already exist make me unlikely to want to write my own ICollectionView from scratch. To me, the best solution is to get the public EntityCollectionView that some of us have been talking about for a year now.

EntityCollectionView? What is that?


Outside of a few old blog entries from Jeff and Brad you probably haven't heard of the EntityCollectionView. The EntityCollectionView is everything that the PagedCollectionView isn't. It is strongly typed, it supports the Entity, it supports IEditableCollectionView against an EntitySet, it supports external delegates to implement adds, removes, and deletes, and finally there is a PagedEntityCollectionView that adds RIA Services integrated paging support. Unfortunately, the current EntityCollectionView is internal and can only be used by the DomainDataSource. It will take lots of time to properly refactor the DDS and get all of the interfaces fully implemented, time that simply didn't exist for the initial release of RIA Services. Anyone who has been following the development of RIA Services knows the DomainDataSource was probably the most actively modified component of RIA Services right up to the end. They would also know that the DomainDataSource also the most monolithic parts of RIA Services.
What we can gather from Jeff's above statement is that he wants to refactor the DomainDataSource to better match the rest of RIA Services itself. That means being more modular and being more programmer driven. For the rest of this post, I am going to discuss some scenarios that I think should be covered by the new classes:

EntityQuery support


In the previous post I had a link to an overview of the ICollectionView. One of the issues with most implementations of ICollectionView is that sorting is slow due to reflection issues. Another issue that is specific to RIA Services is that for loading data we have the EntityQuery but for the ICollectionView we have the Filter and the SortDescriptions. Having two different methods of doing the same thing would be annoying. What would be better is the ability to supply the EntityQuery to the EntityCollectionView. This would allow the same EntityQuery to be used for the load and the filter.
The unknown here is if the ICollectionView.Filter and ICollectionView.SortDescriptions should still be implemented or not. The SortDescriptions could probably be derived from the EntityQuery (and the reverse) but the Filter is tricky.

Read Only Mode and user providable methods for insert and delete

The ViewModel needs to be the owner of the EntityCollectionView and control of insert, deleting, and paging. In many cases, the EntityCollectionView can be left to default functionality but in others the ViewModel needs to provide the actual logic. A good example of this would be to look at how the EntityCollection is implemented in your generated code. That shows an example of how add and delete logic can be externally supplied.
Unfortunately, this does mean that the constructor for the EntityCollectionView may end up being rather complex. It is possible that some kind of "controller" object may be needed that can be supplied during construction and held onto by the ViewModel.

Strongly Typed


One of the biggest problems with the PagedCollectionView is that it is not strongly typed. The problem here is that there may be other logic within the ViewModel that wants to use the same CollectionView that the View itself is seeing. Without strong typing, this requires lots of type casting which is, at best, annoying.

Paging


Yes, the need for paging is obvious, but it also important to keep in mind the type of paging that is needed. It is possible that in some situations that the paging is being done only against already loaded entities. Much like with the update and the delete, we need to be able to override the paging so that the ViewModel can override.

Conclusion


This has been an interested three part series for me as it helped clarify some ideas that I have had for awhile. For this post in particular, if you have any scenarios that you think the EntityCollectionView needs to cover please let me know and I will see if I can modify the post to account for it.

May
29
2010

Advanced Paged Collection View

In the previous post I showed some of the ways that collections of entities can be exposed from your ViewModel. The load examples I showed was relatively simple as it demonstrated a simple load with no ordering or filtering and there was only a single load. In a more realistic example where ordering or filtering is being used and the EntitySet cannot be cleared between loads then only the PagedCollectionView and ObservableCollection will work. In this post, I will show a more full example of how you can combine WCF RIA Services, ViewModel, and PagedCollectionView to fully support filtering, sorting, and multiple loads.

private PagedCollectionView _customers; 
public PagedCollectionView Customers
{ 
    get
    {
        if (_customers == null)
        {
            _customers = new PagedCollectionView(Context.Customers);
            _customers.SortDescriptions.Add(new SortDescription("Name", ListSortDescription.Ascending));

         }
        return _customers;
    }
}

public void LoadCustomersByState(string state)
{
    var qry = this.Context.GetCustomersQuery().Where(c=>c.State == State).OrderBy(c=>c.Name);
    LoadOperation loadOp = this._customerContext.Load(qry);
    Customers.Filter = c=>((Customer)c).State == state;
}

When the PagedCollectionView was created, a SortDescription was set, this ensures that the PagedCollectionView will always be correctly sorted. The load is not clearing the EntitySet so it is possible for customers from multiple states to be loaded at the same time but the filter on the PagedCollectionView makes sure that only the currently selected state’s customers is being shown.

It is possible to get the same effect using the ObservableCollection but it requires refilling the ObservableCollection every time an entity is updated or inserted into the EntitySet which can cause problems for the bound UI controls.

 

The above example shows how to keep the load in sync with the PagedCollectionView, here is a second scenario where the load is separated from what is being shown in the UI:

private PagedCollectionView _customers; 
public PagedCollectionView Customers
{ 
    get
    {
        if (_customers == null)
        {
            _customers = new PagedCollectionView(Context.Customers);
            _customers.SortDescriptions.Add(new SortDescription("Name", ListSortDescription.Ascending));
            _customers.Filter = c=> (string.IsNullEmpty(SelectedState) || ((Customer)c).State == SelectedState);
         }
        return _customers;
    }
}

private string _selectedState = null;
public string SelectedState
{
    get {return _selectedState;}
    set
    {
        _selectedState = value;
        Customers.Refresh(); //this lets the PCV know that the filter changed
        RaisePropertyChanged(“SelectedState”);
    }

public void LoadCustomers()
{
    var qry = this.Context.GetCustomersQuery().OrderBy(c=>c.Name);
    LoadOperation loadOp = this._customerContext.Load(qry);
}

 

Wrap Up

The most important thing that the PagedCollectionView gains you is a clear separation of concerns within the ViewModel. Any business logic code adding, deleting, or updating entities does need to worry about updating the UI, that is taken care of by the PagedCollectionView which is monitoring the EntitySet itself for those changes. The only thing that the PagedCollectionView cannot detect for itself is when the any external values used in the Filter are modified so you do need to keep track of that and call the Refresh method whenever that happens. Other then that, in the ViewModels that the above code would be a part of no other reference to the PagedCollectionView properties would be necessary. The same can not be said for any of the other options that are available. In the last part of this series I will be discussing what is coming in the future.

May
29
2010

View Model Collection Properties for WCF RIA Services

For the most part combining WCF RIA Services with the MVVM pattern is easy. One area of difficulty is in exposing collections of entities from the ViewModel. This post is going to show some of the current possibilities including my favorite solution, the PagedCollectionView. In two follow up posts I will be discussing some more advanced PagedCollectionView examples and then some future possibilities.

Using LoadOperation.Entities

private IEnumerable<Customer> _customers; 
public IEnumerable<Customer> Customers
{ 
    get {return _customers;}
    private set
    {
        _customers = Customers;
        RaisePropertyChanged("Customers");
    }
}

public void LoadCustomers()
{
    LoadOperation loadOp = this.Context.Load(Context.GetCustomersQuery());
    Customers = loadOp.Entities;
}

Pros

  • Simple, easy to understand.
  • Matches example code from RIA Services documentation.

Cons

  • LoadOperation.Entities is read only, so this is only suitable for read only applications.

Using EntitySet

public IEnumerable<Customer> Customers
{ 
    get {return Context.Customers;}
}

Pros

  • Simple
  • EntitySet does implement INotifyCollectionChanged so as it is updated the UI will be automatically refreshed.

Cons

  • Exposing the EntitySet to the view, even hidden behind IEnumerable, gives the view too much access.
  • Binding to the EntitySet means that there is no ability to filter, everything in the EntitySet will be bound to the UI.
  • The built in add/remove abilities of the DataGrid and DataForm do not support the EntitySet

Using ObservableCollection

private ObservableCollection<Customer> _customers; 
public ObservableCollection<Customer> Customers
{ 
    get {return _customers;}
    private set
    {
        _customers = Customers;
        RaisePropertyChanged("Customers");
    }
}

public void LoadCustomers()
{
    this.Context.Load(Context.GetCustomersQuery(), LoadCustomersCompleted, null);
}

private void LoadCustomersCompleted(LoadOperation<Customer> lo)
{
    Customers = new ObservableCollection<Order>(Context.Customers);
}

Pros

  • ObservableCollection is not read only so this code is not limited to read only applications.
  • ObservableCollection does implement INotifyCollectionChanged so as it is updated the UI will be automatically refreshed.

Cons

  • Every insert, delete, clear, detach, attach, and load within the ViewModel has to manually keep the ObservableCollection in synch. This makes it easy to get into situations where the ObservableCollection gets out of synch with the DomainContext. The worst case scenario here is that a deleted entity gets re-added as a new entity accidently because it hadn’t been removed from the ObservableCollection.
  • ObservableCollection implements IList. This means that the built in add and remove for both the DataGrid and DataForm will be enabled even though any entities added or removed directly to the ObservableCollection will not be added or removed from the EntitySet.

Using an ICollectionView

What is ICollectionView?

Marlon Grech has a good primer on the ICollectionView, I suggest you go and read his entry on them and then come back.

Have a good read? Great, so now you know what ICollectionView does. Unfortunately, the classes demonstrated by Marlon are marked as internal in Silverlight so we can’t use them. Fortunately, we did get a consolation prize back in Silverlight 3: PagedCollectionView.

Using PagedCollectionView (PCV)

private PagedCollectionView _customers; 
public PagedCollectionView Customers
{ 
    get
    {
        if (_customers == null)
            _customers = new PagedCollectionView(Context.Customers);
        return _customers;
    }
}

public void LoadCustomers()
{
    LoadOperation loadOp = this.Context.Load(Context.GetCustomersQuery());
}

Pros

  • PCV automatically refreshes based on the contents of the EntitySet.
  • PCV has full sorting and filtering ability. This will be demonstrated in the second post of this series.

Cons

  • The PCV’s implementations of IEditableCollectionView and IPagedCollectionView are not compatible with the EntitySet. However, the incompatibility is reported by the PCV so the built in add/remove abilities of the DataForm and DataGrid are properly disabled.
  • The PCV is not strongly typed limiting its usefulness inside the ViewModel.
  • ICollectionView includes a “CurrentItem” property which is used by bound list controls. For example, if two comboboxes are sharing the same PagedCollectionView for the ItemsSource then changing the selection in one combobox will cause the selection to change in the second combobox as well.

Conclusion

None of the above options are perfect, but the PagedCollectionView is certainly the best option that we currently have. In my next post I will be discussing the PagedCollectionView in more depth and in the third post I will be discussing what the optimal solution would be.

Jan
5
2010

Proposed WCF RIA Services Sessions for MIX10

Earlier today Microsoft opened voting for the MIX10 Open Call entries. I am happy to see that at least eleven of the submissions mention WCF RIA Services. Even if you are not attending MIX10 it is still important that everyone posts as the sessions will be available on the web along with the rest of the MIX10 sessions.

You can see all of the submissions here.

Real World Silverlight Line of Business ApplicationsMix10_Vote_grn_240

I do have my own horse in this race, and it is the session I have linked above. The application I will be showing is actually rather important from a historical perspective as it is the application I have been writing for the last year. If you have been helped by any of my blog entries, answers on the forums or tweets then this is the application you have to thank. The total list of technologies that I used (and in some cases changed) are:

  1. Silverlight 2 –> 3
  2. Data Services –> .Net RIA Services –> WCF RIA Services
  3. Enitty Framework
  4. Deep Earth –> Bing Silverlight Map Control –> ESRI Silverlight API
  5. XAML Power Tools (thanks Karl!)
  6. Prism
  7. SandDock/SandRibbon –> Telerik Controls
  8. SQL Server 2005/2008
  9. Visual Studio 2008
  10. ArcGIS Server

As you can see, I have a pretty large stack of stuff that I have used so I will not be able to cover all of it in depth. If my session is selected I will be open to suggestions on what pieces I cover more than other pieces.

Jan
2
2010

Alternate URLs for this blog

I had someone a few days ago who couldn't bring up RiaServicesBlog.Net for some strange reason but one of the other URLs worked. There are currently three different URLs that point to this blog:

www.riaservicesblog.net

www.riaservicesblog.com

www.colinblair.com

All three should work although I prefer to use the www.riaservicesblog.net address for public linking. The "official" url as far as my host is concerned is the colinblair.com one so if you are having trouble then that is the one most likely to work.

Dec
29
2009

Fredrik Normén: WCF RIA Services DomainService life-cycle and adding Transactions

Fredrik Normén just posted up an extremely good blog post on the lifecycle of the DomainService during a Submit operation. Since I had the same subject on my todo list, I am going to cross it off by telling you to go read what Fredrik posted.

WCF RIA Services DomainService life-cycle and adding Transactions

 

Dec
24
2009

Thoughts on Modular WCF RIA Services

 

I had an interesting question tweeted to me yesterday from Ariel Ben Horesh requesting my opinion on sharing data models between Prism modules using WCF RIA Services. My opinion is that there is a 1:1 relationship between an editable DomainService/DomainContext and a module. My reasoning is that both a module and a DomainContext are a single unit of work. I would further suggest that is you have a module that requires two separate editable DomainContexts that you actually have two separate modules.

Notice that I keep saying “editable DomainContexts”. If you have a DomainContext which has only read only entities then I see no problem with putting that DomainContext in a shared library referenced by multiple modules. You can even put in ExternalReferences from your modules DomainContext to the shared DomainContext if you really want. I usually discourage the use of ExternalReference as I feel that people misuse the functionality to attach two editable DomainContexts to each other but I don’t see a problem with a non-editable DomainContext.

Ariel then asked how events/commands could be used between the modules using entity data when the modules are not sharing data and, after I gave my answers, asked for some examples. In response, I created this Sample Project which creates several pseudo-modules. It is not using MEF or Prism to create actual modules, just standard WCF RIA Services Class Libraries which are representing modules.

One module, ParentModule, has a model which contains only the Parent entity. ParentModule represents the primary module of an application, the one that works with the “root” table of a database. The Parent entity has a related Child entity which has a ChildTypeID. The other two modules (ChildHeightModule and ChildWidthModule) represent modules that modify only one type of Child entity. One of the Child modules has the Parent entity in its model and the other does not.

Communicating by Key

The primary way of communicating between modules is to pass primary keys. For example, if the application has a Parent entity and wants the Child modules to load the Child entities of that Parent then it simply needs to pass the ParentID to the two child modules which can then easily load data based on the ParentID.

Communicating by Interface

Sometimes just passing keys around isn’t good enough and you need access to entire entities between different modules. The solution to that is to implement shared interfaces on your entities. If you check my sample project you will find that I implement several interfaces using generics. Using the shared entities I could pass an entire Parent entity from the ParentModule to either of the Child modules as an IParent. The limitation of the interface versions of the entities is that they cannot interact with the local module’s DomainContext (i.e. you can’t set the Parent property of the Child to the IParent entity).

I use this technique extensively and it really helps when created shared code to do operations on the different entities. For example, both the ChildWidth and ChildHeight entities implement the IChildDimension interface. If I wanted to create an IValueConverter that operated on objects that implement IChildDimension that is a really easy thing to do. I could also pretty easily have a module that gets sent all  of the IChildDimension entities from all currently loaded modules and displays them all in a grid.

Communicating by Cloning

The third option is to use the WCF RIA Services Contrib ApplyState/ExtractState extensions to clone the entity between the DomainContexts of two different modules. Both ParentModule and ChildWidthModule have the Parent entity. They are different types in different namespaces but they both have the same DataMember properties. This means that the IDictionary<string,object> extracted from Parent in the ParentModule can be applied to a Parent entity in the ChildWidthModule. This is not recommended. Extracting the state from one module and applying it in another is inherently brittle and can create a maintenance nightmare. However, I am sure that someone will hit a situation where cloning is the only solution that works for them so I include it here for that person.

Dec
16
2009

RIA Services Enterprise Business Application: The Movie

A step by step guide was requested for how I created the Enterprise Business Application from my previous blog entry. The video is rushed as I was fitting it into lunch, I apologize in advance if it is too difficult to follow.

Part One: http://www.screencast.com/t/NGNiZjg3ZjY

Part Two: http://www.screencast.com/t/NGJkYTEw

Part Three: http://www.screencast.com/t/MWQ2MjdiYTct

Commentary: I made a mistake in Part One when editing the project file. In the second section that I paste in, where it says:

Include="..\EnterpriseTest.Web\resource\

the EnterpriseTest.Web needs to be changed to EnterpriseTest.AppServices.Web for both resource files.

In Part Three I was running out of time (I only get 5 minutes per video from Jing) so it gets disjointed at the end. Basically, just keep compiling, going thorugh the errors, and resolving the references. At the end you should have working application.

Timeline

I did not record any audio for the videos. If you can't figure out what I am doing let me know which the file and time code is and I will place a comment here explaining what is going on.

Dec
7
2009

RIA Services Enterprise Business Application Attempt Part One

A question that has come up a few times on the forums is how the Silverlight Business Application template can be modified to make it more enterprise friendly. This means moving the Authentication DomainService into a separate WCF RIA Services Class Library and removing the RIA Link from the main application. Attached is my first attempt at doing this. What I have done is create a new WCF RIA Services class library named AppServices. At this point, there is no change in any functionality and other then some namespace differences everything should work exactly like the original template did.

I have several additional changes that I am planning to make. My planned steps:

  1. Refactor the Business Application Template to use a class library (complete)
  2. Build in the MEF links from Brad's example here
  3. Convert the sample project into a Visual Studio template and add to RIA Services Contrib
  4. Prove the template my re-implementing Brad's PDC demo using the new template

EnterpriseBusinessApplication08.zip (2.11 mb) C# VS 2008 Version

BusinessApplicationTemplate.zip (2.19 mb) C# VS 2010 Version

The part I am most worried about is step 3, converting something this complex into a Visual Studio template is not something I have done before and I am not sure what the best method is to accomplish this. If anyone has any tips or blog urls that I should take a look at please let me know. Also, if you disagree with any design decisions I am making let me know. For example, I am not sure about the AppServices name I picked for the project. 

Thanks to Max Paulousky who wrote an article on CodeProject that solved a problem I was having with getting the WebContext to find the AuthenticationDomainContext.

Update: There is now a VS2008 version and I improved on Max's original fix by casting to WebAuthenticationService instead of FormsAuthentication so that the code no longer needs to be changed to switch to WindowsAuthentication. That change was made to both versions. Some people are having trouble with errors saying that a DLL isn't trusted. Brad has a blog entry explaining the problem

Dec
3
2009

Bug in the Create DomainService wizard

In a previous blog post I documented an undocumented breaking change in the DomainService wizard. It turns out that it is really a bug.

 

When you create a DomainService using the July .NET RIA Services you would get an update that looks like this:

public void UpdateMyEntity(MyEntity currentMyEntity)
{
    this.ObjectContext.AttachAsModified(currentMyEntity, this.ChangeSet.GetOriginal(currentMyEntity));
}

The new version gives you a version that looks like this:

public void UpdateMyEntity(MyEntity currentMyEntity)
{
    if ((currentMyEntity.EntityState == EntityState.Detached))
    {
        this.ObjectContext.AttachAsModified(currentMyEntity, this.ChangeSet.GetOriginal(currentMyEntity));
    }
} 

It turns out that the new version is a mistake, not a change that was undocumented in the breaking changes document, and it is causing major problems for people. The recommendation is that all Updates should be modified to remove the If check so that the resulting method looks like the original .NET RIA Services version.

Month List