16、信息卡片与个性化网站打造

信息卡片与个性化网站打造

1. 个性化与信息卡片简介

个性化能为网站和应用带来诸多好处,像亚马逊和网飞等公司在这方面就做得相当出色。很多人一提到个性化,首先就会想到电商网站,因为电商网站通常有用户的购买历史记录,通过对这些购买产品的元数据进行汇总和挖掘,就能为用户提供未来购买的推荐。

不过,当用户首次访问网站时,即便网站有商品销售,也没有该用户的购买历史,也就缺乏强大的数据支持来生成有针对性的推荐。在信息卡片出现之前,很多网站实现个性化需要用户手动输入个人信息,但用户刚访问网站时往往不太愿意透露过多个人信息,这就限制了个性化的实现。

而信息卡片的出现改变了这一状况,用户提供数据的操作变得简单,使得首次访问网站时的个性化体验更容易实现。只需借助信息卡片中的一个数据元素,再结合一些后端数据服务,就能在用户首次访问时为其提供个性化体验。

2. 后端数据服务介绍

这里使用的后端数据服务由 StrikeIron 免费提供。StrikeIron 是一个网络服务的在线市场,它提供的超级数据包(Super Data Pack)包含了多个不同主题领域的数据,其中就有本章要用到的政府相关信息。

3. 注册 StrikeIron 数据服务

要使用这些服务,首先需要注册 StrikeIron 超级数据包服务,具体步骤如下:
1. 访问 StrikeIron 产品页面:http://www.strikeiron.com/tools/tools_overview.aspx。
2. 在免费 API 部分,选择超级数据包。
3. 点击“Get It!”按钮。
4. 查看并接受许可协议后,点击“Subscribe”。
5. 若尚未注册,需注册一个账户并完成超级数据包的注册。

注册完成后,点击“Your Account”,记录下用户名和密码,后续会用到。

4. 创建网站

注册成功后,就可以在网站中使用这些服务了。创建网站的步骤如下:
1. 打开 Visual Studio。
2. 在 Visual Studio 中,选择“File” -> “New” -> “Website”来创建新网站。
3. 在“New Web Site”对话框中,选择“ASP.NET Web Site”,并将位置设置为“C:\BeginningCardspace\Chapter15\PersonalGovernment”,然后点击“OK”。

5. 引用个人政府网站的服务

创建好基础网站后,需要为个人政府网站添加对各个 StrikeIron 网络服务的引用,具体如下:

5.1 添加 ZipCodeInformation 服务引用

该服务用于检索任何美国邮政编码对应的城市、州和郡信息。添加引用的步骤如下:
1. 右键单击项目,选择“Add Web Reference”。
2. 在 URL 字段中输入“http://sdpws.strikeiron.com/sdpZIPCodeInfo?WSDL”,然后点击“Go”按钮。
3. 在“Web Reference Name”字段中,将名称改为“ZipCodeInformation”。
4. 点击“Add Reference”。

5.2 添加 StateInformation 服务引用

此服务会返回给定美国州的相关信息,如人口、网站、州长和时区等。添加步骤如下:
1. 右键单击项目,选择“Add Web Reference”。
2. 在 URL 字段中输入“http://sdpws.strikeiron.com/sdpStateInformation?WSDL”,点击“Go”按钮。
3. 在“Web Reference Name”字段中,将名称改为“StateInformation”。
4. 点击“Add Reference”。

5.3 添加 SenatorInformation 服务引用

该服务用于返回给定美国州的参议员信息,包括参议员姓名、党派和办公室联系信息等。添加步骤如下:
1. 右键单击项目,选择“Add Web Reference”。
2. 在 URL 字段中输入“http://sdpws.strikeiron.com/sdpUSSenators?WSDL”,点击“Go”按钮。
3. 在“Web Reference Name”字段中,将名称改为“SenatorInformation”。
4. 点击“Add Reference”。

5.4 添加 CountyWebSites 服务引用

如果给定的郡有网站,该服务会返回其 URL。添加步骤如下:
1. 右键单击项目,选择“Add Web Reference”。
2. 在 URL 字段中输入“http://sdpws.strikeiron.com/sdpUSCountyWebsites?WSDL”,点击“Go”按钮。
3. 在“Web Reference Name”字段中,将名称改为“CountyWebsites”。
4. 点击“Add Reference”。

