Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

9. díl - Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Tomáš Herceg       15.07.2008       C#, VB.NET, ASP.NET WebForms, HTTP/HTML       24091 zobrazení

V tomto díle se podíváme na to, jak nastavit přístupová práva na různé stránky pro jednotlivé uživatele a role v ASP.NET aplikacích, a dále si povíme něco o tématech a skinech. Také si pořádně probereme sitemapy a navigaci na stránkách včetně psaní vlastního sitemap providera, který část menu vygeneruje podle seznamu kategorií v databázi.

V minulém dílu jsme začali vyvíjet naši aplikaci pro evidenci toho, co jsme kdy komu půjčili a rádi bychom ještě někdy viděli. Dnes navrhneme a vytvoříme strukturu celé aplikace, naučíme se řídit přístup k jednotlivým stránkám, abychom zabezpečili, že se uživatelé dostanou jen k funkcím, ke kterým mají oprávnění.

Otevřete si tedy projekt z minula a budeme pokračovat dál. Vytvoříme několik ContentPages pro naši MasterPage.Master. Už máme hotovou stránku Default.aspx, na které se bude zobrazovat seznam vypůjčených věcí.

Struktura projektu a jednotlivé stránky

  • Admin - složka, ve které budou stránky pro administrátora
    • Users.aspx - správa uživatelů a přidělování rolí
    • Categories.aspx - správa kategorií výpůjček
  • Default.aspx - seznam vypůjčených věcí, filtrování podle kategorií, uživatele, popisu a stavu vrácení, mazání položek
  • Lend.aspx - stránka pro zadání/editaci informací o výpůjčce
  • Login.aspx - přihlašovací dialog

Vytvořte tedy do kořenového adresáře aplikace novou Content Page a pojmenujte ji Lend.aspx. Dále vytvořte novou stránku (už ne Content Page) pomocí Add New Item, a pojmenujte ji Login.aspx. Tato stránka nebude začleněna do MasterPage.master, přidělali bychom si tím spoustu práce, museli bychom například pracně schovávat menu atd.

Při vytváření nových stránek si samozřejmě zvolte programovací jazyk, který v nich chcete používat. V tomto seriálu zveřejňuji kód jak v jazyce VB.NET, tak i v jazyce C#.

Přidání nové Content Page Přidání nové stránky Login.aspx

Přidání nové stránky Login.aspx

Dále vytvořte složku Admin a do ní přidejte dvě Content Pages. Vytvořte je tak, jako obvykle, a pak je do složky Admin přetáhněte. Vaše webová aplikace by nyní měla vypadat takto:

Soubory v naší webové aplikaci

Vytvoření rolí, uživatelů a nastavení přístupových práv pro složky

Pro tyto účely je spolu s Visual Studiem dodávána webová aplikace, ve které lze vše přehledně nastavit. Občas je s touto aplikací hodně vztekání, protože poměrně často padá, ale zkusíme ji použít, snad budeme mít štěstí. Klikněte nahoře v okně Solution Explorer na ikonku ASP.NET Configuration.

V novém okně prohlížeče se spustí úžasná webová aplikace ASP.NET Configuration Tool.

 ASP.NET Configuration Tool

Přepněte se na záložku Zabezpečení (Security) a klikněte na odkaz Vytvořit nebo spravovat role (Create or manage roles). Na objevivší se stránce přidejte roli admin a tlačítkem Zpět se vraťte na stránku Zabezpečení.

Klikněte na odkaz Vytvořit uživatele (Create user) a vytvořte uživatele s uživatelským jménem admin a přiřaďte jej do role admin. Vymyslete si nějaké heslo a zadejte e-mailovou adresu. Přidejte ještě alespoň dva další uživatele neadministrátory, ať máme na čem testovat. Pak se opět vraťte na stránku Zabezpečení.

Poslední věc, kterou provedeme, je nastavení přístupových pravidel. Klikněte na tlačítko Spravovat pravidla přístupu (Manage access rules).

Klikněte na složku Vypujcky a na tlačítko Přidat pravidlo. Pravidlo nastavte podle obrázku (odepřít přístup nepřihlášeným uživatelům).

Odepření přístupu nepřihlášeným

Dále klikněte na složku Admin a vytvořte pravidlo podle následujícího obrázku:

 Povolit přístup roli Admin

Do této složky jsme povolili přístup všem, co mají roli admin. Přidejte této složce ještě jedno pravidlo podle tohoto obrázku:

Odepřít přístup všem uživatelům 

Tím do této složky povolíme přístup jen uživatelům, kteří mají roli admin. Všichni ostatní budou mít přístup zakázaný. Jen ještě v celkovém přehledu zkontrolujeme pořadí pravidel, první musí být povolení přístupu pro admina, až druhé musí být zákaz přístupu všem. Při ověřování přístupu se toti použije první pravidlo, které se vztahuje na daného uživatele.

Výsledné nastavení pravidel

Webovou aplikaci pro správu přístupových práv můžeme nyní zavřít, už ji nebudeme potřebovat. Mimochodem pokud chcete vidět, jak tenhle krám spadne, klikněte na tlačítko Hotovo :-). To, co jsme nyní udělali pomocí tohoto nástroje, je možné udělat i bez něj. Do databáze bychom poslali 3 INSERT příkazy - první pro vytvoření role, druhý pro vytvoření uživatele, a třetí do tabulky UsersInRoles, která obsahuje každé přiřazení uživatele do role. Pokud chcete, podívejte se na strukturu tabulky, ať chápete, jak to funguje. Pro každého uživatele bude v této tabulce tolik záznamů, v kolika je rolích, každý záznam obsahuje položky UserName a RoleName. Pro každou dvojici uživatel - role tam bude jeden záznam. Oba sloupce jsou pomocí klíčů navázány na tabulku Users resp. Roles.

Dále webová aplikace nastavila přístupová práva, což bychom mohli udělat sami v souboru web.config. Když se do něj podíváte, uvidíte v něm novou sekci, kterou tam Configuration Tool vygeneroval.

     <authorization>
<
deny users="?" />
</
authorization>

Tím se řekne, že nepřihlášení uživatelé nemají v aplikaci co dělat. Dále se nám vygeneroval i soubor web.config ve složce Admin. Je v něm pouze konfigurační sekce authorization:

         <authorization>
<
allow roles="admin" />
<
deny users="*" />
</
authorization>

Tady je povolená role admin a zakázán přístup pro úplně všechny uživatele (otazník jsou nepřihlášení, hvězdička jsou všichni).

Je dobré si uvědomit, že soubor web.config může změnit většinu nastavení ze souborů web.config a machine.config v kořenovém adresáři aplikace, upravená nastavení se pak vztahují pouze na danou složku. To, která nastavení se dají přepsat, a která ne, se samozřejmě dá nastavit, takže konfigurační model ASP.NET je velice silný a modulární a umožňuje provozovatelům webhostingů efektivně povolit či zakázat změny některých nastavení.

Ještě drobnost

Toto nastavení přístupových práv ještě není úplně ideální, uživatelé se totiž někde potřebují přihlásit, a to na stránce Login.aspx, na kterou se ale nyní nedostanou, protože přihlášení nejsou. Pro tuto stránku musíme přístup nepřihlášeným explicitně povolit. Povolíme jim navíc ještě složku App_Themes, aby se na stránku mohly stáhnout styly. Nastavení pro určité cesty můžeme přepsat v souboru web.config, a to pomocí elementu location, který umístěte mimo sekci system.web. Vše, co je uvnitř location, platí jen pro danou cestu a může měnit obecné nastavení pro celou aplikaci.

   <location path="login.aspx">
<
system.web>
<
authorization>
<
allow users="?" />
</
authorization>
</
system.web>
</
location>

<
location path="App_Themes">
<
system.web>
<
authorization>
<
allow users="?" />
</
authorization>
</
system.web>
</
location>

Tím jsme nepřihlášeným povolili přístup do složky App_Themes a na stránku login.aspx.

Menu a navigace v aplikaci

V této aplikaci bychom si menu klidně mohli udělat sami, budou v něm 4 položky pro administrátora a 2 pro běžné uživatele, ale ukážeme si, jak fungují ASP.NET SiteMaps, které ušetří spoustu práce hlavně u rozsáhlejších menu, kde podle oprávnění uživatelů potřebujeme zobrazovat různé položky, některé navíc třeba ještě vybíráme z databáze a ostatní jsou statické.

Jak Sitemapy fungují?

