changes are submitted to the server).
.
A custom operation is one that is called at any time on the client, but whose execution is
deferred on the server until a changeset is submitted. Custom operations act upon entities,
and are actually created as methods on their associated entities on the client in addition to
being created as methods on the domain context that is generated for the domain service.
764 .
chaPter 35 WcF riA SerViceS
consuMinG a doMain serVice in silVerliGht
Before you look at actually consuming a domain service in
the Silverlight project, take a look at what RIA Services has
generated for you. As mentioned earlier in the chapter, RIA
Services automatically generates code in the Silverlight project
to communicate with the server. This code is generated in
a folder called Generated_Code, which is not added to the
project, but can be seen if you select the Silverlight project in
the Solution Explorer and click the Show All Files
button. Code is generated by RIA Services in files under
this folder (as shown in Figure 35-6), with the primary code
generated file being < web project name > .g.vb (or .cs).
For example, for the sample project, the primary code gen
file is Chapter35Sample.Web.g.vb (or .cs).
You can open this file to inspect its contents and see what
the code generator has created for you. Of particular interest, you will note that the entities
(or presentation model classes) exposed by domain services in the web project will have a
corresponding class generated in this file (decorated with attributes from the metadata classes or
the classes themselves). You will also find that for each domain service on the client there will be a
corresponding domain context class created, which handles communicating with the domain service
from the client. The operations exposed by a domain service will be created on the corresponding
domain context, and you call the operations on the domain context instead of attempting to
reference the domain service itself.
fiGure 35-6
Note that corresponding operations for the Insert/Update/Delete operations
on the domain service are not created on the domain context, because these
operations are managed by the changeset. Changes made to a collection of
entities retrieved from the server via a query operation are handled by the RIA
Services framework in a changeset, and when SubmitChanges is called on the
domain context, the framework will handle calling the Insert/Update/Delete
operations on the domain service as required.
If you follow standard RIA Services naming conventions, a domain service called CustomersService
in the web project will result in a corresponding domain context in the Silverlight project called
CustomersContext.
Consuming a Domain service in silverlight .
765
Now, attempt to populate a data grid with a list of customers retrieved from the server. You have
two primary means of doing so: either using a declarative XAML-based approach or a code-based
approach. The XAML-based approach is the easiest way to get started, so
this section will use that approach.
The easiest way to get started with the XAML-based approach is to simply
use the Data Sources window (as detailed in Chapter 18), and drag and
drop an entity exposed by a domain context from this window and onto
your page. You will find that a data source has already been created in your
project for each data context created by the RIA Services code generator (as
shown in Figure 35-7), so you don’t need to worry about creating the data
sources yourself.
For this example you will be consuming the CustomersService that exposes the Customer entities
from the Entity Framework model on the server, so drag and drop the Customer entity (from the
CustomersContext data source, that is, the selected item in Figure 35-7) onto the page. This will
create a data grid with a column for each property on the entity. Now if you look at the XAML you
can see how it ties together:
<riaControls:DomainDataSource AutoLoad="True" QueryName="GetCustomersQuery"
Name="CustomerDomainDataSource" Height="0" Width="0">
<riaControls:DomainDataSource.DomainContext>
<my:CustomersContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<data:DataGrid AutoGenerateColumns="False" Height="250"
ItemsSource="{Binding ElementName=CustomerDomainDataSource, Path=Data}"
Name="CustomerDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
<data:DataGrid.Columns>
<!--This code has been removed for purposes of brevity-->
</data:DataGrid.Columns>
</data:DataGrid>
The DomainDataSource control being used is a part of the RIA Services framework, and provides
the bridge to declaratively access the domain context in XAML. The DomainDataSource control
is specifying that it should use the CustomersContext (which corresponds to the CustomersService on
the server) as its domain context, and that the query operation that should be called on this domain
context is GetCustomersQuery. The AutoLoad property on the DomainDataSource control is set
to True, meaning this query will be called as soon as the page is loaded. Finally, the ItemsSource
property is set on the data grid, where it uses element name binding to bind to the DomainDataSource
control and use that as its source of data.
Now you can run your project, and you will find that the data grid is automatically populated with
the results of the query from the server (as shown in Figure 35-8).
fiGure 35-7
766 .
chaPter 35 WcF riA SerViceS
fiGure 35-8
As discussed previously, the advantage of returning an IQueryable from a domain service
operation is that RIA Services enables you to specify filtering, sorting, grouping, and paging
options — all of which will be performed on the server. This is also very easy to do in XAML
by specifying descriptors on the DomainDataSource — let’s take a look at performing each of
these in turn.
Add a textbox to the page that will automatically filter the customers by the company name, and
call it searchTextBox. Now you can add a filter descriptor to the DomainDataSource that specifies
the name of the property to filter (PropertyPath) and the operator specifying how the matching
will be done (Operator). You can then add a ControlParameter to the filter descriptor, which links
to the textbox (by providing the name of the textbox), uses the text in the textbox as the search
criteria (by providing the name of the property on the textbox to get the value from), and runs the
filter each time the text is changed (by providing the name of the event on the textbox that will
invoke the filtering when raised).
<riaControls:DomainDataSource AutoLoad=”True” QueryName=”GetCustomersQuery”
Name=”CustomerDomainDataSource” Height=”0” Width=”0”>
<riaControls:DomainDataSource.DomainContext>
<my:CustomersContext />
</riaControls:DomainDataSource.DomainContext>
<riaControls:DomainDataSource.FilterDescriptors>
<riaControls:FilterDescriptor PropertyPath=”CompanyName”
Operator=”Contains”
Value=”{Binding ElementName=searchTextBox, Path=Text}” />
</riaControls:DomainDataSource.FilterDescriptors>
</riaControls:DomainDataSource>
Sorting is automatically handled by the data grid (click the column headers to sort by that column),
and if the results are paged it will automatically go back to the server to get the new page of results
according to the current page and sort criteria. You can, however, specify the initial sorting using
sort descriptors on the DomainDataSource, by providing the name of the property to sort on, and
the sort direction:
Consuming a Domain service in silverlight .
767
<riaControls:DomainDataSource AutoLoad=”True” QueryName=”GetCustomersQuery”
Name=”CustomerDomainDataSource” Height=”0” Width=”0”>
<riaControls:DomainDataSource.DomainContext>
<my:CustomersContext />
</riaControls:DomainDataSource.DomainContext>
<riaControls:DomainDataSource.SortDescriptors>
<riaControls:SortDescriptor PropertyPath=”CompanyName” Direction=”Ascending” />
</riaControls:DomainDataSource.SortDescriptors>
</riaControls:DomainDataSource>
Grouping again is handled in a similar manner by providing group descriptors, and simply
providing the name of the property to group on:
<riaControls:DomainDataSource AutoLoad=”True” QueryName=”GetCustomersQuery”
Name=”CustomerDomainDataSource” Height=”0” Width=”0”>
<riaControls:DomainDataSource.DomainContext>
<my:CustomersContext />
</riaControls:DomainDataSource.DomainContext>
<riaControls:DomainDataSource.GroupDescriptors>
<riaControls:GroupDescriptor PropertyPath=”SalesPerson” />
</riaControls:DomainDataSource.GroupDescriptors>
</riaControls:DomainDataSource>
Paging the data in the grid (to display, for example, 20 customers at a time) is easy with
the DataPager control. Add the control to your page, bind its Source property to the
DomainDataSource control, and provide its PageSize property with the number of items to be
displayed in the data grid:
<data:DataPager PageSize="20"
Source="{Binding Data, ElementName=CustomerDomainDataSource}"/>
Note that the page size specifies how many items should be displayed in the grid, not how many items
should be retrieved from the server. If you just set the PageSize property the entire collection will still
be retrieved from the server and paged on the client instead. To retrieve just a single page of items
at a time and go back to the server to retrieve more items when navigating between pages, you will
need to set the LoadSize property on the DomainDataSource control. Generally, you will want to set
both properties to the same value. Now, it will retrieve and display a single page of items, and it will
request and display a new page of items from the server each time you navigate to a new page with the
DataPager control.
In the background, any changes you make to the data in the data grid (such as adding rows,
deleting rows, and updating values) will be tracked in a changeset by the RIA Services framework.
Submitting these changes back to the server is a case of calling the SubmitChanges() method on the
domain context. Add a button to the page called SubmitButton. In its Click event handler (in the
code-behind), add the following line of code:
Vb
CustomerDomainDataSource.SubmitChanges()
768 . chaPter 35 WcF riA SerViceS
c#
CustomerDomainDataSource.SubmitChanges();
Clicking the button will now submit any changes you ’ ve made back to the server.
As you can see, RIA Services is an extremely powerful framework for managing data, greatly
simplifying functionality that was once complex to implement, and making it very quick and easy to
create very functional business applications.
You can also reject any changes made using the RejectChanges() method on the
DomainDataSource control.
The fi nal page that implements loading, fi ltering, sorting, grouping, paging, and saving the data is
shown in Figure 35 - 9.
The DomainDataSource control makes it very easy to consume data from RIA
Services in a Silverlight application; however, at times you may wish to interact
with the domain service in code instead. This is possible by creating an instance
of the corresponding domain context and using the methods on it. However,
note that communication with the domain service is performed asynchronously,
requiring your code to be structured accordingly.
fiGure 35 - 9
summary .
769
suMMary
In this chapter you learned how WCF RIA Services can vastly simplify architecting and developing
an end-to-end data-driven Silverlight application, through its combination of prescriptive design
patterns, code generation, and feature-rich framework. RIA Services provides many more features
than described here, including decorating classes and their properties with attributes (such as
validation rules which RIA Services enforces), using metadata classes (i.e., classes associated with
the entities being passed between the server and the client that attributes can be applied to and
projected onto the associated entities such that the original entities don’t need to be modified),
sharing code between the server and the client, built-in authentication and security functionality,
and much more. However, this chapter should help you get started using RIA Services to provide a
means for communicating between your Silverlight application and the server.
PART VIII
configuration and resources
. chaPter 36: Configuration Files
. chaPter 37: Connection Strings
. chaPter 38: Resource Files
36 36
Configuration files
what’s in this chaPter?
.
Understanding the NET configuration system
.
Using configuration files within your application
.
Storing custom types in configuration files
One of the challenges of building applications is adjusting the way the application functions
on the fly without having to rebuild it. There’s a long history of applications using
configuration files to control the way an application runs. .NET applications use a series of
XML configuration files that can be adjusted to determine application behavior. This chapter
explores the structure of these configuration files and demonstrates how you can store custom
information using a configuration section handler.
confiG files
The .NET Framework configuration system consists of several configuration files (discussed
in the following sections) that can be used to adjust one or more applications on a computer
system. Part of this system is an inheritance model that ensures that configurations can be
applied at the appropriate level. This model is such that sections defined in a configuration