Link: https://channel9.msdn.com/Shows/CZSK-videa
Další skvělá feature C# 6.0, žádné hardcoded řetězce:
using Stuff = Some.Cool.Functionality class C { static int Method1 (string x, int y) {} static int Method1 (string x, string y) {} int Method2 (int z) {} string f<T>() => nameof(T); } var c = new C() nameof(C) -> "C" nameof(C.Method1) -> "Method1" nameof(C.Method2) -> "Method2" nameof(c.Method1) -> "Method1" nameof(c.Method2) -> "Method2" nameof(z) -> "z" // inside of Method2 ok, inside Method1 is a compiler error nameof(Stuff) = "Stuff" nameof(T) -> "T" // works inside of method but not in attributes on the method nameof(f) -> "f" nameof(f<T>) -> syntax error nameof(f<>) -> syntax error nameof(Method2()) -> error "This expression does not have a name"
Zdroj: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/nameof
Vývoj vlastního PowerShell příkazu (CmdLet) je velice snadné a rychlé – ideální pro často opakované akce, případně akce u zákazníka, kde nemusí být vždy vzdálený přístup do jeho infrastruktury. Za posledních pár let už jsem jich napsal desítky a jsem jsem z toho stále nadšen, hlavně tou jednoduchostí, v podstatě jsem tím zcela nahradil jednoúčelové konzolové aplikace, kde již navíc není nutné řešit parsování argumentů, přehledná výpis na konzolovou obrazovku, všechno je již tak nějak vyřešeno. Jako příklad jednoho z CmdLetů bych uvedl snadné nasazení jedné naší aplikace hostované v Azure, kde s každým zákazníkem bylo vždy nutné přihlásit se na portál Azure, vytvořit hosting pro aplikaci, nastavit domény, standard mód, vytvořit a nastavit DB, connection string do aplikace, vytvořit storage provider, přihlašovací údaje zapsat do aplikace, nastavit zálohování, a tak bych mohl pokračovat….. až po finální nahrání zkompilované verze – prostě práce na minimálně 2-4h a to ještě s rizikem chyby. Nyní k tomu slouží dva CmdLety, jeden pro přihlášení k Azure, druhý už pro založení tenantu a provedení všech potřebných akcí zcela automaticky.
V tomto prvním díle ukážu pouze základ, založení Visual Studio projektu a jeho nastavení.
Základem vlastního PowerShell CmdLetu je založený projekt typu Class Library
Volba verze .NET Frameworku je závislá na požadované verzi PowerShellu, pokud například skriptujete akce pro SharePoint 2010, musíte nastavit .NET Framework verze maximálně 3.5.
Po založení projektu je nutné ručně přidat potřebné reference, hlavní referencí je System.Management.Automation.dll, kterou naleznete (případně dle vaší verze PowerShellu):
C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0
Následně se již můžeme vrhnout na prvním CmdLet, pro první sample klasicky Hello World, založíme novou třídu a pojmenujeme jí GetHelloWorldMessage:
A začneme přidávat atributy a base třídu:
Samotnou funkčnost implementujete přetížením metody ProcessRecord(), která je definována v base PSCmdLetu a navíc přidáme jeden vstupní parametr pro specifikaci jména uživatele – tento parametr je označen jako povinný.
using System; using System.Collections.Generic; using System.Linq; using System.Management.Automation; using System.Text; using System.Threading.Tasks; namespace DevIT.PowerShell.Samples { [Cmdlet(VerbsCommon.Get, "HelloWorldMessage")] public class GetHelloWorldMessage : PSCmdlet { [Parameter(Mandatory = true, HelpMessage = "Zadejte Vaše jméno.")] public string YourName { get; set; } protected override void ProcessRecord() { WriteVerbose("Spouštíme hrozně složitou akci..."); WriteObject(string.Format("Vítejte, {0}!", YourName ?? string.Empty)); } } }
Nyní už jenom zkompilujeme, spustíme konzoli PowerShellu, nalistujeme adresář s výsledným DLL souborem a importujeme ho do sady dostupných PowerShell příkazů:
Import-Module .\DevIT.PowerShell.Samples.dll
Následně již můžeme zavolat příkaz Get-HelloWorldMessage:
Případně rovnou s parametrem Get-HelloWorldMessage -YourName “Pavel”
Nebo klasicky parametrem –? zobrazit dostupné volby, při prvním volání nápovědy však budete vyzván k přegenerování nápovědy, která se generuje na základě atributů uvedených u CmdLetu i samotných parametrů:
Vyzkoušejte dekompiler: http://reflexil.net/
Nikdy jsem na to zatím nenarazil, nebo si toho minimálně nevšimnul, ale v LINQ dotazu platí následující:
Guid.Empty != new Guid("00000000-0000-0000-0000-000000000000")
konkrétní příklad:
var a = query.Where(row => row.InvoiceId == Guid.Empty);
var b = query.Where(row => row.InvoiceId == new Guid("00000000-0000-0000-0000-000000000000"));
logicky bych čekal, že výsledek bude identický, tedy a i b budou obsahovat kolekci identických objektů, ale výsledek je ten, že a obsahuje prázdnou kolekci, b obsahuje všechny záznamy kde je InvoiceId rovno Guid.Empty, což je sice to samé, LINQ to ale zjevně interpretuje jinak a první příklad je tedy nefunkční, respektive nevrací očekáváné výsledky.
Na otázku PROČ jsem nenašel žádnou smysluplnou odpověď. BUG?
Hláška: Attach Security Warning
Popis: Attaching to this process can potentially harm your computer. If the information below looks suspicious or you are unsure, do not attach to this process.
[more]
Postup deaktivace:
Tuto chybu jsem tak nějak nepochopil, zřejmě je to bug ve Visual Studiu 2010. Projekt nelze kompilovat a hlásí to chybu “error 348: Compilation failed. Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.”
Na jediné řešení na které jsem přišel je, že je potřeba otevřít .csproj v poznámkovém bloku a odstranit elementy <ProjectTypeGuids>, následně znovu otevřít projekt.
Zvláštní, ale funguje to.
Společnost RedGate se bohužel rozhodla zpoplatnit asi nejznámější produkt mezi .NET vývojáři, a to produktu .NET Reflector (http://www.reflector.net/).
Tento produkt měl sice spoustu much, ale hodně krát nám pomohl objasnit chování některých nedeterministických funkcí a knihoven, zejména v SharePointu. To co mě mrzí nejvíce není ani samotné zpoplatnění (v celku zanedbatelných 35 USD), ale to že RedGate na tom od převzetí od vývojáře Lutz Roedera v roce 2008 neudělal vůbec nic! Tedy integraci do menu Visual Studia nepovažuji za pokrok.
Naštěstí se objevila další open source alternativa jménem ILSpy: http://wiki.sharpdevelop.net/ilspy.ashx
Která je až nápadně podobná .NET Reflectoru, takže přechod není tak bolestný
Samotný ILSpy je ale založený na UI WPF, .NET Reflector stále využívá Windows Forms. To ale samozřejmě není z pohledu funkčnosti důležité, hlavní jsou skutečné features:
Stránka projektu: http://wiki.sharpdevelop.net/ilspy.ashx
Twitter: http://twitter.com/ilspy
Problém je v tom, že aktuálně přihlášený uživatel nemá přístup k danému klíči v registrech systému.
Konkrétně jde o klíč v registrech:
HKEY_CLASSES_ROOT\AppID\{61738644-F196-11D0-9953-00C04FD919C1}
Aby jste tedy mohli změnit nastavení konkrétního DCOM objektu, je potřeba provést změnu nastavení v registrech a tento klíč přiřadit vlastníkům ze skupiny Administrators.
Pokud nyní zavřete správu DCOM objektů a znovu otevřete, již bude možné modifikovat nastavení IIS WAMREG admin Service DCOM objektu.
Search Crawler na publishing portálu indexuje vždy kompletní stránku, tak jak dostane HTML, tak ho uloží do své databáze. To je ovšem problém, neboť následně při vyhledávání vyhledává texty i v navigaci webu nebo hlavičce a patičce. Tyto elementy jsou ale ve většině případů pro všechny stránky na portále stejné, uživatel tak dostává nerelevantní výsledky (navíc stále stejné):
Neexistuje možnost, jak automaticky donutit Search Server, aby toto chování změnil a například ignoroval stále stejné elementy na stránce, případně jinak pomocí tagu vynechával zvolené oblasti v master page.
Udělal jsem si proto malého pomocníka, který se vloží do masterpage v podobě:
[more]
<DevIT:SearchCrawlTrimmedControl runat="server" SearchAccount="MySearchAccount"> zde vlozte menu, header, footer... vse co chcete skryt pred indexerem </DevIT:SearchCrawlTrimmedControl>
Kde uvnitř ovládacího prvku SearchCrawlTrimmedControl jsou všechny elementy, které chci skrýt před indexerem obsahu. Tato třída pak následně podle přistupujícího účtu skryje nebo zobrazí vybrané elementy.
/// <summary> /// Ovladaci prvek pro skyti vsech nepotrebnych veci v masterpage pri indexovani - aby se indexoval pouze samotny obsah stranky /// <DevIT:SearchCrawlTrimmedControl runat="server"> /// <!-- zde vlozte menu, header, footer... vse co chcete skryt pred indexerem --> /// </DevIT:SearchCrawlTrimmedControl> /// </summary> public class SearchCrawlTrimmedControl : Control { public string SearchAccount { get { string ret = ViewState["SearchAccount"] as string; if (string.IsNullOrEmpty(ret)) return "spsearch"; return ret; } set { ViewState["SearchAccount"] = value; } } protected override void Render(HtmlTextWriter writer) { bool render = true; SPUser cu = SPContext.Current.Web.CurrentUser; if (cu != null) { if (cu.LoginName.ToLower().EndsWith(SearchAccount)) { render = false; } } if (Context.Request != null && Context.Request.UserAgent != null && Context.Request.UserAgent.ToLower().Contains("robot")) { render = false; } if (render) { base.Render(writer); } else { } } }