Om forkellige måder at stukturerer sine koder med ASP.NET


13 April 2002 @ 21:06

Her vise en trin vis overgang fra procedural til Objektorienteret kodning. Artiklen giver en indføring i de mange forskellige metoder som kan anvendes til at præsenterer data med ASP.net


af Anders Bodeval Carlsen

ASP.NET er et godt redskab til at få struktureret sine koder.
Du har utroligt mange forskellige metoder til din rådighed når,
du skal skrive en kode. Men netop pga. de mange muligheder kan det hele 
godt gå hen og virke temmeligt uoverskueligt. Man kan gøre det samme på et
utal af måder. 

Hvad er den bedste måde at gøre det på?.

Et hurtigt svar er - "Den der virker" !
Har du kodet tilstrækkeligt meget asp er dette svar sikker ikke længere
tilstrækkeligt, men vil snarre lyde som - "Den som kan genbruges" eller
"Den som hjælper mig til at forstå og overskue den problemstilling jeg arbejder med"

Og det er netop det som ASP.NET åbner mulighed for. - Objektorienteret Programmering. 

For at hjælpe mig selv og andre på vejen til at mestre ASP.NET har jeg lavet. 
En række enkle eksempler hvor det samme bliver udført, men med anvendelse 
af nogle af de forskellige metoder som jeg er bekendt med. 

-----------------------------------------------------------------

Eks 1.

<% @Page Language="C#"%>
<html>
<body>
<%
String MyString = "Hej Verden!";

for(int i = 0; i < 3; i++)
  Response.Write(MyString);
%>

<%= MyString %>
</body>
</html>

Husk side direktivet. <% @Page Language="C#"%> ellers ligner det jo
stort set asp som vi kender det.

---------------------------------------------------------------------
Eks. 2

<% @Page Language="C#" %>
<script Language="C#" runat="server">
void SkrivStreng()
{
 String MyString = "Hej Verden!"; 
 for(int i = 0; i < 3; i++)
    Response.Write(MyString);
}
</script>

<html>
<body>
<%
SkrivStreng();
%>
</body>
</html>


Her har jeg koden ind i en funktion

------------------------------------------------------------------------
Eks. 3

<% @Page Language="C#" Debug="true" %>

<script Language="C#" runat="server">
void Page_Load(Object sender, EventArgs e) {
  MyDiv.InnerHtml = SkrivStreng("Hej Verden!",3);

}

string SkrivStreng(String MyString, int Antal) {

    String result = "";
    for(int i = 0; i < Antal; i++)
        result += MyString;
    return result;
}

</script>

<html>
<body>
<div runat="server" id="MyDiv" />
</body>
</html>



Her har jeg tilføjet eventhandleren Page_Load som indtræffer. 
Funkitionen SkrivStreng er ændret så den returnerer resultatet istedet for 
at udskrive det. For at gøre funktionen mere fleksibel og genbrugelig
har jeg tilfølet nogle parametre til funktionen.
Husk at når du bruger runat=server skal html-koden være wellformed.
Det vil sige at div-tag'et skal afsluttes enten ved at skrive <div /> eller
<div></div>

I det næste eksempel vil jeg indkapsle funktionen i et objekt.

------------------------------------------------------------------------
Eks. 4

<% @Page Language="C#" Debug="true" %>
<script Language="C#" runat="server">
class MyClass 
{
public string SkrivStreng(String MyString, int Antal)
{
    String result = "";
    for(int i = 0; i < Antal; i++)
        result += MyString;
    return result;
}
}

void Page_Load(Object sender, EventArgs e) {

    MyClass obj = new MyClass();
    MyDiv.InnerHtml = obj.SkrivStreng("Hej Verden!",3);
}
</script>

<html>
<body>
    <div runat="server" id="MyDiv" />
</body>
</html>


Her har jeg indkapslet funktionen i et en class. 
Dermed er jeg forberedt til at koden kan blive puttet ind i en seperat fil.
Men først vil jeg lige omskrive MyClass så at man kan sætte argumenterne som properties.

------------------------------------------------------------------------
Eks. 5

<% @Page Language="C#" Debug="true" %>
<script Language="C#" runat="server">
public class MyClass 
{
    private String _MyString = "";
    private int _Antal = 0;

