您的位置:首页 > 移动开发

深入Atlas系列:探究Application Services(1) - Profile Service分析与使用

2016-07-29 00:00 405 查看
  ASP.NET AJAX提供了Profile Service,允许开发人员异步地从服务器端访问Profile信息。从RTM开始,客户端的Profile Service还提供了对于Profile Group的支持,因此可以说已经相当成熟了。那么对于Profile Service的细节,是否大家都了解了呢?从ScriptManager的使用上来看,ProfileService是能够扩展的,那么应该如何扩展呢?细心的朋友们应该也发现了,在web.config中也增加了对于Profile Service的配置,那么这些配置应该如何使用呢?

在这篇文章里,我们将一起来讨论Profile Service使用方式的一些细节。

1、ASP.NET Profile基础

这部分简单地描述了ASP.NET Profile的使用,如果已经了解ASP.NET Profile的朋友就可以跳过这部分了。

在ASP.NET中,可以使用Profile,只需在web.config中进行定义即可。例如:

<
system
.web
>

<
anonymousIdentification
enabled
="true"

/>

<
profile
enabled
="true"
defaultProvider
="SqlProvider"

>

<
providers
>

<
add

name
="SqlProvider"

connectionStringName
="SqlServices"

applicationName
="ProfileBaseApplication"

type
="System.Web.Profile.SqlProfileProvider"

/>

</
providers
>

<
properties
>

<
add
name
="ZipCode"
allowAnonymous
="true"

/>

<
add
name
="RecentSearchList"

type
="System.Collections.Specialized.StringCollection"

serializeAs
="Xml"

allowAnonymous
="true"

/>

</
properties
>

</
profile
>

</
system.web
>

在运行时,则可以通过当前Context的Profile属性获得当前用户的Profile信息,Profile属性是一个继承ProfileBase的ProfileCommon类实例,根据web.config的中的定义提供了强类型的属性访问。例如:

public

void
Page_Load(
object
sender, EventArgs e)
{

this
.Profile.ZipCode
=

"...
"
;
}

在web.config中也可以定义ProfileGroup。例如:

<
properties
>

<
add
name
="ZipCode"

/>

<
group
name
="Address"
>

<
add
name
="Street"

/>

<
add
name
="City"

/>

<
add
name
="State"

/>

<
add
name
="CountryOrRegion"

/>

</
group
>

</
properties
>

这样就定义了一个ProfileGroup,它会被定义成一个ProfileGroupBase的子类ProfileGroupXXXX(例如上面的定义则是ProfileGroupAddress),然后这个ProfileGroup也提供了相应的强类型属性。这样,就可以通过如下的方式访问到:

public

void
Page_Load(
object
sender, EventArgs e)
{

this
.Profile.Address.City
=

"..."
;
}

Profile是一个非常容易使用的东西,我们能够为其赋值,它能够使用指定Provider自动地进行保存。另外在web.config文件中,我们也能够为Profile的的各项值定义各种属性,例如是否能够被匿名用户使用,是否只读,甚至让ProfileCommon类继承自定义的Profile子类。详细信息,请感兴趣的朋友们参考MSDN相关章节。

2、配置ASP.NET AJAX Profile Service

查看ASP.NET AJAX提供的配置文件,在<configSections />可以看到如下定义:

<
configSections
>

<
sectionGroup
name
="microsoft.web"
type
="Microsoft.Web.Configuration.MicrosoftWebSectionGroup, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
>

<
sectionGroup
name
="scripting"
type
="Microsoft.Web.Configuration.ScriptingSectionGroup, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
>

<
sectionGroup
name
="webServices"
type
="Microsoft.Web.Configuration.ScriptingWebServicesSectionGroup, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
>

<
section
name
="jsonSerialization"
type
="Microsoft.Web.Configuration.ScriptingJsonSerializationSection, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
requirePermission
="false"

/>

<section name="profileService" type="Microsoft.Web.Configuration.ScriptingProfileServiceSection, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" />

<
section
name
="authenticationService"
type
="Microsoft.Web.Configuration.ScriptingAuthenticationServiceSection, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
requirePermission
="false"

/>

</
sectionGroup
>

</
sectionGroup
>

</
sectionGroup
>

</
configSections
>

请注意加粗的部分,它说明在web.config中,我们可以配置Profile Service的一些属性。根据分析代码(事实上从web.config的注释中也能得察一二),可以得到配置的使用方式。例如:

<
profileService
enabled
="true"

writeAccessProperties
="ZipCode, Address.Street"

readAccessProperties
="Address.State"

/>

如果将enabled设为false,则在使用Profile Service时会抛出异常。writeAccessProperties和readAccessProperties属性(在这里感谢Cat Chen的提醒,请注意在Beta1版本中,web.config中的注释是错误的)分别定义了可以使用Profile Service设置和获取的属性列表。由于System.Web.UI.WebControls.StringArrayConverter的作用,能够使逗号分割的字符串与字符串数组之间进行转换。另外,能够使用“.”来表述Group中的某个Profile信息,例如“Address.State”则表示了Address这个Group下的State信息。

请注意,虽然定义了writeAccessProperties和readAccessProperties,但是从客户端设法设置或读取“不被允许”的Profile属性也不会出现错误,只是设置或者读取无法成功而已。

3、使用Profile Service读取Profile信息

从客户端获取Profile信息的主要逻辑如下:

调用Sys.Services.ProfileService.load(propertyNames, loadCompletedCallback, failedCallback, userContext)。

