1. Trang chủ
  2. » Công Nghệ Thông Tin

ASP.NET 4 Unleased - p 104 pdf

10 274 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 584,72 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

CHAPTER 21 Data Access with WCF Data Services .AddQueryOption“playerId”, 1 .Expand“Weapon” .Expand“Player” .Expand“Creature” orderby kill.KillTime descending select kill; killsRepeater.D

Trang 1

CHAPTER 21 Data Access with WCF Data Services

.AddQueryOption(“playerId”, 1)

.Expand(“Weapon”)

.Expand(“Player”)

.Expand(“Creature”)

orderby kill.KillTime descending

select kill;

killsRepeater.DataSource = q;

killsRepeater.DataBind();

}

The first thing we do in this code is create an instance of the service proxy, which is a

generated class that inherits from the System.Data.Services.Client.DataServiceContext

class This class exposes properties for each of the entity sets exposed by the service In our

case, we have players, weapons, and creatures and foreign key relationships that enable

them all to link to the kill log (A Kill is another entity exposed by the service.)

The custom service context client proxy takes as a constructor parameter a Uri that

contains the address of the service In a production scenario, you might use service

discovery, a service registry, or Web.config files to store the URLs of the services

The next thing we do is call CreateQuery<Kill>(“GetMyKills”) There’s quite a bit of

func-tionality packed into this one method call CreateQuery() doesn’t actually talk to the

service; it is merely asking us for the shape of the rows that will be returned from the query

(the Kill class) and for either the name of a service method to invoke or the name of an

entity set to query If we had simply supplied the string ”Kills” to the method, we would

be querying the Kills entity set directly and not invoking a custom method

Next you can see that the output of the CreateQuery() method is something queryable;

so we can chain method calls onto this method in a “fluent” style We use the Expand()

method to tell the WCF Data Service that for every Kill we return, also expand the

speci-fied relationship properties This enables us to bring over all the data related to an entity

in a single method call rather than making a bunch of chatty calls with high overhead

and latency In our case, we want the names of the weapons and creatures that were

killed

If we wanted, we could supply virtually any additional LINQ queries to the end of our

statement, but in this case we were happy with sorting the kills in descending order by

time so that the players see their most recent kill first

At this point, the service has still not been queried All we’re doing up to this point is

build-ing an in-memory expression tree The service will not actually be called until we, directly

or indirectly, invoke GetEnumerator() on the query object For the code in Listing 21.1,

we won’t make the actual network call until somewhere inside the DataBind() method of

the repeater control

Figure 21.2 shows what the MyKills.aspx page looks like when fed data from the WCF

Data Service

Trang 2

The great part about using WCF Data Services is that, with a few minor exceptions, the

classes coming back from the service containing results are just specialized C# classes This

means if I want to know the name of the weapon used in a particular kill (and I’ve

pre-expanded the property chain), I can refer to kill.Weapon.Name Likewise, to find the name

of the creature killed, I can refer to kill.Creature.Name

This property chaining syntax still works with ASP.NET’s binding syntax and templating

system The code in Listing 21.2 shows MyKills.aspx; you can see how the

DataBinder.Eval() calls work perfectly well with nested properties returned on the entity

objects from the WCF Data Service

LISTING 21.2 MyKills.aspx

<form id=”form1” runat=”server”>

<div>

<asp:Repeater ID=”killsRepeater” runat=”server”>

<ItemTemplate>

