[notice:图片上传不好使,等好使了我再加上]
最近开始学习RIAService,先说安装。本来今天刚在博客园上看到一篇有讲RIA安装的。但好像很复杂,要先把SL等都卸载了才行。但是我安装的时候超级简单,首先在下载安装包(点此处),然后一路Next下来就好了。我也不知道为什么,我的环境是Win7+VS2008SP1+Silverlight3+Experssion Studio3。
这篇文章的内容基本来是RiaServiceOverviewPreview文档,已经有牛人在园子做翻译了,如:
微软RIA服务2009年7月预览版官方手册第1节(翻译:戴石麟)
微软RIA服务2009年7月预览版官方手册第2节(翻译:戴石麟)
Microsoft .NET RIA Services快速上手
我这里的东西是紧接微软RIA服务2009年7月预览版官方手册第2节(翻译:戴石麟)的。虽然他马上肯定就要翻译,但我也献个丑。不要期望有什么我的心得,都是从文档里学的。
言归正转,首先我们建立一个依赖于RIA Link的Sliverlight应用程序GeneratedCode。其中SL工程是client端(client-tier),Web工程是server端(mid-tier).
现在我们来模拟整个Code-Generation(CG,我自己的简写,让我想起了GC)过程。
1.在server建立一个数据实体Person类,有两个属性:FristName,LastName,我把它放在Server的Data文件夹下(Persion.cs):
1
public
partial
class
Person
2

{
3
[Key]
4
public string FristName
{ get; set; }
5
6
[Key]
7
public string LastName
{ get; set; }
8
9
}
10
为了识别KeyAttribute属性,将要引用System.ComponentModel.DataAnnotations.dll并引用此命名空间,[Key]的作用唯一标识实体对象的值。
2.在server端建立一个示例数据的生成器,用于得到具体的数据(PersionData.cs)
PersonData
1
public class PersonData
2

{
3
4
List<Person> persons = new List<Person>(
5
new Person[]
6
{
7
new Person()
{ FristName = "JR", LastName = "Smith" },
8
new Person()
{ FristName="Jack",LastName="Chan"}
9
});
10
public IList<Person> Persons
11

{
12
get
13
{
14
return persons;
15
}
16
}
17
18
}
19
3.好了,现在我们来建立RiaService(PersonService.cs)。我们要把服务端的数据的属性,方法暴露给服务器端,中间,需要一个服务和一个代理,其中的服务派生自DomainService,位于服务端。;
Code
1
namespace GeneratedCode.Web.Data
2

{
3
[EnableClientAccess]
4
public class PersionService:DomainService
5
{
6
private PersonData _personData = new PersonData();
7
8
public IEnumerable<Person> GetPersons()
9
{
10
return _personData.Persons;
11
}
12
}
13
}
14
这里要注意两点:1)该类应继承自DoaminService(位于System.Web.DomainServices下)以被识别为RIA服务。2)该类要增加[EnableClientAccess]属性,以便客户端能够访问该类以及方法(位于Syste.Web.Ria下)
4.现在我们就可以看看RIA的CG功能如何了,Builde整个解决方案,并选中GeneratedCode工程,然后[Project]->[Show All Files]把生成的文件显示出来(注意:一定要选中工程,选中解决方案是不行的,会找不到Show All Files菜单。让我们来看看都生成了些什么:
可以看到在GeneratedCode工程(Silverlight工程)中生成了一个名叫Generated_code的文件夹(bin,obj不关注),并且生成了一个名叫GeneratedCode.Web.g.cs的文件名。这是一个以你的Web工程的名字开头的的cs文件(Web工程名.g.cs),g代表这是自动生成的文件(Generate code),打开看一看里面的内容(代码过长,在最后):
1)首先是一个继承自RiaContextBase的RiaContext类,我们暂不管他
2)然后是一个继承自DomainContext的PersonContext类,他是重点,这就是之前所说的客户端于服务端(DomainService)的代理,他有三个构造函数
(1)PersionContext():默认构造函数,用默认的数据服务Uri
(2)public PersionContext(Uri serviceUri) : 用一个指定的数据服务Uri
(3)public PersionContext(DomainClient domainClient) : 用一个指定的DomainClient实例构造
接着往下看,我们看到了什么?没错是:
Code
1
public EntityList<Person> Persons
2

{
3
get
4
{
5
return base.Entities.GetEntityList<Person>();
6
}
7
}
8
public EntityQuery<Person> GetPersonsQuery()
9

{
10
return base.CreateQuery<Person>("GetPersons", null, false, true);
11
}
显然,上速两个函数就把PersonService的方法“代理”过来了。这就意味着,在客户端我们可以用PersonContext的方法最终调用到PersonService的方法,然后得到数据。、
(4)我们再往下看,看到了一个继承自实体Entity的Person类(实体代理类)。里面包含了Person类的属性,并加上了[Key()]和[DataMember]属性。此类是实体类找客户端代理实体类,与实体类同名,包含了实体因所有的公开属.
5.最后我们来总结一下RIAService的CG:
1)哪些会CG
(1)所有服务端引用的程序集都会被分析
(2)所有继承自DomainService和标记主[EnableClientAccess]属性的类也会被分析
(3)(2)中的那样的类的所有公有方法也会被分析,以决定将在客户端上以一种什么样的实体形式来呈现
2)怎么CG
(1)实体代理类(客户端继承自Entity的Person类)会与实体类(服务端的Person类)共用同一个namespace,
(2)实体代理类与实体类的名称相同(都为Person)
(3)实体类的每个公有属性都会在实代理类暴露出来(FristName,LastName)
(4)实体类用户定义的属性都会在实体代理类得以呈现(本文未提及)
6.结语
好了,第一部分的CG就到这里吧,敬请拍砖,下次将是Metadata与Shared Code的CG。
Code
1
//------------------------------------------------------------------------------
2
// <auto-generated>
3
// This code was generated by a tool.
4
// Runtime Version:2.0.50727.4927
5
//
6
// Changes to this file may cause incorrect behavior and will be lost if
7
// the code is regenerated.
8
// </auto-generated>
9
//------------------------------------------------------------------------------
10
11
namespace GeneratedCode
12

{
13
using System;
14
using System.Collections.Generic;
15
using System.ComponentModel;
16
using System.ComponentModel.DataAnnotations;
17
using System.Linq;
18
using System.Web.Ria.Data;
19
using System.Windows.Ria.Data;
20
21
22
/**//// <summary>
23
/// Context for the RIA application.
24
/// </summary>
25
/// <remarks>
26
/// This context extends the base to make application services and types available
27
/// for consumption from code and xaml.
28
/// </remarks>
29
public sealed partial class RiaContext : System.Windows.Ria.RiaContextBase
30
{
31
32
Extensibility Method Definitions#region Extensibility Method Definitions
33
34
/**//// <summary>
35
/// This method is invoked from the constructor once initialization is complete and
36
/// can be used for further object setup.
37
/// </summary>
38
partial void OnCreated();
39
40
#endregion
41
42
43
/**//// <summary>
44
/// Initializes a new instance of the RiaContext class.
45
/// </summary>
46
public RiaContext()
47
{
48
this.OnCreated();
49
}
50
51
/**//// <summary>
52
/// Gets the context that is registered as a lifetime object with the current application.
53
/// </summary>
54
/// <exception cref="InvalidOperationException"> is thrown if there is no current application,
55
/// no contexts have been added, or more than one context has been added.
56
/// </exception>
57
/// <seealso cref="Application.ApplicationLifetimeObjects"/>
58
public new static RiaContext Current
59
{
60
get
61
{
62
return ((RiaContext)(System.Windows.Ria.RiaContextBase.Current));
63
}
64
}
65
}
66
}
67
namespace GeneratedCode.Web.Data
68

