决战.NET
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.5 ProfileService

ASP.NET AJAX提供了另一个内建的Service——Profile Service,与Authentication Service相同,Profile Service也是与ASP.NET所提供的Profile结合,允许设计师通过JavaScript来访问位于Server端的Profile信息。与Authentication Servce结合后,Profile Service可以让设计师在不刷新网页的状态下,实现无刷新登录及无刷新带出用户设定的功能。最常见的应用例子就是于门户网站常见的,在使用者登录后,在首页的某个区域显示该用户所设定的友情链接功能。那具体该如何做呢?请照着下面步骤,在前例的Authentication网页中添加Profile的功能。

1. 在SecureFolder中新增一个名为ProfileTest.aspx的网页。

2. 在页面中加入一个ScriptManager控件。

3. 放入显示和输入Profile信息的控件及访问Profile Service的JavaScript程序代码,如程序4-17所示。

4. 在web.config启动Profile功能,这里有两个区段,一个启动ASP.NET内建的Profile功能,另一个启用ASP.NET AJAX所提供的Profile Service,如程序4-18所示。

5. 在Default.aspx网页中添加一个HyperLink控件,NavigateUrl设为/SecureFolder/Profile-Test.aspx,Text设为Go Profile Form。

程序4-17

    Samples\4\AuthenticationTest\SecureFolder\ProfileTest.aspx
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ProfileTest.aspx.cs"
      Inherits="ProfileTest" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <script language=javascript>
            //Profile成功读取时调用的函数
            function OnLoadCompleted(numProperties, userContext, methodName)
            {
              $get("txtData").value =  Sys.Services.ProfileService.properties.Data;
              $get("Text2").value = Sys.Services.ProfileService.properties.
                ComplexData.Data1;
              $get("Text3").value = Sys.Services.ProfileService.properties.
                ComplexData.Data2;
            }
            //Profile成功储存时调用的函数
            function OnSaveCompleted(numProperties, userContext, methodName)
            {
              alert("OK");
          }
            //读取或储存Profile时,失败时调用的函数
            function OnProfileFailed(error_object, userContext, methodName)
            {
                alert("Profile service failed with message: " +
                    error_object.get_message());
            }
            //储存Profile信息
            function SaveProfile()
            {
              Sys.Services.ProfileService.properties.Data = $get("txtData").value;
              Sys.Services.ProfileService.properties.ComplexData.Data1 =
                $get('Text2').value;
              Sys.Services.ProfileService.properties.ComplexData.Data2 =
                $get('Text3').value;
              Sys.Services.ProfileService.save(null,OnSaveCompleted,
                OnProfileFailed, null);
            }
            //读取Profile信息
            function LoadProfile()
            {
              Sys.Services.ProfileService.load(null,OnLoadCompleted,
                OnProfileFailed, null);
            }
            //在网页载入时调用的函数,此处调用LoadProfile来读取使用者的Profile
            function pageLoad()
            {
              LoadProfile();
            }
            </script>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            Data:
            <input id="txtData" type=text /><br />
            ComplexData.Data1:
            <input id="Text2" type=text /><br />
            ComplexData.Data2:
            <input id="Text3" type=text />
            <input id="Button1" type="button" value="Save Profile" honclick=
              "SaveProfile()" /></div>
        </form>
    </body>
    </html>

程序4-18

    Samples\4\AuthenticationTest\web.config
    <system.web>
            .............
            <!-- 启动ASP.NET的Profile功能-->
            <profile enabled="true">
                <!-- 定义Profile中的属性 -->
                  <properties>
                    <!-- 单一属性 -->
                    <add name="Data" type="System.String" defaultValue=""/>
                    <!-- 复杂属性 -->
                    <group name="ComplexData">
                          <add name="Data1" type="System.String"/>
                          <add name="Data2" type="System.String"/>
                    </group>
                  </properties>
            </profile>
    <system.web.extensions>
            <scripting>
                <webServices>
                    <authenticationService enabled="true"/>
                    <!-- 启用ASP.NET AJAX的Profile Service,
                    readAccessProperties中可设定允许Profile Service读取的Profile属性,
                    writeAccessProperties则设定允许写入的属性,每个属性都必须以;分隔,
                    当有复杂属性时,必须以<Group Name>.<Property Name>方式于此指定-->
                    <profileService enabled="true"
                      readAccessProperties="Data,ComplexData.Data1,
                        ComplexData.Data2"
                      writeAccessProperties="Data,ComplexData.Data1,
                        ComplexData.Data2"/>
                </webServices>
            </scripting>
        </system.web.extensions>
    ...........

