Author Archives: Robert Haken

avatar Neznámé

About Robert Haken

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

Visual Studio: Když nefunguje klávesová zkratka Ctrl+Shift+F12 – Next Error

Ve VisualStudiu mi přestala fungovat klávesová zkratka Ctrl+Shift+F12, přestože při ověření v Options je korektně namapovaná.

Obvyklou příčinou bývá požírání klávesové zkratky jinou aplikací. Vylučovací metodou se ukázalo, že pachatelem je Microsoft Teams, které když běží, klávesová zkratka ve VS nefunguje (přestože samotná aplikace Teams mezi svými Keyboard shortcuts zkratku nemá uvedenou).

Zavření aplikace Teams pomůže, Ctrl+Shift+F12 začne fungovat.

…pokud byste chtěli hlasovat pro feedback na UserVoice:
https://microsoftteams.uservoice.com/forums/555103-public-preview/suggestions/17156756-application-hides-the-ctrl-shift-f12-keyboard-sh

WebForms: Když nefunguje asynchronní AutoPostBack na RadioButtonech

Pokud bojujete s nefunkčním AutoPostBack na asp:RadioButton v ASP.NET WebForms při asynchronním postbacku, pak je to způsobeno tím, že ASP.NET nerenderuje k RadioButtonu označenému jako Checked klientskou obsluhu události onclick. Zřejmě je to by-design ochrana proti vícenásobné obsluze změn, tedy aby se událost vykonala pouze na jednom z radiobuttonů ve skupině, ne na tom označovaném i odznačovaném.

Možnosti řešení jsou tedy dvě:

  1. Zahrnout i RadioButtons do UpdatePanelu, aby se přerenderovaly a obsluhy událostí správně přenastavily.
  2. Obskurní work-around, který vyrenderuje obsluhu na všech RB taky může být
CisloSmlouvyNoveRB.InputAttributes["checked"] = "true";

ASP.NET Core – Dependency Injection & Unit-testing – záznam, slides a dema [WUG Days Brno 10/2016]

5lides a dema z mé přednášky pro WUG Days Brno ze 8.10.2016:

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

 

Working Effectively with Legacy Code – záznam a slides [WUG Days Brno 10/2016]

Slides z mé přednášky pro WUG Days Brno ze 9.10.2016:

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

Dotčená témata

  • „definice“ Legacy Code
  • Refactoring Mindset
  • Roslyn Code Analyzers – C#, StyleCop, SonarLint, Global Suppressions
  • Testability – extract dependencies do virtuálních metod + override v testu
  • Mocking – Moq
  • Dependency Injection

1Password for Teams – první dojmy z trial (výběr týmového password manageru)

Po necelém týdnu vzdávám další pokusy s 1Password for Teams. Má sice výrazně přehlednější UI a celkově je UX propracovanější, nicméně pro platformu Windows je to zatím příliš nestabilní a nehotové, než abych to risknul a ještě za to platil minimálně dvojnásobek než za (uživatelsky nepřívětivější) LastPass.

Nalezená pozitiva

  • existuje beta-verze samostatné Windows aplikace (nejenom browser extension)
  • první dojem z UI je velmi příjemný, vypadá to ovladatelně (UX pochází z Mac, hodně podobné SplashID)

Nalezená negativa

  • menší počet podporovaných platforem (Windows je jen beta, WP není, iOS a Android jsou), z browserů má Chroma, Safari, Firefox, Opera
  • zřejmě nemá podporu fingerprint auth na Windows, jen na iOS
  • cena $4/user/měsíc (a to ještě jen při využití akce do 14/OCT, jinak Pro verze za $12, i když asi i verze Standard by šla použít)
  • celkově vypadá, že je Mac-based a Windows platforma je ještě v plenkách
  • zakládat a práva nastavovat lze jen na trezory, nikoliv na složky (to by ještě odpovídalo shared folders v LastPass), nejde vytvářet podsložky/hierarchičtější strukturu
  • nemá auto-fill na formulářové údaje
  • lze vytvářet jen záznamy některého z definovaných typů (šablon), nelze přidávat vlastní šablony, i když záznamu dle šablony lze změnit/odebrat (nikoliv přidat) jednotlivá pole
  • nemá import hesel z Chrome, pro import se nabízí jen .csv (= více práce, ale kvalitnější výsledek)
  • nemá zřejmě vzdálenou/hromadnou změnu hesla
  • nemá zřejme „security challenge“ (duplicitní hesla, stará hesla, atp.)
  • Dotaz na uložení nového hesla v browser extension je poměrně agresivní, samotný Chrome nebo LastPass se ptají decentněji. 1P se navíc ptá úplně vždycky a nenašel jsem cestu, jak mu říct „pro tuto site nechci heslo ukládat, nikdy“.
  • browser extension pro Chrome je tak nějak závislá na samostatné Windows aplikaci (beta). Integrace na browser je sice technologicky asi sofistikovanější, ale celkově se to nechová moc spolehlivě. Na zapamatování hesla se to neptá buď vůbec, nebo naopak pořád do zblbnutí, i když ho zapamatovat nechci, občas padá, atp.

