Data Service - 2. 数据服务 (1)

[ 2009-04-23 11:30:44 | 作者: yuhen ]
字号: | |
1. 服务操作

除了公开 "数据" 外,服务通常还包含一些基本的应用逻辑。比如 User Service 通常会包含 Register,毕竟 Password 加密算法不会被其他服务所知晓和引用。
public class Test : DataService<TestEntities>
{
    public static void InitializeService(IDataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);
        config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
    }

    [WebInvoke(Method="Post")]
    public void Register(string username, int age)
    {
        this.CurrentDataSource.AddToUsers(new User { Name = username, Age = age });
        this.CurrentDataSource.SaveChanges();
    }
}

为了便于测试,我们可以用 Fiddler 的 Request Builder 功能来测试 Data Service。

uploads/200904/23_112611_1.png


注意选择 Post 方式,而且不能省略单引号。

SetServiceOperationAccessRule 用于设定服务方法的权限,我们可以直接给出具体的方法名或用 "*" 表示全部方法。和 WCF RESTful 相同,WebGet 和 WebInvoke 特性用于设定请求方式。

Data Service 对服务操作有一些具体的限制。
  • 此方法只能接受 [in] 参数。如果对参数进行定义,则每个参数的类型必须为基元类型。
  • 此方法必须返回 void、IEnumerable<T>、IQueryable<T>、T 或基元类 (如整数或字符串)。T 必须为一个类,此类表示数据服务将公开的数据模型中的某个实体类型。若要支持查询选项(如排序、分页和筛选),服务操作方法应返回 IQueryable<T>。
  • 必须用 [WebGet] 或 [WebInvoke] 属性为此方法添加批注。[WebGet] 使您能够通过使用 GET 请求调用此方法;[WebInvoke] 使您能够通过使用 PUT、POST 或 DELETE 请求调用此方法。
  • 可以用 SingleResultAttribute 为服务操作添加批注,指定此方法的返回值是一个实体而不是一个实体集。这一区别确定了生成的响应序列化。例如,当使用 AtomPub 序列化时,单个资源类型实例将表示为一个 entry 元素,而单个实例集将表示为一个 feed 元素。
我们试着写一个查询方法。
[WebGet]
public IQueryable<User> Users2(int minAge)
{
    return this.CurrentDataSource.Users.Where(u => u.Age >= minAge);
}

Data Service 通过判断 Request Accept 来决定返回格式。我们返回 JSON 结果。

uploads/200904/23_112616_2.png

{
    "d": [
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(5)",
                "type": "TestModel.User"
            },
            "Id": 5,
            "Name": "user5",
            "Age": 14,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(5)/UserDetail"
                }
            }
        },
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(6)",
                "type": "TestModel.User"
            },
            "Id": 6,
            "Name": "user6",
            "Age": 18,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(6)/UserDetail"
                }
            }
        }
    ]
}

我们还可以添加查询选项,比如排序。

http://localhost:2394/Test.svc/Users2?minAge=14&$orderby=Age%20desc
{
    "d": [
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(6)",
                "type": "TestModel.User"
            },
            "Id": 6,
            "Name": "user6",
            "Age": 18,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(6)/UserDetail"
                }
            }
        },
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(5)",
                "type": "TestModel.User"
            },
            "Id": 5,
            "Name": "user5",
            "Age": 14,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(5)/UserDetail"
                }
            }
        }
    ]
}

注意:Data Service 对 URI 中的参数和属性名称区分大小写。

2. 侦听器

所谓侦听器就是 Data Service 允许我们截获请求,并添加自定义逻辑的一种手段。通常用于添加一些附加规则或者进行访问身份验证。
[QueryInterceptor("Users")]
public Expression<Func<User, bool>> FilterUser()
{
    return u => u.Name != "user1";
}

当请求 http://localhost:2394/Test.svc/Users 时,我们会发现 user1 被过滤掉。这种方式很有用,比如过滤掉管理员信息。
{
    "d": [
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(2)",
                "type": "TestModel.User"
            },
            "Id": 2,
            "Name": "user2",
            "Age": 11,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(2)/UserDetail"
                }
            }
        },
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(3)",
                "type": "TestModel.User"
            },
            "Id": 3,
            "Name": "user3",
            "Age": 12,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(3)/UserDetail"
                }
            }
        },
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(4)",
                "type": "TestModel.User"
            },
            "Id": 4,
            "Name": "user4",
            "Age": 13,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(4)/UserDetail"
                }
            }
        },
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(5)",
                "type": "TestModel.User"
            },
            "Id": 5,
            "Name": "user5",
            "Age": 14,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(5)/UserDetail"
                }
            }
        },
        {
            "__metadata": {
                "uri": "http://localhost:2394/Test.svc/Users(6)",
                "type": "TestModel.User"
            },
            "Id": 6,
            "Name": "user6",
            "Age": 18,
            "UserDetail": {
                "__deferred": {
                    "uri": "http://localhost:2394/Test.svc/Users(6)/UserDetail"
                }
            }
        }
    ]
}

我们可以用类似下面这样的方式来验证访问者信息,以便决定返回策略。
[QueryInterceptor("Users")]
public Expression<Func<User, bool>> FilterUser()
{
    return u => HttpContext.Current.Request.UserHostAddress == "127.0.0.1";
}

当然,实际的验证策略可能是用户身份信息。 还有就是查询侦听器不能包含参数。

另外一种侦听器是针对修改行为的。
[ChangeInterceptor("Users")]
public void OnUserChange(User user, UpdateOperations action)
{
    if (action == UpdateOperations.Add && user.Name.ToLower().Contains("admin"))
        throw new DataServiceException(400, "The user name is not allowed to contain 'admin' !");
}

当客户端增加一个包含 "admin" 字符串的用户时,将触发异常。

uploads/200904/29_095248_snap1.png
[最后修改由 yuhen, 于 2009-04-29 09:53:14]
评论Feed 评论Feed: http://www.rainsts.net/feed.asp?q=comment&id=807

这篇日志没有评论。

发表评论
表情图标
[smile] [confused] [cool] [cry]
[eek] [angry] [wink] [sweat]
[lol] [stun] [razz] [redface]
[rolleyes] [sad] [yes] [no]
[heart] [star] [music] [idea]
UBB代码
转换链接
表情图标
悄悄话
用户名:   密码:  
验证码 * 请输入验证码