在使用者登录后,便可点击链接浏览ProfileTest.aspx网页,此时pageLoad函数会被调用,本例子调用了LoadProfile函数读取该使用者的Profile,LoadProfile函数则是调用了ASP.NET AJAX所提供的ProfileService对象的load函数来读取Profile信息。与Authentication Service相同,在调用load函数时,必须分别指定当读取成功、读取失败时所调用的函数,此处是设定为成功时调用OnLoadCompleted函数,失败时则调用OnProfileFailed函数,load函数的第一个参数一个数组类型,可让设计师明确指定要读取的Profile属性,如该属性为null,代表着要将web.config中所指定可读取的Profile属性读回。此参数的设计用途很明显,并不是每个网页都需要全部的Profile信息,明确指定需要读回的Profile属性,可提高网页的性能,如程序4-19 所示,便是仅读回ComplexData.Data1 及ComplexData.Data2 的Profile属性值,而不读取Data属性。

程序4-19

    Sys.Services.ProfileService.load(["ComplexData.Data1","ComplexData.Data2"],
                    OnLoadCompleted, OnProfileFailed, null);

当Profile属性读回后,设计师便可通过Sys.Services.ProfileService.properties.<属性名>来访问该Profile属性值。当需要储存Profile属性时,则必须调用Sys.Services.ProfileService.save函数,与load函数相同,第一个参数是数组类型,可明确指定要储存的Profile属性名称,第二及第三个参数则是指定储存成功及失败所调用的函数。读者们可执行此程序,在登录后点击Go Profile Form,输入一些信息,点击储存后,将浏览器关闭,再次执行并登录后点击Go Profile Form,即可看到先前所输入的信息,如图4-11所示。

true

图4-11

不是说要做出友情链接的功能吗?这个范例未免也太简单了吧?呵,要实现这个功能也不难,请照着以下步骤做。

1. 在web.config中新增一个Profile properties来储存联结,这是一个StringCollection类型的属性,别忘了设定Profile Service的readAccessProperties及writeAccessProperties哦,如程序4-20所示。

2. 修改ProfileTest.aspx,加入可以让使用者键入联结的控件,如程序4-21所示。

程序4-20

    Samples\4\AuthenticationTest\web.config
    <!-- 启动ASP.NET的Profile功能-->
            <profile enabled="true">
                <!-- 定义Profile中的属性 -->
                  <properties>
                    <!-- 单一属性 -->
                      <add name="Data" type="System.String" defaultValue=""/>
                      <!-- 复杂属性 -->
                      <group name="ComplexData">
                        <add name="Data1" type="System.String"/>
                        <add name="Data2" type="System.String"/>
                      </group>
                      <add name="Links" type="System.Collections.Specialized.
                        StringCollection" />
                  </properties>
            </profile>
    ...............
    <system.web.extensions>
            <scripting>
                <webServices>
                    <authenticationService enabled="true"/>
                    <!-- 启用ASP.NET AJAX的Profile Service,
                    readAccessProperties中可设定允许Profile Service读取的Profile属性,
                    writeAccessProperties则设定允许写入的属性,每个属性都必须以;分隔,
                    当有复杂属性时,必须以<Group Name>.<Property Name>方式于此指定-->
                    <profileService enabled="true"
                      readAccessProperties="Data,ComplexData.Data1,ComplexData.
                        Data2,Links"
                      writeAccessProperties="Data,ComplexData.Data1,ComplexData.
                        Data2,Links"/>
                </webServices>
            </scripting>
        </system.web.extensions>

程序4-21

    Samples\4\AuthenticationTest\SecureFolder\ProfileTest.aspx
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ProfileTest.aspx.cs"
      Inherits="ProfileTest" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <script language=javascript>
            function AddLink()
            {
              var links = $get("links");
              links.options.length = links.length+1;
              links.options[links.length-1]=
                new Option($get("txtNewLink").value,$get("txtNewUrl").value);
            }
            function OnLoadCompleted(numProperties, userContext, methodName)
            {
              $get("txtData").value =  Sys.Services.ProfileService.properties.Data;
              $get("Text2").value = Sys.Services.ProfileService.properties.
                ComplexData.Data1;
              $get("Text3").value = Sys.Services.ProfileService.properties.
                ComplexData.Data2;
              $get("links").options.length = 0;
              $get("links").options.length =
                Sys.Services.ProfileService.properties.Links.length;
              for(var i = 0; i < Sys.Services.ProfileService.properties.Links.
                length; i++)
              {
                var s = Sys.Services.ProfileService.properties.Links[i].split(',');
                if(s.length == 2)
                      $get("links").options[i] = new Option(s[0],s[1]);
                else
                      $get("links").options[i] = new Option(s[0],s[0]);
              }
            }
            function OnSaveCompleted(numProperties, userContext, methodName)
            {
              alert("OK");
            }
            function OnProfileFailed(error_object, userContext, methodName)
            {
                alert("Profile service failed with message: " +
                    error_object.get_message());
            }
            function SaveProfile()
            {
              Sys.Services.ProfileService.properties.Data = $get("txtData").value;
              Sys.Services.ProfileService.properties.ComplexData.Data1 =
                $get('Text2').value;
              Sys.Services.ProfileService.properties.ComplexData.Data2 =
                $get('Text3').value;
              var links = $get("links");
              Sys.Services.ProfileService.properties.Links = new
                Array(links.options.length);
              for(var i = 0; i < links.options.length; i++)
                Sys.Services.ProfileService.properties.Links[i] =
                          links.options[i].text +","+ links.options[i].value;
              Sys.Services.ProfileService.save(null,OnSaveCompleted,
                OnProfileFailed, null);
            }
            function LoadProfile()
            {
              Sys.Services.ProfileService.load(null,OnLoadCompleted,
                OnProfileFailed, null);
            }
            function pageLoad()
            {
              LoadProfile();
            }
            </script>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            Data:
            <input id="txtData" type=text /><br />
            ComplexData.Data1:
            <input id="Text2" type=text /><br />
            ComplexData.Data2:
            <input id="Text3" type=text />
            <br />
            <select id=" links" name="links">
                <option selected="selected"></option>
            </select>
            &nbsp;Name&nbsp;
            <input id="txtNewLink" type="text" />
            Url<input id="txtNewUrl" type="text" />
            <input id="btnAdd" type="button" value="Add" onclick=
              "AddLink()" /><br />
            <input id="Button1" type="button" value="Save Profile" onclick=
              "SaveProfile()" />&nbsp;
        </div>
        </form>
    </body>
    </html>

执行此程序后,就可以在ProfileTest.aspx中新增链接,这些链接信息会以<名称>,<Url>的方式存在Profile的Links属性中,而Links属性是一个字符串数组,这代表着用户可储存1 个以上的链接信息至Links属性中,如图4-12所示。

true

图4-12

如果不用Select来显示链接,而真正地使用超链接呢?很简单,只要放个div控件到网页中,在更新Select时也顺便更新它就行了,如程序4-22所示。