5.5 添加 CityWebSites 服务引用

若给定的城市有网站,此服务会返回其 URL。添加步骤如下:
1. 右键单击项目,选择“Add Web Reference”。
2. 在 URL 字段中输入“http://sdpws.strikeiron.com/sdpUSCityWebsites?WSDL”,点击“Go”按钮。
3. 在“Web Reference Name”字段中,将名称改为“CityWebSites”。
4. 点击“Add Reference”。

5.6 添加 CensusInformationForZipCode 服务引用

该服务会为给定的邮政编码返回美国人口普查期间收集的大量数据。添加步骤如下:
1. 右键单击项目,选择“Add Web Reference”。
2. 在 URL 字段中输入“http://sdpws.strikeiron.com/sdpCensus?WSDL”,点击“Go”按钮。
3. 在“Web Reference Name”字段中,将名称改为“CensusInformationForZipCode”。
4. 点击“Add Reference”。

6. 创建收集邮政编码的页面

创建项目时,Visual Studio 会自动生成一个名为 Default.aspx 的网页表单,用它来收集用户的邮政编码信息,具体操作如下:
1. 点击“Design”按钮进入页面设计模式。
2. 向表单中添加一个 Label 控件,将其 Text 属性设置为“Welcome to Personal Government”。
3. 再添加一个 Label 控件,将 Text 属性设置为“Please enter your U.S. ZIP Code”。
4. 添加一个 TextBox 控件,命名为“tbZipCode”。
5. 添加一个 Button 控件,命名为“btnNext”。
6. 将 btnNext 的 PostBackUrl 属性设置为“PersonalizedHome.aspx”。

7. 创建显示个性化内容的页面

前面创建的页面会收集用户的邮政编码信息,并将其传递给名为 PersonalizedHome.aspx 的二级页面。这个二级页面会以邮政编码为参数调用多个后端网络服务,然后显示这些服务返回的个性化汇总数据。具体步骤如下:
1. 右键单击项目,选择“Add New Item”。
2. 在“Add New Item”对话框中,选择“Web Form”,并将表单命名为“PersonalizedHome.aspx”。

接下来对页面进行一些设置和代码编写:
1. 查看页面源代码,将其修改为如下内容:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PersonalizedHome.aspx.cs" Inherits="PersonalizedHome" ValidateRequest="false" %>
<!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 id="Head1" runat="server">
    <title>Home</title>
</head>
<body style="font-size: 10pt; color: black; font-family: Arial">
    <form id="form1" runat="server">
        &nbsp;<table style="width: 491px">
            <tr>
                <td colspan="3">
                    <asp:Panel ID="pnlHeader" runat="server" Height="50px" Width="450px">
                    </asp:Panel>
                    </td>
            </tr>
        </table>
        <asp:Panel ID="pnlStateInfo" runat="server" Height="189px" Width="490px">
        </asp:Panel>
        <hr />
        <asp:Panel ID="pnlCityInfo" runat="server" Height="103px" Width="487px">
        </asp:Panel><hr />
        <asp:Panel ID="pnlSenatorInfo" runat="server" Height="196px" Width="488px">
        </asp:Panel>
        <hr />
        <asp:Panel ID="pnlCensusInformation" runat="server" Height="154px" Width="487px">
        </asp:Panel>

    </form>
</body>
</html>
  1. 右键单击 PersonalizedHome.aspx,选择“View Code”。
  2. 在文件顶部添加两个变量“userID”和“password”,并填入之前注册 StrikeIron 账户时的用户名和密码,代码如下:
public partial class PersonalizedHome : System.Web.UI.Page
{
    //TODO: Add your userID and password here.
    //if you don't have a userid and password, sign up here:
    //http://www.strikeiron.com/ProductDetail.aspx?p=257
  string userID = "username@hotmail.com ";
  string password = "password";
  1. 修改 Page_Load 事件,使其实现以下功能:
    • 从之前的页面获取邮政编码。
    • 使用该邮政编码从 StrikeIron 获取城市、郡和州的信息。
    • 将这些值存储到会话变量中。
    • 为每个面板指定渲染委托。

修改后的代码如下:

protected void Page_Load(object sender, EventArgs e)
{
    string postalCode = Request.Params["tbZipCode"];

    if (!String.IsNullOrEmpty(postalCode))
    {
        Session["postalCode"] = postalCode;
        ZipCodeInformation.RegisteredUser zcUser = new ZipCodeInformation.RegisteredUser();
        zcUser.UserID = userID;
        zcUser.Password = password;
        ZipCodeInformation.LicenseInfo zcLicenseIfo = new ZipCodeInformation.LicenseInfo();
        zcLicenseIfo.RegisteredUser = zcUser;
        ZipCodeInformation.SDPZipCodes zipCodeService = new ZipCodeInformation.SDPZipCodes();
        zipCodeService.LicenseInfoValue = new ZipCodeInformation.LicenseInfo();
        zipCodeService.LicenseInfoValue = zcLicenseIfo;
        ZipCodeInformation.ZipCodeOutput zipCodeInfo = zipCodeService.GetZipCode(postalCode);

        // Use the ZIP code to retrieve city, state, and county. 
       // These will be used with the other services.

        Session["city"] = zipCodeInfo.ServiceResult.ZipCodes[0].PreferredCityName;
        Session["state"] = zipCodeInfo.ServiceResult.ZipCodes[0].State;
        Session["county"] = zipCodeInfo.ServiceResult.ZipCodes[0].County;
        pnlStateInfo.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderStateInfo));
        pnlCityInfo.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderCountyAndCityInfo));
        pnlCensusInformation.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderCensusInfo));
        pnlSenatorInfo.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderSenatorInfo));
        pnlHeader.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderHeader));
    }
}
  1. 添加 RenderHeader 方法,代码如下:
public void RenderHeader(HtmlTextWriter writer, System.Web.UI.Control control)
{
    writer.Write("<h2>Your Government Information" + "</h2>");

}
  1. 添加 RenderStateInfo 方法,该方法调用 StateInformation 服务,并使用 HTML 表格在面板中渲染结果,代码如下:
public void RenderStateInfo(HtmlTextWriter writer, System.Web.UI.Control control)
{

    StateInformation.SDPStateInformation stateService = new StateInformation.SDPStateInformation();
    StateInformation.StateInformationOutput stateInfo;
    StateInformation.LicenseInfo stateLicenseInfo = new StateInformation.LicenseInfo();
    StateInformation.RegisteredUser stateUser = new StateInformation.RegisteredUser();
    stateUser.UserID = userID;
    stateUser.Password = password;
    stateLicenseInfo.RegisteredUser = stateUser;   
    stateService.LicenseInfoValue = stateLicenseInfo;
    string state = (string)Session["state"];
    if (state.Length == 2)
    {
        stateInfo = stateService.GetStateInformationForAbbreviation(state);
    }
    else
    {
        stateInfo = stateService.GetStateInformation(state);
    }
    writer.WriteLine("<h1><b>" + stateInfo.ServiceResult.StateInformation[0].State + "</b></h1>");
    writer.WriteLine("<a href=\"http://" + stateInfo.ServiceResult.StateInformation[0].Website + "\">http://" + stateInfo.ServiceResult.StateInformation[0].Website + "</a>");                
    writer.WriteLine("<br>");
    writer.Write("<table>");
    writer.Write("<tr>");
    writer.Write("<td>Governor</td>");
    writer.Write("<td>" + stateInfo.ServiceResult.StateInformation[0].Governor + "</td>");
    writer.WriteLine("</tr>");
    writer.Write("<tr>");
    writer.Write("<td>State Capital</td>");
    writer.Write("<td>" + stateInfo.ServiceResult.StateInformation[0].Capital + "</td>");
    writer.WriteLine("</tr>");
    writer.Write("<tr>");
    writer.Write("<td>Population</td>");
    writer.Write("<td>" + stateInfo.ServiceResult.StateInformation[0].Population.ToString() + "</td>");
    writer.WriteLine("</tr>");
    writer.Write("<tr>");
    writer.Write("<td>Area</td>");
    writer.Write("<td>" + stateInfo.ServiceResult.StateInformation[0].Area.ToString() + "</td>");
    writer.WriteLine("</tr>");
    writer.Write("<tr>");
    writer.Write("<td>Time Zone</td>");
    writer.Write("<td>" + stateInfo.ServiceResult.StateInformation[0].Timezone + "</td>");
    writer.WriteLine("</tr>");
    writer.WriteLine("</table>");


}
  1. 添加 RenderSenatorInfo 方法,该方法调用 SenatorInformation 服务,并使用 HTML 表格在面板中渲染结果,代码如下:
