深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持
生活随笔
收集整理的這篇文章主要介紹了
深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在上一篇文章中,我們討論了使用ASP.NET AJAX默認的Profile Service。一般來說,它已經能夠迎合大多數應用的需要了。不過除此之外,ASP.NET AJAX還提供了讓我們自定義Profile Service的機制。要自定義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中指定即可。如下:
<asp:ScriptManager?ID="ScriptManager1"?runat="server"?ScriptMode="Debug">
????<ProfileService?Path="CustomProfileService.asmx"?/>
</asp:ScriptManager>
打開頁面后,可以在頁面中發現如下的JavaScript代碼:
Sys.Services.ProfileService.set_path('/CustomProfileService.asmx');
出現“/”是因為我測試的頁面在根目錄下。因此,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里,這個方法的代碼如下:
[WebMethod]
public?IDictionary<string,?object>?GetAllPropertiesForCurrentUser()
{
??? ProfileService.CheckProfileServicesEnabled();
??? return?ProfileService.GetProfile(HttpContext.Current,?null);
}
2、GetPropertiesForCurrentUser方法
這個方法的作用是獲得當前用戶指定的Profile信息,它的輸入JSON字符串形式如下:
['ZipCode',?'Address.City',?'Address.State']
它的返回值的JSON字符串和GetAllPropertiesForCurrentUser相同,就不再贅述了。
在類中,這個方法的代碼如下:
[WebMethod]
public?IDictionary<string,?object>?GetPropertiesForCurrentUser(string[]?properties)
{
????ProfileService.CheckProfileServicesEnabled();
????return?ProfileService.GetProfile(HttpContext.Current,?properties);
}
可以看到,GetAllPropertiesForCurrentUser和GetPropertiesForCurrentUser中都是使用了ProfileService.GetProfile靜態方法來獲得結果的,我們來仔細看一下這個方法的實現。如下:
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數量。代碼如下:
[WebMethod]
public?int?SetPropertiesForCurrentUser(IDictionary<string,?object>?values)
{
????ProfileService.CheckProfileServicesEnabled();
????return?ProfileService.SetProfile(HttpContext.Current,?values);
}
起關鍵作用的方法是ProfileService.SetProfile靜態方法,我們來仔細看一下這個方法:
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>的實現:
public?T?ConvertToType<T>(object?obj)
{
????return?(T)?ObjectConverter.ConvertObjectToType(obj,?typeof(T),?this);
}
它直接調用了內部的ObjectConverter.ConverObjectToType方法,這不就是我們所需要的功能嗎?
等一下!別高興的太早!請注意,這是一個范型方法!我們這里只能獲得一個Profile屬性的類型對象,不能在編譯期指定調用哪種具體類型的范型方法,也就是說,我們不能在這里簡單地使用這個范型方法。我們在這里需要對范型方法的調用進行“后期綁定”,因為只有在執行期才能獲得范型的類型。
后期綁定?這不就是Reflection提供的功能嗎?因此,我們可以使用.NET Framework 2.0的Reflection機制,它已經對于范型類型提供了支持。在這里,我們可以這么做:
JavaScriptSerializer?serializer?=?new?JavaScriptSerializer();
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支持吧。
一、在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中指定即可。如下:
<asp:ScriptManager?ID="ScriptManager1"?runat="server"?ScriptMode="Debug">
????<ProfileService?Path="CustomProfileService.asmx"?/>
</asp:ScriptManager>
打開頁面后,可以在頁面中發現如下的JavaScript代碼:
Sys.Services.ProfileService.set_path('/CustomProfileService.asmx');
出現“/”是因為我測試的頁面在根目錄下。因此,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里,這個方法的代碼如下:
[WebMethod]
public?IDictionary<string,?object>?GetAllPropertiesForCurrentUser()
{
??? ProfileService.CheckProfileServicesEnabled();
??? return?ProfileService.GetProfile(HttpContext.Current,?null);
}
2、GetPropertiesForCurrentUser方法
這個方法的作用是獲得當前用戶指定的Profile信息,它的輸入JSON字符串形式如下:
['ZipCode',?'Address.City',?'Address.State']
它的返回值的JSON字符串和GetAllPropertiesForCurrentUser相同,就不再贅述了。
在類中,這個方法的代碼如下:
[WebMethod]
public?IDictionary<string,?object>?GetPropertiesForCurrentUser(string[]?properties)
{
????ProfileService.CheckProfileServicesEnabled();
????return?ProfileService.GetProfile(HttpContext.Current,?properties);
}
可以看到,GetAllPropertiesForCurrentUser和GetPropertiesForCurrentUser中都是使用了ProfileService.GetProfile靜態方法來獲得結果的,我們來仔細看一下這個方法的實現。如下:
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數量。代碼如下:
[WebMethod]
public?int?SetPropertiesForCurrentUser(IDictionary<string,?object>?values)
{
????ProfileService.CheckProfileServicesEnabled();
????return?ProfileService.SetProfile(HttpContext.Current,?values);
}
起關鍵作用的方法是ProfileService.SetProfile靜態方法,我們來仔細看一下這個方法:
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>的實現:
public?T?ConvertToType<T>(object?obj)
{
????return?(T)?ObjectConverter.ConvertObjectToType(obj,?typeof(T),?this);
}
它直接調用了內部的ObjectConverter.ConverObjectToType方法,這不就是我們所需要的功能嗎?
等一下!別高興的太早!請注意,這是一個范型方法!我們這里只能獲得一個Profile屬性的類型對象,不能在編譯期指定調用哪種具體類型的范型方法,也就是說,我們不能在這里簡單地使用這個范型方法。我們在這里需要對范型方法的調用進行“后期綁定”,因為只有在執行期才能獲得范型的類型。
后期綁定?這不就是Reflection提供的功能嗎?因此,我們可以使用.NET Framework 2.0的Reflection機制,它已經對于范型類型提供了支持。在這里,我們可以這么做:
JavaScriptSerializer?serializer?=?new?JavaScriptSerializer();
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支持的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 65536 gradle
- 下一篇: Page.LoadTemplate的使用