DomainDataSource Extension Methods

by Alex Meyer-Gleaves 13 August 2009 - 1:48 AM

To add a new item or edit an existing item in the DomainDataSource that ships with the .NET RIA Services, you must first cast the DataView property to an IEditableCollectionView. Jeff Handley does a good job of explaining the reason for this in his DomainDataSource.DataView post.

David Yack left a comment on the .NET RIA Services forum with a link to his post where he shares his inherited DomainDataSource class. The inherited class adds methods for adding and editing items that do all the casting to IEditableCollectionView for you. I really liked the idea but didn’t want to create my own derived class, so I took his implementation and turned it into a set of extension methods that are exposed on all DomainDataSource instances.

Update (24-09-2009): Added a Remove extension method. Thanks to Phil Steel for posting the code in his comment.

/// <summary>
///    Extensions to the <see cref="DomainDataSource"/> for adding and editing items.
/// </summary>
public static class DomainDataSourceExtensions
{
    /// <summary>
    /// Adds a new item to the collection.
    /// </summary>
    /// <typeparam name="T">The type of the item to add.</typeparam>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    /// <returns>The newly added item.</returns>
    public static T AddNew<T>(this DomainDataSource source)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        return (T)collection.AddNew();
    }

    /// <summary>
    /// Edits an item in the collection.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    /// <param name="itemToEdit">The item to edit.</param>
    public static void EditItem(this DomainDataSource source, object itemToEdit)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        collection.EditItem(itemToEdit);
    }

    /// <summary>
    /// Removes an item from the collection.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    /// <param name="itemToRemove">The item to remove.</param>
    public static void Remove(this DomainDataSource source, object itemToRemove)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        collection.Remove(itemToRemove);
    }

    /// <summary>
    /// Commits the add or edit transaction.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    public static void CommitNewAndEdit(this DomainDataSource source)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        if (collection.IsAddingNew)
        {
            collection.CommitNew();
        }
        if (collection.IsEditingItem)
        {
            collection.CommitEdit();
        }
    }

    /// <summary>
    /// Cancels the add or edit transaction.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    public static void CancelNewAndEdit(this DomainDataSource source)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        if (collection.IsAddingNew)
        {
            collection.CancelNew();
        }
        if (collection.IsEditingItem)
        {
            collection.CancelEdit();
        }
    } 
}

Thanks for sharing the code David.

Tags: ,

Silverlight | Web Development

Controlling your Service method implementation in WSCF.blue

by Alex Meyer-Gleaves 8 August 2009 - 3:26 AM

I have added some new options to WSCF.blue that control how the methods in your service class are code generated. It was a post in the Discussions forum on our CodePlex site that prompted me to finally add the feature that I myself have wanted for some time now. The default service class code generated by WSCF.blue contains operation method implementations that throw a NotImplementedException. The issue with this approach is that you need to manually update the generated code to call another class that contains your actual service implementation, otherwise you will loose your implementation code during the regeneration process. You can now decide if you would like your service implementation to exist in a partial class or abstract class that can be defined in a separate file. These options can be found in the Service Method Implementation group in the Code Generation options dialog.

Options for Service Method Implementation

The first and default option is to generate method bodies that throw a NotImplementedException. Making this option the default keeps the behaviour consistent with previous builds of WSCF.blue. However, using this option will always result in your having to perform same manual modifications to the generated service class.

[System.ServiceModel.ServiceBehaviorAttribute()]
public class FooService : IFooService
{
    public virtual FooResponse Foo(FooRequest request)
    {
        throw new System.NotImplementedException();
    }
}

Selecting the partial class option will cause the generated service class to be marked as partial. It will also contain operation methods that call through to a partial method that can be defined in another partial class and in another file. This file must be created manually yourself, but once created it will remain untouched when you regenerate your service code.

[System.ServiceModel.ServiceBehaviorAttribute()]
public partial class FooService : IFooService
{
    public virtual FooResponse Foo(FooRequest request)
    {
        return FooImplementation(request);
    }
}

The naming convention for the partial method is the name of the operation method suffixed with Implementation. In the example above you can see the Foo operation method calls a FooImplementation method that is expected to be present in your partial class definition. You will receive a compiler error until you have defined your partial class containing the appropriate partial methods.

public partial class FooService
{
    protected FooResponse FooImplemenation(FooRequest request)
    {
        FooResponse response = new FooResponse();
        // Some web service processing code.
        return response;
    }
}

Your partial class definition should be created in a separate file to the service class that calls it. This will ensure you do not have to make any changes when regenerating your service code, which is obviously the very issue the option is designed to solve.

Because a partial class can be defined in a separate file, but must reside within the same project, an abstract class option was added that allows you to place your service implementation in another assembly. This option causes an abstract service class containing abstract operation methods to be code generated.

[System.ServiceModel.ServiceBehaviorAttribute()]
public abstract class FooService : IFooService
{
    public abstract FooResponse Foo(FooRequest request);
}

You can then inherit from the abstract service class and place your implementation in the overridden abstract methods. Similar to the partial class approach, this allows you to separate your implementation into another file that remains untouched when you regenerate your service code, but also allows for the implementation to be created in another assembly.

public class FooServiceImplemenation : FooService
{
    public override FooResponse Foo(FooRequest request)
    {
        FooResponse response = new FooResponse();
        // Some web service processing code.
        return response;
    }
}

Both the partial class and abstract class approaches are equally valid, and both result in the desired outcome of protecting your implementation code. The important points to remember are that when using the partial class option, your implementation class must have the same name as the code generated service class and must be defined in a file within the same project. When using the abstract class option, your implementation class cannot have the same name as the code generated service class but can be defined in a file that is not in the same project. Which you prefer to use entirely up to you and is probably a matter of taste for the most part.

I hope you find this feature useful, I know I certainly will. Please report any WSCF.blue bugs in the Issue Tracker and feel free to raise your suggestions in the Discussions forum.

Tags: ,

Web Services | WSCF

About the author

Alex Meyer-Gleaves I'm a Technical Architect living in Australia (that island like continent in the southern hemisphere). I love Microsoft .NET and C#. I hate early mornings, slow drivers and Lotus Notes.

Google Shared

 

Month List

Recent Posts

Recent Comments

Comment RSS

Links

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010