如果propertyNames为空,则调用服务器端GetAllPropertiesForCurrentUser方法,否则使用_clonePropertyNames函数剔出propertyNames中重复的属性名,然后调用服务器端_GetPropertiesForCurrentUser方法。

服务器端根据得到的参数,从Profile信息中提取信息并构造出一个Dictionary<string, object>数组。

如果成功,则根据服务器端返回对象,调用_unflattenProperties方法将该对象转换为Profile属性以及Profile Group,最后调用loadCompletedCallback回调函数。

如果失败,调用failedCallback函数。

  需要注意的是,如果需要加载所有的Profile,在第1步中则必须使用null作为第一个参数,如果使用了一个空数组,则不会加载任何Profile属性。

关于第2步中的方法访问,ASP.NET AJAX中的Application Services都是基于ASP.NET AJAX的客户端Web Services访问能力的。在默认情况下Profile Service会访问“ScriptServices/Microsoft/Web/Profile/ProfileService.asmx”,由于不存在这个文件,ASP.NET AJAX将会查找Microsoft.Web.Profile.ProfileService类并调用该类的方法,这个就是“Assembly-based Web Services Access”。不过令人扼腕的是,虽然在当前版本的ASP.NET AJAX中还保留了这个机制,但是根据“白皮书”和可靠来源基本上可以确定这个功能会在下一个版本中被移除。这让我感到非常不可思议。个人认为,ASP.NET AJAX的一个重要特点,就是提供了一个能够扩展的模型。对于客户端来说,无论Control,Action,Validator乃至Behavior,几乎方方面面都能有规可循地进行扩展。很自然,服务器端也是,可能ASP.NET AJAX服务器端中最典型的应用就是Control Tookit了。其良好的复用性让人可谓眼前一亮。既然封装成了一个组件,则分发和部署则成为了一件重要的事情。许多ASP.NET AJAX组件必须通过客户端和服务器端的配合,然后使用客户端访问服务器端的Web Services方法来执行。如果需要在程序集中进行输出Javascript,则可以使用内嵌资源。但是如果客户端需要访问的Web Services文件是独立于程序集之外的话,那么还是增加了分发和部署的难度,甚至在开发与维护方面也变得需要管理多个对象,非常麻烦。而“Assembly-based Web Services Access”就能很好地解决这个问题。这样优秀的特性为什么会被取消?

在第4步中,从服务器端得到的数据是以如下JSON形式出现的:

{

"
ZipCode
"
:
"..."
,

"
Address.City
"
:
"..."
,

"
Address.State
"
:
"..."

}

Profile Group也是通过“.”分割来表示的。很自然,如果在load方法的第一个参数需要传递一个Profile Group中的一个属性时,也需要使用这样的表示方法。

另外,loadCompletedCallback和failedCallback函数的签名分别如下:

//
propertyNumber:成功加载的Profile数量,同一个Profile Group下的属性会分别计算

//
userContext:调用load时传入的userContext

//
methodName:方法名,值为"Sys.Services.ProfileService.load"

function
loadCompletedCallback(propertyNumber, userContext, methodName)
{
...
}

//
error:错误对象,存放了错误信息

//
userContext:调用load时传入的userContext

//
methodName:方法名,值为"Sys.Services.ProfileService.load"

function
failedCallback(error, userContext, methodName)
{
...
}

事实上,这两个回调函数都可以在调用load时不指定,这样就会使用默认的回调函数和默认的userContext,它们可以通过以下方法设置:

Sys.Services.ProfileService.set_loadCompleteCallback(callback);
Sys.Services.ProfileService.set_defaultFailedCallback(callback);

在load方法调用成功后,就可以在客户端获得使用Profile的值了,例如:

var
zipCode
=
Sys.Services.ProfileService.properties.ZipCode;

var
city
=
Sys.Services.ProfileService.properties.Address.City;

var
state
=
Sys.Services.ProfileService.properties.Address.State;

4、使用Profile Service设置Profile信息

从客户端设置Profile信息的主要逻辑如下:

调用Sys.Services.ProfileService.save(propertyNames, saveCompletedCallback, failedCallback, userContext) 。

调用_flattenProperties,根据propertyNames将Sys.Services.ProfileService.properties中的信息变为JSON形式。如果propertyNames为null,则表示保存所有Profile属性。

调用服务器端SetPropertiesForCurrentUser方法,服务器端会将JSON字符串转变为IDictionary<string, object>,并保存在Profile中。

如果成功,则调用saveCompletedCallback回调函数。

如果失败,则调用failedCallback回调函数。

在第2步中,如果需要表示Profile Group中的属性,依旧通过“.”来分割。如果需要修改Profile信息,直接修改properties对象即可。如果需要创建Profile Group,则需要使用到客户端的Sys.Services.ProfileGroup类。例如:

Sys.Services.ProfileService.properties.ZipCode
=

"...

"
;

if
(
!
Sys.Services.ProfileService.properties.Address)
{
Sys.Services.ProfileService.properties.Address
=

new
Sys.Services.ProfileGroup();
}
Sys.Services.ProfileService.properties.Address.City
=

"...

"
;

如果某Profile属性为复杂类型,则使用JSON形式在客户端赋值即可。

至于回调函数的签名,和load一模一样,只是methodName的值变为了"Sys.Services.ProfileService.save"。

在这篇文章中,我们简单讨论了ASP.NET AJAX的使用方法。在下一篇文章中,我们将一起来看一下配合ScriptManager来自定义Profile Service。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