niedziela, 2 września 2012

ASP.NET Personalizacja

Jako że od pewnego czasu moja praca zawodowa zmierza bardziej w kierunku ASP postanowiłem nauczyć się czegoś nowego. Tym razem zajmę się personalizacją.

Dodawanie prostej właściwości personalizacji

Powiedzmy że chcemy przechować następujące informacje o użytkowniku:
  • imię
  • nazwisko
  • data ostatniej wizyty
  • wiek
  • status członkostwa
Na początek utwórzmy sobie nowy pusty projekt:

Aby skorzystać z dobrodziejstw personalizacji należy wykonać kilka zmian w pliku Web.config
W sekcji <system.web> należy dodać element <profile> a w nim kolejny element <properties>. To właśnie tam można zdefiniować wszystkie właściwości które będą przechowywane przez silnik personalizacji.
W moim przypadku Web.config wygląda w tej chwili tak:

<configuration>
    <system.web=".web">
      <profile>
        <properties>
          <add name="FirstName" />
          <add name="LastName" />
          <add name="LastVisited" />
          <add name="Age" />
          <add name="Member" />
        </properties>
      </profile>
      <compilation debug="false" targetframework="4.5">
      <httpruntime targetframework="4.5">
    </httpruntime></compilation></system>
</configuration>
Po zdefiniowaniu właściwości personalizacji wykorzystanie ich jest wyjątkowo łatwe.
Utworzymy teraz prosty formularz, który pobiera wcześniej ustalone informacje od użytkowników.
Przykładowy kod pliku aspx może wyglądać tak:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <p>Imię:
                <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
            </p>
            <p>Nazwisko:
                <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
            </p>
            <p>Wiek:
                <asp:TextBox ID="TextBox3" runat="server" MaxLength="3"></asp:TextBox>
            </p>
            <p>
                <asp:RadioButtonList ID="RadioButtonList1" runat="server">
                    <asp:ListItem Value="1">Tak</asp:ListItem>
                    <asp:ListItem Value="0" Selected="True">Nie</asp:ListItem>
                </asp:RadioButtonList>
            </p>
            <p>
                <asp:Button ID="Button1" runat="server" Text="Zatwierdź" OnClick="Button1_Click" />
            </p>
            <hr />
            <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
        </div>
    </form>
</body>
</html>


Obsługa zdarzenia Button_Click:
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (Page.User.Identity.IsAuthenticated)
        {
            Profile.FirstName = TextBox1.Text;
            Profile.LastName = TextBox2.Text;
            Profile.Age = TextBox3.Text;
            Profile.Member = RadioButtonList1.SelectedItem.Text;
            Profile.LastVisited = DateTime.Now.ToString();

            Label1.Text = "Przechowwane informacje to:" +
                "Imię: " + Profile.FirstName +
                "Nazwisko: " + Profile.LastVisited +
                "Wiek: " + Profile.Age +
                "Członek: " + Profile.Member +
                "Ostatnia wizyta: " + Profile.LastVisited;
        }
        else {
            Label1.Text = "Musisz być pozytywnie zweryfikowany!";
        }
    }

W tym przykładzie zakładamy na razie, że użytkownik przeszedł już proces uwierzytelniania. Jeśli teraz nie dalibyśmy tego if'a, to wystąpiłby wyjątek.
Samym procesem uwierzytelniania zajmę się później.

Fajne jest to że VisualStudio rozpoznaje właściwości wpisane w plik Web.config przy pisaniu metody obsługi kliknięcia przycisku:

Jest to możliwe dzięki temu, że klasa Profile jest ukryta i kompilowana dynamicznie w tle za każdym razem, gdy modyfikowany jest plik Web.config.

Wszystkie elementy przechowywane w systemie personalizacji są rzutowane na określony typ. Domyślnym typem jest String.

Dodawanie grup właściwości personalizacji.

Jeśli potrzebna nam jest większa ilość właściwości personalizacji może zachodzić potrzeba uporządkowania ich w grupy. Jest to możliwe poprzez prostą modyfikację w pliku Web.config. Oto zmodyfikowana część <profile>:

<profile>
      <properties>
        <add name="FirstName"/>
        <add name="LastName"/>
        <add name="LastVisited"/>
        <add name="Age"/>
        <add name="Member"/>

        <group name="MemberDetails">
          <add name="Member"/>
          <add name="DateJoined"/>
          <add name="PaidDuesStatus"/>
          <add name="Location"/>
        </group>

        <group name="FamilyDetails">
          <add name="MarriedStatus"/>
          <add name="DateMarried"/>
          <add name="NumberChildren"/>
          <add name="Location"/>
        </group>
        
      </properties>
</profile>

Jak widać dodane zostały nowe właściwości wewnątrz znaczników <group> które obowiązkowo muszą posiadać atrybut "name". Dzięki temu możwmy się odwoływać do właściwości profilu w następujący sposób:

Profile.MemberDetails.Location
Profile.FamilyDetails.Location

Jak widać mamy teraz 2 atrybuty Location do których możemy się odwołać podając uprzednio nazwę grupy.

Zmiana domyślnego typu przechowywanej wartości

Aby domyślnym typem nie był string, wystarczy do ustalonych już właściwości dodać atrybut "type":

<add name="FirstName" type="System.String"/>
<add name="LastName" type="System.String"/>
<add name="LastVisited" type="System.DateTime"/>
<add name="Age" type="System.Int32"/>
<add name="Member" type="System.Boolean"/>

Podobnie możemy ustawiać wartości domyślne za pomocą atrybutu "defaultValue":

<add name="Member" type="System.Boolean" defaultValue="false"/>


Co jednak zrobić jeśli chcemy przechowywać własny zdefiniwoany przez siebie typ danych?
Stwórzmy sobie klasę reprezentującą wózek z zakupami:


public class ShoppingCart
{
    [Serializable]
 public class ShoppingCart()
 {
  private string PID;
        private string CompanyProductName;
        private int Number;
        private decimal Price;
        private DateTime DateAdded;

        public ShoppingCart(){}

        public string ProductID{
            get{return PID;}
            set {PID = value;}
        }

        public string ProductName
        {
            get{return CompanyProductName;}
            set{CompanyProductName=value;}
        }

        public int NumberSelected{
            get{return Number;}
            set{Number = value;}
        }

        public decimal ItemPrice{
            get{return Price;}
            set{Price = value;}
        }

        public DateTime DateItemAdded
        {
            get{return DateAdded;}
            set{DateAdded=value;}
        }

 }
}

Zauważmy, że klasa posiada atrybut Serializable. Jest to wymagane w wypadku, gdy korzystamy z niej jako wartości personalizacji, która jest zapisywana po stronie serwera w jakimś magazynie danych. Można ją wtedy przenieść np do bazy danych w postaci binarnej lub xml.

Teraz w pliku Web.config możemy dodać np coś takiego:

<add name="Cart" type ="SchoppingCart" serializeAs="Binary"/>

Atrybut SerializeAs może przyjmować następujące wartości:

  • Binary - przechowywanie w postaci binarnej
  • ProviderSpecific - przechowywanie w postaci zdefiniowanej przez dostawcę (silnik personalizacji nie dokonuje serializacji lecz dostawca)
  • String - ustawienie domyślne, przchowywanie w postaci łańcucha znaków
  • XML- serializacja do postaci XML