Jednoduché diskusní fórum

5. díl - Jednoduché diskusní fórum

Tomáš Herceg       02.11.2007       C#, VB.NET, ASP.NET WebForms, Databáze       30117 zobrazení

Po delší odmlce přichází pátý díl oblíbeného seriálu o programování v ASP.NET 2.0. V tomto díle si ukážeme, jak používat komponentu FormView pro přidávání záznamů do databáze. Také si ukážeme nejčastější útoky na webové aplikace a hlavně způsoby, jak jim zabránit. Také si předvedeme, jak validovat a kontrolovat vstupy uživatele jednoduše a spolehlivě.

V minulém díle tohoto seriálu jsme se naučili, jak vytvořit databázi a jak do ní přidat tabulky a data z nich zobrazit na stránce. Dnes se naučíme záznamy do tabulek přidávat a ukážeme si to na velice jednoduchém diskusním fóru, které napíšeme. Webové aplikace mohou být nebezpečné, pokud jsou špatně napsané. Ukážeme si i dva možné útoky na tuto aplikaci a také způsob, jak jim zabránit. ASP.NET nám v tom vydatně pomůže, takže nebudeme mít téměř žádnou práci.

Začínáme

Vytvořte si tedy novou webovou aplikaci (ASP.NET Web Site) v jazyce, který je vám bližší. Přidejte si do aplikace jednu databázi, pokud nevíte jak, podívejte se do minulého dílu. Nyní do databáze vytvoříme jednoduchou tabulku, kde budeme "skladovat" všechny příspěvky uživatelů do diskuse. Tabulka to bude velmi jednoduchá, stačí uchovávat jenom pár údajů. Přidejte tedy do databáze sloupce podle obrázku.

Struktura tabulky Posts

Nezapoměňte kliknout na první řádek pravým tlačítkem a vybrat volbu Set Primary Key , aby se první sloupec tabulky nastavil jako primární klíč. Navíc mu dole v okně vlastností nastavte Identity Specification na hodnotu Yes takto:

Nastavení automatického zvyšování indexu

Tím zajistíme, že pokud přidáme do tabulky záznam, nastaví se do sloupce PostId automaticky unikátní hodnota. První záznam tedy dostane jedničku, druhý dvojku, třetí trojku atd. Pokud tyto záznamy smažeme, další záznam dostane číslo čtyři. Očíslování tedy nebude souvislé a nepoznáme z něj počet záznamů, ale to ani není cílem. Cílem je, aby každý záznam měl určitě číslo jiné. A to splněno bude.

Nyní stiskněte klávesy Ctrl+S, aby se tabulka vytvořila v databázi. Visual Studio se nás ještě zeptá na název tabulky, zadejte Posts a potvrďte.

Zadání názvu tabulky 

Malá odbočka aneb pojmenovávání sloupců

Záměrně pojmenovávám sloupce v tabulce anglicky. Každý programátor by měl anglicky umět a pokud to neumí, měl by se to rozhodně co nejdříve naučit. Angličtina je ve světě programování naprosto nezbytná. Protože tohle je tutoriál pro začátečníky, vysvětlím, co názvy sloupců říkají, abyste se neztratili.

Název tabulky Posts znamená česky něco jako příspěvky. Jeden příspěvek je post, z čehož dostáváme název prvního sloupce - PostId - ID příspěvku. Dále máme sloupce Title, což znamená název (v našem případě název příspěvku), pak následuje Message (česky zpráva), dále pak Author (autor, v našem případě jeho jméno nebo přezdívka) a PostDate (datum příspěvku). Každý má na pojmenování databází jiné zásady, je to věc zvyku, ale je dobré mít všude jednotný systém.

V tuto chvíli byste měli tedy sami umět vysvětlit, jaká data budou uchovávána v každém sloupci a z jejich datových typů byste měli umět odvodit, jestli to bude datum, text (a jak maximálně dlouhý) atd. Zkuste si to, pokud váháte, mrkněte do článku Úvod do jazyka SQL.

Vypsání příspěvků a nastavení ConnectionStringu

Nyní budeme chtít vypsat všechny příspěvky z tabulky do stránky. Jelikož příspěvky v diskusním fóru většinou nejsou data vhodná k zobrazení v tabulce, nepoužijeme komponentu GridView, ale komponentu DataList. Ta umí zobrazit více záznamů a navíc si můžeme přesně zvolit, jak budou záznamy vypadat. Přidejte tedy do stránky komponenty SqlDataSource a DataList. Z miulého dílu již víte, jak nastavit SqlDataSource a jak vytvořit ConnectionString, tedy jak nastavit připojení do databáze. Nastavte tedy do  SqlDataSource naši databázi a při nastavování dotazu vyberte všechny sloupce z tabulky Posts. Většinu věcí zvládnete sami, na dvou obrázcích ukážu, kde začít a kam se máte dostat.

Zahájit konfiguraci SqlDataSource

Nastavení SQL dotazu

Ještě než kliknete na tlačítko Next, nastavíme třídění záznamů podle data přidání sestupně. Nahoře tedy bude příspěvek nejnovější a dole ten nejstarší. Klikněte na tlačítko Order By a dialogové okno nastavte podle obrázku:

Nastavení třídění záznamů

Nyní můžete pokračovat dále a odklikat OK a Next až do konce. Budeme mít nastavený SqlDataSource. Teď si trochu pohrajeme s komponentou DataList.

Základní nastavení komponenty DataList

Klikněte na komponentu DataList a v podokně úloh nastavte jako zdroj dat náš nastavený SqlDataSource1. Komponenta si ihned vytáhne z datového zdroje popis struktury a zobrazí nějaká vzorová data, jak asi budou vypadat na stránce.

Nastavení datového zdroje do DataListu

Vzhled výpisu příspěvků zatím necháme tak, jak je, a vrhneme se na přidávání diskusních příspěvků a přidávání záznamů do databáze. Ještě před tím si ale povíme o dvou možných způsobech útoku na webové aplikace, které nás mohou potkat právě pokud necháme uživatele zadávat údaje a následně je někde vypisujeme.

Trocha bezpečnosti

Jak všichni jistě víme, existují určití zlí lidé, kteří se snaží upozornit na sebe tím, že nám všem škodí. Například tím, že kradou, zabíjí, jezdí na silnici příliš pomalu nebo zase příliš rychle, anebo třeba útočí na webové aplikace, nejčastěji za účelem získání dat, ke kterým by neměli mít přístup. Pokud uchováváte v databázi osobní údaje uživatelů, nesmíte připustit, aby se k nim někdo nepovolaný dostal, jinak vám hrozí žaloba a trest. Zajištění bezpečnosti webové aplikace napojené na databázi je opravdu nutné.

Útok SQL injection

Představme si, že na webové stránce máme textová pole, do kterých má uživatel napsat své uživatelské jméno a heslo. Jak tedy bude vypadat SQL příkaz, který ověří, zda je uživatel v databázi a jestli má správné heslo? Většina začátečníků to udělá nějak takto (předpokládejme proměnné jmeno a heslo s hodnotami z textových polí):

sql = "SELECT * FROM uzivatele WHERE jmeno='" + jmeno + "' AND heslo='" + heslo + "'"

Pokud uživatel tedy napíše jméno tom a heslo jerry, výsledný SQL dotaz bude vypadat takto: SELECT * FROM uzivatele WHERE jmeno='tom' AND heslo='jerry'. To vypadá dobře. Má to ovšem jeden zásadní problém - když přijde na web hacker, zkusí jako jméno napsat třeba toto: tom' --. A co se nestane? Naše SQL nyní bude vypadat takto: SELECT * FROM uzivatele WHERE jmeno='tom' --' AND heslo='cokoliv to je úplně fuk'. Jenže --, tedy 2 pomlčky, v SQL znamenají komentář, tedy to co je za nimi, se již neprovede. A bez komentáře to je jen SELECT * FROM uzivatele WHERE jmeno='tom'. Díky tomu se hacker dostane dovnitř, aniž by znal heslo, to se totiž nikde netestuje. To je ta lepší varianta, pokud napíše dostatečně sofistikovaný dotaz, zkopíruje si databázi k sobě a vám ji na serveru třeba smaže.

Jak z toho ven? Možná si řeknete, že stačí odebrat apostrofy z textu, ale existují i metody, které obejdou i toto (ne vždy a všude fungují, ale občas ano). Problém je v tom, že když jeden TextBox ošetřit zapomenete, máte bezpečnostní díru. ASP.NET, ale i jiné technologie, nabízí tzv. SQL parametry. V zásadě to znamená to, že do SQL dotazu místo dosazování konkrétních hodnot zapíšete jen název proměnné a hodnoty proměnných pošlete zvlášť, až po samotném dotazu. ASP.NET nás tlačí k používání parametrů, pokud si na ně zvyknete, tento typ útoku se vám nemůže stát, ať útočník napíše cokoliv. Hlavně nikdy neskládejte SQL příkaz, to téměř vždycky zavání bezpečnostní dírou. Pokud důsledně vždy použijete parametry, tento útok vám nehrozí, pokud neuděláte jinou botu.

SQL dotaz s parametry vypadá nějak takto: SELECT * FROM uzivatele WHERE jmeno = @jmeno AND heslo = @heslo. Hodnoty parametrů se nastavují zvlášť a nikdy se do dotazu nedosazují. Tím pádem jsme z nebezpečí venku, tento způsob zatím nebyl nijak prolomen.

Ještě jedna poznámka k uvedenému příkladu - ukládat hesla do databáze jen tak je naprostý nesmysl - pokud někdo už databázi stáhne, dozví se i hesla. A vzhledem k tomu, že 99% uživatelů používá všude stejné jméno a heslo, je to dost velké riziko. Proto se používá hash (čti "heš"). Hash je funkce, které nasypete nějaká data (v našem případě heslo) a ona je zakóduje tak, že se z výsledku již původní heslo dostat nedá. Důležité je, že dvě stejné hodnoty dají vždycky stejný hash a je velmi těžké (neřku-li nemožné ani s nejlepšími superpočítači) vymyslet dva vstupy tak, aby hash vyšel stejně. Do databáze tedy můžeme uložit jen hash našeho hesla. Při testování spočítáme hash toho, co napsal uživatel, a obě hodnoty porovnáme. Když jsou stejné, heslo je správné. V praxi se ještě pro každého uživatele vygenerujea uloží náhodný řetězec (tzv. sůl), která se před hashováním přidá za heslo, a to celé se teprve zahashuje. Stejný postup se provede i při ověřování - heslo se osolí (přidá se za něj příslušná sůl) a pak se teprve spočítá hash. Má to tu výhodu, že pokud více uživatelů má stejné heslo, nejde to poznat, protože každý má jinou sůl, a tím pádem i úplně jiný výsledný hash. Ale to je věc jiná, o uživatelích se budeme bavit až v příštím díle.

Útok Script injection

Tento typ útoku není tak nebezpečný, ale dokáže znepříjemnit život mnoha webovým vývojářům. Pokud máme hloupé diskusní fórum, stačí napsat jako text diskusního příspěvku třeba toto:

<script type="text/javascript">location.href='http://www.vbnet.cz';</script>

Všichni bychom měli vědět, co to udělá. Pokud příspěvek vypíšete do stránky, připravte se na to, že při jejím načtení bude hned prohlížeč přesměrován na náš server VbNet.cz. Javascript se tedy spustí, což určitě nechceme. Tady je nejlepším řešením použít metodu HtmlEncode, tedy převod speciálních znaků na HTML entity. Znak < se tedy převede na &lt; a znak > na &gt;. Prohlížeč nyní bude vědět, že to nejsou HTML značky, a vypíše je jako text. To by mělo k odražení tohoto útoku stačit.

Hodí se poznamenat, že ASP.NET automaticky hlídá, zda-li uživatel neposílá kusy HTML. Pokud to udělá, nastane výjimka a zobrazí se chybová stránka. To ale většinou nechceme, takže to musíme ručně vypnout. Pak si ale musíme tyto situace ošteřit ručně a zakódovat příslušné texty, jinak nám hrozí reálné nebezpečí.

Jak na přidávání příspěvků

Přidejte do stránky komponentu FormView. Ta umí pracovat s jedním záznamem, což zde právě potřebujeme. FormView má tři režimy zobrazení - Insert, Edit a ReadOnly. První režim přidává záznamy, druhý je upravuje, a třetí pouze zobrazuje. My chceme pouze přidávat, proto nastavte hodnotu vlastnosti DefaultMode na hodnotu Insert. Nastavte této komponentě také datový zdroj SqlDataSource1, úplně stejně, jako jsme to udělali komponentě DataList. Nyní by měl FormView vypadat asi takto:

Komponenta FormView

To se nám rozhodně nelíbí, takže bychom vzhled měli upravit. Navíc datum se bude vyplňovat automaticky. Přepněte se tedy do režimu Source View a podívejme se na kód komponenty FormView, který vypadá takto:

        <asp:FormView ID="FormView1" runat="server" DataKeyNames="PostId" DataSourceID="SqlDataSource1"
DefaultMode="Insert">
<EditItemTemplate>
PostId:
<asp:Label ID="PostIdLabel1" runat="server" Text='<%# Eval("PostId") %>'></asp:Label><br />
Title:
<asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>'> </asp:TextBox><br />
Message:
<asp:TextBox ID="MessageTextBox" runat="server" Text='<%# Bind("Message") %>'> </asp:TextBox><br />
Author:
<asp:TextBox ID="AuthorTextBox" runat="server" Text='<%# Bind("Author") %>'> </asp:TextBox><br />
PostDate:
<asp:TextBox ID="PostDateTextBox" runat="server" Text='<%# Bind("PostDate") %>'> </asp:TextBox><br />
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
Text="Update"> </asp:LinkButton>
<asp:LinkButton ID="UpdateCancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
Text="Cancel"> </asp:LinkButton>
</EditItemTemplate>
<InsertItemTemplate>
Title:
<asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>'> </asp:TextBox><br />
Message:
<asp:TextBox ID="MessageTextBox" runat="server" Text='<%# Bind("Message") %>'> </asp:TextBox><br />
Author:
<asp:TextBox ID="AuthorTextBox" runat="server" Text='<%# Bind("Author") %>'> </asp:TextBox><br />
PostDate:
<asp:TextBox ID="PostDateTextBox" runat="server" Text='<%# Bind("PostDate") %>'> </asp:TextBox><br />
<asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
Text="Insert"> </asp:LinkButton>
<asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
Text="Cancel"> </asp:LinkButton>
</InsertItemTemplate>
<ItemTemplate>
PostId:
<asp:Label ID="PostIdLabel" runat="server" Text='<%# Eval("PostId") %>'></asp:Label><br />
Title:
<asp:Label ID="TitleLabel" runat="server" Text='<%# Bind("Title") %>'></asp:Label><br />
Message:
<asp:Label ID="MessageLabel" runat="server" Text='<%# Bind("Message") %>'></asp:Label><br />
Author:
<asp:Label ID="AuthorLabel" runat="server" Text='<%# Bind("Author") %>'></asp:Label><br />
PostDate:
<asp:Label ID="PostDateLabel" runat="server" Text='<%# Bind("PostDate") %>'></asp:Label><br />
</ItemTemplate>
</asp:FormView>

Vzhledem k tomu, že budeme záznamy zatím jen přidávat, smažte celé sekce ItemTemplate a EditItemTemplate. Nyní by kód měl vypadat asi takto:

        <asp:FormView ID="FormView1" runat="server" DataKeyNames="PostId" DataSourceID="SqlDataSource1"
DefaultMode="Insert">
<InsertItemTemplate>
Title:
<asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>'> </asp:TextBox><br />
Message:
<asp:TextBox ID="MessageTextBox" runat="server" Text='<%# Bind("Message") %>'> </asp:TextBox><br />
Author:
<asp:TextBox ID="AuthorTextBox" runat="server" Text='<%# Bind("Author") %>'> </asp:TextBox><br />
PostDate:
<asp:TextBox ID="PostDateTextBox" runat="server" Text='<%# Bind("PostDate") %>'> </asp:TextBox><br />
<asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
Text="Insert"> </asp:LinkButton>
<asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
Text="Cancel"> </asp:LinkButton>
</InsertItemTemplate>
</asp:FormView>

To, co je uvnitř značky InsertItemTemplate je tzv. šablona. Šablony se v ASP.NET používají velmi často k nadefinování vzhledu a struktury záznamů. Zde vidíme, že se vypíše nějaký text Title:  a za ním je komponenta TextBox, obdobně se vypíší ostatní pole a nakonec tam máme dvě tlačítka. Jediné, co nám asi bude divné, jsou záhadné hodnoty vlastnosti Text, totiž <%# Bind("Title") %>. Říká se jim tzv. binding expressions a jsou to vlastně kusy kódu, které vypisují data z databáze. Funkce Bind má jako parametr název sloupce, jehož hodnotu má použít. Místo tohoto záhadného kousku kódu se tedy do textového pole vypíše hodnota sloupce z databáze (v tomto konkrétním případě se nevypíše nic, protože záznam vytváříme a v databázi ještě není). Co je však důležitější, při přidání záznamu se hodnota této vlastnosti vezme a uloží se do databáze. Tomuto procesu se často říká Data Binding, což by se dalo česky přeložit jako "provázání s daty". Aby přidávání záznamu vypadalo hezky, změňte kód komponenty FormView takto:

            <asp:FormView ID="FormView1" runat="server" DataKeyNames="PostId" DataSourceID="SqlDataSource1"
DefaultMode="Insert">
<InsertItemTemplate>
<h2>Přidat příspěvek do fóra</h2>
<table>
<tr>
<td>Předmět:</td>
<td>
<asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>' Width="400px"
MaxLength="50"></asp:TextBox>
</td>
</tr>
<tr>
<td>Autor:</td>
<td>
<asp:TextBox ID="AuthorTextBox" runat="server" Text='<%# Bind("Author") %>' Width="400px"
MaxLength="50"></asp:TextBox>
</td>
</tr>
<tr>
<td>Zpráva:</td>
<td>
<asp:TextBox ID="MessageTextBox" runat="server" Text='<%# Bind("Message") %>' Width="400px"
Height="100px" TextMode="MultiLine" MaxLength="2000"></asp:TextBox>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center">
<asp:Button ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert" Text="Přidat příspěvek" />
<asp:Button ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Storno" />
</td>
</tr>
</table>
</InsertItemTemplate>
</asp:FormView>

Provedl jsem v šabloně několik změn - textová pole jsem umístil do tabulky, aby se úhledně zarovnala, nastavil jsem ručně šířku polí a u pole pro zprávu jsem nastavil TextMode na hodnotu MultiLine, takže se textové pole chová jako textarea. A konečně komponenty LinkButton jsem nahradil komponentami Button. To kvůli tomu, aby stránka fungovala i bez zapnutého javascriptu. Kompomenta LinkButton totiž odesílá formulář pomocí javascriptu, tento typ tlačítka totiž vypadá jako odkaz. Odeslat formulář odkazem je ale nemožné bez použití javascriptu, proto raději použijeme Button, což je obyčejné input type=submit. To funguje samozřejmě i bez klientských skriptů.

Pokud se podíváme, jak nyní komponenta pro přidání příspěvku vypadá, myslím, že můžeme být spokojeni, je to rozhodně lepší. Pokud si ještě pohrajeme s CSS styly, bude to vypadat ještě o několik řádů lépe.

FormView s lepší šablonou

Nastavení SqlDataSource pro podporu přidávání záznamů

Samotná komponenta nám ale ještě fungovat nebude, nezadali jsme do datového zdroje SQL příkaz pro přidávání záznamů a nevytvořili parametry. To musíme napravit. Najděte si tedy v okně kódu komponentu SqlDataSource1, její kód by měl vypadat takto:

        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" 
SelectCommand="SELECT [PostId], [Title], [Message], [Author], [PostDate] FROM [Posts] ORDER BY [PostDate] DESC"></asp:SqlDataSource>

Pokud chceme zobrazovat záznamy, máme nastavený SelectCommand. Pokud chceme záznamy přidávat, nastavíme InsertCommand. Místo hodnot, které chceme dosadit, použijeme parametry. Doporučuji je pojmenovat stejně jako příslušné sloupce, ať je jasné, co k čemu patří. Nastavte tedy InsertCommand, kód by pak měl vypadat takto:

        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" 
SelectCommand="SELECT [PostId], [Title], [Message], [Author], [PostDate] FROM [Posts] ORDER BY [PostDate] DESC"
InsertCommand="INSERT INTO [Posts] ([Title], [Message], [Author], [PostDate]) VALUES (@Title, @Message, @Author, GETDATE())"></asp:SqlDataSource>

Jako hodnotu do sloupce PostDate jsme nedali parametr, ale funkci GETDATE(), která vrátí aktuální datum a čas v době provádění příkazu. Tím se automaticky vloží aktuální datum a čas a nemusíme se tedy o něj starat. Nyní ještě musíme nadefinovat parametry dotazu a říci, jaké budou mít datové typy. Upravte tedy kód komponenty takto:

        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT [PostId], [Title], [Message], [Author], [PostDate] FROM [Posts] ORDER BY [PostDate] DESC"
InsertCommand="INSERT INTO [Posts] ([Title], [Message], [Author], [PostDate]) VALUES (@Title, @Message, @Author, GETDATE())">
<InsertParameters>
<asp:Parameter Name="Title" Type="String" Size="50" />
<asp:Parameter Name="Author" Type="String" Size="50" />
<asp:Parameter Name="Message" Type="String" />
</InsertParameters>
</asp:SqlDataSource>

Celý tento postup jsme si mohli odpustit a "naklikat" to přes designer. Stačilo by kliknout na odkaz Configure Data Source v panelu úkolů pro SqlDataSource v Design Mode a na okně, kde se vybírá SQL příkaz rozkliknout tlačítko Advanced kde bychom zaškrtnuli Generate INSERT, UPDATE and DELETE commands. Tento postup by nám ovšem vygeneroval příkazy pro úpravy záznamů a pro jejich mazání, které nepotřebujeme. Chci ale, abyste viděli i kód a rozuměli, co dělá.

Jak funguje FormView a samotné přidávání záznamů

To, co jsme teď udělali, již umí přidat záznam do databáze. Bez jediného řádku programového kódu. Pokud si stránku spustíme, umožní nám FormView zadat nový příspěvek do diskusního fóra. Jakmile vyplníme potřebná pole, máme k dispozici dvě tlačítka. Možná jste si všimli jejich vlastností CommandName, tlačítko pro přidávání má hodnotu této vlastnosti Insert a tlačítko pro zrušení má hodnotu Cancel. A to je celé kouzlo - jakmile klikneme na tlačítko, FormView si sám zachytí událost ItemCommand, která nastane, když odešleme formulář kterýmkoliv tlačítkem či komponentou zevnitř. Pokud FormView zachytí příkaz Insert, automaticky vezme hodnoty všech polí, které mají nastaven Data Binding pomocí funkce Bind a předá je do hodnot parametrů příslušné komponenty SqlDataSource. Pak na této komponentě zavolá metodu Insert, aby se příkaz provedl. Podobně funguje úprava záznamů, opět to jde bez jediného řádku kódu.

Úprava komponenty DataList

 

Nyní je čas na úpravu vzhledu komponenty DataList, opravte tedy kód, aby vypadal takto:

        <asp:DataList ID="DataList1" runat="server" DataKeyField="PostId" DataSourceID="SqlDataSource1">
<ItemTemplate>
<div class="post">
<h3><asp:Literal ID="TitleLiteral" runat="server" Text='<%# Eval("Title") %>' Mode="Encode"></asp:Literal></h3>
<p><asp:Literal ID="MessageLiteral" runat="server" Text='<%# Eval("Message") %>' Mode="Encode"></asp:Literal></p>
<p>
<small>Vložil <strong>
<asp:Literal ID="AuthorLiteral" runat="server" Text='<%# Eval("Author") %>' Mode="Encode"></asp:Literal></strong>,
<em>
<asp:Literal ID="PostDateLiteral" runat="server" Text='<%# Eval("PostDate", "{0:d. MMMM yyyy H:mm}") %>'></asp:Literal></em>.
</small>
</p>
</div>
</ItemTemplate>
</asp:DataList>

Máme zde opět binging expressions, tentokrát jen Eval, protože potřebujeme data vytáhnout z databáze. Zpět je již nevracíme. Rozdíl mezi Bind a Eval je právě v tom, jestli data při dalším odeslání budeme vracet zpátky. Pokud ano, musíme použít Bind, jinak nám stačí Eval. V posledním Eval na konci ještě specifikujeme formát, v jakém se má vypsat datum a čas publikování. Všimněte si, že vše vypisuji do komponenty Literal. Je to jednoduchý způsob, jak vypsat do stránky text. Pokud navíc komponentám Literal nastavím vlastnost Mode na hodnotu Encode, provede se automaticky převod speciálních znaků na HTML entity, a tím pádem zabráníme útoku script injection.

Ochrana proti útokům nebo hlouposti uživatele

ASP.NET se snaží chránit webové aplikace proti záškodníkům, co nejvíce to jde. Pokud se pokusím do fóra poslat jakýkoliv příspěvek, který bude obsahovat HTML značku, dostaneme výjimku.

Záškodnický příspěvek

Chybová hláška

Aplikace je sice ochráněna proti tomuto útoku, chybovou stránku samozřejmě můžeme přesměrovat na něco ve stylu V aplikaci došlo k chybě, opakujte akci znovu. Co ale dělat v případě, že píšeme např. fórum o webdesignu, kde chceme, aby nám uživatelé posílali své HTML, abychom jim mohli vysvětlit, proč nefungují a co je na nich špatně. Musíme tedy kontrolu vypnout, a to přímo v direktivě Page. Přidejte tedy do prvního řádku ve stránce parametr ValidateRequest="false". Tím se kontrola vypne a požadavek se provede s tím, co uživatel poslal. Znamená to, že si ale musíme všechny vstupy zkontrolovat a všude provádět HTML endocing. První řádek by měl vypadat takto:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" ValidateRequest="false" %>

Vzhledem k tomu, že používáme parametry v SQL příkazu, vyhnuli jsme se útoku SQL injection, a díky tomuto opatření a použití komponent Literal se zapnutým HTML encodingem jsme zabránili i útoku script injection. Aplikace by tedy měla být zabezpečená proti útokům.

Validace vstupů

Proti útokům již aplikaci zabezpečenou máme, nikolivěk proti hlouposti nebo nepozornosti uživatele. Pokud uživatel nevyplní předmět, nastane chyba, protože se budeme snažit vložit prázdnou hodnotu do sloupce, kde být nemá (nepovolovali jsme hodnoty NULL v databázi nikde). Chce to tedy zobrazit červenou hvězdičku vedle textového pole, pokud není vyplněno.

Validace je v ASP.NET vyřešena velice elegantně - máme k dispozici sadu validátorů, tedy komponent, které kontrolují vstup (jednak hned na klientovi poocí javascriptu, pokud to jde, ale hlavně i na serveru). Pokud je vstup špatný, komponenta FormView data do databáze nepošle. Stránka se vrátí klientovi zpátky a zobrazí se validátory. Najděte si tedy šablonu komponenty FormView a přidejte za tetové pole pro předmět příspěvku komponentu RequiredFieldValidator. Tento validátor zaručí, že se neprovede žádná akce, pokud nebude komponenta vyplněná. Hodnotu vlastnosti ErrorMessage nastavte na znak *, je to to, co se zobrazí, pokud je vstup špatně. Přidejte také vlastnost ControlToValidate="TitleTextBox", kde její hodnota je ID komponenty, kterou kontrolujeme. Celý kód validátor by měl vypadat takto:

<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="*" ControlToValidate="TitleTextBox"></asp:RequiredFieldValidator>

Sami si zkuste přidat validátory i pro další dvě textová pole, mělo by to vypadat takto:

            <asp:FormView ID="FormView1" runat="server" DataKeyNames="PostId" DataSourceID="SqlDataSource1"
DefaultMode="Insert">
<InsertItemTemplate>
<h2>
Přidat příspěvek do fóra</h2>
<table>
<tr>
<td>Předmět:</td>
<td>
<asp:TextBox ID="TitleTextBox" runat="server" Text='<%# Bind("Title") %>' Width="400px" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="*" ControlToValidate="TitleTextBox"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>Autor:</td>
<td>
<asp:TextBox ID="AuthorTextBox" runat="server" Text='<%# Bind("Author") %>' Width="400px" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ErrorMessage="*" ControlToValidate="AuthorTextBox"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>Zpráva:</td>
<td>
<asp:TextBox ID="MessageTextBox" runat="server" Text='<%# Bind("Message") %>' Width="400px" Height="100px" TextMode="MultiLine" MaxLength="2000"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ErrorMessage="*" ControlToValidate="MessageTextBox"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center">
<asp:Button ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert" Text="Přidat příspěvek" />
<asp:Button ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Storno" />
</td>
</tr>
</table>
</InsertItemTemplate>
</asp:FormView>

Možná jste si všimli vlastností CausesValidation u tlačítek - tlačítko Storno má tuto vlastnost nastavenou na hodnotu false, což znamená, že pokud na něj klikneme, validace se provádět nebude. Zrušit přidávání totiž můžeme i když jsme některé z polí nevyplnili. Byl by nesmysl nutit uživatele vyplnit všechna pole, pokud chce přidávání zrušit. Ve většině případů možná tlačítko Storno vymažete úplně, ani v tomto případě nemá moc význam.

Pokročilejší validace

Pokud je některá stránka složitější, potřebujeme často validovat některé komponenty při kliknutí na jedno tlačítko, a validovat jiné komponenty při kliknutí na tlačítko jiné. I to je možné - stačí všem tlačítkům, textovám polím a validátorům nastavit vlastnost ValidationGroup="něco", kde něco je libovolný název skupiny (je jedno jaký, ale komponenty, které se mají validovat najednou, jej musí mít stejný). Pokud kliknete na tlačítko a má tuto vlastnost vyplněnou, zkontrolují se jen ty komponenty, které mají vlastnost ValidationGroup nastavenou na stejnou hodnotu jako toto tlačítko. Takto můžete jedněm komponentám přidat ValidationGroup="prvni" a druhým ValidationGroup="druha" a tím je rozdělíte na dvě skupiny. Jedno tlačítko bude validovat jen první skupinu, druhé jen tu druhou.

Vylepšení vzhledu fóra

Nyní můžeme přidat do stránky opět nějaký CSS soubor, aby fórum vypadalo lépe. Nejsem designér ani grafik, takže nemám estetické cítění, ale mohlo by to vypadat třeba nějak takto:

Diskusní fórum s jednoduchým CSS stylováním

To je pro tento díl vše. Pokud chcete vědět, jak jsem udělal střídání barev, vězte, že stačí zkopírovat v komponentě DataList šablonu ItemTemplate a přidat ji do komponenty ještě jednou jako AlternatingItemTemplete. Pak jen v jedné nastavíte elementu div jinou hodnotu atributu class a ostylujete zvlášť. Komponenta DataList použije pro renderování každé sudé položky šablonu AlternatingItemTemplate, pokud je tato šablona vyplněna.

Příště si ukážeme úpravy a mazání záznamů a v některém z příštích dílů se podíváme na správu uživatelů. Doufám, že se vám seriál líbí, omlouvám se, že jsem si dal s tímto dílem na čas, a doufám, že další díl vyjde již brzy. Jakékoliv připomínky či náměty pište do fóra.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

 

 

Nový příspěvek

 

Diskuse: Jednoduché diskusní fórum

Děkuji za příspěvek,

přesně to jsem potřeboval.

František Hajdekr

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Přehledné, jednoduché, srozumitelné, stravitelné, sdělitelné.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Text TextBoxu uložím do XML.

Pokud text znovu z XML do TextBoxu načtu, má zachované formátování, ale TextBox neumí automaticky přizpůsobit svou výšku (LabelBox.Height) délce textu - nastaví posuvník a to je dobré při opravě textu, ale nepraktické při čtení více příspěvků.

Přizpůsobit se délce textu umí Label nebo Literal, ty ale neumí zobrazit TextBoxovo formátování a sám Label ani Literal žádný vlastní edit-mód nemá...

Má Makrosoft nebo někdo z Vás něco, co umí obě věci současně?

Díky za info.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Krista pána, tohle není věc Microsoftu. Uvědomte si, že vše na webu je záležitostí HTML - ASP.NET je jen tenká vrstva nad tím.

Takže správný dotaz by měl znít, jestli něco takového umí HTML.

Odpověď je NE. Jedině že byste si napsal nějaký javascript, který to udělá, ale spočítat, kolik místa zabere text v textovém poli, to nebude vůbec jednoduché.

Naučte se nejdřív HTML a CSS, bez toho webové aplikace nedělejte.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Učit se základy v mém věku je obtížnější, nežli dělat ve Vašem věku hlavního softwarového architekta, to mi věřte :)

Učím se způsobem pokus - omyl.

Takže (pro další podobné týpky, jako jsem já) jsem to zmastil následovně:

1)při ukládání textu z TexBoxu do XML (v mém případě přes řádek DataSetu) používám:

Rows("pozn") = Server.HtmlEncode(TextBox2.Text)
DataSet.WriteXML(cestaXML)

Při opravě textu ho načítám podobně:

TextBox2.Text = Server.HtmlDecode(Rows("pozn"))

Při načtení do Labelu používám pozměněný postup:

Label1.Text = Rows("pozn").Replace(Chr(13) & Chr(10), "<br>")

Při načítání do DataListu a jeho Labelů jsem využil možnosti formátovat Eval:

<asp:Label ID="Pozn" runat="server"  
  Text='<%# Eval("pozn").Replace(Chr(13) & Chr(10), "<br>") %>'></asp:Label>

Takže tím jsem zachoval alespoň to nejednodušší formátování v diskuzním fóru, které nabízí TextBox. Stále si myslím, že by mohl někdo chytrý vyrobit komponentu, která by ukládala jako TextBox a načítala jako Label(jde o to přizpůsobení se délce textu). Mohla by mít i další možnosti formátování a současně by to nemusela být kredenc jako je "freetextbox" a jiné podobné.

Zdravím

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Můžete mi někdo poradit? Dělám web který je založený na webservice a víceméně z DEMO webprojektu kde to funguje to chci nasadit na ostrý webprojekt, a pokaždé když dám do HEAD registraci Javascriptu tak mi to začne nadávat, možná je něco na co jsem zapomněl ale už nevím ...

Původní web:

<head runat="server">
    <title>Titulek ...</title>
    <!--label>this best way when you make routing for call javascript to page. you make it for css too.</label-->
    <%= string.Format("<script src='{0}' type='text/javascript' language='javascript'></script>", ResolveUrl("~/JS/SearchJS.js"))%>
</head>

Ostrý web:

<head runat="server">

       <%= string.Format("<script src='{0}' type='text/javascript' language='javascript'></script>", ResolveUrl("~/JS/SearchJS.js"))%> 

   <!--label>this best way when you make routing for call javascript to page. you make it for css too.</label-->
   <!--  
        <script src="~/JS/SearchJS.js" type="text/javascript"></script> 
   -->

    <title>Titulek ...</title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>

Já už fakt nevím, zkoušel jsem i tu zaREMovanou registraci: <script src="~/JS/SearchJS.js" type="text/javascript"></script> ale pak mi JAVA nechodí

Chyba:

Kolekci Controls nelze upravovat, protože ovládací prvek obsahuje bloky kódu (například <% ... %>).

Popis: Při provádění aktuálního webového požadavku došlo k neošetřené výjimce. Další informace o chybě a o jejím původu v kódu naleznete v trasování zásobníku.

Podrobnosti o výjimce: System.Web.HttpException: Kolekci Controls nelze upravovat, protože ovládací prvek obsahuje bloky kódu (například <% ... %>).

Zdrojová chyba:

Při provádění aktuálního webového požadavku byla vygenerována neošetřená výjimka. Informace týkající se původu a umístění výjimky lze zjistit pomocí níže uvedeného trasování zásobníku výjimek.

Trasování zásobníku:

[HttpException (0x80004005): Kolekci Controls nelze upravovat, protože ovládací prvek obsahuje bloky kódu (například <% ... %>).]

System.Web.UI.ControlCollection.AddAt(Int32 index, Control child) +8680674

System.Web.UI.PageTheme.SetStyleSheet() +450

System.Web.UI.Page.OnInit(EventArgs e) +8710854

System.Web.UI.Control.InitRecursive(Control namingContainer) +333

System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +378

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Dobrý den,

v ASP .net jsem naprostý začátečník a to samé platí pro html a css, tak ne že tady zase někdo vypění a vynadá mi že je to blbost. :D

Potřeboval bych vědět, jakým způsobem jste udělali na těchto stránkách to menu např: Blogy. Zajímá mě, jak docílíte toho, že celý box Blogy změní barvu a po najetí na link, ten samotný link také změní barvu. Je to uděláno pomocí css stylů, nebo to nějaká chytrá komponenta umí?

Díky za radu,

PetrS

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ano, mohla by to umět nějaká komponenta, ale ta by to stejně dělala pomocí javascriptu a css, jinak to nejde.

Takže správný dotaz je, jak se to dělá v css, a jestli na to případně není nějaká komponenta.

Komponenta není, v CSS se to dělá pomocí vlastnosti backgroun-image a selectoru :hover.

Například:

a { background-image('obr1.jpg'); }  /* normální pozadí */
a:hover { background-image('obr2.jpg'); }  /* pozadí při najetí myši */
nahlásit spamnahlásit spam 0 odpovědětodpovědět

To ano ale nějak mi to nejde nastavit vnořené. Podíval jsem se na vaše css a na kod stránky, udělal jsem to věřím že stejně a přesto mi to nejde.

#posts2 a:hover  
        {
            background-color: gray; 
        }
#hilitedTxt a:hover
        {
        background-color:Yellow  ;
        }


<div id ="posts2">
                    <h3><asp:Literal  ID="TitleLiteral" runat="server" Text='<%# Eval("Title") %>' Mode="Encode"></asp:Literal></h3>
                    <a href ="" id="hilitedTxt"><asp:Literal ID="MessageLiteral" runat="server" Text='<%# Eval("Message") %>' Mode="Encode"></asp:Literal></a><asp:Literal ID="Literal1" runat="server" Text='<%# Eval("Message") %>' Mode="Encode"></asp:Literal>
                    <p>
                        <small>Vložil<strong>
                            <asp:Literal ID="AuthorLiteral" runat="server" Text='<%# Eval("Author") %>' Mode="Encode"></asp:Literal></strong>,

                            <em><asp:Literal ID="PostDateLiteral" runat="server" Text='<%# Eval("PostDate", "{0:d. MMMM yyyy H:mm}") %>'></asp:Literal></em>.

                        </small>
                    </p>
                </div> 

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Otázečka

Řeším klasické stránky s MS SQL databází

a chtěl jsem, aby na základě Textbox1_KeyUp Textového pole

se začal filtrovat např. Listbox

Zjistil jsem, že to asi "nejde" pouze je dostupné

"Textbox1_Change" - po stisku ENTER

(pokud se pletu budu rád, když mne z toho vyvedete)

Tak jsem hledal dál, jak vyvolat událost, a našel jsem Javascript

kde např. viz pole HLEDAT - Google kde funguje "Intellsence"

