Ado και ado.net, ομοιότητες και διαφορές

Πληροφορίες σχετικές με την ASP, ASP.NET και με τις εφαρμογές που είναι γραμμένες με αυτήν.

Συντονιστές: WebDev Moderators, Super-Moderators

Απάντηση
Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από skeftomilos » 03 Ιαν 2006 04:10

Λοιπόν, τι θα λέγατε για λίγη εξάσκηση σε ADO και ADO.NET; Ετοίμασα μερικά απλά παραδειγματάκια που δείχνουν τις ομοιότητες και διαφορές μεταξύ αυτών των δύο τεχνολογιών.

Τα παραδείγματα προϋποθέτουν μία βάση με όνομα Demo.mdb. Η βάση είναι όσο πιο απλή γίνεται. Αποτελείται ένα πίνακα Demo, ο οποίος έχει ένα text πεδίο Data, και περιέχει τρεις εγγραφές:

- London
- Paris
- Rome

Υπάρχουν τρία παραδείγματα με ADO και πέντε με ADO.NET, τα οποία παράγουν το ίδιο οπτικό αποτέλεσμα.

Εικόνα
__________________________________________________________________________________

ADO-1-Connection.asp

Κώδικας: Επιλογή όλων

<%
  Set connection = Server.CreateObject&#40;"ADODB.Connection"&#41; 
  connection.Open "DRIVER=&#123;Microsoft Access Driver &#40;*.mdb&#41;&#125;; DBQ=" & Server.MapPath&#40;"Demo.mdb"&#41; 
  Set RS = connection.Execute&#40;"SELECT * FROM Demo"&#41;
%>
<html>
  <body>
    <h2>ADO-1-Connection</h2>
    <ul>
<%
  Do While Not RS.EOF
%>
      <li><%=RS&#40;"Data"&#41;%></li>
<%
    RS.MoveNext
  Loop
%>
    </ul>
  </body>
</html>
Η πιο απλή μέθοδος στο ADO είναι να δημιουργηθεί μία Connection και να κληθεί η μέθοδος Execute. Μας δίνει ένα Recordset το οποίο το διατρέχουμε με ένα βρόγχο Do...Loop. Μέσα στο βρόγχο πρέπει να υπάρχει η εντολή RS.MoveNext διαφορετικά αν το ξεχάσουμε δημιουργείται ατέρμονας βρόγχος και η σελίδα «κολλάει».
__________________________________________________________________________________

ADO-2-Command.asp

Κώδικας: Επιλογή όλων

<%
  Set connection = Server.CreateObject&#40;"ADODB.Connection"&#41; 
  connection.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;
  Set command = Server.CreateObject&#40;"ADODB.Command"&#41;
  command.ActiveConnection = connection
  command.CommandText = "SELECT * FROM Demo"
  Set RS = command.Execute
%>
<html>
  <body>
    <h2>ADO-2-Command</h2>
    <ul>
<%
  Do While Not RS.EOF
%>
      <li><%=RS&#40;"Data"&#41;%></li>
<%
    RS.MoveNext
  Loop
%>
    </ul>
  </body>
</html>
Μπορούμε να δημιουργήσουμε ένα αντικείμενο Command για να έχουμε περισσότερο έλεγχο στην εκτέλεση του query. Στην πραγματικότητα πάντα δημιουργείται αντικείμενο Command, ακόμα και αν δεν το δηλώσουμε ρητά. Π.χ. στο προηγούμενο παράδειγμα μόλις καλέσαμε την connection.Execute δημιουργήθηκε ένα τέτοιο αντικείμενο πίσω από το παραβάν.
__________________________________________________________________________________

ADO-3-Command-Parameters.asp

Κώδικας: Επιλογή όλων

<!--#INCLUDE FILE="adovbs.inc"-->
<%
  Set connection = Server.CreateObject&#40;"ADODB.Connection"&#41; 
  connection.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;
  Set command = Server.CreateObject&#40;"ADODB.Command"&#41;
  command.ActiveConnection = connection
  command.CommandText = "SELECT Data FROM Demo WHERE Len&#40;Data&#41; >= ?"
  command.Parameters.Append command.CreateParameter&#40;"MinimumLength", adInteger, adParamInput, , 5&#41;
  Set RS = command.Execute
