Author Archives: Robert Haken

avatar Neznámé

About Robert Haken

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

Pozor na ImageUrl, resp. UrlPathEncode() a znaky % (procenta) nebo # (hash)

Při bezstarostném používání Image.ImageUrl jsem narazil na zajímavý problém – pokud se Vám v názvu souboru nebo v cestě k němu vyskytne % (procenta) nebo # (hash), pak máte problém – metoda HttpUtility.UrlPathEncode(), kterou Image.ImageUrl a mnohé další controly pro encodování URL odkazů používají, Vám tyto znaky neencoduje:

<asp:Image ImageUrl="~/Folder #3/File.jpg" runat="server" />

udělá

<img src="/Folder%20#3/File.jpg" />

protože

HttpUtility.UrlPathEncode("/Folder #3/File.jpg") == "/Folder%20#3/File.jpg"

Metoda UrlPathEncode() totiž encoduje jen mezerník a non-ASCII znaky.

Správné samozřejmě je, abyste se na webových serverech pokusili těmto znakům vyhnout. Nicméně uživatelé jsou tvořiví a tak se můžete dočkat překvapení stejně jako já.

Osobně si myslím, že se jedná o bug v metodě UrlPathEncode(), resp. o nenaplnění očekávaného contractu, nicméně Microsoft to samozřejmě interpretuje jako by-design a radí, ať si uděláte Replace() těchto znaků sami.

Nezbývá tedy než:

myImage.ImageUrl = path.Replace("%", "%25").Replace("#", "%23");

Mimochodem obdobných vychytávek se můžete dočkat i se znakem + (plus).

web.config transformace – Screencast, slides, dema [MSTV 2009]

Screencast, který jsem svého času vytvořil pro MSTV.cz

Slides a dema ke screencastu:

Viz též:

Generátor klíčů GP WebPay (PayMuzo) hlásí chybu „Illegal key size“

Při poslední z implementací GP WebPay (PayMuzo) se nám stalo, že nám generátor klíčů obchodníka zahlásil chybu

exception encrypting data - java.security.InvalidKeyException: Illegal key size

Po chvilce testování (na dvou různých PC) jsme zjistili, že to dělá při Heslu pro keystore delším 8 a více znaků. Pokud jsme heslo zkrátili na 7 a méně znaků, vygenerování klíčů proběhlo úspěšně.

Verzi utility lze popsat jako „(c) 2004/2005 Muzo a.s.“ v UI a velikost souboru GenCert.jar 33567 bytů, víc mě nad tím bádat nebaví.

Pokud byste někdo bojoval s implementací GP WebPay pro .NET, tak se mi klidně ozvěte, máme to hotový a určitě se nějak dohodneme… ;-)

X509Certificate2: CryptographicException: The system cannot find the file specified.

Pokud vytváříte ve webové aplikaci X509Certificate2

myCertificate = new X509Certificate2(rawData, password);
//nebo
myCertificate = new X509Certificate2(fileName, password);

pak můžete být po nasazení své funkční aplikace na produkční server (např. hosting) obdařeni výjimkou

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password)

…přestože soubor s certifikátem buď zaručeně existuje (fileName), nebo se ani nepoužívá (rawData).

Problém souvisí s tím, že v produkčním prostředí Vaše aplikace beží pod uživatelským účtem, který nemá založen profil, který se má certifikát vytvořit (volně přeloženo, omlouvám se za případnou nepřesnost).

Řešením je použití přetížení constructoru, kterým zvolíte cílové uložiště certifikátu:

 

myCertificate = new X509Certificate2(rawData, password, X509KeyStorageFlags.MachineKeySet);
//nebo
myCertificate = new X509Certificate2(fileName, password, X509KeyStorageFlags.MachineKeySet);

Web Deployment Dev10 (VS2010, NET4) – Slides a dema [TechEd Praha 2009]

Slides a dema z přednášky na konferenci TechEd Praha 2009:

Z přednášky nebyl pořizován záznam, část tématiky o web.config transformacích lze najít ve v podobě screencastu, který jsem svého času dělal pro MSTV.cz.

Pozor na UpdatePanel a unikátní názvy (ID) controlů

AJAXový UpdatePanel se chová zvláštně vůči logice naming-containerů, pokud se tedy potkáte s názvy (ID) controlů, nepůjde Vaše stránka zkompilovat. Stačí zkusit následujících jednoduchý snippet:

<asp:TextBox ID="SomethingTB" runat="server" />
<asp:Repeater ID="MyRepeater" runat="server">
  <ItemTemplate>
    <asp:UpdatePanel runat="server">
      <ContentTemplate>
        <asp:TextBox ID="SomethingTB" runat="server" />
      </ContentTemplate>
    </asp:UpdatePanel>
  </ItemTemplate>
</asp:Repeater>

…při kompilaci budete obšťastněni chybovými hláškami

D:\Development\UpdatePanelCompiler\Default.aspx(18,57): error CS0102: The type '_Default' already contains a definition for 'SomethingTB'
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\updatepanelcompiler\1c44388f\ad38e94\App_Web_r7xfjqxf.0.cs(231,59): error CS0111: Type 'ASP.default_aspx' already defines a member called '__BuildControlSomethingTB' with the same parameter types

Transaction log narůstá, backup nepomáhá, shrink neúčinný

Na MSSQL serveru se občas stává, že backupování přestane truncatovat transaction log a ten narůstá a narůstá.

Z nějakého důvodu je potřeba udělat sekvenci shrink-backup-shrink, aby bylo dosaženo požadovaného účinku:

1) Run this code:

DBCC SHRINKFILE(pubs_log, 2)

2) Run this code if you want to truncate the transaction log and not keep a backup of the transaction log. Truncate_only invalidates your transaction log backup sequence. Take a full backup of your database after you perform backup log with truncate_only:

BACKUP LOG pubs WITH TRUNCATE_ONLY

-or-

Run this code if you want to keep a backup of your transaction log and keep your transaction log backup sequence intact. See SQL Server Books Online topic „BACKUP“ for more information:

BACKUP LOG pubs TO pubslogbackup

3) Run this code:

DBCC SHRINKFILE(pubs_log, 2)

Aktualizace pro SQL 2008

V SQL Serveru 2008 již není BACKUP LOG WITH TRUNCATE_ONLY přepínač použitelný, místo toho je možné přepnout DB do Simple recovery modelu a udělat shrink logu. Pak je možné přepnout zpět na Full.

-nebo-

Update od Martina Falty pro SQL 2008+ (díky)

DBCC SHRINKFILE(pubs_log, TRUNCATEONLY)

Viz http://technet.microsoft.com/en-us/library/ms189493(v=sql.100).aspx

Excel: Podmíněný součet SUMIF s podmínkou na (ne)prázdné buňky

Chvíli jsem bádal, jak zapsat podmínku do funkce SUMIF, pokud chci sečíst jen buňky, kterým odpovídá kritérium (ne)prázdné buňky.

Pro prázdné buňky je to

=SUMIF(C2:C10;"=";B2:B10)

Pro neprázdné buňky je to

=SUMIF(C2:C10;"<>";B2:B10)

…pozoruhodná podoba podmínky, ale hlavně, že to funguje.

Fiddler: Zachytávání lokálního ASP.NET Web Development Serveru (aktualizováno)

Fiddler je výborný nástroj pro zachytávání HTTP provozu – zobrazí Vám přesnou podobu HTTP requestu a responsu, kterou Váš počítač dělá vůči webovým serverům.

Ve skutečnosti Fiddler funguje jako proxy-server. Při spuštění se nastaví v Internet Options jako proxy a veškeré běžné požadavky tak jdou přes něj. Problém je v tom, že ne zas tak úplně veškeré, Innternet Explorer i .NET Framework natvrdo směřují veškeré požadavky na „localhost“ a „127.0.0.1“ mimo proxy, přestože je proxy zapnutý i pro intranet.

První podmínkou pro zachytávání Fiddlerem je tedy používat pro browsing adresu v podobě http://mujpocitac:1234/MyPage.aspx, čímž jdou takové požadavky přes proxy a dostane je Fiddler.

Další problém je však v tom, že ASP.NET Web Development Server (Visual Studio, Web Developer Express, …) přijímá požadavky pouze na „localhost“ a ostatní zamítá.

Řešením je překlad adresy ve Fiddleru. Fiddleru můžeme přidat pravidlo, aby požadavky na „mujpocitac“ převáděl na podobu „localhost“. Do CustomRules.js (Rules ~ Customize rules…) přidáme na začátek události BeforeRequest:

static function OnBeforeRequest(oSession:Fiddler.Session)
{
    oSession.host = oSession.host.replace("mujpocitac", "localhost");
}

…a je to.

(Samozřejmě ten překlad by se dal udělat i odolnější, aby fungovaly i adresy http://mujpocitac/mujpocitac/mujpocitac.aspx a nebylo z nichhttp://localhost/localhost/localhost.aspx)

Update pro Windows Vista

Ve Windows Vista je mimo výše uvedeného potřeba ještě ve Fiddleru v Options vypnout volbu „Enable IPv6“.

Nastavení Image.Source z kódu

myImage.Source = new BitmapImage(new Uri("images/myImage.jpg", UriKind.Relative));