[<%# DataBinder.Eval(Container.DataItem, “KillTime”) %>]

<a href=’Player.aspx?playerId=

<%# DataBinder.Eval(Container.DataItem, “PlayerID”) %>’>

<%# DataBinder.Eval(Container.DataItem, “Player.Name”) %></a>

&nbsp;fragged&nbsp;

<a href=’Create.aspx?creatureId=

<%# DataBinder.Eval(Container.DataItem, “CreatureID”) %>’>

<%# DataBinder.Eval(Container.DataItem, “Creature.Name”) %></a>

with a

<a href=’Weapon.aspx?weaponId=

<%# DataBinder.Eval(Container.DataItem, “WeaponID”) %>’>

<%# DataBinder.Eval(Container.DataItem, “Weapon.Name”) %></a>

(<%# DataBinder.Eval(Container.DataItem, “Notes”) %>)

<br />

</ItemTemplate>

</asp:Repeater>

</div>

</form>

FIGURE 21.2 Displaying “My Kills” with data from WCF Data Service

Trang 3

The main thing to take away from this code listing is that we can use the dot notation in

the data binder’s Eval() method to access and render nested properties on the bound

item

The moral of this story is that whether you access a WCF Data Service because your

infra-structure prevents direct SQL access or because another team has decided to expose its

data that way, it’s incredibly simple to create a service reference and start working with

the data on that service Also keep in mind that WCF Data Services aren’t just simple

query services; you can insert, delete, and update as well, and data services can even be

configured to support optimistic concurrency checking, which comes in handy for

high-volume intranet applications

To add a new creature to the system and update a kill using the service reference, we can

just use the code shown in Listing 21.3 When querying data, the web service is not

contacted until code invokes GetEnumerator() on the query When modifying data, the

change requests are not sent to the service until you invoke the SaveChanges() method

on the service context

LISTING 21.3 Adding and Updating Entities with a WCF Data Service Proxy

ZombieKillaService.ZombieKillaContainer svc = new

ZombieKillaService.ZombieKillaContainer(

new Uri(“http://localhost:5000/ZombieKilla.svc”));

svc.MergeOption =

System.Data.Services.Client.MergeOption.PreserveChanges;

ZombieKillaService.Creature creature = new ZombieKillaService.Creature()

{

Armor = 215,

Hitpoints = 512,

Name = “Fantastically Big Zombie”

};

svc.AddToCreatures(creature);

svc.SaveChanges();

Response.Write(“Created a new creature with ID of “ +

creature.ID.ToString());

ZombieKillaService.Player player = svc.Players.FirstOrDefault();

ZombieKillaService.Weapon weapon = svc.Weapons.FirstOrDefault();

ZombieKillaService.Kill kill = new ZombieKillaService.Kill() {

KillTime = DateTime.Now,

PlayerID = player.ID,

CreatureID = creature.ID,

WeaponID = weapon.ID,

Notes = “Awesome shot!”

};

CHAPTER 21 Data Access with WCF Data Services

Trang 4

From this listing, you can see that the service reference proxy gives us classes that we can

instantiate to represent any of the entities hosted by the data service In addition, we also

get methods such as AddToCreatures() that queue up all the work necessary to add an

entity to an entity set on the server We can also query for a specific item, make changes

to it (or items related to it), and save those changes as well You can do a few hundred

other things with the data service proxy, but this is an ASP.NET book so we’re going to

stick to the basics for this chapter

Using Data Services with a Data Context

In the previous section, we built a sample application that displays the kill log from a

fictional video game called Zombie Killa This kill log is exposed as a WCF Data Service,

and we communicated with that service through an automatically generated proxy class

In this section, we take a look at how we can talk to the WCF Data Service without using

any generated code or classes by using the DataServiceContext class directly

As with the generated proxy, we create an instance of the proxy by providing it with the

URL of the WCF Data Service After that, we can create our own queries (and make

changes, inserts, and deletes) by invoking various methods on the context In the code in

Listing 21.4, we call CreateQuery() and pass it the name of the entity set we want to

query: Players

LISTING 21.4 Querying a Data Service Manually with a DataServiceContext

// NOTE: Not using auto-generated client proxy, using generic client with POCO

View Models!

DataServiceContext ctx = new DataServiceContext(

new Uri(“http://localhost:5000/ZombieKilla.svc”));

ctx.IgnoreMissingProperties = true;

var q = from ViewModels.Player player in

ctx.CreateQuery<ViewModels.Player>(“Players”)

.Expand(“Kills”).Expand(“Kills/Weapon”).Expand(“Kills/Creature”)

where player.ID == Int32.Parse(Request[“playerId”])

select player;

ViewModels.Player p = q.FirstOrDefault();

StringBuilder sb = new StringBuilder();

sb.Append(p.Name + “<br/>”);

foreach (ViewModels.Kill kill in p.Kills)

{ sb.AppendFormat(“ Killed {1} with a {2} ({3})<br/>”,

kill.KillTime, kill.Creature.Name, kill.Weapon.Name, kill.Notes);

}

placeHolder.Controls.Add(new LiteralControl(sb.ToString()));

Trang 5

The calls to Expand() differ slightly from the previous samples The beauty of WCF Data

Service relationship expansion is that we can expand multiple levels So, not only can I

ask for a player, but I can also ask for that player’s kills, and, for each of those kills I can

obtain the weapon and creature used for that kill All this comes over the wire as a single

response; I don’t need to make multiple calls to get all the referential and lookup data.

Finally, the code calls FirstOrDefault() to actually send the query over the wire The

DataServiceContext class is so powerful that it knows how to convert the information in

the payload from the service into the data type required by the client When we create the

query, we pass it the type ViewModels.Player This is a Plain Old CLR Object (POCO) class

that we created that is little more than a code-based schema that tells the service how to

shape the response Listing 21.5 shows the code for the ViewModels.Player class and the

ViewModels.Kill class

LISTING 21.5 The ViewModels.Player Class and ViewModels.Kill Class

public class Player

{

public int ID { get; set; }

public string Name { get; set; }

public ICollection<Kill> Kills { get; set; }

}

public class Kill

{

public int ID { get; set; }

public int PlayerID { get; set; }

public int CreatureID { get; set; }

public DateTime KillTime { get; set; }

public string Notes { get; set; }

public Player Player { get; set; }

public Creature Creature { get; set; }

public Weapon Weapon { get; set; }

}

If you find that you create or refresh a client-side proxy every time the entity definitions

change on the service, creating your own view models might be a better idea This gives

you the added benefit of placing all these view models in a shared assembly that can be

used by multiple web applications or multiple service clients

Another advantage of the view model approach using the raw data service context is that

you can decorate these view models with any attributes you want, including those that

might be compatible with various client-side validation frameworks or other custom uses

for your ASP.NET or ASP.NET MVC applications With an auto-generated proxy, any changes

you make or decorations you add can be wiped out every time you refresh the reference

CHAPTER 21 Data Access with WCF Data Services

Trang 6

The real power here is that you can choose whether you want to access a raw data service

context or one created by adding a service reference Which option you choose and when

should be based on how frequently your service entities change and how much extra

functionality you want to put into the client-side objects

Summary

In this chapter you learned a little bit about WCF Data Services and the OData protocol

There are countless strategies for getting data in and out of your ASP.NET application

ranging from traditional raw SQL access to service-based data access such as WCF Data

Services

WCF Data Services provide developers with a platform-independent way of querying and

manipulating data without needing to know the specifics of the underlying schema or

even the underlying data store

Whether you choose to access a WCF Data Service using a raw data context, a generated

data context wrapper, or even through a raw HTTP request, these services provide

incredi-ble value and can dramatically increase productivity, code reuse, and even scalability of

distributed applications

For more information on WCF Data Services, check out MSDN’s page for them at

http://msdn.microsoft.com/en-us/data/bb931106.aspx

Trang 7

This page intentionally left blank

Trang 8

Using the Navigation

Controls

Understanding Site Maps Using the SiteMapPath Control Using the Menu Control

Using the TreeView Control Building a SQL Hierarchical Data Source Control Summary

In this chapter, you learn how to use the SiteMapPath,

Menu, and TreeView controls You can use all three of these

controls to enable users to navigate your website

Furthermore, you can use the Menu and TreeView controls

independently of website navigation You can bind these

two controls to other data sources such as XML documents

or database data

This chapter explores different methods of binding the Menu

and TreeView controls to different data sources and shows

you how to format the rendered output of both of these

controls You also learn how to take advantage of Ajax

when working with the TreeView control

In the final section, we build a SqlHierarchicalDataSource

control, which enables you to bind controls such as the

TreeView and Menu controls to hierarchical database data

Understanding Site Maps

Before you learn about the navigation controls, you first

need to understand Site Maps All three navigation controls

use Site Maps to retrieve navigation information A Site

Map enables you to represent the navigational relationships

between the pages in an application, independent of the

actual physical relationship between pages as stored in the

file system

Site Maps use the provider model In the next chapter, you

learn how to create custom Site Map providers to store Site

Maps in custom data stores such as database tables The

examples in this chapter take advantage of the default XML

Site Map provider, which enables you to store a Site Map in

an XML file

Trang 9

CHAPTER 22 Using the Navigation Controls

By default, the navigation controls assume the existence of an XML file named

Web.sitemap, which is located in the root of your application

For example, Listing 22.1 contains a simple Site Map

LISTING 22.1 Web.sitemap

<?xml version=”1.0” encoding=”utf-8” ?>

<siteMap xmlns=”http://schemas.microsoft.com/AspNet/SiteMap-File-1.0” >

<siteMapNode

url=”~/Default.aspx”

title=”Home”

description=”The home page of the Website”>

<! Product Nodes >

<siteMapNode

title=”Products”

description=”Website products”>

<siteMapNode

url=”~/Products/FirstProduct.aspx”

title=”First Product”

description=”The first product” />

<siteMapNode

url=”~/Products/SecondProduct.aspx”

title=”Second Product”

description=”The second product” />

</siteMapNode>

<! Services Nodes >

<siteMapNode

title=”Services”

description=”Website services”>

<siteMapNode

url=”~/Service/FirstService.aspx”

title=”First Service”

description=”The first service” />

<siteMapNode

url=”~/Products/SecondService.aspx”

title=”Second Service”

description=”The second service” />

</siteMapNode>

</siteMapNode>

Trang 10

A Site Map file contains <siteMapNode> elements There can be only one top-level node

In the case of Listing 22.1, the top-level node represents the website’s home page

A <siteMapNode> supports three main attributes:

title—A brief title that you want to associate with a node

description—A longer description that you want to associate with a node

url—A URL that points to a page or other resource

The url attribute is not required Both the Products and Services nodes do not include a

url attribute because these nodes do not represent pages to which you can navigate

Each <siteMapNode> can contain any number of child nodes In Listing 22.1, both the

Products and Services nodes include two child nodes

The Site Map in Listing 22.1 represents a website that has the following folder and page

structure:

Default.aspx

Products

FirstProduct.aspx

SecondProduct.aspx

Services

FirstService.aspx

SecondService.aspx

The navigational structure of a website as represented by a Site Map is not required to

have any relationship to the navigational structure of a website as stored in the file

system You can create any relationship between the nodes in a Site Map that you want

The SiteMapPath control enables you to navigate easily to any parent page of the current

page It displays the standard breadcrumb trail that you see on many popular websites (see

Figure 22.1)

You can use the SiteMapPath control simply by declaring the control in a page The

control automatically uses the Web.sitemap file located in the root of your application For

example, the page in Listing 22.2 includes the SiteMapPath control (see Figure 22.2)

Ngày đăng: 06/07/2014, 18:20

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN