使用 OData 动作实现服务器端行为

开放式数据协议 (OData) 可以在数据服务上定义“服务动作”。 服务动作是在数据服务上定义的特殊操作。 通过服务动作可将行为注入到本来以数据为中心的模型中。 通过服务动作可调用 OData 中的业务逻辑,该逻辑必须在这里绑定到某个给定资源。 服务动作在以下方面不同于基于终结点的常规服务操作

  • 绑定到资源

    与固定终结点上定义的服务操作不同,服务动作通常绑定到资源、实体集(源)或单个实体。 这些资源称为“绑定参数”。 在 WCF Data Services 中,绑定参数只能是实体类型或实体类型的集合。 也可以向服务动作提供非绑定参数。 但是,这些参数只能是基元类型、复杂类型,或者是基元类型或复杂类型的集合。 当服务动作绑定到资源时,服务动作在实体序列化中作为动作资源公开。

  • 有副作用

    服务动作调用的业务逻辑会影响系统,如更改数据或状态,或者调用某个其他业务流程。 因为服务动作总是有副作用,所以只能使用 POST 请求调用它们。 与服务操作不同,非绑定参数在主体消息中提供给服务动作,而不是在 URI 中。 这些非绑定参数在请求的主体中作为 JavaScript 表示法 (JSON) 编码值提供。

  • 不可进一步组合

    服务动作可以有与服务操作相同的返回类型。 但是,与服务操作不同的是,动作不可进一步组合。 这意味着,系统查询选项不可应用于服务动作。

我们将一部数字电影作为资源,对于数字电影,您可能需要完成许多事宜:签出、评级/评论或签入。 这些是用于管理数字电影的 WCF 数据服务可能实现的所有动作示例。 动作在 OData 响应中描述,而此响应包含对其调用此动作的资源。 当用户请求表示数字电影的资源时,从 WCF 数据服务返回的响应将包含有关可用于该资源的动作的信息。 动作的可用性可能取决于数据服务或资源的状态。 例如,一旦数字电影已被签出,其他用户就无法签出。 客户只需指定 URL 即可调用动作。 例如,http://MyServer/MovieService.svc/Movies(6) 标识一部特定的数字电影,而 http://MyServer/MovieService.svc/Movies(6)/Checkout 将对这部特定电影调用此动作。 动作使您能够公开服务模型,但不必公开数据模型。 继续探讨此电影服务示例,您可能希望允许用户对电影评级,但不能直接将评级数据公开为资源。 您可以实现评级动作,以使用户能够对电影评级,但不能直接将评级数据作为资源进行访问。

实现动作

若要实现服务动作,您必须实现 IServiceProviderIDataServiceActionProviderIDataServiceInvokable 接口。 IServiceProvider 使 WCF 数据服务能够获得您的 IDataServiceActionProvider 实现。 IDataServiceActionProvider 使 WCF 数据服务能够创建、查找、描述和调用服务动作。 IDataServiceInvokable 使您能够调用用于实现服务动作行为的代码并获得结果(如果有)。 请记住,WCF 数据服务是“每次调用”的 WCF 服务,也即,每次调用此服务时,都会创建此服务的一个新实例。 确保创建此服务时不执行多余的任务。

IServiceProvider

IServiceProvider 包含一个名为 GetService(Type) 的方法。 WCF 数据服务调用此方法来检索一些服务提供程序,包括元数据服务提供程序和数据服务动作提供程序。 当要求提供数据服务动作提供程序时,请返回您的 IDataServiceActionProvider 实现。

IDataServiceActionProvider

IDataServiceActionProvider 中包含的方法使您可以检索有关可用动作的信息。 当您实现 IDataServiceActionProvider 时,您是在通过动作为您的服务扩展元数据(而元数据是由服务的 IDataServiceMetadataProvider 实现定义的),并且针对这些动作相应地处理调度。

AdvertiseServiceAction

系统调用 AdvertiseServiceAction(DataServiceOperationContext, ServiceAction, Object, Boolean, ODataAction%) 以确定什么动作可用于指定的资源。 仅针对并非始终可用的动作才调用此方法。 该方法用于根据所请求的资源状态或服务状态,检查动作是否应包含在 OData 响应中。 如何实现这一检查完全由您决定。 如果计算可用性的代价很高,并且当前资源处于源中,则可以跳过此检查并公布动作。 如果要返回的当前资源是源的一部分,则 inFeed 参数设置为 true。

CreateInvokable

系统调用 CreateInvokable(DataServiceOperationContext, ServiceAction, array<Object[]) 以创建 IDataServiceInvokable,其中包含一个委托,该委托封装用于实现此动作的行为的代码。 此时将创建 IDataServiceInvokable 实例,但不会调用该动作。 WCF 数据服务动作具有副作用,需要与更新提供程序结合使用才能将这些更改保存到磁盘。 从更新提供程序的 SaveChanges() 方法调用 Invoke() 方法。

GetServiceActions

此方法返回 ServiceAction 实例的集合,这些实例表示由 WCF 数据服务公开的所有动作。 ServiceAction 是动作的元数据表示形式,包括动作名称、其参数和其返回类型等此类信息。

GetServiceActionsByBindingParameterType

此方法返回可绑定到指定绑定参数类型的所有 ServiceAction 实例的集合。 换句话说,也就是所有可作用于指定资源类型(也称为绑定参数类型)的 ServiceAction。当服务返回资源以便包含有关可针对该资源调用的动作的信息时,使用此方法。 此方法应只返回可绑定到确切绑定参数类型(无派生类型)的动作。 此方法针对遇到的每个请求和每种类型调用一次,结果由 WCF 数据服务进行缓存。

TryResolveServiceAction

此方法搜索指定的 ServiceAction,如果找到了 ServiceAction,则返回 true。 如果找到,则在 serviceAction out 参数中返回 ServiceAction

IDataServiceInvokable

此接口提供执行 WCF 数据服务动作的方法。 当实现 IDataServiceInvokable 时,您应负责三件事:

  1. 捕获并可能封送处理参数

  2. 将参数调度到在调用 Invoke() 时实际实现动作的代码

  3. 存储来自 Invoke() 的任何结果,以便可以使用 GetResult() 检索这些结果

参数可作为标记进行传递。 这是因为可以编写与表示资源的标记结合使用的数据服务提供程序,如果是这种情况,则您可能需要将这些标记转换(封送处理)为实际资源,然后才能调度到实际动作。 在封送处理此参数之后,此参数必须处于可编辑状态,以便将在调用动作时对资源所做的任何更改保存并写入到磁盘中。

此接口需要两个方法:Invoke 和 GetResult。 Invoke 调用用于实现动作行为的委托,而 GetResult 返回此动作的结果。

服务动作访问控制

在 WCF 数据服务 中,服务动作在服务范围的可见性由 IDataServiceConfiguration 类的 SetServiceActionAccessRule(String, ServiceActionRights) 方法控制,其方式与使用 SetServiceOperationAccessRule(String, ServiceOperationRights) 方法控制服务操作可见性一样。

服务动作的元数据定义

与服务操作一样,服务动作在服务元数据中定义为 FunctionImport 元素。 服务动作 FunctionImport 包含零个或零个以上 Parameter 元素,这些元素表示绑定参数与非绑定参数。 此外,FunctionImport 的以下特性定义服务动作的行为:

  • IsSideEffecting

    因为服务动作总是有副作用,所以此特性始终为 true。

  • IsBindable

    服务动作通常(但不总是)绑定到资源。 当此特性为 true 时,第一个参数必须是实体类型或实体集合。

  • IsComposable

    因为服务动作不支持额外的查询组合,所以此特性始终为 false。

调用 WCF 数据服务动作

可以使用 HTTP POST 请求来调用动作。 URL 指定资源(后跟动作名称)。 参数在请求的正文中传递。 例如,假设有一个名为 MovieService 的服务,该服务公开了一个名为 Rate 的动作。 您可以使用下面的 URL 针对特定电影调用 Rate 动作:

http://MovieServer/MovieService.svc/Movies(1)/Rate

Movies(1) 指定您要评级的电影,而 Rate 指定 Rate(评级)动作。 评级的实际值将位于 HTTP 请求的正文中,如以下示例所示:

POST http://MovieServer/MoviesService.svc/Movies(1)/Rate HTTP/1.1 
Content-Type: application/json 
Content-Length: 20 
Host: localhost:15238
{ 
   "rating": 4 
}

备注

上面的示例代码只能与支持轻型 JSON 的 WCF Data Services 5.2 和更高版本结合使用。如果使用 WCF 数据服务的更低版本,您必须指定 json 详细内容类型,如下所示:application/json;odata=verbose。

此外,您也可以使用 WCF 数据服务客户端调用动作,如下面的代码段所示。

MoviesModel context = new MoviesModel (new Uri("http://MyServer/MoviesService.svc/"));
            //...
            context.Execute(new Uri("http://MyServer/MoviesService.svc/Movies(1)/Rate"), "POST", new BodyOperationParameter("rating",4) );         

在上面的代码段中,通过使用 Visual Studio 将服务引用添加到 WCF 数据服务,从而生成了 MoviesModel 类。

请参阅

概念

开发和部署 WCF 数据服务

自定义数据服务提供程序(WCF 数据服务)

其他资源

WCF 数据服务

数据服务 (WCF Data Services)