Traduction▲
Cet article est la traduction la plus fidèle possible de l'article original de Brad Abrams, Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 8: WCF Based Data Source.
Source de données basée sur WCF▲
Encore des mises à jour sur ma présentation Mix09 intitulée « building business applications with Silverlight 3 ».
Vous pouvez regarder
La démo requiert les éléments suivants (tout est 100 % gratuit) :
- Visual Studio 2008 Express SP1 (qui comprend SQL Server 2008 Express) ;
- Silverlight 3 ;
- .NET RIA Services.
Vous pouvez, de plus, télécharger les fichiers de la démo complète…
Dans la démo originale, j'ai démontré comment obtenir vos données d'une base de données directement de la couche web. Plusieurs clients en entreprise ont trouvé que leurs systèmes sont plus maintenables et sécurisés s'ils isolent l'accès à la base de données derrière un ensemble de services web, éventuellement dans une zone démilitarisée (DMZ). Cela signifie qu'aucune application ne communique directement avec la base de données. Pourtant il y a souvent un besoin d'ajouter une validation propre à l'application et la logique de l'application aussi bien que la mise en forme et l'agrégation de données dans la couche web.
Pour démontrer ceci, j'ai refactorisé l'application exemple de la première partie de cette procédure pas à pas afin d'accéder à ses données d'un service WCF plutôt que EF directement. Remarquez que tous les autres bouts de l'interface utilisateur sont restés les mêmes.
Définir le service▲
Commençons par définir le service WCF. Dans une application réelle, ce service est défini par un autre groupe et vous êtes seulement autorisé à y accéder, pas à le modifier.
Faites un clic droit sur la solution et ajoutez un nouveau projet WCF Service Application. Je l'ai appelé MyApp.Service, mais vous pouvez choisir ce qui vous convient.
D'abord, nous créons un modèle Entity Framework pour notre base de données… Cela est fait exactement de la même manière que dans la deuxième partie, mais cette fois ça fait partie de notre Service plutôt que dans la couche web. La démo fonctionnerait exactement de la même manière qu'importe la source de données que vous utilisez… EF était juste facile pour moi afin de débuter, ce n'est pas nécessaire pour ce scénario, car nous encapsulons tout derrière une couche de services WCF.
Ensuite, nous définissons l'interface pour notre service
[ServiceContract]
public
interface
ISuperEmployeeService
{
[OperationContract]
IEnumerable<
SuperEmployee>
GetSuperEmployees
(
int
page);
[OperationContract]
SuperEmployee GetSuperEmployee
(
int
empId);
[OperationContract]
void
UpdateEmployee
(
SuperEmployee emp);
}
Ensuite nous l'implémentons.
public
IEnumerable<
SuperEmployee>
GetSuperEmployees
(
int
page)
{
using
(
var
context =
new
NORTHWNDEntities
(
)) {
var
q =
context.
SuperEmployeeSet
.
OrderBy
(
emp=>
emp.
EmployeeID)
.
Skip
(
page *
PageSize).
Take
(
PageSize);
return
q.
ToList
(
);
}
}
Remarquez qu'ici nous mettons en œuvre la pagination en prenant un paramètre de page. Après un bref inventaire des services réels sur le net, j'ai trouvé ceci comme étant un modèle très commun. C'est très facile avec EF d'accéder uniquement à la page de données que nous voulons.
Consommer le service▲
Maintenant consommons ce service depuis la couche web. La raison pour laquelle nous le faisons c'est d'obtenir tous les bénéfices des RIA Services en termes de logique de validation, etc., et être en mesure de personnaliser et de s'arroger les données afin que la vue soit tout juste à point pour le client.
D'abord, nous définissons un type SuperEmployee qui est façonné de manière tout juste à point pour le client. Dans cet exemple simple, je l'ai laissé à peu près le même que l'a renvoyé le service, mais vous pouvez utiliser n'importe quelle forme que vous souhaitez.
Remarquez que nous utilisons des attributs pour spécifier les différentes validations que nous voulons qui soient effectuées sur ces données sur le client ET la couche web.
public
class
SuperEmployee
{
[ReadOnly(true)]
[Key]
public
int
EmployeeID {
get
;
set
;
}
[RegularExpression(
"^(?:m|M|male|Male|f|F|female|Female)$"
,
ErrorMessage =
"Gender must be 'Male' or 'Female'"
)]
public
string
Gender {
get
;
set
;}
[Range(
0
,
10000
,
ErrorMessage =
"Issues must be between 0 and 1000"
)]
public
Nullable<
int
>
Issues {
get
;
set
;}
public
Nullable<
DateTime>
LastEdit {
get
;
set
;}
[Required]
[StringLength(
100
)]
public
string
Name {
get
;
set
;}
public
string
Origin {
get
;
set
;}
public
string
Publishers {
get
;
set
;}
public
string
Sites {
get
;
set
;}
}
Ajoutons maintenant une référence au service que nous venons tout juste de créer.
Faites un clic droit sur le projet et sélectionnez Ajouter une référence de service (Add Service Reference.
Maintenant nous modifions notre DomainService.
1
:
public
class
SuperEmployeeDomainService :
DomainService
2
:
{
3
:
SuperEmployeeServiceClient Context =
new
SuperEmployeeServiceClient
(
);
4
:
5
:
public
IQueryable<
SuperEmployee>
GetSuperEmployees
(
int
pageNumber)
6
:
{
7
:
return
this
.
Context.
GetSuperEmployees
(
pageNumber)
8
:
.
Where
(
emp =>
emp.
Issues >
100
)
9
:
.
OrderBy
(
emp =>
emp.
EmployeeID)
10
:
.
Select
(
emp =>
11
:
new
MyApp.
Web.
SuperEmployee
(
)
12
:
{
13
:
EmployeeID =
emp.
EmployeeID,
14
:
Gender =
emp.
Gender,
15
:
Issues =
emp.
Issues,
16
:
LastEdit =
emp.
LastEdit,
17
:
Name =
emp.
Name,
18
:
Origin =
emp.
Origin,
19
:
Publishers =
emp.
Publishers,
20
:
Sites =
emp.
Sites,
21
:
}
).
AsQueryable
(
);
22
:
}
Remarquez qu'à la ligne 1, nous n'avons plus besoin de dériver de EFDomainService, car il n'y a pas de code d'accès DAL dans la couche web maintenant que nous avons factorisé tout cela dans le service.
À la ligne 3, nous créons une instance du proxy de service web WCF.
À la ligne 5, vous pouvez voir que nous prenons un numéro de page- nous aurons besoin de passer cela depuis le client.
À la ligne 7, nous créons une simple requête LINQ pour modifier la forme des données que nous obtenons du service.
Dans le client Silverlight▲
Maintenant, pour consommer cela dans le client Silverlight c'est très facile… Nous apportons juste quelques modifications au Home.xaml que nous avons créé dans la deuxième partie…
1: <
riaControls
:
DomainDataSource
x
:
Name
=
"dds"
2
:
AutoLoad
=
"True"
3
:
QueryName
=
"GetSuperEmployeesQuery"
4
:
LoadSize
=
"20"
>
5:
6: <
riaControls
:
DomainDataSource.QueryParameters>
7: <
datagroup
:
ControlParameter
ParameterName
=
"pageNumber"
8
:
ControlName
=
"pager"
9
:
RefreshEventName
=
"PageIndexChanged"
10
:
PropertyName
=
"PageIndex"
>
11: </
datagroup
:
ControlParameter>
12:
13: </
riaControls
:
DomainDataSource.QueryParameters>
14:
15: <
riaControls
:
DomainDataSource.DomainContext>
16: <
App
:
SuperEmployeeDomainContext/>
17: </
riaControls
:
DomainDataSource.DomainContext>
18:
19: <
riaControls
:
DomainDataSource.GroupDescriptors>
20: <
datagroup
:
GroupDescriptor
PropertyPath
=
"Publishers"
/>
21: </
riaControls
:
DomainDataSource.GroupDescriptors>
22:
23:
24:
25: </
riaControls
:
DomainDataSource>
26:
Remarquez qu'à la ligne 7 nous obtenons le numéro de page de la méthode GetSuperEmployees() depuis le DataPager. Ceci est mis en place de manière telle que quand le DataPager change les pages, le DDS demande des données du serveur.
Si vous êtes attentif à toute la série de billets de blog, vous remarquerez que j'ai enlevé le tri et le filtrage pour cet exemple. J'ai fait cela parce qu'à la base vous êtes limité par l'expressivité de vos données en back-end. Si vos données en back-end ne prennent pas en charge le tri et le filtrage, alors il est difficile de le faire sur le client ! Vous pourriez faire de la mise en cache sur la couche web, mais c'est un sujet pour un autre jour.
Comme un exercice amusant, supposons que vous puissiez changer la définition du service WCF, comment ajouteriez-vous le filtrage ? Vous pourriez suivre exactement le même schéma que nous utilisons pour la pagination. Ajoutez un argument au service WCF, ajoutez le même à la méthode de requête GetSuperEmployees() sur le serveur, ensuite ajoutez un autre ControlParameter au DDS obtenant ses données à partir d'un contrôle sur le formulaire. Assez facile! Faites-moi savoir si vous l'essayez.
L'étape finale consiste à lier le DataPager à une collection « shim », juste pour le faire progresser.
1: <
data
:
DataPager
x
:
Name
=
"pager"
PageSize
=
"1"
Width
=
"379"
2
:
HorizontalAlignment
=
"Left"
3
:
DisplayMode
=
"FirstLastPreviousNext"
4
:
IsEnabled
=
"True"
5
:
IsTotalItemCountFixed
=
"False"
6
:
Margin
=
"0,0.2,0,0"
>
7: <
data
:
DataPager.Source>
8: <
paging
:
PagingShim
PageCount
=
"-1"
></
paging
:
PagingShim>
9: </
data
:
DataPager.Source>
10: </
data
:
DataPager>
Vous pouvez retrouver l'implémentation du PagingShim dans l'échantillon. (Merci à David Poll pour son aide dessus).
Appuyez sur F5, et nous avons quelque chose de cool ! Cela ressemble beaucoup à l'application précédente, mais celle-ci reçoit toutes ses données via WCF !
Conclusion▲
Cet article conclut la partie sur les sources de données basées sur WCF. La neuvième partie de cette série d'articles sera consacrée à POCO en tant que source de données et au fournisseur d'authentification.
Remerciements▲
Je tiens ici à remercier Brad Abrams de nous avoir autorisés à traduire son article.
Je remercie également ClaudeLELOUP pour sa relecture et ses propositions.