Neutrální poznatky

  • „Personal“ trezor je víceméně stále součástí firemního účtu, v tomto je přidružení odděleného osobního účtu, jak to má LastPass asi pro pracovníky přijatelnější. 1P má nicméně možnost do jednotlivých aplikací připojit libovolný počet účtů, což je vlastně víceméně to samé a navíc by to asi umožnilo připojit i případné break-glass účto-trezory.

Co zkusím dalšího? Dashlane nebo Roboform?

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, to vypadá takto:

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

Pro Edge (Chromium) třeba takto:

2020-01-31_10-50-24.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, …).

Update-Database – Invalid JSON file

Pokud vás cmdlet Update-Database obšťastní hláškou Invalid JSON file2016-10-05_23-27-39.png
…pak je to nejspíš tím, že máte v project.json komentáře (nejsou součástí JSON specifikace a je jen „zásluha“ Visual Studia, že je zahazuje).

Related: https://github.com/aspnet/EntityFramework/issues/5704

LastPass Enterprise – první dojmy po týdnu v trial (výběr týmového password manageru)

Pro začátek jsem si vybral jako nejslibnější LastPass Enterprise, otevřel jsem v něm trial a začal naplno testovat. Hned na úvod musím říct, že zatím v podstatě sám, resp. pár kolegů se přidalo, ale týmové interakce jsme si moc neužili (na závadu to ale myslím není).

První dojmy bych shrnul asi takto – Přes naději, že to bude snadný výběr na první dobrou, se ukázalo, že LastPass Enterprise je sice obstojným produktem, který si umím jako náš týmový password manager představit, nicméně naděje ve snadné vítězství se nepotvrdila a mám nutkání zkusit i něco dalšího.

Nalezená pozitiva

  1. Enterprise feature-rich. Kromě mnoha nastavení v Admin Console to má třeba i podporu SAML a REST API.
  2. Cena. Ve srovnání s ostatními zvažovanými je $2/user/month jedna z nejnižších.
  3. Podpora prakticky všech platforem. Extensions prakticky pro všechny browsery, aplikace pro všechny mobilní platformy. Za mě třeba iOS dobrý – podporuje fingerprint ověřování i doplňování hesel do Safari.
  4. Možnost asociace soukromého účtu. Je myslím výhoda, že lze LastPass bez obav používat rovnou i jako osobní password manager s tím, že soukromá hesla si člověk ukládá do asociovaného osobního účtu a nemusí se obávat, že by se na ně někdo z firmy dostal, nebo že by o ně přišel při odchodu z firmy.
  5. Umí víceméně vše, co potřebujeme. Sdílená hesla, vlastní hesla a při troše fantazie lze vyřešit i emergency (break glass) access.
  6. Dospělý produkt. Mají zjevně hodně uživatelů, včetně Enterprise edice. Přežili ve zdraví už i nějaký ten breach. Nějakou dobu už existují a vypadá to, že existovat budou.

Nalezená negativa

  1. Logika “nejrestriktivnějšího oprávnění” na sdílených složkách. Asi nejhorší věc, na kterou jsem zatím narazil, je pravidlo „most restrictive rule applies“ při nastavování oprávnění na sdílené složky. Prakticky to znamená, že pokud máte skupinu Team-A a z jejích členů ještě vyberete skupinu Team-A-Power-Users, tak pokud na sdílené složce dáte právo read skupině Team-A a k tomu právo write skupině Team-A-Power-Users, tak všichni členové Team-A-Power-Users, kteří jsou i členy Team-A ztrácí právo write a uplatní se jim restriktivnější read. Toto chování mi potvrdil i support a zatím se marně snažím dobrat nějakého schématu skupin, jak se vyhnout maintenance hell (Team-A-Except-Power-Users). Zapomeňte na skupinu Everyone, že by se jí dalo dát právo read.
  2. Horší UX v některých situacích. Např. navigace ve složkách, kopírování hesla přes schránku, atp. Částečně to trpí i tím, že desktopová aplikace je „jen“ extension v browseru. I po týdnu používání docela dost často hledám běžné funkce.
  3. Není přímá podpora break-glass emergency přístupu. Edice Enteprise má dokonce vypnutou i Emergency Access feature, která je u osobních účtů pro případ úmrtí uživatele. Není to sice klasický break-glass, ale s nulovou čekací dobou by se to využít dalo. Je to v podstatě i cesta, jak to celé obejít a uspořádat – vytvořit dedikovaný „osobní“ (non-Enterprise) účet, do kterého se uloží příslušný break-glass přístup a v podstatě úplně mimo Enterprise se nastaví Emergency Access s nulovou nebo minimální čekací dobou.

Neutrální aspekty

  1. Reagující support. Za ten týden jsem přes support řešil dva dotazy a reportoval jeden bug. Chybu akceptovali hned a předali do vývoje, dotazy odpovídají zpravidla do 24 hodin a je to takový klasický helpdesk – templatované odpovědi, žádná hluboká snaha o metodickou pomoc (např. s tím pravidlem o restriktivnějších oprávněních, nebo jak uspořádat break-glass).
  2. Data lze zálohovat. Není to sice žádný zázrak, ale celý účet lze exportovat do šifrovaného souboru, který lze pak i offline otevřít v jejich portable klientovi. Lze tak tedy vytvořit offline zálohu, byť zřejmě jen pro jednotlivý účet, nikoliv celou firmu.

Jako další zkusím asi 1Password Team. Mají do 15/OCT akci, že všichni Team zákazníci dostávající life-time edici Pro za cenu Standard, tak abych to případně stihnul využít.

Mimochodem: Tenhle blogpost jsem nakonec psal ve webovém editoru WordPressu, přestože jsem ho rozepsal v Open Live Writeru. Poslední dobou fakt už nějak nemám trpělivost s tím jeho různým przněním flow a formátování při přechodech mezi odstavci, nadpisy, atp.

T-SQL: Smazání všech tabulek a dalších běžných objektů z DB

Zdroj: http://stackoverflow.com/questions/536350/drop-all-the-tables-stored-procedures-triggers-constraints-and-all-the-depend

/* Drop all non-system stored procs */
DECLARE @name VARCHAR(128)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 ORDER BY [name])

WHILE @name is not null
BEGIN
    SELECT @SQL = 'DROP PROCEDURE [dbo].[' + RTRIM(@name) +']'
    EXEC (@SQL)
    PRINT 'Dropped Procedure: ' + @name
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 AND [name] > @name ORDER BY [name])
END
GO

/* Drop all views */
DECLARE @name VARCHAR(128)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 ORDER BY [name])

WHILE @name IS NOT NULL
BEGIN
    SELECT @SQL = 'DROP VIEW [dbo].[' + RTRIM(@name) +']'
    EXEC (@SQL)
    PRINT 'Dropped View: ' + @name
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 AND [name] > @name ORDER BY [name])
END
GO

/* Drop all functions */
DECLARE @name VARCHAR(128)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 ORDER BY [name])

WHILE @name IS NOT NULL
BEGIN
    SELECT @SQL = 'DROP FUNCTION [dbo].[' + RTRIM(@name) +']'
    EXEC (@SQL)
    PRINT 'Dropped Function: ' + @name
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 AND [name] > @name ORDER BY [name])
END
GO

/* Drop all Foreign Key constraints */
DECLARE @name VARCHAR(128)
DECLARE @constraint VARCHAR(254)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)

WHILE @name is not null
BEGIN
    SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
    WHILE @constraint IS NOT NULL
    BEGIN
        SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']'
        EXEC (@SQL)
        PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name
        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
    END
SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
END
GO

/* Drop all Primary Key constraints */
DECLARE @name VARCHAR(128)
DECLARE @constraint VARCHAR(254)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)

WHILE @name IS NOT NULL
BEGIN
    SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
    WHILE @constraint is not null
    BEGIN
        SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint)+']'
        EXEC (@SQL)
        PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name
        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
    END
SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
END
GO

/* Drop all tables */
DECLARE @name VARCHAR(128)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])

WHILE @name IS NOT NULL
BEGIN
    SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
    EXEC (@SQL)
    PRINT 'Dropped Table: ' + @name
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
END
GO

T-SQL: Seznam tabulek bez IDENTITY

SELECT  [schema] = s.name,
        [table] = t.name
	FROM    sys.schemas AS s
			INNER JOIN sys.tables AS t ON s.[schema_id] = t.[schema_id]
	WHERE   NOT EXISTS (SELECT 1
						 FROM   sys.identity_columns
						 WHERE  [object_id] = t.[object_id])
	ORDER BY t.name