Každá ASP.NET aplikace může ve svém konfiguračním souboru definovat několik Sitemap providerů. Tito provideři se konfigurují v souboru web.config v sekci siteMap, princip je velmi podobný jako u Membership. SiteMap Provider nějakým způsobem vygeneruje mapu webu (hierarchickou stromovou strukturu názvů stránek a jejich URL), kterou může pak poskytnout například komponentám Menu nebo TreeView. Tyto komponenty pak mapu webu nějakým způsobem zobrazí.

To, jak provider strukturu webu získá, je čistě věcí tohoto konkrétního providera. ASP.NET má vestavěnou třídu  XmlSiteMapProvider, což je provider, který si strukturu webu vygeneruje podle XML souboru (dává se mu přípona .sitemap). Vy sami si můžete napsat svého vlastního providera (jednoduše odvodíte novou třídu z třídy StaticSiteMapProvider), a můžete si strukturu webu vytáhnout například z databáze, textového souboru nebo čehokoliv jiného. Providery do sebe můžeme i zanořovat, takže například zde na VbNetu máme základní strukturu udělanou pomocí XmlSiteMapProvidera, zatímco seznam blogů v menu nebo seznam kategorií článků je vygenerován providery, které jsme si pro tento účel sami napsali. Napsat vlastního sitemap providera není nic těžkého, ukážeme si to v tomto článku, kdy do menu z databáze vytáhneme seznam kategorií našich výpůjček.

Výhodou použití sitemap je například to, že při vykreslování menu se automaticky zjišťuje, na které stránky má aktuální uživatel přístup (podle přístupových práv, která jsme nastavovali na začátku tohoto dílu), a zobrazí se jen stránky, kam se aktuální uživatel dostane.

Vytváříme základní strukturu menu

Pravým tlačítkem si klikněte na název website v podokně Solution Explorer a vybrte Add New Item.... Do projektu přidejte novou položku Site Map.

image

Visual Studio nám vygeneruje základní strukturu tohoto XML souboru. Upravte obsah takto:

 <?xml version="1.0" encoding="utf-8" ?>
<
siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<
siteMapNode url="~/" title="Root" description="">
<
siteMapNode url="~/Default.aspx" title="Výpůjčky" description="" />
<
siteMapNode url="~/Lend.aspx" title="Nová výpůjčka" description="" />
<
siteMapNode url="~/Admin/Default.aspx" title="Administrace" description="">
<
siteMapNode url="~/Admin/Categories.aspx" title="Nová výpůjčka" description="" />
<
siteMapNode url="~/Admin/Users.aspx" title="Uživatelé" description="" />
</
siteMapNode>
</
siteMapNode>
</
siteMap>

Struktura tohoto souboru je poměrně zřejmá, důležité je upozornění, že každá sitemapa musí mít právě jednu kořenovou položku siteMapNode. Já jsem jí dal název Root, v aplikaci ji zobrazovat vůbec nebudeme, ale být tam musí. Každý element siteMapNode v sobě může obsahovat libovolný počet elementů siteMapNode, díky čemuž můžeme vytvořit libovolnou stromovou strukturu. Celé menu ale musí mít právě jeden kořen.

Minule jsme si povídali o souboru machine.config, je na místě upozornit, že jeho konfiguraci dědí a může měnit nejprve soubor web.config umístěný ve stejném adresáři. Tyto dva soubory dohromady dávají výchozí konfiguraci každé ASP.NET aplikace. Co se nám na ní nelíbí, můžeme (pokud na to máme práva) změnit právě v našem souboru web.config v aplikaci. Proč to znovu připomínám? V souboru web.config v adresáři .NET frameworku (tam, kde je machine.config) je jeden výchozí SiteMap provider už nadeklarován, je to XmlSiteMapProvider nasměrovaný na soubor Web.sitemap. My si jej v naší konfiguraci předeklarujeme, abychom si předvedli, jak to celé funguje.

Do souboru web.config v kořenovém adresáři naší webové aplikace přidejte dovnitř elementu system.web následující kód, který obsahuje konfiguraci našeho sitemap providera. Všimněte si elementu clear/, ten smaže všechny providery, které jsme zdědili, tzn. ty definované v machine.config atd. Pokud bychom ho tam nedali, naše aplikace by měla providery dva (což v principu vůbec ničemu nevadí, použili bychom jen toho našeho, ale je dobré si to uvědomit).

     <siteMap enabled="true" defaultProvider="MySitemapProvider">
<
providers>
<
clear/>
<
add name="MySitemapProvider" type="System.Web.XmlSiteMapProvider"
siteMapFile="Web.sitemap" securityTrimmingEnabled="true" />
</
providers>
</
siteMap>

Zajímavá je vlastnost securityTrimmingEnabled. Pokud ji nastavíme na true, všechny stránky ze složky ~/Admin/ se zobrazí pouze uživatelům, kteří mají do této sekce přístup, tedy těm, kteří mají roli admin. To je obrovská výhoda, nemusíme vůbec řešit, jak schovat běžným uživatelům odkazy do administrační sekce, pokud zapneme security trimming, máme po starostech, sitemapy si to zařídí samy. U každé položky v sitemapě můžeme navíc specifikovat, kterým rolím přesně se zobrazit má, a kterým ne, to se hodí v případě složitějších sitemap a přístupových práv.

Vlastní Sitemap Provider

Aby toho nebylo málo a něco jsme se naučili, napíšeme si nyní vlastního sitemap providera, který se připojí do databáze, zjistí si seznam kategorií výpůjček, a zanoří je pod stránku Výpůjčky. Přidejte si tedy do projektu novou třídu a vyberte si programovací jazyk, který chcete použít. Třídu pojmenujte SqlSiteMapProvider.

 Přidání nové třídy do projektu

ASP.NET nás upozorní, že soubory s kódem patří do složky App_Code, potvrdíme mu, aby tam třídu umístil.

image

Do souboru třídy zkopírujte tento kód. Naši třídu jsme zdědili od StaticSiteMapProvider. Visual Studio nám nyní řeklo, že tato třída vyžaduje, abychom naimplementovali její dvě metody - GetRootNodeCore a BuildSiteMap.

Kód v jazyce Visual Basic .NET

 Imports Microsoft.VisualBasic
Imports System.Web
Imports System.Data.SqlClient

Public Class SqlSiteMapProvider
Inherits StaticSiteMapProvider


End Class

Visual Studio nám ve VB.NET podtrhne název třídy SqlSiteMapProvider, protože ve třídě StaticSiteMapProvider jsou dvě abstraktní metody, které musíme naimplementovat. Položte kurzor za slovo StaticSiteMapProvider a stiskněte klávesu Enter. Visual Studio definice obou požadovaných metod doplní.

Kód v jazyce C#

 using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.UI;
using System.Data.SqlClient;

public class SqlSiteMapProvider : StaticSiteMapProvider
{

}

V C# se to dělá trochu jinak. Když budete chvíli myší jezdit po slově StaticSiteMapProvider, objeví se takový malý titěrný obdélníček, který se po přejetí změní v o něco větší rozbalovací nabídku. Nejjednodušší je kliknout na toto slovo StaticSiteMapProvider a stisknout Shift-Alt-F10, nabídka se rozbalí sama. Klikněte na Implement abstract class StaticSiteMapProvider a Visual Studio požadované deklarace metod do třídy doplní.

C#

 

Nyní musíme tyto dvě metody naimplementovat, ve skutečnosti toho bude o něco více. Mohli bychom napsat providera přesně na míru naší aplikaci, ale to by nebylo ono, nedal by se použít v aplikaci jiné. Když už něco píšeme, můžeme zvážit, jestli nedá o moc víc práce napsat to obecně, abychom věc mohli využívat i jinde.

Co tedy náš provider bude dělat? Připojí se k databázi, provede nějaký dotaz nad nějakou tabulkou, hodnoty z jednoho sloupce použije jako název stránky a hodnoty z jiného sloupce dosadí někam do URL. Do souboru web.config tedy přidejte konfiguraci našeho providera (hned pod prvního providera, kterého jsme již přidali):

         <add name="CategoriesSitemapProvider" type="SqlSiteMapProvider" 
title="Výpůjčky" url="~/Default.aspx"
connectionStringName="VypujckyConnectionString"
selectCommand="SELECT [CategoryId], [Title] FROM [Categories] ORDER BY [Title]"
titleColumn="Title"
urlColumn="CategoryId" urlFormatString="~/Default.aspx?category={0}" />

