Tag Archives: Tipy a Triky

Tipy a triky v .NET a C# – slides, dema a záznam [TechEd Praha 05/2017]

Slides, dema a záznam z mé přednášky pro TechEd DevCon Praha ze 17.5.2017:

Záznam z přednášky je publikován na našem HAVIT YouTube Channel.

Dotčená témata

  • VS – Windows Layouts
  • C# – NoRefactoringsInInactiveCode
  • C# – MSTestV2TestCases
  • VS Keyboard Shortcuts
  • C# – InternalsVisibleTo
  • C# – Test – HardcodedDependenciesTestability
  • VS – [Re-]Attach to process
  • VS – BoxSelection
  • C# – NameOf – nameof()
  • C# – Initializers + InitializersArray
  • VS – MoveLineUpDown
  • C# 5.0 – Caller Info Attributes
  • VS – Extensions.md
  • VS – Personal Tweaks.md
  • C# – Using Without Variable
  • C# – DebuggerDisplay ([DebuggerBrowsable], [DebuggerStepThrough])
  • C# – AsyncLocal

Visual Studio: Spouštění webových projektů do nového maximalizovaného okna browseru

Otravuje mě, že výchozí podoba spuštění webového projektu (otevření webové stránky) z Visual Studia způsobí použití již otevřeného okna browseru a přidání nového tabu (nebo více). Pokud sleduji třeba screencast na druhém monitoru, je otrava, že mi ho překreje nový tab.

Naštěstí se to dá ve Visual Studiu poměrně snadno ochočit. Stačí otevřít menu Browse with… (ať už pravým tlačítkem v Solution Exploreru, nebo v rozbalovacím menu startování aplikace) a v příslušném dialogu založit „nový browser“ s příslušnými parametry příkazového řádku.

Pro Chrome, který používám, to vypadá takto:

2016-10-06_10-51-12.png

…teď už stačí jen zvolit příslušný „browser“ jako Default a je to. Příští spuštění již budou do nového maximalizovaného okna.

Pro další browsery to bude obdobné. Přepínačů samozřejmě existují tuny a dají se tak navolit i další věci (incognito, window size/position, disable plugins, …).

Windows Explorer: Založení/přejmenování souboru s názvem začínajícím tečkou

Pokud potřebujete vytvořit nebo přejmenovat ve Windows Exploreru soubor/složku na jméno, které začíná tečkou (.tfignore, .svn, …), funguje jednoduchý trik – přidejte ještě jednu tečku na konec jména(např. „.tfignore.“). Windows Explorer to překousne a záměru je dosaženo.

…starý trik, ale občas si ho musím připomenout.

SQL: Jsou dvě data (small)datetime ze stejného dne?

Potíž je v tom, že typ (small)datetime obsahuje mimo údaje data i čas. Můžeme samozřejmě zařídit, aby naše záznamy měly tento čas 00:00, ale stejně občas na tento problém narazíme.

Měli bychom rozlišit dvě situace, porovnávání s pevným dnem, nebo hledání shod ve variabilních datech.

Hledání shod ve variabilních datech

Jsme zde v situaci, kdy obě porovnávané složky jsou variabilní, u obou se musíme vypořádat s ignorováním složky dne.

SQL Server 2008 a novější verze mají datový typ date. Pokud tedy nejsme zrovna na nějaké pravěké verzi SQL, ukazuje se jako nejrychlejší (ač možná překvapivě) tato konverze:

SELECT MyColumn FROM MyTable
	WHERE CONVERT(date, DateColumn1) = CONVERT(date, DateColumn2)

Pro starší verze SQL serveru je použitelných několik o dost méně výhodných (pomalejších) podob. Protože SQL 2005 a starší již dnes považuji za pravěk, nebudu již rozebírat jejich výhody/nevýhody a rychlost:

...
WHERE
   (YEAR(Datum1) = YEAR(Datum2)
   AND (MONTH(Datum1) = MONTH(Datum2)
   AND (DAY(Datum1) = DAY(Datum2)

WHERE 
   (YEAR(Datum1) = YEAR(Datum2))
   AND (DATEPART(dayofyear, Datum1) = DATEPART(dayofyear, Datum2))

WHERE CONVERT(varchar(10), Datum1, 101) = CONVERT(varchar(10), Datum2, 101)

WHERE FLOOR(CONVERT(float, Datum1)) = FLOOR(CONVERT(float, Datum2))

Porovnání s pevným dnem

Trochu jiná situace nastává v okamžiku, kdy jeden z údajů je pevný. Například hledáme záznamy založené určitého dne

DECLARE @DateFilter smalldatetime
SET @DateFilter = '20090305'

SELECT Created FROM MyTable
	WHERE
		(Created >= @DateFilter)
		AND (Created < DATEADD(day, 1, @DateFilter))

…zde s výhodou celý problém převádíme na porovnávání s konstantami, a pokud máme k dispozici vhodný index, dokonce na operaci Index Seek.

Kupodivu úplně identický execution plan (Index Seek) a se stejnými časy dotazu (testováno na obrovských datech na MS SQL Serveru 2012) dostáváme i pro podobu:

DECLARE @DateFilter date
SET @DateFilter = '20090305'

SELECT Created FROM MyTable
	WHERE CONVERT(date, Created) = @DateFilter

C# 5: Caller Info Attributes

Zajímavá novinka v C# 5 poslouží například k logování. Následující příklad funguje ve Visual Studio 11 Beta

  class Program
    {
        static void Main(string[] args)
        {
            Log("Message");
        }

        static void Log(string message,
            [CallerMemberName] string callerMemberName = "",
            [CallerFilePath] string callerFilePath = "",
            [CallerLineNumber] int callerLineNumber = 0)
        {
            Console.WriteLine(message);
            Console.WriteLine(callerMemberName);
            Console.WriteLine(callerFilePath);
            Console.WriteLine(callerLineNumber);
        }
    }

Výstupem je např:

Message
Main
d:\Development\CallerAttributes\CallerAttributes\Program.cs
14

Health Monitoring a sledování chyb asynchronních postbacků (AJAX)

Health Monitoring je šikovný vestavěný mechanizmus ASP.NET pro sledování a hlášení problémových situací. Typicky je používán pro zápis výjimek aplikace do event-logu nebo jejich posílání mailem.

Slabinou Health Monitoringu je, že se neumí vypořádat s chybami vzniklými během asynchronních postbacků (AJAX) ani s chybami vzniklými v rámci webových služeb ASP.NET. Přesněji řečeno ASP.NET na tyto chyby nějak nepamatuje a neoznamuje je do web-events mechanizmu, na němž je Health Monitoring závislý.

Podívejme se nyní na cestu, jak doplnit do Health Monitoringu sledování chyb AJAXu, sledování chyb webových služeb ponechávám do samostatného článku. Jak již bylo naznačeno, jde o to, že potřebujeme doplnit chybějící oznamování chyb do web.events mechanizmu. Chyba vzniklá během asynchronního postbacku způsobí vyvolání události ScriptManager.AsyncPostBackError. Potřebujeme se tedy napojit na tuto událost s vlastní obsluhou a v ní chybu předat jako WebRequestErrorEvent.

AjaxHealthMonitoring control

Jedním z možných opakovaně použitelných elegantních řešení je vytvoření vlastního controlu, který se bude umisťovat do stránek stejně jako samotný ScriptManager, např. tedy v MasterPage. Uvádím zde kód kolegy Jirky Kandy, který se s tím vypořádal takto:

public class AjaxHealthMonitoring: Control
{
    #region OnInit
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);

        ScriptManager scriptManager = ScriptManager.GetCurrent(Page);
        if (scriptManager == null)
        {
            throw new InvalidOperationException("Ve stránce nebyl nalezen ScriptManager, který je controlem AjaxHealthMonitoring vyžadován.");
        }
        scriptManager.AsyncPostBackError += new EventHandler<AsyncPostBackErrorEventArgs>(ScriptManager_AsyncPostBackError);
    }
    #endregion

    #region ScriptManager_AsyncPostBackError
    /// <summary>
    /// Obsluha události AsyncPostBackError ScriptManageru. Zajistí vyvolání události health monitoringu.
    /// </summary>
    private void ScriptManager_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
    {
        if (e.Exception != null)
        {
            new WebRequestErrorEventExt(e.Exception.Message, this, e.Exception).Raise();
        }
    }
    #endregion
}

Pro úplnost uvádím odvozenou podobou třídy WebRequestErrorEventExt:

public class WebRequestErrorEventExt : WebRequestErrorEvent
{
    public WebRequestErrorEventExt(string message, object eventSource, Exception exception)
        : base(message, eventSource, WebEventCodes.WebExtendedBase + 999, exception)
    {
    }
}

Control se pak používá ve stránce stejně jako ScriptManager (do výstupního HTML kódu nic nerenderuje):

<asp:ScriptManager ScriptMode="Release" AllowCustomErrorsRedirect="true" runat="server" />
<havit:AjaxHealthMonitoring runat="server" />

ASP.NET Device Filters

Nedávno se mi připomněla jedna starší lahůdka (čti obskurnost, za kterou může ten zpropadený svět heterogenních browserů) – Device Filters. Dovolím si tedy připomenout:

Jde o víceméně elegantní deklaratorní zápis, jak nastavovat různé hodnoty jednotlivých properties controlů a direktiv v ASP.NET v závislosti na browseru. Syntaxe je jednoduchá:

<asp:Label IE:Text="Používáte Internet Explorer" Mozilla:Text="Používáte Firefox" PIE:Text="Používáte Pocket IE" Text="Používáte Buchvíco" runat="server" />

Není to jen o properties controlů, dá se to použít i pro direktivy, takže například pro <%@ Page %> lze nastavit MasterPageFile či Theme. Rozpoznávané browsery se řídí browser-definition-files (App_Browsers, browserCaps).