Author Archives: Robert Haken

avatar Neznámé

About Robert Haken

Software Architect, Founder at HAVIT, Microsoft MVP - ASP.NET/IIS

Refresh stránky po postbacku do počátečního stavu

Při ladění webové aplikace se často dostanete do situace, kdy vyzkoušítě nějaké postback funkce stránky, a pak se chcete vrátit v prohlížeči rychle zpět do původního výchozího stavu (IsPostBack = false), abyste vyzkoušeli něco jiného.

S prohlížečem může být s tímto docela boj, protože Back nás většinou hodí buď na předchozí adresu nebo vytáhne stránku z cache a GET neprovede, Refresh naopak znovu posílá POST data a zopakuje tak poslední postback. Dělá to prostě všechno možný, jen ne nový GET potřebné stránky.

Je na to jednoduchý trik, pokud chceme znovu načíst počáteční stav stránky, stačí změnit něco bezvýznamného v adrese stránky (adresním řádku prohlížeče). Oblíbeným indiferentním trikem je změna malého písmena na velké (pro prohlížeč je to jiná adresa, udělá požadovaný GET počátečního stavu, naopak IIS je case-insensitive, takže mu to nevadí).

http://www.northwind.com/my-page.aspX

…a je to.

Manage auditing and security logs (SeSecurityPrivilege) chybí/mizí

Pokud skupině Exchange Enterprise Servers chybí právo „Manage auditing and security logs“ (SeSecurityPrivilege), což lze snadno ověřit utilitou \SUPPORT\EXDEPLOY\policytest.exe z Exchange CD, pak nám nastávají závažné potíže. Obyčejně nám začne failovat spouštění Exchange služeb, především Information Store.

Do logu můžem dostávat:

Event ID 7024, Service Control Manager:
   „The Microsoft Exchange Information Store service terminated with service-specific error 0 (0x0).“

Event ID 1121, MSExchangeIS:
   „Error 0x80004005 connecting to the Microsoft Active Directory.“

Event ID 5000, MSExchangeIS:
   „Unable to initialize the Microsoft Exchange Information Store service. – Error 0x80004005.“

Event ID 2103, MSExchangeDSAccess:
   „Process MAD.EXE (PID=2356). All Global Catalog Servers in use are not responding:“

…a podobné

Můžeme to snadno napravit setup.exe /domainprep, nicméně někdy ani to trvale nepomůže a dost krušné chvíle nám mohou nastat, pokud toto právo po čase mizí (policytest.exe nejdřív OK, později failuje).

Naštěstí už je člověk naučený, že pokud nějaké právo samovolně mizí, jsou prvním podezřelýmzásady zabezpečení (lokální, doménové, …). Je tedy potřeba ohlídat, aby nám zásady zabezpečení právo „Manage auditing and security logs“ pro doménovou skupinu „Exchange Enterprise Servers“ nelikvidovaly (je to v User Rights Assignments).

GUI pro Sandcastle – Microsoftí generátor dokumentace ála nDoc

Microsoftí projekt Sandcastle se začíná pomalu usazovat, nicméně jeho klíčovým nedostatkem zatím byla absence GUI, grafického uživatelského rozhraní. Naštěstí to někteří vzali do svých rukou, a tak už dnes existuje několik GUI pomůcek pro ovládání Sandcastle a pohodlné generování MSDN-style .NET 2.0 dokumentace.

Vše zajímavé kolem Sandcastle se momentálně děje na webu http://www.sandcastledocs.com/.

Visual Studio 2005 SDK je ke stažení z Microsoft Downloads, je v něm HtmlHelp 2.0.

System.Transactions – dobrý sluha, ale špatný pán

.NET Framework 2.0 zavádí nový namespace System.Transactions, který umožňuje velmi programátorsky pohodlnou práci s transakcemi, a to jako transakcemi ADO.NET/SQL Serveru, tak i MSMQ (Message Queues) a MSDTC (Distributed Transaction Coordinator).

Můžeme tak například celkem transparentně obalit kus kódu transakcí, aniž bychom museli do kódu zasahovat a transakce explicitně nastavovat.