    public int Antal {
    get { return _Antal; }
    set { _Antal = value; }
}

public String MyString {
    get { return _MyString; }
    set { _MyString = value; }
}

public String SkrivStreng()
{
    String result = "";
    for(int i = 0; i < _Antal; i++)
        result += _MyString;
    return result;
}
}

void Page_Load(Object sender, EventArgs e) {

    MyClass obj = new MyClass();
    obj.MyString = "Min Verden";
    obj.Antal = 34;
    MyDiv.InnerHtml = obj.SkrivStreng();
}
</script>

<html>
<body>
    <div runat="server" id="MyDiv" />
</body>
</html>


Her er argumenterne lagt ind i properties som skrives meget let og elegant i C#
Der er nu en skap adskillelse mellem koden og anvendelse af koden.
I det næste eksempel vil jeg gøre den adskillelse endnu merer skarp ved at
Lægge koden i en seperat fil.


------------------------------------------------------------------------
Eks. 6
----------------
fil: Eksempel6.cs
----------------

using System;
using System.Web.UI;

public class MyClass : Page 
{
    private String _MyString = "";
    private int _Antal = 0;

    public int Antal {
    get { return _Antal; }
    set { _Antal = value; }
}

public String MyString {
    get { return _MyString; }
    set { _MyString = value; }
}

public String SkrivStreng()
{
    String result = "";
    for(int i = 0; i < _Antal; i++)
        result += _MyString;
    return result;
}
}


Der er ikke ændret noget på koden med der er tilføjet referencer til system biblioteket.
using System;
using System.Web.U
I;

System er nødvendige for de mest basale ting som f.eks håndteringe af tekst-strenge.
System.Web.UI er nødvendig for at objektet kan indgå i sammenhæng med en ASP.NET applikation.
"public class MyClass : Page" Her er tilføjet ":Page" hvilket betyder at MyPage aver alle egenskaber
og metoder fra Klassen Page, så at de kan kaldes fra MyClass. 

----------------
fil: Eksempel6.aspx
----------------

<% @Page Language="C#" Inherits="MyClass" Src="Eksempel6.cs" %>

<script Language="C#" runat="server">
    void Page_Load(Object sender, EventArgs e) {

        MyClass obj = new MyClass();
        obj.MyString = "Min Verden";
        obj.Antal = 34;
        MyDiv.InnerHtml = obj.SkrivStreng();
}
</script>

<html>
<body>
    <div runat="server" id="MyDiv" />
</body>
</html>


Nu er den oprindelige fil smukt renset for overflødig kode. 
Du vil trygt kunne overlade den til f.eks en designer.
For at jeg kan bruge MyClass er der tilføjet - Inherits="MyClass" Src="Kodestruktur.cs" -
i sidediriktivet.

Men måske gik det alligevel galt med designeren og du kunne ønske dig en endnu bedre
adskillelse af kode og layout.
Det findes der råd for ved hjælp af "user controls"

I det næste eksempel vil jeg opdele applikationen i tre filer. 
En layout fil Eksempel7.aspx
En Webform fil Eksempel7.ascx
Og så klassen fra Eksempel7.cs 

------------------------------------------------------------------------
Eks. 7
----------------
fil: Eksempel7.aspx
----------------

<%@Page Language="C#" %>
<%@ Register TagPrefix="Eksempel" TagName="MyControl" Src="Eksempel7.ascx" %>
<html>
<body>
    <Eksempel:MyControl runat="server" Tekst="Min verden" Antal="34" />
</body>
</html>


Aspx- filen er nu fuldstændigt renset for "buisenes logic" eller kode ved hjælp
af en "user control"
Der laves en reference til Kontrollen 
med ( <%@ Register TagPrefix="Eksempel" TagName="MyControl" Src="Eksempel7.ascx" %> )


----------------
fil: Eksempel7.ascx
----------------

<%@ Control ClassName="MyControl" Inherits="MyClass" Src="Eksempel7.cs" %>

<script Language="C#" runat="server">
    private MyClass obj = new MyClass();
    public String Tekst {
        get { return obj.MyString; }
        set { obj.MyString = value; }
    }

    public int Antal {
        get { return obj.Antal; }
        set { obj.Antal = value; }
    }

    void Page_Load(Object sender, EventArgs e) {
        MyDiv.InnerHtml = obj.SkrivStreng();
    }
</script>
<div runat="server" id="MyDiv" />


Jeg tror at teknikken med at bruge "User Controls" vil være en afløser for
den måde som man ofte har brugt include-filer i Klassisk-ASP. 
En "User Control" Leverer HTML tekst til en aspx-fil.
Side direktivet hedder nu. 
<%@ Control ClassName="MyControl" Inherits="MyClass" Src="Eksempel7.cs" %>
Der er lavet to propeties til kontrollen.

----------------
fil: Eksempel7.cs
----------------

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

public class MyClass : UserControl
{ ............................


Denne fil ligner Eksempel6.cs, men med 2 små ændringer.

using System.Web.UI.WebControls; - er tilføjet
Page er ændret til UserControl. Da Objektet nu skal indgå isammenhæng med
en "User Control" og ikke en side.

------------------------------------------------------------------------
Eks. 8

Det sidste eksempel jeg vil vise idag er hvordan man får puttet koden ind i 
en dll-fil. 

Du ved sikkert at anvendelsen af dll-filer ikke har været særligt sjov at arbejde
med i klassisk ASP, hvilket også har gjort at det ofte kun er blevet anvendet
i situationer hvor man har været tvunget til det. 
Men lige så vanskeligt det har været, lige så let er det i ASP.NET
Der er ikke længre noget med at en dll fil skal registreres. Hvis den er der, så
virker den. Og kompilering kan foretages med et enkelt komando kald. f.eks. fra
en bat-fil. 

Anvendelsen af dll-filer i ASP.NET vil være en kærkommen mulighed for mange udviklerer. 
Koden bliver kompileret en gang for alle, og når den er pakket ind i en dll-fil er koden
skjult for uvedkommende. Man kan beskytte sine intellektuelle rettigheder og undgå 
at der bliver ændret i ens kode. Og endeligt performer webapplikationen bedre.

----------------
fil: compile.bat
----------------

csc /target:library /out:../bin/MyClass.dll Eksempel8.cs
pause


Kompileren csc får 3 argumenter. 
/target:library - Fortæller at det skal være en dll-fil
/out:MyClass.dll - Fortæller hvor dll-filen skal placeres.
Og sidste argument er adressen til koden.

Dll-filen skal ligge i bin biblioteket

----------------
fil: Eksempel8.ascx
----------------

<%@ Control ClassName="MyControl" %>
<%@ Import Namespace="bodeval.dk" %>
<script Language="C#" runat="server">

    private MyClass obj = new MyClass();
    public String Tekst {
        get { return obj.MyString; }
        set { obj.MyString = value; }
    }

    public int Antal {
        get { return obj.Antal; }
        set { obj.Antal = value; }
    }

    void Page_Load(Object sender, EventArgs e) {
        MyDiv.InnerHtml = obj.SkrivStreng();
    }
</script>
<div runat="server" id="MyDiv" />


Her er der kun lavet en lille ændring i toppen af filen i forhold til
Eksembel7.ascx
Istedet for at refererer til klassen med Inherits="MyClass" Src="Eksembel6.cs" 
er der lavet en Import med Import Namespace="bodeval.dk"

----------------
fil: Eksempel8.cs
----------------

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace bodeval.dk
{

    public class MyClass : UserControl
    {
        private String _MyString = "";
        private int _Antal = 0;

        public int Antal {
            get { return _Antal; }
            set { _Antal = value; }
        }

        public String MyString {
            get { return _MyString; }
            set { _MyString = value; }
        }

        public String SkrivStreng()
        {
        String result = "";
        for(int i = 0; i < _Antal; i++)
            result += _MyString;
        return result;
        }
    }
}




Den eneste ændring der er foretaget her er at der 
er tilføjet. -

namespace bodeval.dk
{
    .... class 
}



Klassisk ASP er ved at være fortid. 
Find tid til ASP.NET - Internettet branchen er dynamisk. 
Klassisk ASP har været et fint redskab, men nu skal vi videre. :-)


Valid XHTML 1.0!