WCF RIA Services. Start. Part 1

Original author: Brian Noyes
WCF RIA Services. Start. Part 1
WCF RIA Services. Receive data. Part 2
WCF RIA Services. Data update. Part 3 of
WCF RIA Services. Introducing the Model-View-ViewModel (MVVM) pattern. Part 4

From translator


In this series of translations, there is a good share that I personally added, as the original uses an outdated VS, as well as missing some, in my opinion, important points, without which the assimilation of the material is greatly complicated. Go.

Caution. Lots of pictures!

Introduction


Imagine that you need to create a serious business application, the client of which operates with a lot of data distributed in various places, and which must be somehow collected. To implement this task, you will need to learn a number of new technologies and approaches, write a bunch of code, debugging. What is the result? If it’s rude, then just sending data from the server side of the application to the client and vice versa. Well, work with the database. And what would you like to focus on first of all? On the implementation of data transfer? Or on the logic of processing, manipulating, presenting this data? I think you will choose the second.

WCF RIA Services offers automation of data transfer and the creation of multilevel applications based on Silverlight, focusing the developer’s attention on the logic of work. You write only once a copy of the server code, and it is automatically ported and becomes available on the client side, without the need for manual duplication or application of other tricks on the part of the developer. Also on the client all server capabilities remain, such as validation, access rights, and many others.

In this series of articles, you will become familiar with the main features of WCF RIA Services, see in practice what advantages this approach provides. The diagram below shows what WCF RIA Services is responsible for:
image

today we’ll use the standard, simplest Silverlight template. In subsequent parts, we will increase our knowledge by finalizing the application and using new techniques, tactics and technologies, one of which will be the Model-View-ViewModel (MVVM) pattern and unit testing.

Tasks solved by the application being created


Just an electronic notebook in which you can enter an event, give it a name, artist, project, start and end date. In general, nothing complicated or unusual, but a good understanding of what needs to be done will only facilitate understanding of how to do this within the framework of the technology being studied.

Learned aspects of WCF RIA Services:


  • Project Links - A link between a Silverlight client project and a server-side web application or library class. The server project defines or creates links to domain services, entities, metadata, and also provides a mechanism by which the code defined on the server is accessible to the client. Thanks to the link, all the code necessary for the client is generated dynamically at compile time.

  • Domain Services - The core of WCF RIA Services. They determine the operations available to perform on the server. Basically, they come down to CRUD (write, read, update, delete), however, they can be any others that you consider necessary. All these operations are automatically available on the client side thanks to WCF, and the client does not need to know almost anything about the server side.

  • Entities - you need to determine the types of entities on the server side, and the client part will operate on them thanks to automatic code generation. It is also possible to use validation and other metadata. Entity types on the server and client side are used for serialization / deserialization operations, when transferring data between them. Entities can be created using the Entity Framework, LINQ to SQL, or Plain Old CLR Objects (POCO).

  • Domain Context - a client analogue of domain services. Autogenerates the code, thanks to which you get access to the functionality of the server side. It contains a WCF proxy, which provides the ability to call a service, as well as manages requests that will need to be executed on the server side, tracks changes in entities and much more.

  • DomainDataSource is a data source object that is used to execute queries and notify the server of changes made. Direct binding in XAML and more is facilitated.

Step 1: Create a Silverlight application and a link to the server side.


We use a simple database that will save tasks, as well as all related information. To do this, you will need to run the TaskManager.sql script located in the project’s horse, create a database and schema, fill the database with initial values.

Create a new project named "TasksManager" . The ability to use WCF RIA Services is inherent in any type of Silverlight application. However, let's start with the simplest one and select the Silverlight Application template.


After clicking on the OK button, the following dialog box opens, in which you need to add a bird to "Enable WCF RIA Services".


Thanks to it, the necessary links to the server project will be created, code generation and other functions described earlier will appear.
Click OK and wait for the creation of the project.

Step 2: Create Domain Model Entities


Since WCF RIA Services is primarily designed to move data back and forth from client to server and back, you will need some data model data. Out of the box Entity Framework is supported. However, it is possible to use LINQ to SQL in the WCF RIA Services Toolkit. If you create your own domain service, you can work with POCO. Now we will use the standard Entity Framework.