程序4-22

    Samples\4\AuthenticationTest\SecureFolder\ProfileTest.aspx
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ProfileTest.aspx.cs"
        Inherits="ProfileTest" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <script language=javascript>
            function LoadLinksArea()
            {
              var linkArea = $get("LinksArea");
              var s = "<table>";
              for(var i = 0; i < Sys.Services.ProfileService.properties.Links.
                length; i++)
              {
                  var linkUrl = Sys.Services.ProfileService.properties
                  .Links[i].split(",");
                  s = s + "<tr><td><a href='http://"+linkUrl[1]+"'>"+linkUrl[0]
                    +"</td></tr>";
              }
              linkArea.innerHTML = s+"</table>";
            }
            function RefreshLinksArea()
            {
              var linkArea = $get("LinksArea");
              var s = "<table>";
              var links = $get("Links");
              for(var i = 0; i < links.options.length; i++)
              {
                  s = s +
                  "<tr><td><a href='http://"+links.options[i].value+"'>"+
                    links.options[i].text+"</td></tr>";
              }
              linkArea.innerHTML = s+"</table>";
            }
            function AddLink()
            {
              var links = $get("Links");
              links.options.length = links.length+1;
              links.options[links.length-1]= new Option($get("txtNewLink").value,
                $get("txtNewUrl").value);
              RefreshLinksArea();
            }
            function OnLoadCompleted(numProperties, userContext, methodName)
            {
              $get("txtData").value =  Sys.Services.ProfileService.properties.Data;
              $get("Text2").value =
                Sys.Services.ProfileService.properties.ComplexData.Data1;
              $get("Text3").value =
                Sys.Services.ProfileService.properties.ComplexData.Data2;
              $get("Links").options.length = 0;
              $get("Links").options.length =
                Sys.Services.ProfileService.properties.Links.length;
              for(var i = 0; i <
                Sys.Services.ProfileService.properties.Links.length; i++)
              {
                var s = Sys.Services.ProfileService.properties.Links[i].split(',');
                if(s.length == 2)
                    $get("Links").options[i] = new Option(s[0],s[1]);
                else
                    $get("Links").options[i] = new Option(s[0],s[0]);
              }
              LoadLinksArea();
            }
            function OnSaveCompleted(numProperties, userContext, methodName)
            {
              alert("OK");
            }
            function OnProfileFailed(error_object, userContext, methodName)
            {
              alert("Profile service failed with message: " +
                  error_object.get_message());
            }
            function SaveProfile()
            {
              Sys.Services.ProfileService.properties.Data = $get("txtData").value;
              Sys.Services.ProfileService.properties.ComplexData.Data1 =
                $get('Text2').value;
              Sys.Services.ProfileService.properties.ComplexData.Data2 =
                $get('Text3').value;
              var links = $get("Links");
              Sys.Services.ProfileService.properties.Links =
                new Array(links.options.length);
              for(var i = 0; i < links.options.length; i++)
                Sys.Services.ProfileService.properties.Links[i] =
                  links.options[i].text +","+ links.options[i].value;
              Sys.Services.ProfileService.save(null,OnSaveCompleted,
                OnProfileFailed, null);
            }
            function LoadProfile()
            {
              Sys.Services.ProfileService.load(null,OnLoadCompleted,
                OnProfileFailed, null);
            }
            function pageLoad()
            {
              LoadProfile();
            }
            </script>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            Data:
            <input id="txtData" type=text /><br />
            ComplexData.Data1:
            <input id="Text2" type=text /><br />
            ComplexData.Data2:
            <input id="Text3" type=text />
            <br />
            <select id="Select1" name="links">
                <option selected="selected"></option>
            </select>
            &nbsp;Name&nbsp;
            <input id="txtNewLink" type="text" />
            Url<input id="txtNewUrl" type="text" />
            <input id="btnAdd" type="button" value="Add" onclick=
              "AddLink()" /><br />
            <div id=LinksArea>
            </div>
            <input id="Button1" type="button" value="Save Profile"
              onclick="SaveProfile()" />&nbsp;
        </div>
        </form>
    </body>
    </html>

完成后的结果如图4-13所示。

true

图4-13

你是否有种感觉,innerHTML加上div后,相当地好用呢?

ProfileGroup

在多数情况下,我们都会在网页载入时调用ProfileService.load函数来读取该使用者的Profile,因此相关的Profile属性在读取成功后,便会定义于ProfileService.properties中,设计师可以直接访问这些属性。但是若在未调用load函数情况下访问ProfileService.properties时,这些属性事实上是不存在的,不过由于JavaScript的语法,当访问的变量不存在时,即自动声明该变量,并给予undefine的值,所以这样的写法不会引发语法错误。只是当该属性是复杂属性,例如ComplexData时,直接键入ProfileService.properties.ComplexData.Data1,这种语法就不能执行了,因为JavaScript虽然会为我们声明ComplexData变量,但由于其值是默认的undefine,访问其Data1变量便成了不合法的动作,如程序4-23所示。

程序4-23

    function ManualDefine()
    {
        Sys.Services.ProfileService.properties.Data = "TEST";
        //不合法的访问,因为ComplexData是undefine.
        Sys.Services.ProfileService.properties.ComplexData.Data1 = "TEST1";
        //不合法的访问,因为ComplexData是undefine.
        Sys.Services.ProfileService.properties.ComplexData.Data2 = "TEST2";
    }
    function pageLoad()
    {
        //LoadProfile();
            ManualDefine();
    }

此时必须依赖Sys.Services中所定义的ProfileGroup对象,以程序4-24的方式来赋值。

程序4-24

    function ManualDefine()
    {
        Sys.Services.ProfileService.properties.Data = "TEST";
        Sys.Services.ProfileService.properties.ComplexData = new
          Sys.Services.ProfileGroup();
        Sys.Services.ProfileService.properties.ComplexData.Data1 = "TEST1";
        Sys.Services.ProfileService.properties.ComplexData.Data2 = "TEST2";
        Sys.Services.ProfileService.properties.Links = new Array(2);
        Sys.Services.ProfileService.properties.Links[0] = "Hinet,www.hinet.net";
        Sys.Services.ProfileService.properties.Links[1] = "ASP.NET,www.asp.net";
        Sys.Services.ProfileService.save(null,OnSaveCompleted, OnProfileFailed,null);
    }

程序4-24是模拟未调用ProfileService的load函数,以程序的方式来储存Profile时的做法。