%>
<html>
  <body>
    <h2>ADO-3-Command-Parameters</h2>
    <ul>
<%
  Do While Not RS.EOF
%>
      <li><%=RS&#40;"Data"&#41;%></li>
<%
    RS.MoveNext
  Loop
%>
    </ul>
  </body>
</html>
Όταν θέλουμε να περάσουμε κάποια παράμετρο στο query, π.χ. ένα Id, καλό είναι να χρησιμοποιήσουμε από ένα αντικείμενο Parameter για κάθε παράμετρο. Υπάρχει βέβαια η απλούστερη μέθοδος όπου συνθέτουμε το query με συνένωση string, αλλά υπάρχουν σοβαρά προβλήματα ασφάλειας. Για παράδειγμα έστω ότι έχουμε την εξής εντολή:

Κώδικας: Επιλογή όλων

query = "SELECT * FROM Customers WHERE CustomerId = " & Request&#40;"Id"&#41;
Ένας hacker μπορεί να παίξει πολλά παιχνίδια με ένα τέτοιο query. Π.χ. μπορεί να κανονίσει ώστε η τιμή της Request("Id") να είναι "CustomerId", και σε αυτή την περίπτωση το query που θα εκτελεστεί θα είναι...

Κώδικας: Επιλογή όλων

SELECT * FROM Customers WHERE CustomerId = CustomerId
...το οποίο όπως καταλαβαίνετε επιστρέφει όλους τους πελάτες. Ακόμα πιο επικίνδυνα είναι τα πράγματα στην περίπτωση που έχουμε να κάνουμε με SQL Server, όπου επιτρέπονται περισσότερα από ένα queries στην ίδια εντολή. Εκεί οι hackers κάνουν party! Η λύση είναι τα αντικείμενα Parameter, που ελέγχουν τον τύπο της παραμέτρου. Αν π.χ. η παράμετρος είναι τύπου integer δε μπορεί κανείς να δώσει string, βγαίνει σφάλμα.
__________________________________________________________________________________

ADO.NET-1-DataReader.aspx

Κώδικας: Επιλογή όλων

<%@ Import Namespace="System.Data.OleDb" %>
<%
  Dim connection = New OleDbConnection&#40;"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;&#41;
  Dim command = New OleDbCommand&#40;"SELECT * FROM Demo", connection&#41;
  connection.Open&#40;&#41;
  Dim reader = command.ExecuteReader&#40;&#41;
%>
<html>
  <body>
    <h2>ADO.NET-1-DataReader</h2>
    <ul>
<%
  Do While reader.Read&#40;&#41;
%>
      <li><%=reader&#40;"Data"&#41;%></li>
<%
  Loop
  connection.Close&#40;&#41;
%>
    </ul>
  </body>
</html>
Στο ADO.NET τα αντικείμενα δε δημιουργούνται με Server.CreateObject γιατί το .NET είναι μια τεράστια βιβλιοθήκη αντικειμένων και περιέχει τα πάντα, δε χρειάζονται επομένως εξωτερικά compomemts όπως στην ASP. Υπάρχουν τα γνώριμα αντικείμενα Connection και Command, αλλά όχι το Recordset. Αυτό καταργήθηκε γιατί ήταν δύσχρηστο και προσπαθούσε να κάνει πολλά πράγματα μαζί. Στο .NET υπάρχει πλατύτερη κατανομή των διαφόρων εργασιών.

Ο πιο άμεσος τρόπος για να διαβάσουμε τα περιεχόμενα της database είναι με έναν DataReader. Καλούμε την μέθοδο ExecuteReader μίας Command και αντί για Recordset παίρνουμε έναν DataReader, τον οποίο έπειτα διατρέχουμε με ένα βρόγχο Do...Loop. Δεν υπάρχει κίνδυνος να ξεχάσουμε την MoveNext γιατί δεν υπάρχει. Κάθε φορά που καλείται η μέθοδος Read προχωράει στην επόμενη γραμμή.
__________________________________________________________________________________

ADO.NET-2-DataAdapter-DataTable.aspx

Κώδικας: Επιλογή όλων

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%
  Dim adapter = New OleDbDataAdapter&#40;"SELECT * FROM Demo", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;&#41;
  Dim dataTable = New DataTable&#40;&#41;
  adapter.Fill&#40;dataTable&#41;
%>
<html>
  <body>
    <h2>ADO.NET-2-DataAdapter-DataTable</h2>
    <ul>
<%
  Dim row
  For Each row In dataTable.Rows
%>
      <li><%=row&#40;"Data"&#41;%></li>
<%
  Next
%>
    </ul>
  </body>
</html>
Ο DataReader έχει ένα βασικό ελάττωμα, προχωράει μόνο εμπρός. Αν θέλουμε να διαβάσουμε τα δεδομένα με όποια σειρά θέλουμε, πρέπει να τα αποθηκεύσουμε πρώτα κάπου για να τα έχουμε πρόχειρα. Δε χρειάζεται όμως να παιδευόμαστε, υπάρχει έτοιμη η λύση. Το DataTable είναι ο αποθηκευτικός χώρος που χρειαζόμαστε, και ο DataAdapter αναλαμβάνει να γεμίσει το DataTable με τα δεδομένα. Στην πραγματικότητα πίσω από όλα αυτά δημιουργείται αυτόματα ένας DataReader, αλλά δε χρειάζεται να μας απασχολούν τέτοιες λεπτομέρειες. Εμείς απλά δημιουργούμε ένα DataTable, και ένα DataAdapter για να το γεμίσει. Δε χρειάζεται καν να ασχοληθούμε με την Connection γιατί ανοιγοκλείνει αυτόματα.
__________________________________________________________________________________

ADO.NET-3-DataAdapter-Command-DataTable.aspx

Κώδικας: Επιλογή όλων

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%
  Dim connection = New OleDbConnection&#40;"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;&#41;
  Dim adapter = New OleDbDataAdapter&#40;&#41;
  adapter.SelectCommand = New OleDbCommand&#40;"SELECT * FROM Demo", connection&#41;
  Dim dataTable = New DataTable&#40;&#41;
  adapter.Fill&#40;dataTable&#41;
%>
<html>
  <body>
    <h2>ADO.NET-3-DataAdapter-Command-DataTable</h2>
    <ul>
<%
  Dim row
  For Each row In dataTable.Rows
%>
      <li><%=row&#40;"Data"&#41;%></li>
<%
  Next
%>
    </ul>
  </body>
</html>
Ίδιο με το προηγούμενο με τη διαφορά ότι δηλώνεται ρητά το αντικείμενο Command. Ο DataAdapter περιέχει εντός του την απαραίτητη Command για τα SELECT queries, αλλά μπορούμε αν θέλουμε να την ορίσουμε ρητά. Γενικά στο ADO.NET υπάρχει μεγάλη ευελιξία και μπορούμε το ίδιο πράγμα να το γράψουμε με πολλούς τρόπους. Οι DataAdapters στην πραγματικότητα περιέχουν όχι μόνο μία αλλά τεσσερις Commands, από μία για τα SELECT, INSERT, UPDATE και DELETE queries.
__________________________________________________________________________________

ADO.NET-4-DataBinding.aspx

Κώδικας: Επιλογή όλων

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%
  Dim connection = New OleDbConnection&#40;"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;&#41;
  Dim adapter = New OleDbDataAdapter&#40;&#41;
  adapter.SelectCommand = New OleDbCommand&#40;"SELECT * FROM Demo", connection&#41;
  Dim dataTable = New DataTable&#40;&#41;
  adapter.Fill&#40;dataTable&#41;
  towns.DataSource = dataTable
  towns.DataBind&#40;&#41;
%>
<html>
  <body>
    <h2>ADO.NET-4-DataBinding</h2>
    <ul>
      <asp&#58;Repeater id="towns" runat="server">
        <ItemTemplate>
          <li><%# Container.DataItem&#40;"Data"&#41;%></li>
        </ItemTemplate>
      </asp&#58;Repeater>
    </ul>
  </body>
</html>
Εδώ ερχόμαστε στα πολύ ενδιαφέροντα. Το data binding είναι μια πρωτοτυπία της ASP.NET, δεν υπάρχει κάτι ανάλογο στην κλασική ASP. Η βασική ιδέα είναι να απαλλαγούμε από τους βρόγχους Do..Loop, For...Next κ.λπ. που μας υποχρεώνουν να έχουμε ένα σωρό <% %> <% %> και να μπαινοβγαίνουμε HTML-Κώδικα. Για να κάνουμε data binding πρέπει να βάλουμε ένα server-side control στη σελίδα. Τα server-side controls είναι άλλη μία πρωτοτυπία της ASP.NET. Ξεχωρίζουν από το attribute runat="server".

Το πιο ευέλικτο από αυτά τα controls είναι ο Repeater, που όπως λέει και το όνομά του επαναλαμβάνει συνεχώς το ίδιο μοτίβο για όλες τις γραμμές που έρχονται από τη βάση δεδομένων. Εμείς πρέπει να κάνουμε δύο πράγματα. Πρώτον να γεμίσουμε ένα DataTable, να το δώσουμε στον Repeater μέσω της ιδιότητας DataSource, και να καλέσουμε την DataBind(). Δεύτερον να γράψουμε μέσα στο tag <ItemTemplate> τον HTML κώδικα που θα επαναληφθεί για κάθε γραμμή. Μέσα σε αυτό τον κώδικα θα προσθέσουμε εκφράσεις όπως <%#Container.DataItem("ProductName")%> που είναι ένας ειδικός τύπος του γνωστού <%=...%> και χρησιμοποιείται αποκλειστικά στο DataBinding.

Το <ItemTemplate> δεν είναι το μοναδικό template που έχουμε στη διάθεσή μας. Υπάρχουν και τα <AlternatingItemTemplate>,
<SeparatorTemplate>, <HeaderTemplate> και <FooterTemplate> που μπορούμε να χρησιμοποιήσουμε αν θέλουμε.
__________________________________________________________________________________

ADO.NET-5-Command-Parameters.aspx

Κώδικας: Επιλογή όλων

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%
  Dim connection = New OleDbConnection&#40;"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath&#40;"Demo.mdb"&#41;&#41;
  Dim command = New OleDbCommand&#40;"SELECT * FROM Demo", connection&#41;
  command.Connection = connection
  command.CommandText = "SELECT Data FROM Demo WHERE Len&#40;Data&#41; >= ?"
  command.Parameters.Add&#40;"MinimumLength", OleDbType.Integer&#41;.Value = 5
  connection.Open&#40;&#41;
  Dim reader = command.ExecuteReader&#40;CommandBehavior.CloseConnection&#41;
  towns.DataSource = reader
  towns.DataBind&#40;&#41;
%>
<html>
  <body>
    <h2>ADO.NET-5-Command-Parameters</h2>
    <ul>
      <asp&#58;Repeater id="towns" runat="server">
        <ItemTemplate>
          <li><%# Container.DataItem&#40;"Data"&#41;%></li>
        </ItemTemplate>
      </asp&#58;Repeater>
    </ul>
  </body>
</html>
Αυτό το παράδειγμα δείχνει πώς προσθέτουμε μία παράμετρο σε μία Command. Η ιδέα είναι ίδια όπως στο ADO, αλλά διαφέρουν λίγο οι λεπτομέρειες όπως τα ονόματα των σχετικών μεθόδων. Κάτι άλλο που δείχνει είναι ότι μπορούμε να κάνουμε data binding και με ένα DataReader, δεν είναι υποχρεωτικό το DataTable. Στην πραγματικότητα υπάρχει ακόμα περισσότερη ευελιξία, καθώς μπορούμε να κάνουμε data binding ακόμα και με ένα απλό Array.
__________________________________________________________________________________

Όλα τα παραπάνω αρχεία μαζί με τη βάση δεδομένων βρίσκονται σε αυτό το zip: data-demo.zip. Για να τρέξουν τα παραδείγματα χωρίς πρόβλημα πρέπει ο φάκελος να έχει permissions read-write για τους χρήστες IUSR_ΌνομαΥπολογιστή και ASPNET. Ακόμα πρέπει να είναι εγκατεστημένη κάποια έκδοση του .NET Framework, και φυσικά ο IIS.

Πλήρες εγχειρίδιο για το ADO μπορείτε να βρείτε και να κατεβάσετε από το site της Microsoft σε μορφή chm: MDAC 2.8 Software Development Kit. Για το ADO.NET θα πρέπει να κατεβάσετε ολόκληρο το SDK για το .NET Framework, το οποίο όμως είναι ένα αρκετά ογκώδες download (> 100MB): .NET Framework SDK 1.1. Το .NET Framework 1.1 είναι εδώ: .NET Framework 1.1. Μπορείτε βέβαια να προτιμήσετε την πρόσφατη έκδοση 2.0, αν και πρακτικά δεν θα έχει διαφορά αν είστε σε φάση γνωριμίας με το .NET.
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Άβαταρ μέλους
cordis
Administrator, [F|H]ounder, [C|S]EO
Δημοσιεύσεις: 27622
Εγγραφή: 09 Οκτ 1999 03:00
Τοποθεσία: Greece
Επικοινωνία:

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από cordis » 03 Ιαν 2006 14:19

πολύ καλό! και μόλις έχω πάρει την απόφαση να ασχοληθώ με .NET.. :P
Δεν απαντάω σε προσωπικά μηνύματα με ερωτήσεις που καλύπτονται από τις ενότητες του forum. Για ο,τι άλλο είμαι εδώ για εσάς.
- follow me @twitter

Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από skeftomilos » 03 Ιαν 2006 16:52

Πάντως η μετάβαση από .NET σε PHP είναι κατά κάποιο τρόπο ένα πολιτισμικό σοκ. Οπότε φαντάζομαι ότι και η αντίστροφη μετάβαση δεν πρέπει να είναι πολύ εύκολη. :)
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Άβαταρ μέλους
cordis
Administrator, [F|H]ounder, [C|S]EO
Δημοσιεύσεις: 27622
Εγγραφή: 09 Οκτ 1999 03:00
Τοποθεσία: Greece
Επικοινωνία:

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από cordis » 03 Ιαν 2006 20:21

δεν είμαι PHPας :P για να ζήσω γράφω σε PowerBuilder :P PHP it's for fun! ;)
Δεν απαντάω σε προσωπικά μηνύματα με ερωτήσεις που καλύπτονται από τις ενότητες του forum. Για ο,τι άλλο είμαι εδώ για εσάς.
- follow me @twitter

Άβαταρ μέλους
geoki
Δημοσιεύσεις: 309
Εγγραφή: 07 Ιαν 2002 01:00
Τοποθεσία: Giannitsa

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από geoki » 04 Ιαν 2006 21:59

Φίλε skeftomile ευχαριστούμε πολύ για το πάρα πολύ διαφωτιστικό tutorial που έφτιαξες .

Πρέπει να σκεφτείς σοβαρά την πιθανότητα να εκμεταλλευτής το συγγραφικό σου ταλέντο σε συσχετισμό με τις πολλές γνώσεις που έχεις στον προγραμματισμό.

Είμαι σίγουρος ότι και άλλοι μέσα στο forum όπως κι εγώ έχουμε βοηθηθεί από τα πολύ χρήσιμα post που κάνεις. Συνέχισε .....

Άβαταρ μέλους
ThyClub
Honorary Member
Δημοσιεύσεις: 5312
Εγγραφή: 17 Νοέμ 2003 00:21
Τοποθεσία: Hell's Kitchen
Επικοινωνία:

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από ThyClub » 05 Ιαν 2006 03:35

geoki έγραψε:Φίλε skeftomile ευχαριστούμε πολύ για το πάρα πολύ διαφωτιστικό tutorial που έφτιαξες .

Πρέπει να σκεφτείς σοβαρά την πιθανότητα να εκμεταλλευτής το συγγραφικό σου ταλέντο σε συσχετισμό με τις πολλές γνώσεις που έχεις στον προγραμματισμό.
Μπορεί ( εγώ είμαι σίγουρος ) να το κάνει ήδη :wink:

Το:

Κώδικας: Επιλογή όλων