Tím jsme vytvořili novou konfiguraci siteMapProvidera. Vlastnost type říká, která třída se má použít pro vygenerování sitemapy, pokud byste si providera chtěli zařadit do nějakého vlastního namespace, musíte jej do vlastnosti type uvést také, aby jej ASP.NET našlo.

Našemu providerovi jsme nastavili poměrně hodně atributů. Vlastnosti title a url patří kořenové položce, do které se kategorie z databáze vypíší, provider tuto kořenovou položku musí vygenerovat, takže mu je nutné sdělit, jak ji má pojmenovat a kam má odkazovat. Atribut connectionStringName určuje název připojovacího řetězce k databázi, kterou chceme použít, selectCommand je příkaz, který se nad databází spustí, titleColumn je název sloupce, který bude obsahovat názvy stránek, urlColumn jsou hodnoty, které se dosadí do hodnoty urlFormatString pomocí standardních formátovacích funkcí, tedy na místo řetězce {0}.

V našem případě děláme select do tabulky kategorií, jako názvy položek menu použijeme názvy kategorií a do URL dosadíme hodnotu ze sloupce CategoryId, tedy jednoznačného identifikátoru dané kategorie.

Inicializace providera

Abychom mohli providera napsat a používat tuto konfiguraci v souboru web.config, musíme vědět, jak provider funguje. Zjistit se to dá například z dokumentace. Už máme nadeklarovanou metodu BuildSiteMap, uvnitř ní se připojíme k databázi a sestavíme sitemapu, resp. její čast. Metoda GetRootNodeCore jen zavolá BuildSiteMap a vrátí její výsledek.

Abychom se dostali k položkám v konfiguraci souboru web.config a věděli, kam se máme připojovat, musíme přepsat metodu Initialize. Ta jako parametr dostane kolekci všech vlastností, které jsme ve web.config specifikovali. Přidejte tedy dovnitř třídy SqlSiteMapProvider tento kód:

Kód v jazyce Visual Basic .NET

 #Region "Properties and configuration"

Private _title As String
''' <summary>
''' Název kořenové položky
''' </summary>
Public Property Title() As String
Get
Return _title
End Get
Set(ByVal value As String)
_title = value
End Set
End Property

Private _url As String
''' <summary>
''' URL kořenové položky
''' </summary>
Public Property Url() As String
Get
Return _url
End Get
Set(ByVal value As String)
_url = value
End Set
End Property

Private _connectionStringName As String
''' <summary>
''' Název connectionStringu, který použijeme k připojení do databáze
''' </summary>
Public Property ConnectionStringName() As String
Get
Return _connectionStringName
End Get
Set(ByVal value As String)
_connectionStringName = value
End Set
End Property

Private _selectCommand As String
''' <summary>
''' SQL příkaz, který vybere seznam položek
''' </summary>
Public Property SelectCommand() As String
Get
Return _selectCommand
End Get
Set(ByVal value As String)
_selectCommand = value
End Set
End Property

Private _titleColumn As String
''' <summary>
''' Název sloupce s názvy stránek
''' </summary>
Public Property TitleColumn() As String
Get
Return _titleColumn
End Get
Set(ByVal value As String)
_titleColumn = value
End Set
End Property

Private _urlColumn As String
''' <summary>
''' Název sloupce s hodnotami, které se budou dosazovat do URL
''' </summary>
Public Property UrlColumn() As String
Get
Return _urlColumn
End Get
Set(ByVal value As String)
_urlColumn = value
End Set
End Property

Private _urlFormatString As String
''' <summary>
''' URL adresa, do které se budou dosazovat hodnoty z datbaáze
''' </summary>
Public Property UrlFormatString() As String
Get
Return _urlFormatString
End Get
Set(ByVal value As String)
_urlFormatString = value
End Set
End Property

Public Overrides Sub Initialize(ByVal name As String, ByVal attributes As System.Collections.Specialized.NameValueCollection)
MyBase.Initialize(name, attributes)

'načíst hodnoty parametrů z konfigurace
If attributes("title") IsNot Nothing Then
Me.Title = attributes("title")
Else : Throw New ArgumentException("title")
End If

If attributes("url") IsNot Nothing Then
Me.Url = attributes("url")
Else : Throw New ArgumentException("url")
End If

If attributes("connectionStringName") IsNot Nothing Then
Me.ConnectionStringName = attributes("connectionStringName")
Else : Throw New ArgumentException("connectionStringName")
End If

If attributes("selectCommand") IsNot Nothing Then
Me.SelectCommand = attributes("selectCommand")
Else : Throw New ArgumentException("selectCommand")
End If

If attributes("titleColumn") IsNot Nothing Then
Me.TitleColumn = attributes("titleColumn")
Else : Throw New ArgumentException("titleColumn")
End If

If attributes("urlColumn") IsNot Nothing Then
Me.UrlColumn = attributes("urlColumn")
Else : Throw New ArgumentException("urlColumn")
End If

If attributes("urlFormatString") IsNot Nothing Then
Me.UrlFormatString = attributes("urlFormatString")
Else : Throw New ArgumentException("urlFormatString")
End If
End Sub
#End
Region

Kód v jazyce C#

     #region "Properties and configuration"

private string _title;
/// <summary>
/// Název kořenové položky
/// </summary>
public string Title
{
get { return _title; }
set { _title = value; }
}

private string _url;
/// <summary>
/// URL kořenové položky
/// </summary>
public string Url
{
get { return _url; }
set { _url = value; }
}

private string _connectionStringName;
/// <summary>
/// Název connectionStringu, který použijeme k připojení do databáze
/// </summary>
public string ConnectionStringName
{
get { return _connectionStringName; }
set { _connectionStringName = value; }
}

private string _selectCommand;
/// <summary>
/// SQL příkaz, který vybere seznam položek
/// </summary>
public string SelectCommand
{
get { return _selectCommand; }
set { _selectCommand = value; }
}

private string _titleColumn;
/// <summary>
/// Název sloupce s názvy stránek
/// </summary>
public string TitleColumn
{
get { return _titleColumn; }
set { _titleColumn = value; }
}

private string _urlColumn;
/// <summary>
/// Název sloupce s hodnotami, které se budou dosazovat do URL
/// </summary>
public string UrlColumn
{
get { return _urlColumn; }
set { _urlColumn = value; }
}

private string _urlFormatString;
/// <summary>
/// URL adresa, do které se budou dosazovat hodnoty z datbaáze
/// </summary>
public string UrlFormatString
{
get { return _urlFormatString; }
set { _urlFormatString = value; }
}

public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes)
{
base.Initialize(name, attributes);

//načíst hodnoty parametrů z konfigurace
if (attributes["title"] != null)
{
this.Title = attributes["title"];
}
else throw new ArgumentException("title");

if (attributes["url"] != null)
{
this.Url = attributes["url"];
}
else throw new ArgumentException("url");

if (attributes["connectionStringName"] != null)
{
this.ConnectionStringName = attributes["connectionStringName"];
}
else throw new ArgumentException("connectionStringName");

if (attributes["selectCommand"] != null)
{
this.SelectCommand = attributes["selectCommand"];
}
else throw new ArgumentException("selectCommand");

if (attributes["titleColumn"] != null)
{
this.TitleColumn = attributes["titleColumn"];
}
else throw new ArgumentException("titleColumn");

if (attributes["urlColumn"] != null)
{
this.UrlColumn = attributes["urlColumn"];
}
else throw new ArgumentException("urlColumn");

if (attributes["urlFormatString"] != null)
{
this.UrlFormatString = attributes["urlFormatString"];
}
else throw new ArgumentException("urlFormatString");
}

#endregion

Tento strašně dlouhý kód nedělá nic závratného. Nadeklaroval jsem si pro každý přidaný atribut v souboru web.config vlastnost a přepsal metodu Initialize, ve které jsem hodnoty vlastností vytáhnul z kolekce Attributes. Vzhledem k tomu, že všechny jsou povinné, pokud nebyly specifikovány, vyhazuji ArgumentException s názvem parametru, který chybí.

Možná si říkáte, že aby to bylo napsané správně se vším všudy, potřebujeme desetkrát víc kódu, než kdybychom to napsali jednoduše a snadno. Toto však ale už není seriál pro začátečníky, takže se snažím ukázat, jak se to dělá doopravdy. Je velmi vhodné používat vlastnosti, nikdy totiž nevíte, kdy v budoucnu budete chtít hlídat, jaké hodnoty se přiřazují. S proměnnými se to pak upravuje velice špatně, s vlastnostmi je to hračka, prostě do nich přidáte nějakou validaci.

Odbočka - pár tipů pro Visual Studio

Když se podíváte na každou deklaraci vlastnosti, je to poměrně dost kódu. Vypisovat ho ručně není nic příjemného, takže využijeme toho, co Visual Studio umí. Pro každý jazyk je to trochu jinak, ale v obou je to velmi jednoduché.

Deklarace vlastností

Kód v jazyce Visual Basic .NETVe VB.NET stačí napsat dovnitř třídy slovo Property a zmáčknout tabulátor. Visual Studio automaticky vygeneruje kód pro deklaraci vlastnosti. Napíšete _titleColumn a klávesou tabulátor se přepnete do dalšího pole, napíšete TitleColumn a tabulátorem se přepnete opět na další pole. Je to velmi rychlé a elegantní.

Kód v jazyce C#V C# použijeme Refactor - nadeklarujeme privátní proměnnou dovnitř třídy, klikneme na ni pravým tlačítkem a v menu Refactor vybereme položku Encapsulate Field. Potvrdíme dvě dialogová okna a vlastnost se nám vytvoří.

XML komentáře

XML komentáře jsou věcí velice dobrou, pokud pečlivě okomentujete každou vlastnost a metodu, při jejím používání vám Visual Studio zobrazuje tento komentář spolu s IntelliSense. To je velmi užitečné zvlášť když používáte třídy, které neznáte, nebo které jste nepsali vy. Navíc se z těchto komentářů dá vygenerovat pěkná dokumentace.

Ve VB.NET stačí napsat tři apostrofy, v C# tři lomítka, a Visual Studio si už samo vygeneruje potřebnou strukturu. Pokud nechcete zadávat rozšířené parametry a stačí vám jen summary (souhrn), můžete ostatní elementy smazat, například Visual Basic je tam přidává a zabírá to hrozně místa.

Obě tyto techniky jsou vidět na kratičkém instruktážním videu, které jsem pro tento článek vytvořil:

Regiony

Kód, který tvoří nějakou logickou část, je vhodné uzavřít do regionů. Jsou to ty řádky začínající dvojkřížem - #Region a #End Region, resp. #region a #endregion. Celý region můžete na boku rozbalit nebo sbalit malým rozbalovátkem, aby nezabíral místo.

Vygenerování sitemapy

Nyní naimplementujeme metodu BuildSiteMap, která se připojí k databázi a vygeneruje sitemapu. To, jak se připojit k databázi, byste měli znát, kdyžtak se podívejte na článek Komunikace s MS SQL databází od Tomáše Jechy. Pak už je to velmi jednoduché:

Kód v jazyce Visual Basic .NET
     Private root As SiteMapNode

Public Overrides Function BuildSiteMap() As System.Web.SiteMapNode
SyncLock Me

If root Is Nothing Then 'pokud je třeba generovat, generujeme

'vytvořit kořenovou položku
root = New SiteMapNode(Me, Guid.NewGuid().ToString(), Me.Url, Me.Title)

'podpoložky natáhnout z databáze
Dim con As New SqlConnection(ConfigurationManager.ConnectionStrings(Me.ConnectionStringName).ConnectionString)
Dim com As New SqlCommand(Me.SelectCommand, con)
con.Open()
Dim reader As SqlDataReader = com.ExecuteReader() 'provést dotaz

While reader.Read() 'projít vrácené záznamy
Dim node As New SiteMapNode(Me, Guid.NewGuid().ToString(), String.Format(Me.UrlFormatString, reader(Me.UrlColumn)), reader(Me.TitleColumn))
AddNode(node, root)
End While

reader.Close() 'zavřít reader a spojení
con.Close()

End If

Return root 'vrátíme kořenovou položku

End SyncLock
End Function


Protected Overrides Function GetRootNodeCore() As System.Web.SiteMapNode
Return BuildSiteMap()
End Function
Kód v jazyce C#
     private SiteMapNode root;

public override System.Web.SiteMapNode BuildSiteMap()
{
lock (this)
{
if (root == null) //pokud je třeba generovat, generujeme
{
//vytvořit kořenovou položku
root = new SiteMapNode(this, Guid.NewGuid().ToString(), this.Url, this.Title);

//podpoložky natáhnout z databáze
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[this.ConnectionStringName].ConnectionString);
SqlCommand com = new SqlCommand(this.SelectCommand, con);
con.Open();

SqlDataReader reader = com.ExecuteReader(); //provést dotaz
while (reader.Read())
{
//projít vrácené záznamy
SiteMapNode node = new SiteMapNode(this, Guid.NewGuid().ToString(), string.Format(this.UrlFormatString, reader[this.UrlColumn]), reader[this.TitleColumn].ToString());
AddNode(node, root);
}

reader.Close();
//zavřít reader a spojení
con.Close();
}

return root; //vrátíme kořenovou položku
}
}


protected override System.Web.SiteMapNode GetRootNodeCore()
{
return BuildSiteMap();
}

Jak to funguje? Protože metoda BuildSiteMap se může spustit v několika vláknech víckrát zároveň, použijeme zámek (Synclock ve VB.NET resp. lock v C#), čímž zabezpečíme, že se kód uvnitř zamčené sekce nespustí dvakrát zároveň. Druhé vlákno jednoduše počká, až první ze zamčené sekce vyleze.

Pokud je proměnná root prázdná, musíme sitemapu vygenerovat, jinak pouze kořenovou položku sitemapy vrátíme, protože je sitemapa už vygenerovaná a drží se v paměti, aby se nenatahovala z databáze při každém požadavku, to by hrozně zpomalovalo a zatěžovalo chudinku databázi.

Když máme sitemapu generovat, tak vytvoříme nejprve kořenovou položku - přiřadíme do ní novou instanci třídy SiteMapNode, jako argumenty konstruktoru předáme aktuálního providera, nějaký unikátní klíč (v tomto případě generujeme nový GUID - unikátní identifikátor), dále jí předáme URL a název. Tím jsme vytvořili kořenovou položku Výpůjčky odkazující na adresu Default.aspx, která bude obsahovat všechny kategorie.

Nyní se připojíme k databázi a vytvoříme nový SQL dotaz. Po spuštění projdeme všechny výsledky, které nám databáze na dotaz vrátila, a pro každý výsledek vytvoříme opět novou SiteMapNode, do níž nastavíme vytažené hodnoty z databáze. Pro náhradu {0} za hodnotu sloupce CategoryId použijeme standardní funkci String.Format. Aby bylo jasné, do jaké kategorie se mají položky zařadit, musíme je metodou AddNode začlenit pod položku root. Metoda AddNode je deklarována ve třídě, ze které je náš SqlSiteMapProvider odvozen, to jen aby bylo jasné, kde se tam ta metoda vzala. Po přečtení všech záznamů akorát stačí zavřít spojení a je hotovo.

Metoda GetRootNodeCore pouze zavolá naši metodu BuildSiteMap. Sitemapa se vygeneruje, pokud ještě vygenerovaná není, a pokud je, tak už se jen vrátí. Tím zajistíme, že se nám sitemapa nebude generovat stále znovu a znovu, prostě se sestaví jednou a hotovo.

Začlenění sitemap do sebe

Nyní musíme říci, kam se má struktura vygenerovaná naším providerem začlenit. Otevřete soubor Web.sitemap a nahraďte element siteMapNode ukazující na stránku ~/Default.aspx tímto elementem:

     <siteMapNode provider="CategoriesSitemapProvider" />

Tím jsme zajistili, že místo položky Výpůjčky natvrdo nadefinované v tomto souboru se uloží kořenová položka providera, kterého jsme uvedli. CategoriesSitemapProvider je jméno (atribut name) našeho druhého providera ze souboru web.config, kde jsou také jeho patřičná nastavení. Jako výchozího providera jsme nastavili MySiteMapProvider, který používá soubor web.sitemap. Do tohoto souboru se na příslušné místo tedy doplní seznam kategorií z databáze.

Je samozřejmě úplně jedno, jaké typy providerů do sebe začleníme, do našeho databázového providera jsme mohli začlenit ještě další providery, nebo naopak našeho databázového použít jako výchozího a začlenit do něj web.sitemap. Anebo celé menu vygenerovat pouze z databáze, opravdu nejsme ničím omezeni, v konfiguraci si jednoduše nastavíme providery a je to.

Přidáváme menu do stránky

Nyní máme sitemapu nachystanou, jen ji budeme chtít někde zobrazit. Otevřete si stránku MasterPage.master a oddíl header upravte takto:

         <div id="header">
<div id="loggedUser">
Přihlášený uživatel: <strong><asp:LoginName ID="LoginName1" runat="server" /></strong>.
<asp:LoginStatus ID="LoginStatus1" runat="server" />
</div>
<div id="menu">
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false" SiteMapProvider="MySiteMapProvider" />
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" Orientation="Horizontal">
</asp:Menu>
</div>
</div>

Za textem Přihlášený uživatel vypíšeme jeho uživatelské jméno (komponenta LoginName, nedělá nic jiného, že vypíše jméno aktuálně přihlášeného uživatele) a pak tlačítko Odhlásit (komponenta LoginStatus). Komponenta LoginStatus zobrazuje tlačítko Odhlásit či Přihlásit podle toho, jestli je někdo aktuálně přihlášen, nebo není.

Pro vykreslení menu jsme použili komponentu Menu. Musíme jí nastavit nějaký datový zdroj, který jí sitemapu poskytne, předáme jí tedy SiteMapDataSource. Ten jsme nastavili, aby nezobrazoval hlavní kořenovou položku (tu položku Root ze souboru web.sitemap, která tam musela být, i když jsme ji vlastně nechtěli), a aby používal providera MySiteMapProvider, tedy sitemapu z XML souboru. Samotnému Menu jsme ještě nastavili orientaci na vodorovnou, naše menu je totiž řádkové a nikoliv sloupcové.

Skiny a témata

Obecně se doporučuje co nejvíce se snažit oddělit vzhled od obsahu stránek, k tomu také byly zavedeny CSS styly. Vzhledem k tomu, že v ASP.NET používáme komponenty, často u určitého typu nastavujeme stále ty samé vlastnosti na stále ty samé hodnoty. Abychom se tomuto nepříjemnému faktu vyvarovali, přináší nám ASP.NET skiny. O tématech samotných jsme už mluvili, pokud vše týkající se vzhledu dáme do příslušné složky App_Themes, můžeme si témata přepínat ať už v konfiguraci, nebo programově, a pomocí nich měnit vzhled stránek. Se skiny je to podobné, jsou to vlastně takové CSS styly na ASP.NET komponenty. Přidáme si tedy do našeho tématu (do složky App_Themes/Default) nový skin:

Přidání nové položky

Vytvoření nového skinu

Do tohoto souboru přidejte tento kód:

 <asp:Menu runat="server" 
StaticMenuItemStyle-CssClass="menuItem" StaticHoverStyle-CssClass="menuItemSelected"
DynamicMenuItemStyle-CssClass="menuItemDynamic" DynamicHoverStyle-CssClass="menuItemSelected" />

Tím jsme řekli, že všem komponentám Menu, které se objeví na stránce, se nastaví tyto čtyři vlastnosti na zde uvedené hodnoty, pokud v deklaraci komponenty ve stránce nenastavíme tyto vlastnosti jinak. Do skinů rozhodně nepatří vlastnost ID (naopak runat="server" tam být musí). Skiny se nejčastěji používají právě pro vlastnosti specifikující vzhled.

Všimněte si také, že ze style vlastností používám výhradně vlastnost CssClass a konkrétní vzhled dospecifikuji v CSS souboru. Je to proto, že pokud budeme styly nastavovat natvrdo zde, budou se do stránky renderovat jako inline styly. S rozsáhlejšími komponentami pak docela rychle narůstá velikost vygenerovaného HTML, protože se definice stylu opakuje pro každou položku. Je dobrým zvykem vše dělat přes CSS styly, které stejně většinou už máme nachystané od designéra.

Každá komponenta má navíc ještě vlastnost SkinID, což je ekvivalent třídy v CSS. Pokud ve skinu uvedu v deklaraci komponenty vlastnost SkinID, dané vlastnosti se nastaví pouze těm komponentám ve stránce, které mají SkinID nastaveno na stejnou hodnotu. Takto můžu v aplikaci přebarvit například všechna tlačítka na modro (což se mimochodem v CSS dělá dost blbě, protože se tím přebarví i textová pole a vše, co má značku input), akorát všem tlačítkům s textem Zrušit nastavím ve stránce SkinID na Cancel a pak je ve skinu všechny obarvím na červeno, protože uvedu Button znovu s nastaveným SkinID na Cancel a červenou barvou. Pro každou komponentu tedy můžete mít jeden výchozí vzhled a libovolně mnoho dalších pomocí SkinID.

Otestování sitemapy

Nyní budeme chtít naše menu otestovat. Otevřete si podokno Database Explorer (pokud ho nevidíte, zapněte v jej menu View), rozbalte databázi Vypujcky a klikněte pravým tlačítkem na tabulku Categories. Vyberte položku Show Table Data, čímž zobrazíte, co v tabulce je.

 Zobrazení dat tabulky Categories Vyplnění testovacích kategorií

Do této tabulky přidejte kategorie podle obrázku (první sloupec nevyplňujte, měl by se vyplnit sám; pokud se nevyplní, tak jste v minulém dílu zapomněli nastavit Identity Specification pro tuto tabulku, tak to musíte napravit).

To je celé. Když nyní stisknete Ctrl+F5, měla by se zobrazit prázdná červená stránka s adresou Login.aspx?returnUrl=%2fVypujcky%2fdefault.aspx. Zatím jsme ještě na stránku nepřidali přihlašovací dialog. Musíme to tedy napravit.

Přihlašovací dialog

Vraťte se do Visual Studia a otevřete stránku Login.aspx. Záhlaví nechte, její HTML změňte takto:

 <html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
<title>Výpůjčky - přihlášení</title>
</
head>
<
body>
<form id="form1" runat="server">
<div id="window">

<asp:Login ID="Login1" runat="server">
</asp:Login>

</div>
</form>
</
body>
</
html>

Do souboru SkinFile.skin přidejte tento řádek, aby se na nadpis Přihlášení v komponentě Login použila třídy title:

 <asp:Login runat="server" TitleTextStyle-CssClass="title" />

Aby stránka hezky vypadala, přidejte ještě tyto definice do souboru App_Themes/Default/StyleSheet.css.

 #window
{
    
width: 400px;
    
margin: 200px auto;
    
padding: 30px;
    
background-color: White;
}
#window table
{
    
width: 100%;
}
#window .title
{
    
color: #921f1f;
    
font-size: 150%;
    
font-weight: bold;
}

.menuItem {
    
width: 120px;
    
padding: 5px 0px;
    
text-align: center;
    
background-color: transparent; }

.menuItemDynamic
{
    
width: 120px;
    
padding: 5px 0px;
    
text-align: center;
    
background-color: #efd6d6; } .menuItemSelected {
    
width: 120px;
    
padding: 5px 0px;
    
text-align: center;
    
background-color: #cd7f7f; }

Tím jsme nastylovali div s id window tak, aby byl 400 pixelů široký, vevnitř měl okraj 30px na všech stranách, a vycentroval se na střed 200 pixelů od horního okraje. Všechny tabulky, které jsou uvnitř, budou mít šířku 100%, to je kvůli komponentě Login, ta se vyrenderuje jako tabulka. Nadpis bude větším písmem, tučně a tmavě červenou barvou. To je celé. Přihlašovací stránka bude nyní vypadat takto. Není to nic moc, ale nám to musí stačit.

Přihlašovací stránka

Přihlaste se jako admin. Uvidíte celé menu s našimi položkami, když najedete na položku Výpůjčky, rozbalí se podkategorie, které jsme naším providerem vytáhli z databáze. Vidíme, že máme přístup i do administrační sekce.

Položky vytažené z databáze se zaintegrovaly do menu

Pokud kliknete na tlačítko Odhlásit, dostanete se opět na přihlašovací stránku. Jakmile se přihlásíte jako normální uživatel, v menu už administrátorskou kategorii neuvidíte. Vše tedy funguje tak, jak má.

Pokračování příště

To je pro tento díl všechno, doufám, že se vám seriál líbí a že vám je užitečný. Jakékoliv dotazy, náměty a připomínky pište do diskuse.

 

hodnocení článku

2 bodů / 2 hlasů       Hodnotit mohou jen registrované uživatelé.

 

 

 

Nový příspěvek

 

Pozdrav

Ahoj :-)

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

Pozdrav

Ahoj :-)

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

Pozdrav

Ahoj :-)

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

Pozdrav

Ahoj :-)

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den, dělám podle pokynů, ale siteMapNode ve web.config nemám a když se snažím ten kód tam vložit, pořád mi to háže chyby, že to tam nepatří... Můžete mi prosím poradit, co dělám špatně?

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

Zpátky na stromy!!! Neumím číst, místo ve web.sitemap jsem to hledal ve web.config...

Mea culpa...

Vše funguje... OK

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den, mám problém s ohlášením, script pro přihlášení mám v kořenovém adresáři a jmenuje se Default.aspx, po přihlášení, když se proklikám na odkaz např.: /Admin/Uzivatele.aspx tak se nejde odhlásit respektive nedojde k správnému přesměrování a napíše mi to tuto chybu: Popis: HTTP 404. Hledaný prostředek (nebo některá z jeho závislých součástí) byl možná odebrán, přejmenován nebo dočasně není k dispozici. Zkontrolujte následující adresu URL, zda je správně zadaná.

Předem velice děkuji za odpověď.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Ahoj, video mi rika, ze nebylo nalezeno... mozete na to kouknout?

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Zdravím,

po přidání nebo ubrání kategorie se nepřegeneruje menu (už to tady někdo zmiňoval). Jakým způsobem tedy zavolat generování menu v případě změny v kategoriích, aby změna byla ihned do menu promítnuta. Díky moc

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

Také jsem toto jednu dobu řešil, zkoušel jsem co se dalo, ale pokaždé mi to vyhazovalo nějakou chybu. Tak by mě taky zajímalo jak to udělat i když to nyní nutně nepotřebuji.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den.

Chtěl jsem se zeptat jestli existuje v ASP.NET možnost řízení obsahu stránky pomocí role uživatele. Zatím se tu řešily přístupy pro celé stránky.

Naříklad: pro uživatele s rolí1 zobrazit tabulku s daty a pro uživatele s rolí2 ji nezobrazit.

Určitě to jde udělat tak, že si načtu k uživateli příslušnou roli a pomocí podmínek to prostě naprogramuju.

Zajímalo by mě jestli pro to nejsou nějaké nástroje přímo v komponentách ASP.NET. Pokud už se to tu někde řešilo tak se omlouvám že jsem si nevšiml ;-)

Děkuji za odpověď

Honza

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Ahoj je to super seriál a strašně rád bych si ho vyzkoušel až dokonce, ale zasekl jsem se na jedné věci.¨

Když chci zadat v ASP nastroj pro spravu webu zabezpečení tak mi vyskočí hláška

Cannot open database "Vypujcky" requested by the login. The login failed. Login failed for user 'Rob-notas\Rob'.

Už fakt nevím co bych měl ještě nastavit...Ověřování mám User Windiws Authentication

Tak snad někdo poradí.Díky Rob

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

JE default.aspx content page z masterPage.master

asi hloupá otázka ale nejak nevim tak se radeji priptam

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

To jestli je stránka vnořena do master pages poznáš už z její deklarace na začátku stránky,kde bude něco jako tato klauzule:

MasterPageFile="~/Masterpage.master"

a také tak,že stránka neobsahuje ContentPlaceHolder.

Ale to jsou opravdu základy a myslim,že je to z článku dosti patrné ;)

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den,

ve třídě SqlSiteMapProvider.vb ve funkci buildsitemap() se mi všechny slova root podtrávají i po skontrolování nemohu njít chybu nevíte prosím někdo čím by to mohlo být?

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

Ahoj,

nejspíš ti chybí na začátku třídy deklarace:

public class SqlSiteMapProvider : StaticSiteMapProvider
{   
    private SiteMapNode root;
    ...
    ..
    .
}

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

Ahoj, ještě se omlouvám, poprvé jsem si nevšiml, že používáš VB.

Pro VB to bude tuším takto:

Public Class SqlSiteMapProvider
   Inherits StaticSiteMapProvider

   Private root As SiteMapNode
   ...
   ..
   .
End Class

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den, mám celkem podstatný problém. Při spuštění v IE8 se mi zobrazí přihlašovací formulář, po přihlášení se zobrazí hlavní stránka ale Menu se zobrazí pouze hlavní a po najetí se ItemMenu Výpůjčky nezobrazí vůbec a místo ItemMenu Administrace se zobrazí pouze bílý obdélník. Zkoušel jsem to jak ve své website, kterou jsem vytvořil podle tutorialu, tak se staženými soubory od Tomáše. Poradí někdo co s tím? Děkuji

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Netusite nekdo, co je potreba provest, aby se submenu ukazovalo i v Exploreru, ted mam verzi 8.

V Opere to chodi.

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

Je to tady několikrát řešeno od opravdových odborníků. Tak že je to třeba jen najít přes hledání ! V kostce asi takto: buď zvolit režim kompatibility v IE8 a nebo to ošetřit v kódu a testovat verze a druhy prohlížečů. Víc ze mě nevymáčknete.

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

Diky za reakci. Chvili jsem hledal, ale ne moc dusledne.

Libor

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

Režim kompatibility to řeší.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den,

nejprve chci poděkovat za velmi zdařilé stránky.

Mám dva problémy:

1. Web Site Administration Tool

Při pokusu o přihlášení mi vypíše

An error was encountered. Please return to the previous page and try again.

2. Spíš asi problém ve win, ale při každém spuštění prohlížení stránek, co jsem vytvořil mi visual studio spustí místo prohlíže notepad.

Můžete mi poradit?

Děkuji

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Po spusteni ASP.NET Configuration Tool a kliknuti na zalozku Security dostanem chybovu hlasku:

There is a problem with your selected data store. This can be caused by an invalid server name or credentials, or by insufficient permission. It can also be caused by the role manager feature not being enabled. Click the button below to be redirected to a page where you can choose a new data store. 

The following message may help in diagnosing the problem: Invalid object name 'Users'. 

Co s tym?

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den,

předem bych chtěl poděkovat za tento seriál je velmi poučný a napsaný velmi srozumitelnou formou.

Dále bych se chtěl zeptat, postupoval jsem dle návodu, co se týče implementace qlSiteMapProvidera i inicialiazce a vygenerování sitemapy, ale hlásí mi to následující error:

Chybová zpráva kompilátoru: CS0246: Název typu nebo oboru názvů StaticSitecMapProvider nebyl nalezen (pravděpodobně jste neuvedli direktivu using nebo odkaz na sestavení).

Zdrojová chyba:

 

Řádek 10: 
Řádek 11: 
Řádek 12: public class SqlSiteMapProvider : StaticSitecMapProvider
Řádek 13: {
Řádek 14:  

Mohl by jsi mi prosím pomoci?

Předem děkuji za odpověď.

Tomáš

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

problem vyřešen... bylo tam písmenko navíc... ;)

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Zdravím Tomáši,

prosím o nastínění řešení, jakým způsobem doladit menu, aby jednotlivé položky byly odsazené, případně oddělené nějakým separátorem, podobně jako to máte v prvním díle tohoto seriálu. Tuším, že by to měly řešit nějaké vlastnosti objektu menu ? Pomocí CSS stylu chápu to nastavení barvy a fontu, ale ty mezery a případné oddělovače jedn. položek menu už ne. Díky a pokud máte pocit, že jsem měl více samostudovat, tak vězte, že jsem se snažil. Pokud přesto máte pocit, že bych to už měl vědět, tak to máte pravdu. Omlovám se, ale už si nevím rady. Díky

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

Pokud v CSS uvedete třídu .moje { font-weight: bold; } a v HTML kódu stránky uděláte třeba <span class="moje">, pak se na tento span aplikuje daná CSS třída. To není věc ASP.NET, ale věc čistě věc HTML a CSS.

Pokud v ASP.NET používáte styly, např. vlastnost Font-Bold="true", tak to do stránky vygeneruje tzv. inline styl <span style="font-weight: bold;">. Pokud máte takovýchto komponent ve stránce 100 a nastavujete víc vlastností (tučné písmo, barvu atd.), tak je inline stylů ve stránce hodně a je to škaredé. Lepší je tedy místo nastavení vlastností Font-Bold, ForeColor, BackColor atd. nastavit vlastnost CssClass na hodnotu "moje" a příslušný vzhled si dodefinovat v souboru CSS. Pak ASP.NET vyrenderuje pouze <span class="moje"> a je to přesně to, co se očekává a chce.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Zdravim,

mam taky nejaky problem...postupoval som krok za krokom presne podla clanku, login funguje spravne ale po prihlaseni sa mi vobec nezobrazuje samotne menu...problem bude asi niekde v SqlSiteMapProvider ale naozaj netusim kde...mozete poradit pls????

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

Pan Lubos Blader by mel aspon dvakrat dele premyslet nez se znovu ptat.. Diskuze se stava roztokem vody namisto uzitecne stavy.

(Taky sem se chtel podivat na vase provedeni diskuze;-)

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Zdravim,

mam drobnou pripominku na usnadneni prace a dotaz k webu:

1) pridavat Content Page do libovolneho adresare je jednodussi pres Add -> New Item a zvolit Web Content Form. V nasledujicim dialogu je pak mozne zvolit libovolnou Master Page;

2) co pouzivas na obarveni kodu na strankach? Dlouho neco pouzitelneho hledam a nejak nejsem spokojeny. Ale tohle vypada dobre. Predem dik za odpoved.

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

Každý máme jinou metodu, ale myslím, že kliknout v Solution Exploreru na MasterPage a z kontextové nabídky rovnou vytvořit ContentPage je naprosto srovnatelné.

K obarvování kódu používám vlastní plugin do Windows Live Writeru, který kód z Visual Studia umí obarvit. Kdyžtak ho můžu hodit na blog, aby z toho měli užitek všichni.

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

No, ja na tu "moji" metodu prisel teprve pred par dny a rychle jsem si na ni zvyknul. Mel jsem totiz ve zvyku nejen prejmenovat a pripadne presunout soubor, ale i zmenit jmeno Partial Class (a Inherits). Ale to je vec kazdeho, jak se zaridi.

K tomu obarvovani - nepotesil jsi me. Shanim neco na obarvovani do fora, aby to bylo automatizovane. Presto diky za nabidku, mozna ji vyuziji jini.

Kazdopadne jen tak dal, dobra prace!

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Předně bych rád autora pochválil za vynikajicí články (nejen tento), které mi už několikrát velice pomohly. A chtěl bych se zeptat, jak dosáhnout toho, aby se do menu přidávaly položky z databáze jako samostatné MenuItem, ne pouze jako child jiné MenuItem. Zkoušel jsem v třeba během čtení sql příkazu změnit stávající addnode(node, root) na Return root, ale to se vrátí pouze první položka z databáze...

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

Každý SiteMap provider bohužel může vracet pouze jednu kořenovou položku, na kterou jsou hierarchicky jako dceřinné položky navázány všechny ostatní. Jedinou možností je tedy už potom nechat si z DB vygenerovat menu celé a vytvořit nějakou root položku, kterou pak v menu jednoduše nezobrazíte (jako to máme v článku).

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

díky za bleskovou odpověď

takže nejelegantnější řešení asi bude si vygenerovat celou strukturu menu včetně statických položek... tím sice ztratí provider na univerzálnosti, ale co se dá dělat... přidávat do menu položky v události Page_Load na master page je asi prasárna co...

taky jsem se chtěl zeptat jestli je nějaká možnost přenesení obsahu stávajícího databázového souboru do databázového serveru na webu, třeba nějaký nástroj který by automaticky vygeneroval sql query - mám tam docela dost záznamů a dávat je znova bych opravdu nechtěl...

Pavel Mach

(minule jsem se zapomněl podepsat, za což se omlouvám)

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

Položky menu se generují při startu aplikace, ne při každém požadavku, to by bylo zbytečné a zatěžovalo by to databázi.

Jinak provider nemusí ztratit na univerzálnosti ani tak, popište strukturu menu v nějakém svém vlastním souboru a přidejte si do něj instrukci pro umístění položek z databáze. Univerzální to bude také.

Databáze se dají přenášet pomocí nástroje Database Publishing Wizard, stačí, když jeho název napíšete do Googlu a přenese vás to na download. Nebo se to dá udělat přímo v novém Visual Studiu 2008 v okně Server Explorer, pravým tlačítkem kliknete na databázi a vyberete tuším Publish to provider.

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

tak už mi to funguje, jak menu tak přenesení databáze - díky moc

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

Mně sem tam něco nejede,nemohl bys mi poslat Vypujcky jak fungují na konci 2.části.Už jsem to dělal asi 3x a vžycky něco nefunguje.

Díky

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

Uff. Todle jsem vubec nepochopil.

Neslo by to popsat vice, i pro uplne lamy.

Dik EdaP

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Ahoj,

mám problém se spuštěním "ASP.net Web Application Administration".Chvíli se stránka načítá a poté vyhodí hlášku:

" Tool Has Timed Out

As a security measure, the Web Site Administration Tool times out after a period of inactivity. Changes to machine.config or web.config may also result in the tool needing to be restarted. To continue configuring your web site, restart the tool."

Nějak netušim co s tim..poradí někdo?

díky moc

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

Zkuste zmáčknout v prohlížeči F5 nebo Ctrl-F5, občas mi to dělalo také, stačilo stránku zaktualizovat.

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

to už jsem právě zkoušel.Hledal jsem i na googlu,kde jsem bohužel nenašel žádnou pořádnou informaci o řešení,někdo psal o blokování antivirem či firewallem,tak jsem to testnul a bez úspěchu:( Rád bych Web Application Admin obešel tím že bych do DB dal uživatele,role,... sám,ale netušim jak udělat INSERT pro usera.stále mi to hází nějaké chyby.Mohl by jsi s tim pomoct?

díky

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den,

musím nejdřív také pochválit autora za články, které mě hodně pomohly. Žádnou chybu nemám, ale jeden dotaz jo. Když v administraci přidám nebo uberu sekci, tak v samotném menu se mi tato změna neprojeví hned. Může mi někdo osvětlit při jaké příležitosti se provede vygenerování sitemapy? Popřípadě jak zajistit aby se menu reloudlo po každém zásahu do tabulky s názvama sekcí? Díky

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

V příkladu pro C# mas chybu (metoda Initialize ve třídě SqlSiteMapProvider). V C# se indexy pole píší do hranatych zavorek....

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

Jo, to je tak, když to člověk převede konvertorem, pak zjistí, že to nefunguje, tak si to opraví ve Visual Studiu, ale už ne v článku. Díky za upozornění, opravil jsem to.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Zdravim mam takovej dotaz u Visual Web Developeru 2005 se při vytvoření nového souboru s koncovkou aspx. vytvořil i soubor pro pro programování v c# nebo vb (Default.aspx.cs). Ale u Visual Web Developeru 2008 se už soubor s příponou .cs nevytváří. Pro psani kodu v C# je tedy nutné vytvořit nový soubor zvlášt a poté ho nějak napojit na Default.aspx ?

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

Už jsem to vyřešil par don za blbej dotaz.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

"Položte kurzor za slovo StaticSiteMapProvider a stiskněte klávesu Enter. Visual Studio definice obou požadovaných metod doplní." Ospravedlňujem sa ale nedoplnilo.

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

Pak děláš něco špatně. Máš ten soubor v jazyce VB.NET? A je ve složce App_Code? Funguje tam zvýrazňování syntaxe? Pokud ne, pak to nedoplní.

Jestli to fakt nejde, tak už nevím, tohle umí i Visual Web Developer, takže by to jít mělo.

A jinak nechci to dělat úplně Step by Step, i když to tak skoro je, čtenáře to pak nenutí přemýšlet. Koneckonců tohle je už devátý díl seriálu o ASP.NET, takže byste práci s Visual Studiem měl mít v malíčku.

Pokud se vám opravdu deklarace dvou prázdných metod nevytvoří, tak tenhle krok přeskočte, stejně je tam vložíte v dalších částech spolu s kódem.

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

Ďakujem, Tomáš. Zo všetkým súhlasím :-). Idem študovať.

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

Musim pochvalit autora za serial, nie lepsie som nenasiel zatial nikde inde. To co som nasiel inde ma len poplietlo a znechutilo a tento serial je konecne prehladny a ma presne navnadil na ASP.net.

A suhlasim ze to nema byt v kazdom dieli uplne step by step, tiez som v jednej casti zabudol ako som to robil , tak som sa od diskusneho fora vratil a siel som serial zase odznova.

Teraz som zase pri master page a mam dve otazky:

1. ked som pridaval viacero Content Page, kazda mala rovnake ID="Content1" , to je v poriadku?

2. master page vzdy natahuje ako prvu Content page tu s nazvom Default.aspx?

Diky za ochotu.

P.S.1. Je nejaka kniha o ASP.net 2.0 ktoru by ste odporucili?

P.S.2. V akom vztahu je Silverlight a APS.net?

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

Ospravedlňujem sa za chýbajúcu diakritiku v predošlom príspevku, čítal som pokyny až po odoslaní príspevku :))

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

1. To, že v každé stránce má ovládací prvek Content stejné ID vůbec nevadí. To je pouze název komponenty v rámci stránky. Důležité je, aby dvě komponenty v jedné stránce neměly stejné ID.

2. MasterPage nenatahuje nic, ta se nikdy nespouští. Když do prohlížeče zadáte adresu (např. www.vbnet.cz) a na jejím konci neuvedete stránku, použije se ta, která je na serveru nastavena jako výchozí (standardně Default.aspx). Důležité je ale uvědomit si, že stránka si načítá MasterPage. Webvový server dostane požadavek na stránku s příponou aspx a podívá se do ní na začátek, jestli tam nahoře není vlastnost MasterPageFile. Když je, tak tuto stránku začlení do dané MasterPage.

3. Abych pravdu řekl, ASP.NET jsem učil z anglické knihy ASP.NET 2.0 Applications - Advanced Topics od nakladatelství Microsoft Press (ale není to česky). O českých publikacích přehled nemám, takže doporučit nic nemohu.

4. Silverlight je na ASP.NET nezávislý, je to pouze věc HTML a Javascriptu, ne ASP.NET. Silverlight funguje i na stránkách v čistém HTML, v PHP atd.

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

Cau Tomas, ta palikacia na spravu uzivatelov mi byhodila takuto hlasku

There is a problem with your selected data store. This can be caused by an invalid server name or credentials, or by insufficient permission. It can also be caused by the role manager feature not being enabled. Click the button below to be redirected to a page where you can choose a new data store.

The following message may help in diagnosing the problem: Cannot open database "pozicovna" requested by the login. The login failed. Login failed for user 'CUJAN\holubjan'.

som zaciatocnik, tak v com moze byt problrm, predpokladam ze sa nemoze pripojit na databazu, ale koli comu?

Vdaka

cujan

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

Příčin může být více, ale patrně nemáte na databázi povolenou Windows Authentication. Jak jste SQL Server instaloval? Pokud máte nainstalováno SQL Server Management Studio, zkuste se k němu připojit a ve vlastnostech databázového serveru povolte Windows Authentication. Máte správně nastaven v aplikaci ConnectionString?

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

urcite hlupa otazka, ale kde nastavim tu windows authentification, lebo to bude urcite v tom. vdaka

cujan

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

Spusťte (pod administrátorským účtem) SQL Server Management Studio Express (pokud ho nemáte, musíte ho nainstalovat) a přihlašte se k databázovému serveru. Po přihlášení v okně Object Explorer pravým tlačítkem klikněte na úplně první položku a dejte Properties.

Na záložce Security zaškrtněte Windows Authentication a potvrďte. Pak by to mělo jít, bude asi potřeba restartovat službu SQL Server.

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

vdaka za vsetky rady ale aj tak mi to neide, tak idem skusat dalej.

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

A co přesně vám na tom nejde? Spustit SQL Management Studio Express, přihlásit se k DB, nebo jste provedl pokyny a pořád nefunguje samotná aplikace? Máte Windows Vista nebo Windows XP? Pokud je to Windows Vista, zkuste spustit Visual Studio / Web Developera jako Administrátor.

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

Cau

Mam win xp a vsetko mi ide v pohode, to znamena vytvorenie databazy atd, proste cely serial krok za krokom az ked sa dostanem ku kroku ze mam spustit nastroj na spravu uctov tak mi vyhodi na zalozke security hlasku ze

Cannot open database "Vypujcky" requested by the login. The login failed. Login failed for user 'CUJAN\holubjan'.

nechapem, a authentifikaciu mam nastavenu na windows.

a vsetky predchdzajuce rady som urobil co si mi pisal.

vdaka

cujan

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

A jaký máš ConnectionString? Připojíš se do té databáze z Visual Studia z okna Server Explorer? Pokud ano, tak klikni na tu databázi a v okně vlastností je vlastnost connectionString, kterou si zkopíruj a dej do Web.configu. Pak už by to jít mělo.

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

Caf

uz to ide, bolo to v tom conection stringu.

Vdaka, a uz sa tesim na dalsie pokracovanie serialu. Su to fakt clanky na urovni, ani jedna kniha s prikladami ktora sa predava za tazke prachy sa nechyta na tvoje clanky.

Cujan

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

Knihu možná napíšu, kdybych tak na to měl jenom čas.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Zdravim, mám otázku ohledně menu prostřednictvím sitemap. Chtěl bych, aby nadřazená položna neměla přiřazeny odkaz. Když se na ní klikne, jen se rozbalí podmenu a neotevře se žádná stránka. Myslel jsem, že bude jen stačit zjistit, jestli daná položka má ChildItems, ale to bohužel nemá žádná. Provizorně jsem nastavil všechny potřebné položky na selectable false, ale není to moc elegantní řešení.

Prosím o radu a jinak děkuji za skvělé články. Projel jsem to jen zběžně a hned mě to donutilo některé věci na svých stránkách předělat.

p.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Dobrý den, dnes jsem náhodou přišel na Vaše stránky a prošel celý seriál a ASP. Je to moc pěkně udělané a doufám že v něm budete pokračovat.

Děkuji

Petr Srp

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Postupoval som presne podla pokynov pri vytvarani vlastneho Providera a po sputeni aplikacie mi vyhadzuje tuto chybu :

Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Provider must implement the class 'System.Web.Security.RoleProvider'.

Source Error:

Line 63: <clear/>

Line 64: <add name="MyRoleProvider" type="Altairis.Web.Providers.SimpleSqlRoleProvider" connectionStringName="mojaConnectionString"/>

Line 65: <add name="CategoriesSitemapProvider" type="SqlSiteMapProvider"

Line 66: title="Položky" url="~/Default.aspx"

Line 67: connectionStringName="mojaConnectionString"

Prosim o radu

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

Svého CategoriesSiteMapProvidera jste přidal do špatné sekce k RoleProviderům. Musíte ho přidat do sekce sitemap.

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

jasan..Vdaka za radu..Som to omylom prehliadol :-) Vsetko funguje

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Chvalim autora za super serial o ASP.NET !

prosim ale o radu. Ked postupujem presne podla navodu, mam problem pri spusteni Asp.Net Configuration stranky. Ked spustim po kliknuti na tlacitko tuto stranku tak v casti Security vobec nemam ziadnu ponuku nastavenia prav ale okno s chybovou hlaskou kde sa pise zhruba, ze datasource je invalid. A pri tom som vsetko urobil podla navodu. Vytvorenie databaze, tabuliek atd.

Nevies mi poradit co mozem mat zle ???

Vdaka

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

Zkontrolujte, jestli máte ve web.configu správný connection string.

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

Vdaka. Mal som jedno slovo v kode spolu a malo to byt osobitne :-)

Uz to funguje :-)

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

Ahoj Tomáši.

Mám drobný problém tvůj hezký formulář vypadá dosti dobře ale u mě to ke trošku horší pravděpodobně se mi neaplikují styly. Kontroloval jsem práva a ty snad mám taky dobře nenapadá tě čím by to mohlo být ??

Jinak seriál je super prošel jsem ho celej a je to fakt moc dobrý.

S pozdravem

Patrik

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

Díky za pochvalu. Napadá mě jen jedna věc, možná ve web.configu nemáš téma pro všechny stránky zapnuté. Fungují ti témata na ostatních stránkách? Pokud ano, tak to tím nebude, pokud to nefunguje nikde, pak musíš ve web.configu najít sekci pages a přidat jí atribut:

...
<pages styleSheetTheme="Default">
...

Jinak ještě zkontroluj ty práva na složku App_Themes, těžko říct, čím to je.

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

Diskuse: Píšeme webovou aplikaci v ASP.NET krok za krokem (část 2)

"Vytvořte tedy do kořenového adresáře aplikace novou Content Pages a pojmenujte ji Lend.aspx." Ako?

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

No dobre asi ju tam mám.

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

Kristepane, tohle jsme už v minulých dílech dělali stokrát. Přece nemusím podrobně vypisovat úplně každý detail. A navíc mám pocit, že tam k tomu je i obrázek - pravým tlačítkem se klikne na MasterPage.master a vybere se Add Content Page. Přejmenovat soubor už snad umíte.

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

Kristepane. Step by step. Najprv to urobím a až to funguje, potom to skúmam. Pridať nový formulár sme opakovali viackrát a znova je to s obrázkami. Pomenovať som ju musel cez Rename... Nezlostí sa Tomáš. Samozrejme, že som čakal, že si to niekde bude pýtať meno. :-). A stále ešte nie som na konci. Že by sa zišiel chat na takéto debaty?...

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

Samozrejme, že je to super článok. Ako vždy.

nahlásit spamnahlásit spam 0 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