Original TaskManager.sql
USE [master]
GO
/****** Object:  Database [TaskManager]    Script Date: 06/06/2010 18:01:49 ******/
IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'TaskManager.mdf')
DROP DATABASE [TaskManager.mdf]
GO
CREATE DATABASE [TaskManager.mdf]
GO
USE [TaskManager.mdf]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[User](
	[UserId] [int] IDENTITY(1,1) NOT NULL,
	[Username] [nvarchar](250) NOT NULL,
	[Password] [nvarchar](250) NOT NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
	[UserId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Customer](
	[CustomerId] [int] IDENTITY(1,1) NOT NULL,
	[CustomerName] [nvarchar](250) NOT NULL,
 CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
	[CustomerId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Project](
	[ProjectId] [int] IDENTITY(1,1) NOT NULL,
	[ProjectName] [nvarchar](250) NOT NULL,
	[Description] [nvarchar](max) NULL,
	[CustomerId] [int] NULL,
 CONSTRAINT [PK_Project] PRIMARY KEY CLUSTERED 
(
	[ProjectId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Task](
	[TaskId] [int] IDENTITY(1,1) NOT NULL,
	[TaskName] [nvarchar](250) NOT NULL,
	[Description] [nvarchar](max) NULL,
	[StartDate] [datetime] NULL,
	[EndDate] [datetime] NULL,
	[CustomerId] [int] NULL,
	[ProjectId] [int] NULL,
	[UserId] [int] NULL,
 CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED 
(
	[TaskId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UsersTasks](
	[TaskId] [int] NOT NULL,
	[UserId] [int] NOT NULL,
 CONSTRAINT [PK_UsersTasks] PRIMARY KEY CLUSTERED 
(
	[TaskId] ASC,
	[UserId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TimeEntry](
	[TimeEntryId] [int] IDENTITY(1,1) NOT NULL,
	[StartTime] [datetime] NOT NULL,
	[EndTime] [datetime] NOT NULL,
	[TaskId] [int] NOT NULL,
	[Description] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_TimeEntry] PRIMARY KEY CLUSTERED 
(
	[TimeEntryId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Project]  WITH CHECK ADD  CONSTRAINT [FK_Project_Customer] FOREIGN KEY([CustomerId])
REFERENCES [dbo].[Customer] ([CustomerId])
GO
ALTER TABLE [dbo].[Project] CHECK CONSTRAINT [FK_Project_Customer]
GO
ALTER TABLE [dbo].[Task]  WITH CHECK ADD  CONSTRAINT [FK_Task_Customer] FOREIGN KEY([CustomerId])
REFERENCES [dbo].[Customer] ([CustomerId])
GO
ALTER TABLE [dbo].[Task] CHECK CONSTRAINT [FK_Task_Customer]
GO
ALTER TABLE [dbo].[Task]  WITH CHECK ADD  CONSTRAINT [FK_Task_Project] FOREIGN KEY([ProjectId])
REFERENCES [dbo].[Project] ([ProjectId])
GO
ALTER TABLE [dbo].[Task] CHECK CONSTRAINT [FK_Task_Project]
GO
ALTER TABLE [dbo].[UsersTasks]  WITH CHECK ADD  CONSTRAINT [FK_UsersTasks_Task] FOREIGN KEY([TaskId])
REFERENCES [dbo].[Task] ([TaskId])
GO
ALTER TABLE [dbo].[UsersTasks] CHECK CONSTRAINT [FK_UsersTasks_Task]
GO
ALTER TABLE [dbo].[UsersTasks]  WITH CHECK ADD  CONSTRAINT [FK_UsersTasks_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([UserId])
GO
ALTER TABLE [dbo].[UsersTasks] CHECK CONSTRAINT [FK_UsersTasks_User]
GO
ALTER TABLE [dbo].[TimeEntry]  WITH CHECK ADD  CONSTRAINT [FK_TimeEntry_Task] FOREIGN KEY([TaskId])
REFERENCES [dbo].[Task] ([TaskId])
GO
ALTER TABLE [dbo].[TimeEntry] CHECK CONSTRAINT [FK_TimeEntry_Task]
GO
SET NUMERIC_ROUNDABORT OFF
GO
SET XACT_ABORT, ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS ON
GO
/*Pointer used for text / image updates. This might not be needed, but is declared here just in case*/
DECLARE @pv binary(16)
BEGIN TRANSACTION
SET IDENTITY_INSERT [dbo].[Task] OFF
SET IDENTITY_INSERT [dbo].[Task] ON
INSERT INTO [dbo].[Task] ([TaskId], [TaskName], [Description], [StartDate], [EndDate], [CustomerId], [ProjectId]) VALUES (1, N'Create Project', N'Create a Silverlight Application project with a RIA Services link', '20100601 00:00:00.000', '20100602 00:00:00.000', NULL, NULL)
INSERT INTO [dbo].[Task] ([TaskId], [TaskName], [Description], [StartDate], [EndDate], [CustomerId], [ProjectId]) VALUES (2, N'Define Data Model', N'Create an Entity Framework model for the application data', '20100602 00:00:00.000', '20100603 00:00:00.000', NULL, NULL)
INSERT INTO [dbo].[Task] ([TaskId], [TaskName], [Description], [StartDate], [EndDate], [CustomerId], [ProjectId]) VALUES (3, N'Define domain service', N'Create a domain service to expose task data to the client', '20100603 00:00:00.000', '20100604 00:00:00.000', NULL, NULL)
INSERT INTO [dbo].[Task] ([TaskId], [TaskName], [Description], [StartDate], [EndDate], [CustomerId], [ProjectId]) VALUES (4, N'Use data in the Silverlight client', N'Use the DomainContext and DomainDataSource to access and manipulate the data in the client', '20100604 00:00:00.000', '20100605 00:00:00.000', NULL, NULL)
SET IDENTITY_INSERT [dbo].[Task] OFF
COMMIT TRANSACTION


But before creating the Domain Model Entities, you need to create a database and populate it.
To do this, add the “App_Data” folder to the server side (with the .Web prefix):






Double-click on the created Database * .mdf database. A window will open. We select again in it "Database * .mdf", with the right button - "New request". The query editor opens. Open TasksModel.sql, about which it has already been mentioned, and the copy from everything there, except for the first such lines:
USE [master]
GO
/****** Object:  Database [TaskManager]    Script Date: 06/06/2010 18:01:49 ******/
IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'TaskManager.mdf')
DROP DATABASE [TaskManager.mdf]
GO
CREATE DATABASE [TaskManager.mdf]
GO
USE [TaskManager.mdf]
GO

Click on the “Run” button. All. The database is filled with tables, and the Tasks table is filled with data.

Right-click on TaskManager.Web and select "Add" - "Create Element". Select the “Data” tab in the left window, and in the right select “ADO.NET EDM Model”. Give the name " TasksModel.edmx ".


Add. The EDM Model Wizard dialog box opens. Select the desired database, give the entity name " TaskManagerEntities " and click Next.


In the next step, select the table with a tick. We give the name of the model “ TaskManagerMode l”, and also put a check mark on “ Generate object names in the plural or singular”


Voila. Now you have an Entity Framework data model for all tables in the database. However, in this lesson you will only work with the “Task” table; however, further tables will be added.

Build a solution to make sure everything is done correctly.

After creating the EDM, the designer window should open for you. If it does not automatically open, then double-click in the Solution Explorer for TasksModel.edmx. Next, click on the empty area. And go to the properties window. Change the "Code Generation Strategy" parameter from "No" to "Default". Reassemble.


Now it's time to create a domain service.

Step 3: Create a Domain Service


Now let's create the RIA Services kernel - a domain service. Right-click on the server side: TaskManager.Web - “Add” - “Create Element”. In the left window, select the category “Web”, and on the right “DomainService Class”. Give the name " TasksDomainService ".


After clicking on the Add button, go to the service settings window. Since now we will work only with the Tasks table, we select it. In the “Enable Editing” column, a check mark is not needed. Till. If you put it, then get a set of CRUD. If not, then only Get (reading). Click OK.

The generated code without comments will look like this:
    [EnableClientAccess()]
    public class TasksDomainService : LinqToEntitiesDomainService
    {
        public IQueryable GetTasks()
        {
            return this.ObjectContext.Tasks;
        }
    }


The LinqToEntitiesDomainService class provides a link between the EDM model and RIA WCF services. The EnableClientAccess attribute indicates that this method must be added to the client part during automatic code generation. In this case, we only got the method of reading data from the table, however, you can implement a full CRUD or any other actions on the data that you will need, and which in the end will also be available in the client project. We will consider how to do this in more detail in the following articles.

Also remember that conventions are used that relate to the return type (Queryable) and naming convention (GetName). In this case, we have a delegated entity of the ObjectContext data model, which is created as part of the base class and is used to retrieve the entire Tasks table. You can also improve this query by adding sorting, filters, etc., however, while the return value is of the IQueryable type, WCF RIA Services understands this and forms the appropriate methods that will allow this functionality to be used on the client side.

We will rebuild the project to make sure that everything is done correctly. In a client project, when you click on the icon of two sheets "Show all files", a file with the name TaskManager.Web.g.cs should appear, which contains the generated code for the client.

Step 4: Retrieving Data in the UI Using DomainDataSource


Today we will take advantage of such a feature of WCF RIA Services as drag and drop, using DomainDataSource directly in the UI. In the following parts, we will also look at the MVVM pattern, how to use it in WCF RIA, and how to use DomainDataSource with this approach.

So open MainPage.xaml. Next, open the Data Sources window. Now drag and drop Tasks into the page editor in a white box. Correct the placement. All. In the XAML section, you will see the generated code for the Grid element.




We build and run the application. And enjoy a similar view:


Video for this tutorial




Source code


On github

Also popular now: