This article is Part 2 of the series Silverlight Applications with Telerik OpenAccess ORM
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:
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.
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:
<
UserControl
x:Class
=
"NorthwindWcfRia.MainPage"
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)
{
}
}
}
private
void
btnSave_Click(
object
sender, RoutedEventArgs e)
{
if
(
this
.dbContext.HasChanges ==
false
)
return
;
dbContext.SubmitChanges();
}
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);
}
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.
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:
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:
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.
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: 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. 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. [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
;
}
// ....
}
}
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;
}
}
}
[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.