深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持
一、在ScriptManager中指定Profile Service的Path
在ASP.NET AJAX的客户端脚本中,如果没有使用Sys.Services.ProfileService.set_path方法来指定一个提供Profile Service的地址,就会使用默认的地址,它会使ASP.NET AJAX的Profile Service使用程序集中特定的类。一般来说,我们不需要手动调用Sys.Services.ProfileService.set_path方法,只需要在ScriptManager中指定即可。如下:
<ProfileService Path="CustomProfileService.asmx" />
</asp:ScriptManager>
打开页面后,可以在页面中发现如下的JavaScript代码:
出现“/”是因为我测试的页面在根目录下。因此,Profile Service就会使用指定的Web Service,而不是默认的Web Service类。
二、实现自己的Web Service类
指定了自己的Web Service类,自然就要实现自己的类了。事实上,我们要实现的就是3个方法。就这个方面来说,ASP.NET AJAX中Profile Service使用的默认的Web Service类Microsoft.Web.Profile.ProfileService是我们绝佳的参考。因此,我们在这里分析一下这些方法,对于我们的自定义工作是非常有帮助的。
可能需要注意的一点是,我们在实现这些方法时,从理论上来讲参数类型不用完全和Microsoft.Web.Profile.ProfileService中的方法完全相同。ASP.NET AJAX的能够根据参数的类型尽可能地将获得的JSON字符串转换成需要的类型。不过事实上,似乎Microsoft.Web.Profile.ProfileService里那些方法的参数选择已经是非常合理的。另外,由于客户端Profile Service代码不太容易修改(事实上客户端也不是不能扩展,最极端的情况,不就是我们自己实现一个ProfileService吗?),为了保持返回的JSON字符串能够被正确处理,这些方法的返回值一般来说可以不变。
1、GetAllPropertiesForCurrentUser方法
这个方法的作用是获得当前用户所有的Profile信息,它没有输入的参数,返回的JSON字符串形式如下:
'ZipCode' : ...,
'Address.City' : ...,
'Address.State' : ...
}
它通过GroupName.ProfileName的形式来表示Profile Group,Group中的每一个Profile需要分别列出,而“...”则表示对应Profile值的JSON字符串。
在Microsoft.Web.Profile.ProfileService里,这个方法的代码如下:
public IDictionary<string, object> GetAllPropertiesForCurrentUser()
{
ProfileService.CheckProfileServicesEnabled();
return ProfileService.GetProfile(HttpContext.Current, null);
}
2、GetPropertiesForCurrentUser方法
这个方法的作用是获得当前用户指定的Profile信息,它的输入JSON字符串形式如下:
它的返回值的JSON字符串和GetAllPropertiesForCurrentUser相同,就不再赘述了。
在类中,这个方法的代码如下:
public IDictionary<string, object> GetPropertiesForCurrentUser(string[] properties)
{
ProfileService.CheckProfileServicesEnabled();
return ProfileService.GetProfile(HttpContext.Current, properties);
}
可以看到,GetAllPropertiesForCurrentUser和GetPropertiesForCurrentUser中都是使用了ProfileService.GetProfile静态方法来获得结果的,我们来仔细看一下这个方法的实现。如下:
1 internal static IDictionary<string, object> GetProfile(HttpContext context, string[] properties)
2 {
3 // 当前用户的Profile
4 ProfileBase profile = context.Profile;
5
6 // 如果没有profile,则返回null
7 if (profile == null)
8 {
9 return null;
10 }
11
12 // 作为结果返回的字典
13 IDictionary<string, object> dictResult = new Dictionary<string, object>();
14
15 // 如果properties为null,表示需要返回所有的参数
16 if (properties == null)
17 {
18 // 枚举web.config中注册的每一个Profile属性设置
19 foreach (SettingsProperty property in ProfileBase.Properties)
20 {
21 // 获得Profile属性名称
22 string name = property.Name;
23
24 // 如果web.config配置文件里没有定义ReadAccessProperties,
25 // 或者该Profile属性被定义在ReadAccessPropeties中。
26 if ((ProfileService._allowedGet != null) && ProfileService._allowedGet.ContainsKey(name))
27 {
28 // 则准备输出
29 dictResult.Add(name, profile[name]);
30 }
31 }
32
33 // 返回结果
34 return dictResult;
35 }
36
37 // 枚举参数的每一项,它们是需要输出的Profile信息
38 foreach (string prop in properties)
39 {
40 // 如果web.config配置文件里没有定义ReadAccessProperties,
41 // 或者该Profile属性被定义在ReadAccessPropeties中。
42 if ((ProfileService._allowedGet != null) && ProfileService._allowedGet.ContainsKey(prop))
43 {
44 // 则准备输出
45 dictResult.Add(prop, profile[prop]);
46 }
47 }
48
49 // 返回结果
50 return dictResult;
51 }
这个方法还是非常容易理解和编写的,不需要涉及到任何序列化或者反序列化操作,那些工作完全由ASP.NET的Web Service Access机制代为完成了。
3、SetPropertiesForCurrentUser方法
这个方法的作用是保存当前用户的Profile信息,它的输入JSON字符串形式如下:
'ZipCode' : ...,
'Address.City' : ...,
'Address.State' : ...
}
而它返回的则是正确保存的Profile数量。代码如下:
public int SetPropertiesForCurrentUser(IDictionary<string, object> values)
{
ProfileService.CheckProfileServicesEnabled();
return ProfileService.SetProfile(HttpContext.Current, values);
}
起关键作用的方法是ProfileService.SetProfile静态方法,我们来仔细看一下这个方法:
1 internal static int SetProfile(HttpContext context, IDictionary<string, object> profileValues)
2 {
3 // 如果没有提供保存的Profile值,则返回0
4 if ((profileValues == null) || (profileValues.Count == 0))
5 {
6 return 0;
7 }
8
9 // 获取当前用户的Profile值
10 ProfileBase profile = context.Profile;
11
12 // 如果当前没有Profile,也返回0
13 if (profile == null)
14 {
15 return 0;
16 }
17
18 int count = 0;
19
20 // 获得当前的Serializer,
21 // 以获取JavaScriptTypeResolver和JavaScriptConverter的支持
22 WebServiceData data = WebServiceData.GetWebServiceData(context, context.Request.FilePath);
23 JavaScriptSerializer serializer = data.Serializer;
24
25 // 枚举提供的每一个Profile的值
26 foreach (KeyValuePair<string, object> pair in profileValues)
27 {
28 // 获得Profile的名称
29 string name = pair.Key;
30 if ((ProfileService._allowedSet != null) && ProfileService._allowedSet.ContainsKey(name))
31 {
32 // 通过Profile名称获得在web.config中的Profile定义
33 SettingsProperty property = ProfileBase.Properties[name];
34 // 如果存在这个Profile属性
35 if (property != null)
36 {
37 // 获得Profile属性的类型
38 Type type = property.PropertyType;
39 // 调用内部的ObjectConverter.ConvertObjectToType方法进行转换,
40 // 然后赋值给相应的Profile
41 profile[name] = ObjectConverter.ConvertObjectToType(pair1.Value, type, serializer);
42
43 // 已经保存的Profile属性数量加1
44 count++;
45 continue;
46 }
47 }
48 }
49
50 return count;
51 }
方法也不难理解,不过可以需要对于ASP.NET AJAX的序列化与反序列化能力有一定了解,例如第22和23行构造了一个JavaScriptSerializer的目的是使用包含在WebServiceData内的JavaScriptTypeResolver信息,以此获得从字符串形式的type描述到确定type类型的映射关系。这其实是一个非常有用的特性,不过有点让人想不通的是,在目前的WebServiceData中由于没有方法添加自定义的JavaScriptTypeResolver,因此这个功能的效用为0。难道未来的版本会有办法利用到这个特性?拭目以待吧,虽然我觉得比较困难。
我们也可以看到,这个方法中使用了内部的ObjectConverter.ConvertObjectToType方法来将一个嵌套的Dictionay和List转换为指定的类型。如果我们要使用这个方法,应该怎么做呢?事实上,ASP.NET AJAX提供了我们一定的序列化与反序列化能力。请看JavaScirptSerializer的公有实例方法ConvertToType<T>的实现:
{
return (T) ObjectConverter.ConvertObjectToType(obj, typeof(T), this);
}
它直接调用了内部的ObjectConverter.ConverObjectToType方法,这不就是我们所需要的功能吗?
等一下!别高兴的太早!请注意,这是一个范型方法!我们这里只能获得一个Profile属性的类型对象,不能在编译期指定调用哪种具体类型的范型方法,也就是说,我们不能在这里简单地使用这个范型方法。我们在这里需要对范型方法的调用进行“后期绑定”,因为只有在执行期才能获得范型的类型。
后期绑定?这不就是Reflection提供的功能吗?因此,我们可以使用.NET Framework 2.0的Reflection机制,它已经对于范型类型提供了支持。在这里,我们可以这么做:
Type type = value.GetType(); // 获得所需的Profile属性的Type对象
MethodInfo info = typeof(JavaScriptSerializer).GetMethod("ConvertToType").MakeGenericMethod(type);
return info.Invoke(serializer, new object[] { value });
这样,我们就实现了对于范型方法调用的“后期绑定”:在执行期才决定调用哪个具体类型的范型方法。这么做会有性能损失,例如查找ConvertToType方法并构造相应的范型的MethodInfo,但是如果我们使用Dictionary<Type, MethodInfo>将type和它所对应的MethodInfo保存起来,可以在一定程度上的减少性能的损失。不过使用Method.Invoke造成的性能损失就无法避免了。
另外,我打算在接下来的文章中详细分析一下ASP.NET AJAX中提供给开发人员的序列化与反序列化能力,以及它们是如何配合JavaScriptTypeResolver与JavaScriptConverter提供一定的自定义能力。
我们现在已经知道了如何自定义服务器端的Profile Service支持,但是如果我们一直使用客户端的“标准”功能,还谈不上“自定义”或者“扩展”。那么在下一片文章中,我们一起来讨论一下自定义客户端的Profile Service支持吧。
转载于:https://www.cnblogs.com/JeffreyZhao/archive/2006/11/04/Inside_Atlas_Series__Investigate_the_Application_Services_2.html
深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持相关推荐
- Sharepoin学习笔记—架构系列—Sharepoint服务(Services)与服务应用程序框架(Service Application Framework) 1
Sharepoin学习笔记-架构系列-Sharepoint服务(Services)与服务应用程序框架(Service Application Framework) 1 Sharepoint服务是Sha ...
- 深入Atlas系列:Web Sevices Access in Atlas示例(6) - 在客户端隐藏服务器端类型信息...
如果要在客户端指定服务器端Web Service方法所接收的参数类型,就必须在客户端通过"__type"来指定,但是这就暴露了服务器端的具体类型了,这可不太好.现在我们就来看一下应 ...
- WPF入门教程系列三——Application介绍(续)
接上文WPF入门教程系列二--Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...
- 应用服务Application Services
Application Services用于将域逻辑公开给表示层.使用DTO(数据传输对象)作为参数从表示层调用应用服务.它还使用域对象来执行某些特定的业务逻辑,并将DTO返回给表示层.因此,表示层与 ...
- SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解
1.预置演示环境 这个演示环境继续沿用 SpringSecurit权限管理框架系列(五)-Spring Security框架自定义配置类详解(一)之formLogin配置详解的环境. 2.自定义配置类 ...
- spring boot 跨域请求_SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition...
191222-SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition 在 spring mvc 中,我们知道用户发起的请求可以通过 url 匹配到我们通过@R ...
- Android官方开发文档Training系列课程中文版:创建自定义View之View的创建
原文地址:http://android.xsoftlab.net/training/custom-views/index.html 引言 Android框架含有大量的View类,这些类用来显示各式各样 ...
- 【5年Android从零复盘系列之十七】Android自定义View(12):手势绘制及GestureOverlayView事件详解(图文)
[5年Android从零复盘系列之十七]Android自定义View(12):手势绘制及GestureOverlayView事件浅析 1.基础 掌握View体系事件分发与处理,参考Android自定义 ...
- STM8S系列基于STVD开发,自定义printf函数+TIM5精确延时函数模块化工程示例
STM8S系列基于STVD开发,自定义printf函数+TIM5精确延时函数模块化工程示例
最新文章
- Linux vim 中文显示乱码解决方法
- 解决首次访问jenkins,输入默认密码之后,一直卡住问题
- OpenGL Texture Coordinates纹理坐标的实例
- 基于.NET的WebService的实现
- Python与数据库[2] - 关系对象映射/ORM[4] - sqlalchemy 的显式 ORM 访问方式
- python 获取几小时之前,几分钟前,几天前,几个月前,及几年前的具体时间
- 修改YUM源为本地光驱
- ofbiz中用 ajax 几点注意
- QT的QWebEngineView内存泄漏
- JDK 的下载与安装(非常详细!)
- c语言实验报告(四) 从键盘输入字符串a和字符串b,并在a串中的最小元素(不含结束符)后面插入字符串b....
- 量化交易员珍藏的10本书,一般人不会教你的事
- maxima学习笔记(一)
- 考拉海购成重构互联网版图的最大“变量”
- 电影——《小萝莉的猴神大叔》
- 【统计学笔记】如何判断变量间相关关系,并建立一元线性回归模型?
- MKOnlinePlayer在线音乐播放器
- 云服务器的IP是显示哪里,云服务器的ip在哪里看
- 2021秋招CVTE面经
- CSS如何添加阴影效果?