{
69
using System;
70
using System.Collections.Generic;
71
using System.ComponentModel;
72
using System.ComponentModel.DataAnnotations;
73
using System.Linq;
74
using System.Runtime.Serialization;
75
using System.Web.Ria.Data;
76
using System.Windows.Ria.Data;
77
78
79
public sealed partial class PersionContext : DomainContext
80
{
81
82
Extensibility Method Definitions#region Extensibility Method Definitions
83
84
/**//// <summary>
85
/// This method is invoked from the constructor once initialization is complete and
86
/// can be used for further object setup.
87
/// </summary>
88
partial void OnCreated();
89
90
#endregion
91
92
93
/**//// <summary>
94
/// Default constructor.
95
/// </summary>
96
public PersionContext() :
97
this(new HttpDomainClient(new Uri("DataService.axd/GeneratedCode-Web-Data-PersionService/", System.UriKind.Relative)))
98
{
99
}
100
101
/**//// <summary>
102
/// Constructor used to specify a data service URI.
103
/// </summary>
104
/// <param name="serviceUri">
105
/// The PersionService data service URI.
106
/// </param>
107
public PersionContext(Uri serviceUri) :
108
this(new HttpDomainClient(serviceUri))
109
{
110
}
111
112
/**//// <summary>
113
/// Constructor used to specify a DomainClient instance.
114
/// </summary>
115
/// <param name="domainClient">
116
/// The DomainClient instance the DomainContext should use.
117
/// </param>
118
public PersionContext(DomainClient domainClient) :
119
base(domainClient)
120
{
121
this.OnCreated();
122
}
123
124
public EntityList<Person> Persons
125
{
126
get
127
{
128
return base.Entities.GetEntityList<Person>();
129
}
130
}
131
132
/**//// <summary>
133
/// Returns an EntityQuery for query operation 'GetPersons'.
134
/// </summary>
135
public EntityQuery<Person> GetPersonsQuery()
136
{
137
return base.CreateQuery<Person>("GetPersons", null, false, true);
138
}
139
140
protected override EntityContainer CreateEntityContainer()
141
{
142
return new PersionContextEntityContainer();
143
}
144
145
internal sealed class PersionContextEntityContainer : EntityContainer
146
{
147
148
public PersionContextEntityContainer()
149
{
150
this.CreateEntityList<Person>(EntityListOperations.None);
151
}
152
}
153
}
154
155
[DataContract(Namespace="http://schemas.datacontract.org/2004/07/GeneratedCode.Web.Data")]
156
public sealed partial class Person : Entity
157
{
158
159
private string _fristName;
160
161
private string _lastName;
162
163
Extensibility Method Definitions#region Extensibility Method Definitions
164
165
/**//// <summary>
166
/// This method is invoked from the constructor once initialization is complete and
167
/// can be used for further object setup.
168
/// </summary>
169
partial void OnCreated();
170
partial void OnFristNameChanging(string value);
171
partial void OnFristNameChanged();
172
partial void OnLastNameChanging(string value);
173
partial void OnLastNameChanged();
174
175
#endregion
176
177
178
/**//// <summary>
179
/// Default constructor.
180
/// </summary>
181
public Person()
182
{
183
this.OnCreated();
184
}
185
186
[DataMember()]
187
[Key()]
188
public string FristName
189
{
190
get
191
{
192
return this._fristName;
193
}
194
set
195
{
196
if ((this._fristName != value))
197
{
198
this.ValidateProperty("FristName", value);
199
this.OnFristNameChanging(value);
200
this.RaiseDataMemberChanging("FristName");
201
this._fristName = value;
202
this.RaiseDataMemberChanged("FristName");
203
this.OnFristNameChanged();
204
}
205
}
206
}
207
208
[DataMember()]
209
[Key()]
210
public string LastName
211
{
212
get
213
{
214
return this._lastName;
215
}
216
set
217
{
218
if ((this._lastName != value))
219
{
220
this.ValidateProperty("LastName", value);
221
this.OnLastNameChanging(value);
222
this.RaiseDataMemberChanging("LastName");
223
this._lastName = value;
224
this.RaiseDataMemberChanged("LastName");
225
this.OnLastNameChanged();
226
}
227
}
228
}
229
230
public override object GetIdentity()
231
{
232
return EntityKey.Create(this._fristName, this._lastName);
233
}
234
}
235
}
236