<asp&#58;Repeater id="towns" runat="server"> 
        <ItemTemplate> 
          <li><%# Container.DataItem&#40;"Data"&#41;%></li> 
        </ItemTemplate> 
      </asp&#58;Repeater> 
πάντως μου θυμίζει πολύ τον τρόπο που δουλεύει το smarty:

Κώδικας: Επιλογή όλων

&#123;section name=towns loop=$server&#125;
      <li>&#123;$server&#91;towns&#93;&#125;</li> 
&#123;/section&#125;
στο άκυρο η παρατήρηση μου :D

Megistos
Δημοσιεύσεις: 149
Εγγραφή: 14 Ιουν 2005 15:38

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από Megistos » 05 Ιαν 2006 16:30

skeftomilos έγραψε:Πάντως η μετάβαση από .NET σε PHP είναι κατά κάποιο τρόπο ένα πολιτισμικό σοκ.
Εδώ ήταν από ASP 3.0 σε ASP.NET και να μην πούμε και για ASP.NET 2.0 :wink:
The Flame Still Burns

Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από skeftomilos » 05 Ιαν 2006 22:12

ThyClub έγραψε:Το:

Κώδικας: Επιλογή όλων

<asp&#58;Repeater id="towns" runat="server"> 
        <ItemTemplate> 
          <li><%# Container.DataItem&#40;"Data"&#41;%></li> 
        </ItemTemplate> 
      </asp&#58;Repeater> 
πάντως μου θυμίζει πολύ τον τρόπο που δουλεύει το smarty:
Ναι, και σε μένα αυτή την εντύπωση δίνει, αν και το smarty φαίνεται πολύ πιο ευέλικτο. Ο Repeater απλά επαναλαμβάνει πανομοιότυπα μοτίβα, χωρίς δυνατότητα για παραλλαγές. Δεν έχω κοιτάξει όμως την ASP.NET 2.0, και μπορεί να υπάρχουν εξελίξεις! :)
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Megistos
Δημοσιεύσεις: 149
Εγγραφή: 14 Ιουν 2005 15:38

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από Megistos » 09 Ιαν 2006 18:14

skeftomilos έγραψε:Ο Repeater απλά επαναλαμβάνει πανομοιότυπα μοτίβα, χωρίς δυνατότητα για παραλλαγές.
Εκτός από το template ItemTemplate, έχει και HeaderTemplate, FooterTemplate, AlternateItemTemplate και SeparatorTemplate. Είναι αρκετά για την απλούστατη λειτουργία που εξυπηρετεί αυτό το control. Για πιο εξειδικευμένα designs πάμε σε datagrid ή σε κώδικα με το χέρι. Και custom κώδικα μπορείς να παρεμβάλλεις σε όλα τα asp.net server controls.
The Flame Still Burns

Megistos
Δημοσιεύσεις: 149
Εγγραφή: 14 Ιουν 2005 15:38

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από Megistos » 09 Ιαν 2006 18:27

skeftomilos έγραψε:Όταν θέλουμε να περάσουμε κάποια παράμετρο στο query, π.χ. ένα Id, καλό είναι να χρησιμοποιήσουμε από ένα αντικείμενο Parameter για κάθε παράμετρο. Υπάρχει βέβαια η απλούστερη μέθοδος όπου συνθέτουμε το query με συνένωση string, αλλά υπάρχουν σοβαρά προβλήματα ασφάλειας. Για παράδειγμα έστω ότι έχουμε την εξής εντολή:

Κώδικας: Επιλογή όλων

query = "SELECT * FROM Customers WHERE CustomerId = " & Request&#40;"Id"&#41;
Ένας hacker μπορεί να παίξει πολλά παιχνίδια με ένα τέτοιο query. Π.χ. μπορεί να κανονίσει ώστε η τιμή της Request("Id") να είναι "CustomerId", και σε αυτή την περίπτωση το query που θα εκτελεστεί θα είναι...

Κώδικας: Επιλογή όλων