using (TransactionScope scope = new TransactionScope())
{
   using (SqlConnection connection = new SqlConnection(connectionString))
   {
      SqlCommand command = connection.CreateCommand();
      command.CommandText = "Insert....";
      command.Connection = connection;

      SqlCommand command2 = connection.CreateCommand();
      command2.CommandText = "Update....";
      command2.Connection = connection;

      connection.Open();
      command.ExecuteNonQuery();
      command2.ExecuteNonQuery();
      connection.Close();
   }
   scope.Complete();
}

…vše vypadá krásně a opravdu to může i krásně fungovat, můžeme si ale i pěkně naběhnout.

V první řadě, pokud výše uvedený kód běží vůči SQL2000 serveru, pak se namísto běžné SQL-transakce vytvoří distribuovaná transakce spravovaná MSDTC, Distributed Transaction Coordinatorem – což bude mít velmi nepříjemný dopad na výkon naší aplikace. Při použití s SQL2000 totiž nejsou podporovány tzv. „promotable transactions“.

Pokud používáme SQL2005 server, tento problém odpadá, transakce bude realizována prostřednictvím SqlTransaction.

Dalším problémem však je, že explicitně neurčujeme, co vše je součástí transakce, takže veškeré transakční zdroje (resources), které v rámci transaction-scope používáme, se automaticky zaregistrují jako součást transakce a snadno tak opět skončíme na distribuované transakci spravované MSDTC.

Závěr

Osobně raději pro transakční zpracování SQL používám klasickou SqlTransaction, navíc pokud si vytvoříme malou pomůcku, pak můžeme i SqlTransaction řešit obdobně pohodlným způsobem:

int myID = 5;
object result;

SqlDataAccess.ExecuteTransaction(
   delegate(SqlTransaction transaction)
   {
      // uvnitř lze používat i lokální proměnné (samozřejmě i parametry, statické fieldy atp.)

      SqlCommand cmd1 = new SqlCommand("command string");
      cmd1.Transaction = transaction;
      cmd1.Connection = transaction.Connection;
      cmd1.Parameters.AddWithValue("@MyID", myID);
      cmd1.ExecuteNonQuery();

      SqlCommand cmd2 = new SqlCommand("another command");
      cmd2.Transaction = transaction;
      cmd2.Connection = transaction.Connection;
      result = cmd2.ExecuteScalar();
   });
Související články

GoogleToolbarNotifier.exe – součást Google Toolbar 4

Zaktualizoval se mi Google Toolbar, nu což, dobrá. Do programů spouštěných při startu Windows mi však přibyl GoogleToolbarNotifier.exe. A nejenom, že tam přibyl, i si chtěl hned komunikovat ven kamsi na port 80 (HTTP, možná CLR). O to se Tě Google opravdu nikdo neprosí!!!

Údajně to má být utilitka, která si hlídá, aby v IE nedošlo ke změně výchozího vyhledávače na něco jiného.

Každopádně konvenčně lze spouštění tohoto procesu vypnout v Options Google Toolbaru, na záložce More vypnout „Notify me on settings change“ a „Set and keep Seach settings to Google“. Tím dojde k odstranění spouštěcího klíče z registru (HKCU\Software\Microsoft\Windows\CurrentVersion\Run).

NTBACKUP: Scheduled job failuje – médium není prázdné

Pokud vytvoříme pomocí wizzardu full backup job zálohování na médium – schedulovanej na každý den – a předpokládáme, že budeme prostě jen cyklicky měnit média – tak nám po prvním cyklu zálohy přestanou probíhat, po chvilce pátrání se dostaneme k chybové hlášce „médium není prázdné“.

V základním nastavení ntbackup totiž média nemaže, což lze považovat za rozumné výchozí nastavení, nicméně pro náš případ nevhodné. Pokud bychom to neměli jako scheduled task, aplikace by se nás na smazání zeptala, nicméně takto job sfailuje.

Řešením je přidání parametru /UM do příkazové řádky, kterou příslušný scheduled task provádí. Tím se vynutí smazání média před spuštěním zálohování.

Jak se zbavit namespaces (xmlns) v rootovém elementu XML při serializaci

Při běžné serializaci objektu do XML nám XmlSerializer vytvoří root-element, který má nastavené namespaces, např.

<rootElement xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