Takže mám událost Javascriptu, ale neumím zavolat z Javy VB proceduru :-(

Existuje nějaká možnost? Možná to dělám složitě, je jednodušší cesta. Prostě chci psát do textboxu, a pod tím se mi bude filtrovat Listbox (Filtr LIKE)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Zdravim,

pokusil som to odskusat, publikovat na aspweb.cz

Skopiroval som do adresa na aspweb.cz subory vytvorene prikazom publish website.

dostal som hlasku v browseri

An attempt to attach an auto-named database for file e:\wwwdata\LocalUser\...\Db.mdf failed. A database with the same name exists, or specified file cannot be opened, or it is located on UNC share

preco?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

viděl bych to na nabsolutně zadanou cestu k databázi

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Dobrý den,

zkoušel jsem si podle Vašeho návodu udělat toto fórum. Chtěl jsme se ale zeptat, jak bych z něho mohl vymazat např. vulgární příspěvek od nějakého návštěvníka. Dá se ta jedna konkrétní zpráva vymazat?

Děkuji za odpoved

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zdravím, jsem sice začátečník, ale myslím, že jsem přišel na to, jak smazat příspěvky. Otevřete si "Database Explorer", pravým tlačítkem klinněte na tabulku s názvem "Posts" a vyberte "Show table Data". Objeví se vám tabulka, kde bude všude NULL. Klikněte pravým tlačítkem kamkoliv do prostoru a vyberte "Execute SQL". Pak se vám zobrazí příspěvky a příslušný řádek vlevo vyberete a smažete.

Michal

nahlásit spamnahlásit spam -2 / 2 odpovědětodpovědět

Větší blbost jsem dlouho nečetl :D

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Tohle je ta nejhorší věc kterou jste mohl napsat někomu kdo teprve začíná!!!!!

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Zdravím, prosím o radu.

Co když potřebuju do DB zanést ještě navíc např. IP adresu toho, kdo přidal příspěvek, stejně jako je to zde v diskuzích. Nebo jméno přihlášeného uživatele, aby jej nemusel vypisovat do pole autor. Prostě zapsat proměnnou kterou mám připravenou.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Takhle podobne

/// <summary>

/// Doplneni data

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

protected void LinqDataSource1_Inserting(object sender, LinqDataSourceInsertEventArgs e)

{

Diskuse t = (Diskuse)e.NewObject;

t.CreationDate = DateTime.Now;

}

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Mohl by mi prosím někdo přiblížit (spíš vysvětlit)

jak pan Herceg nastavil každý příspěvek v Datalistu odlišnou barvou?

Procházel jsem si předchozí článek a tam se to nastavuje pro gridwiew a já nejsem schopen to zopakovat u datalistu :(

Nejspíš jsem úplně nepochopil jak používat css celkově i když se mi to nějak používat daří...

Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Už jsem našel tlačítko autoformát :)

Čumim do toho dva dny a dokud se člověk nezeptá, tak nic nenajde.

Jdu si prolouskat co mi to vygenerovalo. Díky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Zdravím,

článek je velice good. Zrovna dělám jeden menší zápočtový projekt :-) a hondě jsem se odtud dozvěděl. Projekt spočívá v tom, že při načtení se zobrazí seznam 20 otázek. Uživatel pomocí např. CheckBoxů vybere správné odpovědi a výsledek testu odešle Buttonem.

Jenže jsem ztroskotal na tomto problému :

Mám FormView ve kterém načítám data z databáze TEST. Ta obsahuje tabulku OTAZKY. V tabulce OTAZKY mam ZADÁNÍ OTÁZKY,A,B,C a POCETbodu.

FormView všechno krásně vytahá a zobrazí.

Jenže teď potřebuju nějakým způsobem zakomponovat CheckBoxy ke každé odpovědi a např do další tabulky uložit to co uživatel zacheckuje. Snad je to srozumitelné... Dík :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nevím, jestli je dobrý nápad si na zápočtový projekt vybrat technologii, kterou se teprve učíte. Pokud po vás ve škole chtějí, abyste to psal v přímo ASP.NET, tak by vás to také měli nejprve naučit, ukládání dat do databáze je poměrně základní věc.

Kdyžtak vydržte do dalšího dílu seriálu (napíšu jej tento týden), budu se tam tomu věnovat.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Základní znalosti k tomu samozdřejmě mám.

Ukládání do databáze a naopak není věc složitá. Jedná se mě pouze o to jakým způsobem vyřešit ty checkboxy.Pokud bych např. vypisoval data pomocí DataListu (všechny otázky najednou pod sebe) a k položkám A,B,C bych chtěl přidat checkboxy tak nastává problém. Pokud edituji např ItemTemplate tak tímto způsobem přidám pouze 3 checkboxy k A,B,C pokud se nepletu. Potom u každé další položky budou právě ty 3 stejné checkboxy. Jak to tedy vyřešit nejjednodušeji ? Pokud se chystáte napsat další článek tak bych byl rád kdyby se tam konkrétně tady tohle vyřešilo. Diky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zkuste si pohrát s kolekcí Controls každé položky v komponentě DataList a projít všechny CheckBoxy:

For i As Integer = 0 To DataList1.Items.Count - 1
    'projít všechny otázky
    Dim chk1 As CheckBox = CType(DataList1.Items(i).FindControl("Odpoved1"), CheckBox)
    Dim chk2 As CheckBox = CType(DataList1.Items(i).FindControl("Odpoved2"), CheckBox)
    Dim chk3 As CheckBox = CType(DataList1.Items(i).FindControl("Odpoved3"), CheckBox)

    'uložit odpovědi do databáze
    '...
Next

Metoda FindControl, kterou má každá komponenta, vrátí komponentu s daným ID, která je uvnitř této komponenty. Protože standardně vrací typ Control, ale vy chcete CheckBox, musíte si to přetypovat pomocí CType. Pokud potřebujete v C#, překonvertujte si kód na adrese http://labs.developerfusion.co.uk/conver... .

Chcekboxy pojmenujte Odpoved1, Odpoved2 a Odpoved3, dále pak pracujte s proměnnými chk1, chk2 a chk3.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Díky za radu ... Nejsem z toho sice moc chytrý ale pokusím se si s tím pohrát.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Co je na tom složitého? Projdete všechny položky komponenty DataList v cyklu a v každé z nich najdete komponenty s ID Odpoved1, Odpoved2 a Odpoved3. Podle toho, jak jsou zaškrtnuté, ověříte správnost a uložíte hodnoty do databáze (nejlépe přímo kódem pomocí SqlConnection a SqlCommand).

Pokud tomuhle nerozumíte, pak máte opravdu jen základní znalosti. Vydržte do dalšího dílu seriálu.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Ahoj,forum mi jede v pohodě, design jsem si upravil pomocí css(to bylo to nejjednoduší), ale nedá se to dát na web, něco jako html, nedá se to otevřít v prohlížeči jako odkaz,(myslím jak si člověk uděla třeba webovou stránku, dá ji server)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

"nedá se to dát na web, něco jako html, nedá se to otevřít v prohlížeči jako odkaz"

To znamená, prosím, co?

"html" stránky z toho skutečně neuděláte. HTML stránky jsou (víceméně) statické, aby tomu tak nebylo a bylo možno obsah vytvářet dynamicky (v tomto případě na základě záznamů v databázi), používají se k tomu různé technologie. No a předmětem těchto článků je jedna z nich - ASP.NET.

Ale stránkám takto vytvořeným sebelepší prohlížeč nebude rozumět (stejně jako v prohlížeči neotevřete třeba stránky v php). Potřebujete server, který danou technologii ovládá a je schopen ji prohlížeči přeložit do běžného html kódu.

Proto pro vystavení takovýchto stránek potřebujete webhosting s podporou technologie ASP.NET.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

je to asi krávovina ale není náhodou:

SELECT * FROM uzivatele WHERE jmeno='tom--'

jen

SELECT * FROM uzivatele WHERE jmeno='tom

bez toho apostrofu

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Povedlo se mi rozjet to diskuzní fórum, ale mám problém se stránkováním. Chtěl bych pokaždé zobrazit tak poslední 3 příspěvky a né všechny. Mohl by mi někdo poradit prosím ...

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Dobry den chtel bych se zeptat jak mam udelat aby to co napisu do textboxu se me ulozilo v nejakem txt dokumentu ale na netu! zkousel sem to ale cesta k tomu souboru neexistuje prodarte prosim

Protected Sub btnOdeslat_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnOdeslat.Click

My.Computer.FileSystem.WriteAllText("D:\Users\Tom1\Documents\Visual Studio 2008\WebSites\WebSite1\text.txt", " " & TextBox3.Text & " ", True)

My.Computer.FileSystem.WriteAllText("D:\Users\Tom1\Documents\Visual Studio 2008\WebSites\WebSite1\text.txt", "Právě " & txtJmeno.Text & " " & TextBox1.Text & " přihlásil soutěžní tým " & TextBox3.Text & " do sotěže " & " a to v kategorii " & TextBox4.Text, True)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Ahoj narazil jsem na problém HtmlEncode. Pokud řetěze obsahuje české znaky udělá mi znich HtmlEncode trochu "bordel". při načtení z db se to opět decoduje do správné podoby, ale ja bych potřeboval, aby se to už do db ukládalo správně. Prosím o radu.

petr

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Ano, mám podobný problém. Mě se to rovnou uloží bez češtiny. Tedy jakoby se odstranily háčky a čárky. A mám to tak uložené i v té databázi. Tim se to pak i špatně zobrazí ve výpisu. Vůbec při ukládání do databáze mám problém s češtinou. Když použiju MS Access tak se mi české znaky uloží např. &#225; Když pro stejnou aplikaci použiju MS SQL 2000 zmizí háčky a čárky. :-(

V ASP jsem to řešil tím, že všechny stránky musely být v UTF-8 a při ukládání do databáze jsem měl nastavenou CODEPAGE=65001. Ale tady to nepomáhá. :-(

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

Zdravím,

V první řadě děkuji za bezkonkurenční metodu psaní takovéhoto seriálu.

Udělal jsem minifórum, a všiml jsem si, že pokud odešlu příspěvek, a následně refreshnu stránku, tak se příspěvek odešle znovu (i přes nevyplněné pole). Nevíte kde je chyba ? Rád bych to odstranil, a jako začátečníka mě nic moc nenapadá děkuji.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Po přidání zkuste přesměrovat na stránku s fórem:

Response.Redirect("/Default.aspx")

Tak se po refreshi už neodešlou data znovu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

zdravim priznivce ASP.NETu,

chvalim vas web, protoze se tu zabyvate praktickym programovanim, to co muze programator vyuzit ve svych aplikacich. Je to opravdu poucne. Zadne velke slozitosti, ukazky jsou pochopitelne a ucelne.

Pro rozsireni ukazkovych kodu posilam odkaz na trosku komplexnejsi free guestbook. Muzete si stahnout i zdrojak. Guestbook obsahuje smajliky i administracni sekci pro mazani nezadoucich prispevku a filtrovani neslusnych slov :-) Sice vyuziva Access databazi, ale myslim ze neni problem napojit na sql server. Dale pokud se pamatuji neni vyuzivano parametru, ale pouze skladani retezce, takze v tomto ohledu je dobre trochu upravit.

Pri teto prilezitosti bych se chtel zeptat: chtel bych rozsirit guestbook o ochranu proti spamu. Jakym zpusobem je realizovano napr. na tomto webu ? Pouzivate pro nahodnou generaci obrazku s pismeny napr adrotator a podle vybraneho obrazku kontrolujete sekvenci pismen ? Nebo lze jit jinou cestou ? ....diky za odpoved :-)

john

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět

Ochrana proti spamu je věcí trochu složitější. V praxi se na to používá speciální stránka (handler), která nějak vygeneruje obrázek s písmeny a ten (ta jeho binární data) pošle do prohlížeče. V html článku to vypadá takto: <img src="Antispam.ashx" />, kde Antispam.ashx je právě ta speciální stránka. V ní normálně přes GDI+ (System.Drawing) vytvoříte obrázek, uložíte ho a pošlete to prohlížeči.

Další věcí, kterou je vhodné k tomuto účelu využít, je CustomValidator. Je to vlastně obecný validátor, který na serveru něco ověří (kód pro ověřování píšete vy jako programátor v události ServerValidate) a pokud se ověření podaří, data odeslaná formulářem se zpracují, jinak je stránka vrácena klientovi. Výhodou je právě to, že si můžete napsat takto vlastní validátor, který se i jako validátor chová.

Napsat takovou věc je ale složitější, ale také si to v některém z příštích dílů ukážeme.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Omlouvám se, že předbíhám látku. Ale chtěl jsem se zeptat pouze principiálně k něčemu z Vašeho textu (nemusíte na tomto místě vysvětlovat postup).

V ASP.NETu se genericky tvořené obrázky musí "někam" uložit a až poté odeslat prohlížeči, nebo je to pouze specifikum těchto speciálních stránek a jinak se dá obrázek generovat přímo do proudu, který odchází prohlížeči?

(osobně to totiž takto mám řešeno v PHP-čku, kde do stránky vygeneruji kód :

<img src="graf.php?....(následují parametry)..">, no a když prohlížeč o takový obrázek požádá, dostává přímo proud binárních dat ve formátu obrázku).

P.S. ptám se proto, protožem jak jsem již kdysi vyjádřil, Vaše články mne zlákaly, abych do budoucna uvažoval o předělání našich firemních stránek právě do ASP-čka, tak si tak trochu postupně oťukávám terén.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Já sám nevím, jak to přesně je, ale když jsem chtěl zobrazit přes GDI+ vytvořený obrázek, musel jsem ho napřed uložit do adresáře a pak přidat do parametru ImageURL odkaz na takto vytvořený soubor.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

A jak se to potom řeší dál? Co s tím uloženým obrázkem? Kdy ho smažete, aby se Vám tam nehromadily, přece požadavek od klienta na zobrazení může přijít okamžitě, nebo třeba za půl hodiny? A jaké mu dáte jmého, aby se vzájemně nepletly různé obrázky pro různé návštěvníky stránek. Tyto otázky právě byly důvodem, proč jsem to já (ale ještě v tom PHP-čku) řešil napřímo.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ne, řeší se to přes tzv. handler. Je to víceméně soubor s procedurou, která něco provede a pošle výsledek do prohlížeče. Takže ve stránce máte třeba <img src="generujObrazek.ashx?parametr1=hodnota" /> a prohlížeč odešle při stahování obrázku požadavek na stránku generujObrazek.ashx. Jakmile to dorazí na server, spustí se příslušná procedura, která obrázek vygeneruje a jeho bajty rovnou pošle do prohlížeče, ani nic nemusí nikam ukládat.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Děkuji, takže to je přesně totéž, co jsem dělal doposud ve "starém" systému.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Jednoduché diskusní fórum

www.asphut.com

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback