This article is Part 2 of the series Silverlight Applications with Telerik OpenAccess ORM

  • WCF RIA Applications with Telerik OpenAccess ORM Part I: The Basics
  • WCF RIA Applications with Telerik OpenAccess ORM Part II: Create, Update, Delete and Validation
  • Introducing Telerik OpenAccess Data Service Wizard
  • WCF Data Services with Telerik OpenAccess ORM
  • WCF End Points Services with Telerik OpenAccess ORM
  • Silverlight Applications for Windows Azure with Telerik OpenAccess ORM Part I: Connection to SQL Azure
  • Silverlight Applications for Windows Azure with Telerik OpenAccess ORM Part II: Developing the Silverlight Client and Deploying the Application

Go Back at the Beginning

In Part 1, we introduced the basics of WCF RIA Services with Telerik OpenAccess ORM and walked you through the “Hello World” equivalent. Let’s go back to the point when you create a new Domain Service:

  • In the Solution Explorer, right-click the server project, select Add, and then select New Item. The Add New Item dialog box appears.
  • In the list of categories, select Data and then select the Telerik OpenAccess Domain Model item. 

This is the Telerik OpenAccess Domain Service template. It helps you to create Telerik OpenAccess Domain Service class for WCF RIA Services applications. Once you select the template and click add,  you will be presented with a dialog that lets you select a number of options for your service, including the most important option - what domain model it will expose.

 

First, you should specify a Domain service class name. This is the name of your service.  The Enable client access option must be checked. It will add the EnableClientAccessAttribute attribute to your domain service class to indicate that it is visible to the client tier. In the Available DataContext classes drop-down, you should choose among the Telerik OpenAccess Domain Models in your project. Finally Enable all entities that you want to be exposed by the domain service. The Enable Edit option specifies whether the entity will be read-only or not. Once you click OK, your domain service will be created and added to the server project.

Create, Update and Delete Operations

Basically, in order to perform CUD operations, your domain service class should expose methods for insert, update, and delete. If you use the Telerik OpenAccess Domain Service template, then those methods will be added automatically. However, if you create a domain service by hand, like it is described in Part 1 of the series, then you have to add those methods manually.

[EnableClientAccess()]
public class NorthwindDomainService
    : OpenAccessDomainService<NorthwindDbContext>
{
    public NorthwindDomainService() : base()
    {
    }
  
    public IQueryable<Customer> GetCustomers()
    {
        return this.DataContext.Customers;
    }     
  
    public void DeleteCustomers(Customer customer)
    {
        // This is a callback method.
        // The actual Delete is performed internally.
    }
  
    public void UpdateCustomers(Customer customer)
    {
        // This is a callback method.
        // The actual Update is performed internally.
    }
  
    public void InsertCustomers(Customer customer)
    {
        // This is a callback method.
        // The actual Insert is performed internally.
    }
}

In order to create a user interface for create, update and delete operations:

  • In the client project, open MainPage.xaml.
  • Add three Buttons controls – for Save, Add and Delete.
  • The following XAML shows a complete layout along with the existing DataGrid (from the previous part).
<UserControl x:Class="NorthwindWcfRia.MainPage"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
    <Grid x:Name="LayoutRoot"
          Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal"
                    Margin="0,3">
            <Button x:Name="btnSave"
                    Content="Save"
                    Click="btnSave_Click" />
            <Button x:Name="btnAdd"
                    Content="Add"
                    Margin="7,0"
                    Click="btnAdd_Click" />
            <Button x:Name="btnDelete"
                    Content="Delete"
                    Click="btnDelete_Click" />
        </StackPanel>
        <data:DataGrid Name="CustomerGrid"
                       Grid.Row="1" />
    </Grid>
</UserControl>

 

  • In the code-behind page for MainPage.xaml, add event handlers for the click event of the buttons.

using System.ServiceModel.DomainServices.Client;
using System.Windows;
using System.Windows.Controls;
using NorthwindWcfRia.Web;
  
namespace NorthwindWcfRia
{
    public partial class MainPage : UserControl
    {
        private NorthwindDomainContext dbContext = new NorthwindDomainContext();
        public MainPage()
        {
            InitializeComponent();
            LoadOperation<Customer> loadOperation = dbContext.Load(
                dbContext.GetCustomersQuery());
            loadOperation.Completed += (s, a) =>
            {
                CustomerGrid.ItemsSource = dbContext.Customers;
            };
        }
        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
        }
        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
        }
        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
        }
    }
}
  • Note, that in the MainPage constructor all Customers are loaded async and set as ItemsSource for the DataGrid.
  • Add the following code in the btnSave_Click event handler. Its purpose is to submit changes to the DomainService, if such changes exist.
private void btnSave_Click(object sender, RoutedEventArgs e)
{
    if (this.dbContext.HasChanges == false)
        return;
    dbContext.SubmitChanges();
}
  • In the btnDelete_Click handler add code for retrieving the currently selected Customer and deleting it.

private void btnDelete_Click(object sender, RoutedEventArgs e)
{
    if (this.CustomerGrid.SelectedItem == null)
        return;
    Customer customerToDelete = this.CustomerGrid.SelectedItem as Customer;
    this.dbContext.Customers.Remove(customerToDelete);
}

  • In the btnAdd_Click event handler a new customer object is created, initialized and passed to the DomainService.
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
    Customer newCustomer = new Customer();
    newCustomer.CustomerID = "ABCDE";
    newCustomer.CompanyName = "MyCompany";
    newCustomer.City = "MyCity";
    newCustomer.ContactName = "MyContactName";
    dbContext.Customers.Add(newCustomer);
}

 

Now you are ready to create, update and delete customers, and use the DomainContext class to submit changes back to the server.

Validation

You can add validation attributes to properties and persistent classes to enforce validation. WCF RIA Services provide several built-in validation attributes that perform common validation checks, and provide the CustomValidationAttribute attribute so you can specify custom validation checks. The default validation attributes in WCF RIA Services are:

  • DateTypeAttribute
  • RangeAtribute
  • RegularExpressionAttribute
  • RequireAttribute
  • StringLengthAttribute

You add the validation attributes to persistent classes in the server project and those validation attributes are propagated to their generated client entity representations. At run time, the validation rules are applied to data from the user. You must add metadata classes to add validation attributes. Note that, when developing a Silverlight application with WCF RIA Services and Telerik OpenAccess ORM, Domain Services automatically generate validation rules by using database attributes such as required fields or maximum string length.

To add a validation attribute, you need to perform the following steps:

  • Add a metadata class for the persistent class. You can find information on how to do that in the distributed Telerik OpenAccess ORM help or in msdn.

On the properties or the persistent class that you want to validate, add the validation attributes that perform validation. The following example shows the RequiredAttribute, RegularExpressionAttribute and StringLengthAttribute attributes applied to the Customer properties.

[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
    internal sealed class CustomerMetadata
    {
        public CustomerMetadata()
        {
        }
        public int CustomerID
        {
            get;
            set;
        }
        [Required]
        [StringLength(10)]
        public string DrvLicNumber
        {
            get;
            set;
        }
        [StringLength(50)]
        public string FullName
        {
            get;
            set;
        }
        [RegularExpression("abc")]
        public string Address
        {
            get;
            set;
        }
        // ....
    }
}

  • In the Silverlight application, open the generated code file in the Generated_Code folder, and notice the validation attributes that are applied in the client code.

However, sometimes the standard validation attributes don’t offer enough flexibility. In these scenarios you need to use the CustomValidation attribute as it is shown in the instructions below:

  • Again you need to create a metadata class for the persistent class.
  • Add a shared code file by using the *.shared.cs naming pattern. The code file will contain the custom validation logic.
  • Add a new method that determines whether the data is valid. The method must have the following characteristics:
    • It must be public and static.
    • It must return a ValidationResult to indicate the result of the validation check.

The following example shows a class called CustomerValidator with a method named IsCustomerValid that validates a Customer object. When the data is not valid you should return the error message and the name of the property that failed the validation.

using System.ComponentModel.DataAnnotations;
  
namespace OA.SL4.RIA.Demo.Web
{
    public class CustomerValidator
    {
        public static ValidationResult IsCustomerValid( 
            Customer customerToValidate, ValidationContext context)
        {
            if (customerToValidate.ZIPCode.EndsWith("Net") == false)
                return new ValidationResult(
                    "ZipCode must end with 'Net'"
                    new string[] { "ZipCode" } );
            else
                return ValidationResult.Success;
        }
    }
}

On the persistent class or property that you want to validate, add the CustomValidationAttribute attribute, passing the type of the validation object and the name of the method that performs the validation. 

[CustomValidation(typeof(CustomerValidator), "IsCustomerValid")]
[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
    internal sealed class CustomerMetadata
    {
        public CustomerMetadata()
        {
        }
    }
}

Final Words

In Part1 and Part2 of the series, we introduced the basics of WCF RIA Services. In the next article, the Telerik Data Service Wizard will be introduced, so stay tuned.

 


Comments

Comments are disabled in preview mode.