To odpovídá XML normě. Může však nastat situace, např. při generování RSS Feedu, kdy namespace definovat nechceme.

Fígl, jak se zbavit namespace definice, spočívá v předhození XmlSerializeru kolekce XmlSerializerNamespaces s jednou „prázdnou“ položkou:

XmlSerializer serializer = new XmlSerializer(typeof (RssFeed));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", null);
StringWriter writer = new StringWriter(CultureInfo.CurrentCulture);
serializer.Serialize(writer, this, ns);

…a je to, výsledné XML bude mít kořenový element jen

<rootElement>
  ...
</rootElement>

SQL2005: Odmazávání starších záloh

Na SQL 2005 Serveru mě velice překvapilo, že pomocí základního maintenance-planu již nelze nastavit automatické odmazávání starších záloh, starších .BAK souborů.

Řešení je naštěstí snadné, i když ho bohužel pomocí wizzardu nedosáhneme. Stačí však ručně modifikovat (pravým tlačítkem – Modify, nebo jen double-click) wizzardem vygenerovaný maintenance-plan a přidat do něj novou úlohu – Maintenance Cleanup Task, v jehož vlastnostech pouze nastavíme v jaké složce máme zálohy, jestli se mají procházet i podsložky a jak staré zálohy se mají zlikvidovat.

Přidání je opravdu snadné, je to snad na tři kliknutí (přetáhnout z toolboxu, nastavit vlastnosti a navázat do workflow protažením příslušné šipky). Na zvážení administrátorů nechávám, jakou závislost čištění udělat na zálohování (poklikáním na vazbu můžeme volit Success, Error, nebo jen Completion). Teoreticky tedy můžeme čištění podmínit úspěšným zálohováním, aby nám po čase nezmizely staré soubory a nové nevznikaly.

Windows 2000 Server: Event ID 1202, SceCli, 0xd : The data is invalid.

Tento warning se nám může množit v Application event logu, po aplikaci šablony zabezpečení Basicdc.inf. Potíž je v tom, že se tato šablona odkazuje na proměnné %SYSVOL%, %DSDIT% a %DSLOG“, které však neexistují (existují jen během Dcpromo procesu).

Stačí tedy tyto environment variables vytvořit. Výchozí složky jsou následující

%SYSVOL% = C:\WINNT\SYSVOL
%DSDIT% = C:\WINNT\NTDS
%DSLOG% = C:\WINNT\NTDS

…a warning je pryč.

Nested Repeaters – vnořování repeaterů

Vnořit Repeatery se může zdát potíž, dokud poprvé neuvidíte, jak je to jednoduché. Celý fígl totiž spočívá v data-bindingu vnitřních repeaterů v obsluze události ItemDataBound vnějšího Repeateru.

V příkladu vnější Repeater iteruje přes všechny obory činnosti (kategorie, skupiny) a vnitřní Repeater zobrazuje položky (zde „zápisy do katalogu“) příslušející danému oboru činnosti (kategorii, skupině).

MyPage.aspx

<asp:Repeater ID="OboryCinnostiRepeater" runat="server">
  <ItemTemplate>
     
   <%# ((OborCinnosti)Container.DataItem).Nazev %>
   
   <asp:Repeater ID="ZapisyRepeater" runat="server">
    <ItemTemplate>
      <%# ((ZapisDoKatalogu)Container.DataItem).Jmeno %>
     </ItemTemplate>
   </asp:Repeater>
  
  </ItemTemplate>
 </asp:Repeater>

MyPage.aspx.cs

private void OboryCinnostiRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
   RepeaterItem item = e.Item;
  
   // zajímají nás jen datové řádky, ne hlavička ani patička
   if ((item.ItemType == ListItemType.Item) || (item.ItemType == ListItemType.AlternatingItem))
   {
    // najdeme si vnitřní Repeater
    Repeater zapisyRepeater = (Repeater)item.FindControl("ZapisyRepeater");
  
    // a nabidnujeme mu data příslušející položce (oboru)
    OborCinnosti obor = (OborCinnosti)item.DataItem;
    ZapisDoKataloguCollection = obor.GetZapisy();
    
    zapisyRepeater.DataSource = zapisyOboru;
    zapisyRepeater.DataBind();
   }
}