WCF RIA Services

WCF RIA Services simplifies the development of n-tier solutions for Rich Internet Applications (RIA), such as Silverlight applications.

WCF RIA Services simplifies the development of n-tier solutions for Rich Internet Applications (RIA), such as Silverlight applications. A common problem when developing an n-tier RIA solution is coordinating application logic between the middle tier and the presentation tier. To create the best user experience, you want your RIA client to be aware of the application logic that resides on the server, but you do not want to develop and maintain the application logic on both the presentation tier and the middle tier. RIA Services solves this problem by providing framework of components, tools, and services that make the application logic on the server available to the RIA client without requiring you to manually duplicate that programming logic. You can create a RIA client that is aware of business rules and know that the client is automatically updated with the latest middle tier logic every time that the solution is re-compiled.
 
The following illustration shows a simplified version of an n-tier application. RIA Services focuses on the box between the presentation tier and the data access layer (DAL) to facilitate n-tier development with a RIA client.
 
n-tier RIA application  
 
RIA Services adds tools to Visual Studio that enable linking client and server projects in a single solution and generating code for the client project from the middle-tier code. The framework components support prescriptive patterns for writing application logic so that it can be reused on the presentation tier. Services for common scenarios, such as authentication and user settings management, are provided to reduce development time.

In RIA Services, you expose data from the server project to client project by adding domain services. The RIA Services framework implements each domain service as a Windows Communication Foundation (WCF) service. Therefore, you can apply the concepts you know from WCF services to domain services when customizing the configuration.
 
Let's create one Silverlight Business Application. Silverlight Business Application is template available if RIA Services is installed.
 
Silverlight Business Application 
 
Remember we have not checked the checkbox for "Enable .NET RIA Services", now we need to check it for enabling .NET RIA Services.
 
Enable .NET RIA Services 
 
The Business Application comes with the following solution structure, where we can find different folders for different functionalities.
 
solution structure 
 
Now we can take any one of the above described methods for Data Access such as LINQ to SQL Classes or ADO.NET Entity Data Model. Let's take an ADO.NET Entity Data Model as our Data Access method.
 
ADO.NET Entity Data Model 
 
After creating the model, let's see how we can add RIA functionality to Silverlight project.
 
Domain Service Class
 
Domain services are WCF services that expose the data access layer to the client project. When you create an instance of a domain service, you specify the entity classes that you want to expose and the data operations that are permitted through the domain service.
 
DomainService and Derived Classes
 
The DomainService class is the base class for all classes that serve as domain services. WCF RIA Services also provides the LinqToEntitiesDomainService<(Of <(<'TContext>)>)> class, which is an abstract class that derives from DomainService. The LinqToSqlDomainService<(Of <(<'TContext>)>)> class is available in the RIA Services Toolkit.
 
