Introduction

This article will demonstrate how to build a Silverlight 4 application that uses (Entity Framework) Complex Types at the client level (through WCF services).

Background  

Before Silverlight 4 - it wasn't possible to use complex types on the client, but now, Silverlight 4 can use RIA services to access the (Complex) types that the Entity Framework creates. In previous versions of Silverlight, it was possible to access simple entity types but not complex types. 

Using the code 

Setting up sample database   

 If you do not have Microsoft's Northwind database installed on your database server, you can download the script here (Download instnwnd.zip - 238.93 KB). Log into your Sql Server Management Studio and open a new query analyzer window and run the unzipped script to create the database (including data) that is used in the Data Access Layer (DAL) within the overall project.  

Create a new (empty) project and add three solution folders, for the data access layer, WCF service and finally the Silverlight client.  

 Creating the Data Access Layer (Entity Model) Project   

Create the data access layer DLL by adding a new Class library to the 'data access layer' solution in the project. 

1_Create_Data_Access_Layer.jpg

 Add an entity framework model to the DAL. 

2_Create_Entity_Framework.jpg

 Select the stored procedure 'Employee Sales by Country' to tyhe entity model. This sproc. will be used as it will return a complex type (fields from multiple tables). 

3_EFChooseDataObjects.jpg 

Bring up the 'Model View' browser so that we can then easily navigate to the entity model. 

7_ViewEntityFrameworkModelBrowser.jpg

Create\import the C# function that will represent the method to call the entity method in the DAL. 

5_CreateFunctionToCallSproc.jpg

Create the complex type (class) for the stored procedure. 

4_Create_Complex_Type.jpg 

Your DAL project structure should look like this.

6_EntityFrameworkProjectStructure.jpg 

Creating the WCF Service Project  

Add a new WCF service to the WCF solution folder in the project. 

9_Create_Wcf_Service.jpg

Add a reference to the data access layer project in your references. 

10_Add_DAL_dll_To_WCF.jpg 

Your newly added DAL project in your WCF project.  

Add the following code to the IOrdersService class 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using OrdersAccessLayer;
 
namespace WcfOrdersService
{ 
    [ServiceContract]
    public interface IOrdersService
    {
 
        /// <summary>
        /// Gets the order details data.
        /// </summary>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        /// <returns>A collection of complex type classes 'Employee_Sales_by_Country_Result'</returns>
        [OperationContract]
        List<Employee_Sales_by_Country_Result> GetOrderDetailsData(DateTime start, DateTime end);      
    }
   
} 

 Add the following code to the OrdersService class.  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using OrdersAccessLayer;
 
namespace WcfOrdersService
{    
    public class OrdersService : IOrdersService
    {
 
      /// <summary>
      /// A reference to the controller class in the DAL project
      /// </summary>
      private OrdersController orderCtrl;
 
      /// <summary>
      /// Initializes a new instance of the <see cref="OrdersService"/> class.
      /// </summary>
      public OrdersService()
      {
          orderCtrl = new OrdersController();
      }
 
 
      /// <summary>
      /// Gets the order details data.
      /// </summary>
      /// <param name="start">The start.</param>
      /// <param name="end">The end.</param>
      /// <returns></returns>
        public List<Employee_Sales_by_Country_Result> GetOrderDetailsData(DateTime start, DateTime end)
        {
            return this.orderCtrl.GetOrderDetails(start, end);
        }
       
    }
} 

Compile the service before adding it to the Silverlight project below. 

Creating the Silverlight 4 Client Project 

Create a new Silverlight project.

12_CreateSilverlightApplication.jpg 

Enable the Silverlight project for RIA services and assign it the OrdersService service.  

13_Enable_Ria_Services.jpg

Add a reference to the WCF service. 

14_Add_WCF_Ref_To_SL.jpg

The Silverlight project after adding the service reference. 

15_SL_Structure_After_Adding_WCF_Service.jpg

Add the following code to the code behind for the MainPage.cs Notice in the method 'SaveScheduleCompleted', that there is some linq performed on the  collection of (entity class) 'Employee_Sales_By_Country_Result'. Thus we are able to create a class in the entity framework and also be able to use it in the client.  

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Silverlight4Console.OrdersServiceReference;
using System.ServiceModel;
 
namespace Silverlight4Console
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            this.LoadOrderDetails();
        }
 
        private void LoadOrderDetails()
        {
            try
            {
                DateTime start = DateTime.Parse("1997-01-01");
                DateTime end = DateTime.Parse("1997-01-31");
 
                OrdersServiceReference.OrdersServiceClient ordersService = new OrdersServiceReference.OrdersServiceClient();
 
                ordersService.GetOrderDetailsDataAsync(start, end);
                ordersService.GetOrderDetailsDataCompleted += new EventHandler<GetOrderDetailsDataCompletedEventArgs>(SaveScheduleCompleted);
            }
            catch (FaultException fe)
            {
                Console.WriteLine(fe.Message);
                Console.WriteLine("stack trace");
                Console.WriteLine(fe.StackTrace);
                Console.ReadLine();              
            }
            catch (CommunicationException commProblem)
            {
                if (commProblem.InnerException is FaultException)
                {
                    Console.WriteLine("An unknown exception was received. " + commProblem.InnerException.Message);
                    Console.ReadLine();
                    return;
                }
                else
                {
                    Console.WriteLine("There was a communication problem. " + commProblem.Message);
                    Console.WriteLine(commProblem.StackTrace);
                }
 
            }
            
        }
 
        /// <summary>
        /// Saves the schedule completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="RiaConsole.TemplateService.SaveScheduleCompletedEventArgs"/> instance containing the event data.</param>
        private void SaveScheduleCompleted(object sender, GetOrderDetailsDataCompletedEventArgs e)
        {                        
            this.personDataGrid.ItemsSource = e.Result.Where(ord=>ord.SaleAmount>2000);            
        }
 
    }
} 

Add the following XAMl code to the MainPage (a simple grid to bind\display order results) 

 <UserControl x:Class="Silverlight4Console.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
 
    <Grid x:Name="LayoutRoot" Background="White">
        <sdk:DataGrid AutoGenerateColumns="true" VerticalAlignment="Center" HorizontalAlignment="Center" Height="100" Margin="57,66,0,0" Name="personDataGrid" Width="auto" />
    </Grid>
</UserControl> 

The overall project structure.  

16_SolutionStructure.jpg

Screen Output

Grid.jpg 

Points of Interest 

Just as a side note, I found it easier to bind the Silverlight application to the WCF service (enabling RIA services), by designing the data access layer, WCF service and then creating the Silverlight application - I found that creating the Silverlight application first with no RIA service to bind to (but still enabling RIA services) meant that it didn't pick up the services when I later enabled them.  

History 

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架