SELECT * FROM Customers WHERE CustomerId = CustomerId
...το οποίο όπως καταλαβαίνετε επιστρέφει όλους τους πελάτες. Ακόμα πιο επικίνδυνα είναι τα πράγματα στην περίπτωση που έχουμε να κάνουμε με SQL Server, όπου επιτρέπονται περισσότερα από ένα queries στην ίδια εντολή. Εκεί οι hackers κάνουν party! Η λύση είναι τα αντικείμενα Parameter, που ελέγχουν τον τύπο της παραμέτρου. Αν π.χ. η παράμετρος είναι τύπου integer δε μπορεί κανείς να δώσει string, βγαίνει σφάλμα.
Ήθελα να συμπληρώσω κάτι εδώ, επειδή είναι αρκετά σοβαρό το θέμα και πολλοί το παραβλέπουν επειδή βαριούνται να κάνουν παραμέτρους. Μία απλούστατη λύση είναι να μετατρέψουμε τον κώδικα σε:

Κώδικας: Επιλογή όλων

query = "SELECT * FROM Customers WHERE CustomerId = " & CInt&#40;Request&#40;"Id"&#41;&#41;
Οπότε αν δεν είναι ακέραιος, απλούστατα πετάει λάθος. Και δεν χρειάζεται να αλλάξουμε όλον τον κώδικα για να χρησιμοποιήσουμε παραμέτρους κ.λπ.

Όσον αφορά τον SQL Server που εκτελεί πολλές εντολές μαζί. πχ στο ίδιο παράδειγμα, μπορεί κάποιος κακόβουλος να εκτελέσει το εξής:

Κώδικας: Επιλογή όλων

SELECT * FROM Customers WHERE CustomerId = CustomerId; DELETE FROM Customers;
Το οποίο με την συνάρτηση CInt() πάλι αποφεύγεται. Αλλά όπως και να έχει αυτό το bug δεν παίζει σε ASP.NET γιατί από default στο machine.config υπάρχει η επιλογή ValidateRequest ενεργοποιημένη. Που σημαίνει ότι ελέγχει το input σε κάθε σελίδα για κώδικα html, sql κ.λπ. και πρέπει να το απενεργοποιήσεις μόνος σου για να περάσει τέτοιος κώδικας από querystring.
The Flame Still Burns

Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από skeftomilos » 09 Ιαν 2006 23:38

@Megistos: Σχετικά με τον Repeater κοίτα τι θέλω να κάνω και δε βρίσκω τρόπο. Θέλω να δημιουργήσω links για κάθε εγγραφή της βάσης, εκτός από μία:

Κώδικας: Επιλογή όλων

<ul>
  <li><a href="#">London</a></li>
  <li>Paris</li>
  <li><a href="#">Rome</a></li>
</ul>
Δηλαδή θέλω έναν έλεγχο του στυλ:

Κώδικας: Επιλογή όλων

<%
  If Container.DataItem&#40;"Data"&#41; = "Paris" Then
    ' Εμφάνιση απλού λεκτικού.
  Else
    ' Εμφάνιση link.
  End If
%>
...το οποίο όμως είναι άκυρο γιατί το αντικείμενο Container ορίζεται μόνο σε blocks <%#...%> και όχι στα απλά <%...%>. Καμιά ιδέα;
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Megistos
Δημοσιεύσεις: 149
Εγγραφή: 14 Ιουν 2005 15:38

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από Megistos » 12 Ιαν 2006 11:49

Κατάλαβα τι λες, όντως αυτό είναι προβληματικό. Βέβαια εγώ εδώ και 2-3 χρόνια δεν δουλεύω με τα Server Controls της .NET γιατί προτιμώ να τα γράφω όλα με το χέρι και να τα ελέγχω manually.

Το συγκεκριμένο πάντως επιτυγχάνεται ως εξής:

Κώδικας: Επιλογή όλων

<asp&#58;Repeater id="towns" runat="server">
  <ItemTemplate> 
    <li><%# IIf&#40;Container.DataItem&#40;"Data"&#41;="Paris", "Paris", "<a href=""#"">" & Container.DataItem&#40;"Data"&#41; & "</a>"&#41; %></li> 
  </ItemTemplate> 
</asp&#58;Repeater>
Στην ουσία το "#" αντικαθιστά το Response.Write και φέρνει στο block το αντικείμενο Container. Οπότε αν μπορείς να κάνεις όλο τον έλεγχο της λειτουργικότητας που θέλεις σε μία πρόταση έχει καλώς. Αλλιώς το κάνεις manually με Reader ή Dataset.

ps: Sorry για το late response αλλά τυχαίνουν κάτι μέρες που πνίγομαι...
The Flame Still Burns

Άβαταρ μέλους
skeftomilos
Script Master
Δημοσιεύσεις: 2888
Εγγραφή: 07 Ιαν 2005 07:22
Τοποθεσία: Αθήνα

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από skeftomilos » 13 Ιαν 2006 00:25

Σωστή η λύση, αλλά όχι και ιδιαίτερα ελκυστική εδώ που τα λέμε. Σε σχέση με άλλα templating systems (π.χ. Smarty) τα server controls της ASP.NET μοιάζουν κάπως αδέξια. Τελικά βρίσκεις τρόπο να γίνει αυτό που θέλεις, αλλά όχι χωρίς παραχωρήσεις.

Μία άλλη τεχνική που δοκίμασα είναι να έχω ένα custom WUC (Web User Control) μέσα σε βρόγχο:

Κώδικας: Επιλογή όλων

<%@ Register Tagprefix="Demo" Tagname="MyListItem" Src="MyListItem.ascx" %>
...
<ul>
<%
  For Each row In dataTable.Rows
    li.MyRow = row
%>
  <Demo&#58;MyListItem id="li" runat="server" />
<%
  Next
%>
</ul>
MyListItem.ascx

Κώδικας: Επιλογή όλων

<script runat="server">
  Public MyRow As DataRow
</script>

  <li><%=MyRow&#40;"data"&#41;%></li>
Δεν έχει σχέση με templates, αλλά μπορεί να απλοποιήσει ένα πολύ σύνθετο βρόγχο.
The pure and simple truth is rarely pure and never simple. Ο μη νους δε σκέπτεται μη σκέψεις για το τίποτα.

Alxdjo
Δημοσιεύσεις: 23
Εγγραφή: 09 Ιαν 2010 11:18

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από Alxdjo » 22 Μαρ 2010 15:38

Να σε καλα γιατι ειχα χαθει στις ομοιοτητες και τις διαφορες τους 8)

elorant
Δημοσιεύσεις: 173
Εγγραφή: 23 Σεπ 2009 23:09

Ado και ado.net, ομοιότητες και διαφορές

Δημοσίευση από elorant » 22 Μαρ 2010 19:20

skeftomilos έγραψε: Δηλαδή θέλω έναν έλεγχο του στυλ:

Κώδικας: Επιλογή όλων

<%
  If Container.DataItem&#40;"Data"&#41; = "Paris" Then
    ' Εμφάνιση απλού λεκτικού.
  Else
    ' Εμφάνιση link.
  End If
%>
...το οποίο όμως είναι άκυρο γιατί το αντικείμενο Container ορίζεται μόνο σε blocks <%#...%> και όχι στα απλά <%...%>. Καμιά ιδέα;
Αυτό θα το πετύχεις ελέγχοντας το event ItemDataBound. Για παράδειγμα:

Κώδικας: Επιλογή όλων

Imports System.Data

    Protected Sub myRepeater_ItemDataBound&#40;ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs&#41; Handles myRepeater.ItemDataBound
        If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
            Dim objData As DataRowView = CType&#40;e.Item.DataItem, DataRowView&#41;
            If objData&#40;"City"&#41;.ToString = "Paris" Then
                ' Εδώ βάζεις τον κώδικα για να κάνεις αλλαγές στο συγκεκριμένο row
                ' Αν για παράδειγμα στο ItemTemplate εμφάνιζες ένα label εδώ θα έπρεπε να γράψεις
                DirectCast&#40;e.Item.FindControl&#40;"lblCity"&#41;, Label&#41;.Text = "bla bla bla"
            End If
        End If
    End Sub
Είναι λίγο μπέρδεμα με τα conversions αλλά σου δίνει πλήρη αυτονομία

Απάντηση

Επιστροφή στο “ASP, ASP.NET”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 0 επισκέπτες