To create a domain service that binds to an ADO.NET Entity model, you create a class that derives from LinqToEntitiesDomainService<(Of <(<'TContext>)>)>. To create a domain service that binds to a custom data object, you create a class that derives from DomainService. When you use the Add New Domain Service Class dialog box to create a domain service, the correct type of domain service based on the entities you expose is automatically created.
 
A domain service class must be marked with the EnableClientAccessAttribute attribute to make the service available to the client project.
 
WCF and Domain Services
 
As a WCF service, the domain service builds upon WCF concepts. The domain service preserves the following:
  • Standard usage of WCF services.
  • Existing WCF programming models constructs, such as operation contracts, operation behaviors, and service behaviors.
  • Standard WCF customization capabilities, such as binding configuration, behavior configuration, and management infrastructure.
The domain context communicates with the domain service by using the WCF ChannelFactory to create a channel and passing to it a service contract that was generated from the domain service.
 
By default, only the Binary endpoint is enabled for domain services.
 
Let's add a Domain Service Class to the Web Project.
 
Domain Service 
 
After pressing Add button you would be notified to add entity to the Domain Service Class.
 
add entity to the Domain Service 
 
Remember if you are not getting any Entity Frameworks listed, then just press cancel and rebuild the Web Project. Follow the above steps again.

By Checking the checkboxes we are enabling Client Access and by Exposing OData endpoint to share data over the web. OData is an emerging set of extensions for the ATOM protocol. By checking the option the Domain Service would will be exposed as OData feed.
 
We can see that along with the EmployeeDomainService.cs we have another CS file auto generated.
 
CS file in WCF 
 
As the filename specifies metadata.cs, it consists of the Entity properties. The following listing shows the details of it.
  1. namespace RIASilverlight4Sample01.Web  
  2. {  
  3.     using System;  
  4.     using System.Collections.Generic;  
  5.     using System.ComponentModel;  
  6.     using System.ComponentModel.DataAnnotations;  
  7.     using System.Linq;  
  8.     using System.Web.DomainServices;  
  9.     using System.Web.Ria;  
  10.     using System.Web.Ria.Services;  
  11.   
  12.     // The MetadataTypeAttribute identifies EmployeeMetadata as the class  
  13.     // that carries additional metadata for the Employee class.  
  14.     [MetadataTypeAttribute(typeof(Employee.EmployeeMetadata))]  
  15.     public partial class Employee  
  16.     {  
  17.   
  18.         // This class allows you to attach custom attributes to properties  
  19.         // of the Employee class.  
  20.         //  
  21.         // For example, the following marks the Xyz property as a  
  22.         // required field and specifies the format for valid values:  
  23.         //    [Required]  
  24.         //    [RegularExpression("[A-Z][A-Za-z0-9]*")]  
  25.         //    [StringLength(32)]  
  26.         //    public string Xyz;  
  27.         internal sealed class EmployeeMetadata  
  28.         {  
  29.    
  30.             // Metadata classes are not meant to be instantiated.  
  31.             private EmployeeMetadata()  
  32.             {  
  33.             }  
  34.   
  35.             public string Contact;  
  36.   
  37.             public string EmailID;  
  38.   
  39.             public string FirstName;  
  40.   
  41.             public long ID;  
  42.   
  43.             public string LastName;  
  44.         }  
  45.     }  
  46. }  
As you see in the listing above, we have an internal sealed class that consists of the properties auto generated.
 
We can set attributes for specific properties for validation purposes; we will see this in later descriptions.
 
Now if you look at the EmployeeDomainService class it has all the CRUD operation methods auto generated. See following listing.
  1. namespace RIASilverlight4Sample01.Web  
  2. {  
  3.     using System;  
  4.     using System.Collections.Generic;  
  5.     using System.ComponentModel;  
  6.     using System.ComponentModel.DataAnnotations;  
  7.     using System.Data;  
  8.     using System.Linq;  
  9.     using System.Web.DomainServices;  
  10.     using System.Web.DomainServices.Providers;  
  11.     using System.Web.Ria;  
  12.     using System.Web.Ria.Services;  
  13.   
  14.     // Implements application logic using the EmployeeDBEntities context.  
  15.     // TODO: Add your application logic to these methods or in additional methods.  
  16.     // TODO: Wire up authentication (Windows/ASP.NET Forms) and uncomment the following to disable anonymous access  
  17.     // Also consider adding roles to restrict access as appropriate.  
  18.     // [RequiresAuthentication]  
  19.     [EnableClientAccess()]  
  20.     public class EmployeeDomainService : LinqToEntitiesDomainService<EmployeeDBEntities>  
  21.     {  
  22.   
  23.         // TODO: Consider  
  24.         // 1. Adding parameters to this method and constraining returned results, and/or  
  25.         // 2. Adding query methods taking different parameters.  
  26.   
  27.        [Query(IsDefault = true)]  
  28.         public IQueryable<Employee> GetEmployees()  
  29.         {  
  30.             return this.ObjectContext.Employees;  
  31.         }  
  32.   
  33.         public void InsertEmployee(Employee employee)  
  34.         {  
  35.             if ((employee.EntityState != EntityState.Added))  
  36.             {  
  37.                 if ((employee.EntityState != EntityState.Detached))  
  38.                 {  
  39.                     this.ObjectContext.ObjectStateManager.ChangeObjectState(employee, EntityState.Added);  
  40.                 }  
  41.                 else  
  42.                 {  
  43.                     this.ObjectContext.AddToEmployees(employee);  
  44.                 }  
  45.             }  
  46.         }  
  47.   
  48.         public void UpdateEmployee(Employee currentEmployee)  
  49.         {  
  50.             if ((currentEmployee.EntityState == EntityState.Detached))  
  51.             {  
  52.                 this.ObjectContext.AttachAsModified(currentEmployee, this.ChangeSet.GetOriginal(currentEmployee));  
  53.             }  
  54.         }  
  55.   
  56.         public void DeleteEmployee(Employee employee)  
  57.         {  
  58.             if ((employee.EntityState == EntityState.Detached))  
  59.             {  
  60.                 this.ObjectContext.Attach(employee);  
  61.             }  
  62.             this.ObjectContext.DeleteObject(employee);  
  63.         }  
  64.     }  
  65. }   
The listing above displays the methods that are auto generated, such as: GetEmployees(), InsertEmployee(), UpdateEmployee(), and DeleteEmployee().
 
The GetEmployees method displays all data available for the Employee entity. We can add some code to filter it, or we can even sort it.
  1. public IQueryable<Employee> GetEmployees()  
  2. {  
  3.     return this.ObjectContext.Employees.OrderBy(e => e.FirstName);  
  4. }  
Data Operations
 
You add methods to a domain service that perform the data operation you want to expose. For example, you can add methods that perform the following operations:
  • Query
  • Update
  • Insert
  • Delete
In addition, you can add the following more complicated operations:
  • Invoke - operations that need to be executed without tracking or deferred execution.
  • Named Update - custom operations that do not fall into simple modification operations.
Conventions
 
When you add methods to perform these operations, the method must match the expected signature for that operation. In addition to matching the signature, the method must include a name prefix that matches the naming convention for that data operation. If the name of the method does not start with the expected prefix, you must apply the corresponding attribute for that operation. The attribute is optional if the name of the operation matches the naming convention. Using the naming convention provides a more consistent experience for developers.
 
You cannot overload methods that are domain operations. You must specify a unique name for each method that can be called from the client project. All methods representing domain service operations must be public. The methods must use serializable types for parameters and return types.
 
You can prevent a method from being exposed by adding the IgnoreAttribute attribute to the method.
 
The data operation signatures are provided in the following tables.
 
Query
 
The query method in the domain context typically has the same name as the domain service query method plus a postfix of Query. For example, a GetEmployeesQuery method in the domain context is generated from a GetEmployees method in the domain service. The domain context query method returns an EntityQuery object that you can use to apply additional operations.
 
All queries from a domain context are executed asynchronously. To execute the query, you pass the EntityQuery object as a parameter in the Load method.
 
Return value
IEnumerable<T>,IQueryable<T>, or entity
Parameters
Any number
Name Prefix
Any name
Attribute
[Query] (C#)
Example
public IQueryable<Product> GetProducts() (C#)
 
Update
 
When the domain service includes methods for updating, inserting, and deleting entities, those methods are not generated in the domain context. Instead, you use the SubmitChanges method on the domain context and the proper operations on the domain service are called. No changes in the data source are made until you call SubmitChanges. You can cancel pending changes by calling the RejectChanges method.
 
The DomainContext class also provides the HasChanges and EntityContainer properties to enable you to evaluate pending changes. The EntityContainer object for a domain context tracks the pending changes. Pending changes does not include calls to invoke operations in the domain service because invoke operations are executed immediately when they are called. When you call SubmitChanges, all pending changes are sent to the domain service together.
 
Return value
None
Parameters
Entity
Name Prefix
Update, Change, or Modify
Attribute
[Update] (C#)
Example
public void UpdateProduct(Product product) (C#)
 
Insert
 
The expected signature values for an insert operation.
 
Return value
None
Parameters
Entity
Name Prefix
Insert, Add, or Create
Attribute
[Insert] (C#)
Example
public void InsertProduct(Product product) (C#)
 
Delete
 
The expected signature values for a delete operation.
 
Return value
None
Parameters
Entity
Name Prefix
Delete or Remove
Attribute
[Delete] (C#)
Example
public void DeleteProduct(Product product) (C#)
 
Invoke
 
The expected signature values for an invoke operation.
 
The domain context will contain a method for each service operation on the domain service. Unlike domain operations, service operations are executed immediately. You do not call the SubmitChanges method. Service operations are executed asynchronously. The service operation returns an InvokeOperation object. You retrieve the value of the Value property to get the returned value from the service operation.
 
Return value
Any
Parameters
Any
Name Prefix
Any
Attribute
[Invoke] (C#)
Example
[Invoke]
public decimal GetCompetitorsPrice(Product product) (C#)
 
Named Update
 
The expected signature values for a named update operation.
 
Parameters
Entity any number of other parameters
Name Prefix
Any name other than one starting with the prefixes for Insert, Update, or Delete
Attribute
[Update(UsingCustomMethod=true] (C#)
Example
[Update(UsingCustomMethod=true]
public void DiscountProduct(Product product, int percentage) (C#)
 
As you see in previous listing we have given an OrderBy method where all the Employees would be ordered by itsit"s FirstName property. By default Visual Studio makes read operation as the default query.
 
In InsertEmployee method you can see an Employee entity is being passed, and based on the EntityState the data would be inserted.
  1. public void InsertEmployee(Employee employee) {  
  2.  if ((employee.EntityState != EntityState.Added)) {  
  3.   if ((employee.EntityState != EntityState.Detached)) {  
  4.    this.ObjectContext.ObjectStateManager.ChangeObjectState(employee, EntityState.Added);  
  5.   } else {  
  6.    this.ObjectContext.AddToEmployees(employee);  
  7.   }  
  8.  }  
  9. }  
In UpdateEmployee method using ObjectContext's AttachAsModified method the particular Employee could can be updated.
  1. public void UpdateEmployee(Employee currentEmployee) {  
  2.  if ((currentEmployee.EntityState == EntityState.Detached)) {  
  3.   
  4.   this.ObjectContext.AttachAsModified(currentEmployee, this.ChangeSet.GetOriginal(currentEmployee));  
  5.   
  6.  }  
  7. }  
In DeleteEmployee method, ObjectContext's DeleteObject method would delete a particular Employee in respect to the EntityState.
  1. public void DeleteEmployee(Employee employee) {  
  2.  if ((employee.EntityState == EntityState.Detached)) {  
  3.   this.ObjectContext.Attach(employee);  
  4.  }  
  5.  this.ObjectContext.DeleteObject(employee);  
  6. }  
The web.config file is updated with the addition of the Domain Service Class to the project.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <configuration>  
  3.   <configSections>  
  4.     <sectionGroup name="system.serviceModel">  
  5.       <section name="domainServices" type="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"  
  6. allowDefinition="MachineToApplication"  
  7. requirePermission="false" />  
  8.     </sectionGroup>  
  9.   </configSections>  
  10.   <system.web>  
  11.     <httpModules>  
  12.       <add name="DomainServiceModule"    type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />  
  13.     </httpModules>  
  14.     <compilation debug="true" targetFramework="4.0">  
  15.       <assemblies>  
  16.         <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />  
  17.       </assemblies>  
  18.     </compilation>  
  19.     <roleManager enabled="true" />  
  20.     <authentication mode="Forms">  
  21.       <forms name=".BusinessApplication02_ASPXAUTH" />  
  22.     </authentication>  
  23.     <profile>  
  24.       <properties>  
  25.         <add name="FriendlyName" />  
  26.       </properties>  
  27.     </profile>  
  28.   </system.web>  
  29.   <system.webServer>  
  30.     <validation validateIntegratedModeConfiguration="false" />  
  31.     <modules runAllManagedModulesForAllRequests="true">  
  32.       <add name="DomainServiceModule"   
  33.     preCondition="managedHandler"     type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />  
  34.     </modules>  
  35.   </system.webServer>  
  36.   <system.serviceModel>  
  37.     <domainServices>  
  38.       <endpoints>  
  39.         <add name="OData"       type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />  
  40.       </endpoints>  
  41.     </domainServices>  
  42.     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />  
  43.   </system.serviceModel>  
  44.   <connectionStrings>  
  45.     <add name="EmployeeDBEntities"  
  46. connectionString="metadata=res://*/Models.EmployeeModel.csdl|res://*/Models.EmployeeModel.ssdl|res://*/Models.EmployeeModel.msl;  
  47. provider=System.Data.SqlClient;provider connection string="Data Source=B314LTRV\SQLEXPRESS;Initial Catalog=EmployeeDB;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />  
  48.   </connectionStrings>  
  49. </configuration>  
Let's go to the Silverlight project and add our custom page to display Employee data.
 
custom page in silverlight 
 
Remember to add all the Silverlight pages into View folder.
 
Silverlight pages 
 
We need to set the navigation to our newly added Employee.xaml page in MainPage.xaml
  1. <UserControl   
  2.   x:Class="RIASilverlight4Sample01.MainPage"  
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
  4.   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  5.   xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"   
  6.   xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"  
  7.   xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"   
  8.   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
  9.   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  10.   mc:Ignorable="d"  
  11. d:DesignWidth="640"  
  12. d:DesignHeight="480">  
  13.     <Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">  
  14.          <Border x:Name="ContentBorder" Style="{StaticResource ContentBorderStyle}">  
  15.             <navigation:Frame x:Name="ContentFrame"  
  16. Style="{StaticResource ContentFrameStyle}"  
  17. Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">  
  18.                 <navigation:Frame.UriMapper>  
  19.                     <uriMapper:UriMapper>  
  20.                         <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>  
  21.                         <uriMapper:UriMapping Uri="/{pageName}"  
  22.      MappedUri="/Views/{pageName}.xaml"/>  
  23.                     </uriMapper:UriMapper>  
  24.                 </navigation:Frame.UriMapper>  
  25.             </navigation:Frame>  
  26.         </Border>  
  27.         <Grid Style="{StaticResource NavigationOuterGridStyle}">  
  28.             <Grid x:Name="NavigationGrid"  
  29.     Style="{StaticResource NavigationGridStyle}">  
  30.                 <Border x:Name="BrandingBorder"  
  31.    Style="{StaticResource BrandingBorderStyle}">  
  32.                     <StackPanel x:Name="BrandingStackPanel"  
  33.     Style="{StaticResource BrandingStackPanelStyle}">  
  34.                         <ContentControl Style="{StaticResource LogoIcon}"/>  
  35.                         <TextBlock x:Name="ApplicationNameTextBlock"  
  36.  Style="{StaticResource ApplicationNameStyle}"                                    Text="{Binding  
  37. ApplicationStrings.ApplicationName, Source={StaticResource ResourceWrapper}}"/>  
  38.                     </StackPanel>  
  39.                 </Border>   
  40.                 <Border x:Name="LinksBorder"  
  41.    Style="{StaticResource LinksBorderStyle}">  
  42.                     <StackPanel x:Name="LinksStackPanel"  
  43.     Style="{StaticResource LinksStackPanelStyle}">  
  44.                         <HyperlinkButton x:Name="Link1"  
  45.      Style="{StaticResource LinkStyle}"   
  46.                                      NavigateUri="/Home"  
  47. TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.HomePageTitle, Source={StaticResource ResourceWrapper}}"/>  
  48.                         <Rectangle x:Name="Divider1"  
  49. Style="{StaticResource DividerStyle}"/>  
  50. <HyperlinkButton x:Name="Link2"  
  51. Style="{StaticResource LinkStyle}"  
  52. NavigateUri="/Employee"  
  53. TargetName="ContentFrame"  
  54. Content="Employee Details"/>  
  55.                         <Rectangle x:Name="Divider2"  
  56. Style="{StaticResource DividerStyle}"/>  
  57.                         <HyperlinkButton x:Name="Link3"  
  58. Style="{StaticResource LinkStyle}"   
  59.                                          NavigateUri="/About"  
  60. TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.AboutPageTitle, Source={StaticResource ResourceWrapper}}"/>  
  61.                     </StackPanel>  
  62.                 </Border>  
  63.             </Grid>  
  64.             <Border x:Name="loginContainer"  
  65. Style="{StaticResource LoginContainerStyle}">  
  66.                 <!-- LoginStatus will be added here in code behind. This is required for the designer view to work -->  
  67.             </Border>  
  68.         </Grid>  
  69.     </Grid>  
  70. </UserControl>  
In our Employee Page let's add a DataGrid and customize it as we did previously.
  1. <navigation:Page           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  2.            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  3.            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  4.            mc:Ignorable="d"  
  5.            xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"  
  6.            xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="RIASilverlight4Sample01.Views.Employee"  
  7. Style="{StaticResource PageStyle}"  
  8. Title="Employee Details"  
  9. d:DesignHeight="480"  
  10. d:DesignWidth="640">  
  11.   <Grid x:Name="LayoutRoot">  
  12.         <Grid.RowDefinitions>  
  13.             <RowDefinition Height="149*" />  
  14.             <RowDefinition Height="331*" />  
  15.         </Grid.RowDefinitions>  
  16.         <data:DataGrid x:Name="dgData"  
  17. IsReadOnly="True"  
  18. AutoGenerateColumns="False">  
  19.       <data:DataGrid.Columns>  
  20.         <data:DataGridTextColumn Binding="{Binding ID}"  
  21. Header="ID"/>  
  22.         <data:DataGridTextColumn Binding="{Binding FirstName}"  
  23. Header="First Name"/>  
  24.         <data:DataGridTextColumn Binding="{Binding LastName}"  
  25. Header="Last Name"/>  
  26.         <data:DataGridTextColumn Binding="{Binding EmailID}"  
  27. Header="Email ID" Width="*"/>  
  28.         <data:DataGridTextColumn Binding="{Binding Contact}"  
  29. Header="Contact"/>  
  30.       </data:DataGrid.Columns>  
  31.     </data:DataGrid>  
  32.   </Grid>  
  33. </navigation:Page>  
Now we will see some good stuff that is available for easy design and implementing data with controls associated. 
 
After clicking on the above option we will see the following pane. If you do not have any Domain Service Class then the list would be empty, for some reason if you have one but still you don't get it; you need to rebuild the solution once again. Remember, this pane is only displayed when a design view is opened (XAML view or Design view).
 
XAML view in silverlight 
 
As you see in the figure above, we have EmployeeDomainContext available to us after we have added the Domain Service Class with respect to Entity Model.
 
Data Sources are used for binding controls with entity; so that the design time can be reduced. As you see in the figure below, we have Employee as an entity and it is preceded with the image of the DataGrid and the properties are preceded with TextBox symbol.
 
DataGrid entity in silverlight 
 
That's right, the following controls would be associated once you drag and drop into the design pane.
 
Data Sources in silverlight 
 
As soon as the DataGrid is added from Data Sources pane the Domain Context would will be added in XAML behind.
  1. <riaControls:DomainDataSource   
  2. AutoLoad="True"   
  3. d:DesignData="{d:DesignInstance my:Employee, CreateList=true}"   
  4. Height="0"   
  5. LoadedData="employeeDomainDataSource_LoadedData"   
  6. Name="employeeDomainDataSource"   
  7. QueryName="GetEmployeesQuery"   
  8. Width="0">  
  9.             <riaControls:DomainDataSource.DomainContext>  
  10.                 <my1:EmployeeDomainContext />  
  11.             </riaControls:DomainDataSource.DomainContext>  
  12. </riaControls:DomainDataSource>
The following is the structure of the DataGrid in XAML after it is added from DataSource. Visual Studio will do automatic binding with each column type.
  1. <sdk:DataGrid AutoGenerateColumns="False"  
  2. Height="200"  
  3. HorizontalAlignment="Left"  
  4. ItemsSource="{Binding ElementName=employeeDomainDataSource, Path=Data}"  
  5. Margin="111,0,0,0"  
  6. Name="employeeDataGrid"  
  7. RowDetailsVisibilityMode="VisibleWhenSelected"  
  8. VerticalAlignment="Top"  
  9. Width="400">  
  10.             <sdk:DataGrid.Columns>  
  11.                 <sdk:DataGridTextColumn x:Name="contactColumn"  
  12.       Binding="{Binding Path=Contact}"  
  13.       Header="Contact"  
  14.       Width="SizeToHeader" />  
  15.                 <sdk:DataGridTextColumn x:Name="emailIDColumn"  
  16.       Binding="{Binding Path=EmailID}"  
  17.                            Header="Email ID"  
  18. Width="SizeToHeader" />  
  19.                 <sdk:DataGridTextColumn x:Name="firstNameColumn"  
  20. Binding="{Binding Path=FirstName}"  
  21. Header="First Name"  
  22. Width="SizeToHeader" />  
  23.                 <sdk:DataGridTextColumn x:Name="iDColumn"  
  24. Binding="{Binding Path=ID}"  
  25. Header="ID"  
  26. Width="SizeToHeader" />  
  27.                 <sdk:DataGridTextColumn x:Name="lastNameColumn"  
  28. Binding="{Binding Path=LastName}"  
  29. Header="Last Name"  
  30. Width="SizeToHeader" />  
  31.             </sdk:DataGrid.Columns>  
  32.         </sdk:DataGrid>  
We have other options other than DataGrid, such as Details and Customize.
 
DataGrid option 
 
If the Details view is selected and dropped on to the designer surface, we will get all the controls in a Grid Panel and the default control associated with it is the TextBox control.
 
controls in a Grid Panel 
  1. <Grid DataContext="{Binding ElementName=employeeDomainDataSource, Path=Data}"  
  2. HorizontalAlignment="Left"  
  3. Margin="168,266,0,0"  
  4. Name="grid1"  
  5. VerticalAlignment="Top">  
  6.             <Grid.ColumnDefinitions>  
  7.                 <ColumnDefinition Width="Auto" />  
  8.                 <ColumnDefinition Width="Auto" />  
  9.             </Grid.ColumnDefinitions>  
  10.             <Grid.RowDefinitions>  
  11.                 <RowDefinition Height="Auto" />  
  12.                 <RowDefinition Height="Auto" />  
  13.                 <RowDefinition Height="Auto" />  
  14.                 <RowDefinition Height="Auto" />  
  15.                 <RowDefinition Height="Auto" />  
  16.             </Grid.RowDefinitions>  
  17.             <sdk:Label Content="Contact:"  
  18. Grid.Column="0" Grid.Row="0"  
  19. HorizontalAlignment="Left"  
  20. Margin="3"  
  21. VerticalAlignment="Center" />  
  22.             <TextBox Grid.Column="1"  
  23. Grid.Row="0" Height="23"  
  24. HorizontalAlignment="Left"  
  25. Margin="3"  
  26. Name="contactTextBox"  
  27. Text="{Binding Path=Contact, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" />  
  28.             <sdk:Label Content="Email ID:"  
  29.   Grid.Column="0" Grid.Row="1"  
  30.   HorizontalAlignment="Left" Margin="3"  
  31.   VerticalAlignment="Center" />  
  32.             <TextBox Grid.Column="1" Grid.Row="1"  
  33.  Height="23"  
  34. HorizontalAlignment="Left"  
  35. Margin="3"  
  36. Name="emailIDTextBox"  
  37. Text="{Binding Path=EmailID, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center"  
  38. Width="120" />  
  39.             <sdk:Label Content="First Name:"  
  40. Grid.Column="0" Grid.Row="2"  
  41. HorizontalAlignment="Left"  
  42. Margin="3"  
  43. VerticalAlignment="Center" />  
  44.             <TextBox Grid.Column="1" Grid.Row="2"  
  45. Height="23"  
  46. HorizontalAlignment="Left"  
  47. Margin="3"  
  48. Name="firstNameTextBox"  
  49. Text="{Binding Path=FirstName, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center"  
  50. Width="120" />  
  51.             <sdk:Label Content="ID:"  
  52. Grid.Column="0" Grid.Row="3"  
  53. HorizontalAlignment="Left"  
  54. Margin="3"  
  55. VerticalAlignment="Center" />  
  56.             <TextBox Grid.Column="1" Grid.Row="3"  
  57. Height="23"  
  58. HorizontalAlignment="Left"  
  59. Margin="3"  
  60. Name="iDTextBox"  
  61. Text="{Binding Path=ID, Mode=TwoWay, NotifyOnValidationError=true}" VerticalAlignment="Center"  
  62. Width="120" />  
  63.             <sdk:Label Content="Last Name:"  
  64. Grid.Column="0" Grid.Row="4"  
  65. HorizontalAlignment="Left"  
  66. Margin="3"  
  67. VerticalAlignment="Center" />  
  68.             <TextBox Grid.Column="1" Grid.Row="4"  
  69. Height="23"  
  70. HorizontalAlignment="Left"  
  71. Margin="3"  
  72. Name="lastNameTextBox"  
  73. Text="{Binding Path=LastName, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center"  
  74. Width="120" />  
  75. </Grid>  
The above listing shows the implementation of Details view in XAML behind. You can notice one thing isNote that the Column header name is separated with a space; this is actually a great thing because in previous versions of Visual Studio we had to customize everything on our own.
 
This is really helpful.
 
We can even change the control for each Column.
 
control of each Column 
 
As you see in the figure above, we have the control options such as TextBox, ComboBox, TextBlock and even we can Customize.
 
Let's have different controls for each column in the Details view and see how it is helpful.
 
control for each Column
 
control of column in silverlight 
 
The following listing shows the Details view in XAML behind.
  1. <Grid DataContext="{Binding ElementName=employeeDomainDataSource, Path=Data}"  
  2. HorizontalAlignment="Left"  
  3. Margin="206,262,0,0"  
  4. Name="grid1"  
  5. VerticalAlignment="Top">  
  6.             <Grid.ColumnDefinitions>  
  7.                 <ColumnDefinition Width="Auto" />  
  8.                 <ColumnDefinition Width="Auto" />  
  9.             </Grid.ColumnDefinitions>  
  10.             <Grid.RowDefinitions>  
  11.                 <RowDefinition Height="Auto" />  
  12.                 <RowDefinition Height="Auto" />  
  13.                 <RowDefinition Height="Auto" />  
  14.                 <RowDefinition Height="Auto" />  
  15.             </Grid.RowDefinitions>  
  16.             <sdk:Label Content="ID:"  
  17. Grid.Column="0" Grid.Row="0"  
  18. HorizontalAlignment="Left"  
  19. Margin="3"  
  20. VerticalAlignment="Center" />  
  21.             <TextBlock Grid.Column="1" Grid.Row="0"  
  22. Height="23"  
  23. HorizontalAlignment="Left"  
  24. Margin="3"  
  25. Name="iDTextBlock"  
  26. Text="{Binding Path=ID, Mode=TwoWay}"  
  27. VerticalAlignment="Center" />  
  28.             <sdk:Label Content="First Name:"  
  29. Grid.Column="0" Grid.Row="1"  
  30. HorizontalAlignment="Left"  
  31. Margin="3"  
  32. VerticalAlignment="Center" />  
  33.             <TextBox Grid.Column="1" Grid.Row="1"  
  34. Height="23"  
  35. HorizontalAlignment="Left"  
  36. Margin="3"  
  37. Name="firstNameTextBox"  
  38. Text="{Binding Path=FirstName, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center"  
  39. Width="120" />  
  40.             <sdk:Label Content="Last Name:"  
  41. Grid.Column="0" Grid.Row="2"  
  42. HorizontalAlignment="Left"  
  43. Margin="3"  
  44. VerticalAlignment="Center" />  
  45.             <TextBox Grid.Column="1" Grid.Row="2"  
  46. Height="23"  
  47. HorizontalAlignment="Left"  
  48. Margin="3"  
  49. Name="lastNameTextBox"  
  50. Text="{Binding Path=LastName, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center"  
  51. Width="120" />  
  52.             <sdk:Label Content="Contact:"  
  53. Grid.Column="0" Grid.Row="3"  
  54. HorizontalAlignment="Left"  
  55. Margin="3"  
  56. VerticalAlignment="Center" />  
  57.             <TextBox Grid.Column="1" Grid.Row="3"  
  58. Height="23"  
  59. HorizontalAlignment="Left"  
  60. Margin="3"  
  61. Name="contactTextBox"  
  62. Text="{Binding Path=Contact, Mode=TwoWay, NotifyOnValidationError=true, TargetNullValue=''}" VerticalAlignment="Center"  
  63. Width="120" />  
  64. </Grid>  
Let's see how we can customize the Data Source.
 
customize the Data Source 
 
The following dialog box would be displayed when we select Customize as displayed in above figure.
 
dialog box in customize data 
 
In code behind of the view (Employee.xaml.cs) we can create an EmployeeDomainContext instance by using the service Namespace and using that we would perform all the operations.
 
EmployeeDomainContext instance 
 
We can use the following constructors based on our requirements:
 
constructors in silverlight
 
silverlight constructors 
 
By simply calling the method described in EmployeeDomainContext we can achieve the respective operations.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Windows;  
  6. using System.Windows.Controls;  
  7. using System.Windows.Documents;  
  8. using System.Windows.Input;  
  9. using System.Windows.Media;  
  10. using System.Windows.Media.Animation;  
  11. using System.Windows.Shapes;  
  12. using System.Windows.Navigation;  
  13. using BusinessApplication02.Web.Services;  
  14.   
  15. namespace BusinessApplication02.Views  
  16. {  
  17.     public partial class Employee : Page  
  18.     {  
  19.         EmployeeDomainContext context = new EmployeeDomainContext();  
  20.   
  21.         public Employee()  
  22.         {  
  23.             InitializeComponent();  
  24.         }  
  25.   
  26.         // Executes when the user navigates to this page.  
  27.         protected override void OnNavigatedTo(NavigationEventArgs e)  
  28.         {  
  29.             LoadData();  
  30.         }  
  31.   
  32.         private void LoadData()  
  33.         {  
  34.             employeeDataGrid.ItemsSource = context.Employees;  
  35.             context.Load(context.GetEmployeesQuery());  
  36.         }  
  37.   
  38.         private void employeeDomainDataSource_LoadedData(object sender, System.Windows.Controls.LoadedDataEventArgs e)  
  39.         {  
  40.   
  41.             if (e.HasError)  
  42.             {  
  43.                 System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);  
  44.                 e.MarkErrorAsHandled();  
  45.             }  
  46.         }  
  47.   
  48.     }  
  49. }  
As you see in the above listing above, when we navigate to the Employee page the data would be loaded.
 
data beis loaded 
 
As you see, in the preceding figure, all Employee data are is displayed.
 
Let's change the GetEmployees() query to get all the employee names in ascending order of First Name.
 
Go back to the EmployeeDomainClass.cs in Service folder of the Web project, and change the query for GetEmployees() method. 
  1. [Query(IsDefault = true)]  
  2. public IQueryable<Employee> GetEmployees()  
  3. {  
  4.     return this.ObjectContext.Employees.OrderBy(m => m.FirstName);  
  5. }  
data beis loaded