public void RenderSenatorInfo(HtmlTextWriter writer, System.Web.UI.Control control)
{

    SenatorInformation.SDPUSSenator senatorService = new SenatorInformation.SDPUSSenator();
    SenatorInformation.RegisteredUser senatorUser = new SenatorInformation.RegisteredUser();
    senatorUser.UserID = userID;
    senatorUser.Password = password;
    SenatorInformation.LicenseInfo senatorLicenseInfo = new SenatorInformation.LicenseInfo();
    senatorLicenseInfo.RegisteredUser = senatorUser;
    senatorService.LicenseInfoValue = senatorLicenseInfo;
    string stateAbbreviation = (string)Session["state"];   
    SenatorInformation.USSenatorOutput senatorInfo = senatorService.GetUSSenators(stateAbbreviation);
    writer.WriteLine("<table>");
    writer.WriteLine("<tr>");
    foreach(SenatorInformation.USSenatorInfo senatorDetail in senatorInfo.ServiceResult.USSenators)
    {
        writer.WriteLine("<td>");   
        writer.WriteLine("<b>Senator " + senatorDetail.FirstName + " " + senatorDetail.LastName + "</b><br/>");
        writer.WriteLine(senatorDetail.Party+ "<br/>");
        writer.WriteLine("Term expires:" + senatorDetail.TermExpires + "<br/><br/>");   
        writer.WriteLine("<table>");
        writer.Write("<tr>");
        writer.Write("<td>Website</td>");
        writer.Write("<td><a href=\"http://" + senatorDetail.Website + "\">http://" + senatorDetail.Website + "</a></td>");
        writer.WriteLine("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Address</td><td></td>");
        writer.Write("</tr>"); 
        writer.Write("<tr>");
        writer.Write("<td><td>" + senatorDetail.Address + "<br/>");
        writer.Write(senatorDetail.CityState + "<br/>");
        writer.Write("</td>");
        writer.WriteLine("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Phone</td>");
        writer.Write("<td>" + senatorDetail.Phone + "</td>");
        writer.WriteLine("</tr>");
        writer.WriteLine("</table>");
        writer.WriteLine("</td>");             
    }
    writer.WriteLine("</tr>");
    writer.WriteLine("</table>");
}
  1. 添加 RenderCountyAndCityInfo 方法,该方法调用 CountyWebSites 服务和 CityWebSites 服务,并在面板中渲染结果。由于并非每个城市和郡都有网站,代码会检查是否返回了网站 URL,如果没有则不显示相关控件,代码如下:
public void RenderCountyAndCityInfo(HtmlTextWriter writer, System.Web.UI.Control control)
{
    CountyWebsites.SDPUSCountyWebSites countyService = new CountyWebsites.SDPUSCountyWebSites();
    CountyWebsites.RegisteredUser countyUser = new CountyWebsites.RegisteredUser();
    countyUser.UserID = userID;
    countyUser.Password = password;
    CountyWebsites.LicenseInfo countyLicenseInfo = new CountyWebsites.LicenseInfo();
    countyLicenseInfo.RegisteredUser = countyUser;
    string county = (string)Session["county"];
    string state = (string)Session["state"];
    countyService.LicenseInfoValue = countyLicenseInfo;
    CountyWebsites.USCountyWebsiteOutput countyInfo = countyService.GetUSCountyWebsite(county, state);
    if (countyInfo.ServiceResult.Websites.Length > 0)
    {
        writer.Write("<b>" + countyInfo.ServiceResult.Websites[0].County + " County</b></br>");
        writer.WriteLine("<a href=\"http://" + countyInfo.ServiceResult.Websites[0].Website + "\">http://" + countyInfo.ServiceResult.Websites[0].Website + "</a>");
        writer.WriteLine("<br/>");
        writer.WriteLine("<br/>");
    }
    CityWebSites.SDPUSCityWebsites cityService = new CityWebSites.SDPUSCityWebsites();
    CityWebSites.RegisteredUser cityUser = new CityWebSites.RegisteredUser();
    cityUser.UserID = userID;
    cityUser.Password = password;
    CityWebSites.LicenseInfo cityLicenseInfo = new CityWebSites.LicenseInfo();
    cityLicenseInfo.RegisteredUser = cityUser;
    cityService.LicenseInfoValue = cityLicenseInfo;
    string city = (string)Session["city"];

    CityWebSites.USCityWebsiteOutput cityInfo =  cityService.GetUSCityWebsite(city,state);
    if (cityInfo.ServiceResult.USCityWebsites.Length > 0)
    {
        writer.Write("<b>" + city + "</b></br>");
        writer.WriteLine("<a href=\"http://" + cityInfo.ServiceResult.USCityWebsites[0].Website + "\">http://" + cityInfo.ServiceResult.USCityWebsites[0].Website + "</a>");
    }

}
  1. 添加 RenderCensusInfo 方法,该方法调用 CensusInformationForZipCode 服务,并使用 HTML 表格在面板中渲染结果,代码如下:
public void RenderCensusInfo(HtmlTextWriter writer, System.Web.UI.Control control)
{
    string postalCode = (string)Session["postalCode"];
    CensusInformationForZipCode.SDPCensus censusService = new CensusInformationForZipCode.SDPCensus();
    CensusInformationForZipCode.RegisteredUser censusUser = new CensusInformationForZipCode.RegisteredUser();
    censusUser.UserID = userID;
    censusUser.Password = password;
    CensusInformationForZipCode.LicenseInfo censusLicenseInfo = new CensusInformationForZipCode.LicenseInfo();
    censusLicenseInfo.RegisteredUser = censusUser;
    censusService.LicenseInfoValue = censusLicenseInfo;
    CensusInformationForZipCode.CensusOutput censusInfo = censusService.GetCensusInfoForZipCode(postalCode);
    if (censusInfo.ServiceResult.CensusInfo.Length > 0)
    {
        writer.WriteLine("<h4>US Census Information for Zip Code " + (string)Session["PostalCode"] + "</h4>");
        writer.WriteLine("<table>");
        writer.Write("<tr>");
        writer.Write("<td>Total Population</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Total_pop.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Median Age</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Median_age.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Gender Composition</td>");
        writer.Write("<td >");
        writer.WriteLine("<table><tr>");
        writer.WriteLine("<td> Male:" + censusInfo.ServiceResult.CensusInfo[0].Male_pop + "<td>");
        writer.WriteLine("<td> Female:" + censusInfo.ServiceResult.CensusInfo[0].Female_pop + "<td>");
        writer.WriteLine("</tr></table>");
        writer.Write("</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Total Housing Units</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Total_housing_units.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Owner/Renter Composition</td>");
        writer.Write("<td >");
        writer.WriteLine("<table><tr>");
        writer.WriteLine("<td> Owner:" + censusInfo.ServiceResult.CensusInfo[0].Owner_occupied_housing_units + "<td>");
        writer.WriteLine("<td> Renter:" + censusInfo.ServiceResult.CensusInfo[0].Renter_occupied_housing_units + "<td>");
        writer.WriteLine("</tr></table>");
        writer.Write("</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Rental vacancy percent</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Rental_vacancy_rate_percent.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Number of households</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Householder_pop.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Average household size</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Avg_household_size.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Number of family households</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Family_households.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("<tr>");
        writer.Write("<td>Average family size</td>");
        writer.Write("<td>" + censusInfo.ServiceResult.CensusInfo[0].Avg_family_size.ToString() + "</td>");
        writer.Write("</tr>");
        writer.Write("</table>");
    }
}

8. 测试解决方案

完成上述步骤后,就可以测试解决方案了,具体步骤如下:
1. 按 F5 启动网站,会看到一个输入界面。
2. 在文本框中输入美国邮政编码,然后点击“Next”按钮。如果不在美国,可以使用邮政编码 98052 进行测试。点击按钮后,网站会调用 StrikeIron 数据服务,并显示该邮政编码对应的所有可用信息。

9. 添加信息卡片支持

前面创建的网站需要用户手动输入邮政编码,现在要对其进行修改,使其能够从信息卡片中获取详细信息,具体步骤如下:
1. 打开 Default.aspx,查看其标记。
2. 修改页面指令,将 validateRequest 参数设置为 false,代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" validateRequest="false"%>
  1. 修改 html 元素,如下所示:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ic >
  1. 右键单击项目,选择“New Folder”,将文件夹命名为“images”。
  2. 右键单击新文件夹,选择“Add Existing Item”。
  3. 找到已完成项目中的 login.png 文件,并将其添加到 Images 文件夹中。
  4. 修改页面主体,请求邮政编码声明,并在用户界面中添加请求信息卡片的元素,完整标记如下:
<body>
    <form id="form1" runat="server" action="PersonalizedHome.aspx" >
     <ic:informationcard 
     name='xmlToken'
     style='behavior: url(#default#informationCard)'
     issuer='http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self'
     tokenType='urn:oasis:names:tc:SAML:1.0:assertion'>
    <ic:add claimType='http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode' optional='false' />

      </ic:informationcard><div>
                &nbsp;<table style="width: 491px">
                    <tr>
                        <td style="width: 159px">
                        </td>
                        <td>
                            <asp:Label ID="Label1" runat="server" Font-Bold="True" Font-Names="Verdana" Font-Size="Medium"
                                Style="z-index: 100; left: 189px; position: absolute; top: 41px" Text="Welcome to Personal Government"
                                Width="305px"></asp:Label>
                            <asp:Label ID="Label3" runat="server" Font-Names="Verdana" Font-Size="Smaller" 
                                Style="z-index: 100; left: 195px; position: absolute; top: 78px" Text="Login with your information card" Width="264px"></asp:Label>
                            &nbsp;
                            <asp:Label ID="Label2" runat="server" Font-Names="Verdana" Font-Size="Smaller" 
                                Style="z-index: 101; left: 196px; position: absolute; top: 176px" Text="Or Enter Your U.S. Zip Code"
                                Width="219px"></asp:Label>
                            <asp:TextBox ID="tbZipCode" runat="server" Style="z-index: 102; left: 192px; position: absolute;
                                top: 204px" Width="209px"></asp:TextBox>
                            <asp:Button ID="btnNext" runat="server" PostBackUrl="PersonalizedHome.aspx" 
                                Style="z-index: 104; left: 414px; position: absolute; top: 202px" Text="Next" Width="50px" />
                        </td>
                    </tr>
                </table>
            </div>
        <asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="~/Images/login.png" PostBackUrl="PersonalizedHome.aspx"
            Style="z-index: 102; left: 214px; position: absolute; top: 108px" />
    </form>
</body>
  1. 右键单击项目,选择“Add ASP.NET Folder”,然后选择“App_Code”。
  2. 添加之前使用过的 TokenHelper.cs 类,该类的副本可以在练习的完整版本的 App_Code 目录中找到。
  3. 右键单击 PersonalizedHome.aspx,选择“View Code”。
  4. 在文件顶部添加以下 using 语句:
using System.IdentityModel.Claims;
using Microsoft.IdentityModel.Samples;
  1. 修改 Page_Load 事件,使其能够处理信息卡片提供的令牌,修改后的代码如下:
protected void Page_Load(object sender, EventArgs e)
{

    string xmlToken;
    xmlToken = Request.Params["xmlToken"];
    if (xmlToken == null || xmlToken == "")
    {
        Session["postalCode"] = Request.Params["tbZipCode"];
    }
    else
    {
         TokenHelper tokenHelper = new TokenHelper(xmlToken);
         RetrieveTokenClaims(tokenHelper.IdentityClaims);
    }

    string postalCode = (string)Session["postalCode"];
    if (!String.IsNullOrEmpty(postalCode))
    {

        ZipCodeInformation.RegisteredUser zcUser = new ZipCodeInformation.RegisteredUser();
        zcUser.UserID = userID;
        zcUser.Password = password;
        ZipCodeInformation.LicenseInfo zcLicenseIfo = new ZipCodeInformation.LicenseInfo();
        zcLicenseIfo.RegisteredUser = zcUser;
        ZipCodeInformation.SDPZipCodes zipCodeService = new ZipCodeInformation.SDPZipCodes();
        zipCodeService.LicenseInfoValue = new ZipCodeInformation.LicenseInfo();
        zipCodeService.LicenseInfoValue = zcLicenseIfo;
        ZipCodeInformation.ZipCodeOutput zipCodeInfo = zipCodeService.GetZipCode(postalCode);

        // Use the ZIP code to retrieve city, state, and county. 
       // These will be used with the other services.

        Session["city"] = zipCodeInfo.ServiceResult.ZipCodes[0].PreferredCityName;
        Session["state"] = zipCodeInfo.ServiceResult.ZipCodes[0].State;
        Session["county"] = zipCodeInfo.ServiceResult.ZipCodes[0].County;
        pnlStateInfo.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderStateInfo));
        pnlCityInfo.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderCountyAndCityInfo));
        pnlCensusInformation.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderCensusInfo));
        pnlSenatorInfo.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderSenatorInfo));
        pnlHeader.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(RenderHeader));
    }
}
  1. 添加 RetrieveTokenClaims 方法,该方法会查询从令牌中获取的声明集,并将提供的声明赋值给同名的会话变量,代码如下:
private void RetrieveTokenClaims(ClaimSet claims)
{
    foreach (Claim claim in claims)
    {
        switch (claim.ClaimType)
        {
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname":
                Session["givenName"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname":
                Session["surName"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier":
                Session["ppid"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress":
                Session["email"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality":
                Session["city"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country":
                Session["country"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode":
                Session["postalCode"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince":
                Session["state"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mobilephone":
                Session["mobile"] = claim.Resource.ToString();
                break;
            case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress":
                Session["street"] = claim.Resource.ToString();
                break;
        }
    }
}
  1. 在 web.config 文件的 appSettings 元素中添加以下元素:
<add key="CertificateSubject" value="www.fabrikam.com"/>
<add key="StoreName" value="My"/>
<add key="StoreLocation" value="LocalMachine"/>
<add key="IdentityClaimType" value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode"/>
<add key="MaximumClockSkew" value="60"/>
</appSettings>
  1. 添加一个名为 personalgovernment 的新虚拟目录(IIS 6)或应用程序(IIS 7),并将其指向该网站。
  2. 为新创建的虚拟目录或应用程序启用 SSL。
  3. 打开 Internet Explorer,浏览到“https://www.fabrikam.com/personalgovernment”,会看到登录屏幕。
  4. 点击“Sign In with Your Information Card”按钮,会提示选择包含有效邮政编码的信息卡片。
  5. 如果已有信息卡片,选择它;如果没有,创建一张卡片并填入邮政编码。若不在美国,可以使用邮政编码 98052。提供信息卡片后,网站会调用 StrikeIron 的六个服务,生成个人政府页面。

10. 总结

通过上述步骤,我们实现了在没有用户账户和用户活动历史信息的情况下进行网站个性化。利用信息卡片和一个简单的邮政编码,就能为用户首次访问网站时提供定制化体验。整个过程涉及到注册后端服务、创建网站页面、添加服务引用、编写代码处理数据和信息卡片等多个步骤,但通过逐步操作,最终可以打造出一个具有个性化功能的政府网站。

流程图

graph LR
    A[开始] --> B[注册StrikeIron服务]
    B --> C[创建网站]
    C --> D[引用服务]
    D --> E[创建收集邮编页面]
    E --> F[创建显示个性化内容页面]
    F --> G[测试解决方案]
    G --> H[添加信息卡片支持]
    H --> I[完成个性化网站]

表格:服务及其功能

服务名称 功能
ZipCodeInformation 检索美国邮政编码对应的城市、州和郡信息
StateInformation 返回给定美国州的人口、网站、州长和时区等信息
SenatorInformation 返回给定美国州的参议员信息
CountyWebSites 返回给定郡的网站 URL(若存在)
CityWebSites 返回给定城市的网站 URL(若存在)
CensusInformationForZipCode 返回给定邮政编码的美国人口普查数据

11. 代码逻辑分析

11.1 Page_Load 事件逻辑

PersonalizedHome.aspx Page_Load 事件中,代码逻辑如下:
1. 首先尝试获取信息卡片提供的令牌 xmlToken
2. 如果 xmlToken 为空,说明用户是手动输入的邮政编码,将其存入会话变量 Session["postalCode"]
3. 如果 xmlToken 不为空,使用 TokenHelper 类处理令牌,并调用 RetrieveTokenClaims 方法从令牌的声明集中提取信息并存入会话变量。
4. 从会话变量中获取邮政编码,使用 ZipCodeInformation 服务获取该邮政编码对应的城市、州和郡信息,并存入会话变量。
5. 为各个面板指定渲染委托,以便后续动态渲染内容。

11.2 渲染方法逻辑

各个渲染方法(如 RenderStateInfo RenderSenatorInfo 等)的逻辑类似:
1. 创建对应服务的实例,并设置用户 ID 和密码进行身份验证。
2. 调用服务的方法获取数据。
3. 使用 HtmlTextWriter 将数据以 HTML 表格或其他格式写入面板。

11.3 RetrieveTokenClaims 方法逻辑

该方法遍历令牌声明集中的每个声明,根据声明类型将其值存入相应的会话变量,方便后续使用。

12. 可能遇到的问题及解决方案

12.1 服务调用失败

  • 原因 :可能是用户 ID 或密码错误,或者网络连接问题。
  • 解决方案 :检查 userID password 是否正确,确保网络连接正常。

12.2 信息卡片无法使用

  • 原因 :可能是信息卡片配置不正确,或者网站的 SSL 配置有问题。
  • 解决方案 :检查信息卡片是否包含有效的邮政编码,确保网站的 SSL 配置正确,并且在 IIS 中正确设置了虚拟目录或应用程序。

12.3 页面显示异常

  • 原因 :可能是 HTML 代码或 CSS 样式有问题,或者服务返回的数据格式不符合预期。
  • 解决方案 :检查 HTML 代码和 CSS 样式,确保没有语法错误;调试服务调用,查看返回的数据格式是否正确。

13. 扩展与优化建议

13.1 增加更多个性化内容

可以根据用户提供的其他信息(如姓名、邮箱等)进一步个性化页面内容,例如显示欢迎消息、发送个性化邮件等。

13.2 提高性能

可以使用缓存机制来减少对后端服务的频繁调用,提高页面加载速度。例如,将常用的服务结果缓存到内存中,在一定时间内直接使用缓存数据。

13.3 增强用户体验

可以添加更多的提示信息和错误处理机制,让用户在使用过程中更加清晰地了解操作步骤和可能出现的问题。例如,在用户输入无效邮政编码时给出明确的提示。

14. 总结回顾

通过一系列的步骤,我们成功地实现了一个基于信息卡片的个性化政府网站。从注册后端服务、创建网站结构、引用服务、收集用户信息到显示个性化内容,每个环节都紧密相连。信息卡片的使用使得用户提供数据更加便捷,为首次访问网站的用户提供了更好的个性化体验。

同时,我们也分析了代码逻辑、可能遇到的问题及解决方案,并提出了一些扩展和优化建议。在实际应用中,可以根据具体需求对网站进行进一步的改进和完善,以满足更多用户的需求。

流程图:代码执行流程

graph LR
    A[Page_Load开始] --> B{是否有信息卡片令牌?}
    B -- 是 --> C[处理令牌并提取信息]
    B -- 否 --> D[获取手动输入的邮政编码]
    C --> E[获取城市、州和郡信息]
    D --> E
    E --> F[设置面板渲染委托]
    F --> G[渲染各个面板内容]

表格:扩展与优化建议及说明

建议 说明
增加更多个性化内容 根据用户其他信息进一步定制页面,如显示欢迎消息、发送个性化邮件
提高性能 使用缓存机制减少后端服务调用,提高页面加载速度
增强用户体验 添加提示信息和错误处理机制,让用户操作更清晰
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值