C# 6.0: Using static [3/10]

Pomůcka, která vám umožní příkazem using „zpřístupnit“ statickou třídu tak, že lze volat její statické metody bez explicitního uvádění jména třídy:

using System.Console;
using System.Math;

class Program
{
    static void Main()
    {
        WriteLine(Sqrt(3*3 + 4*4));
        // odpovídá Console.WriteLine(Math.Sqrt(3*3 + 4*4));
    }
}

Zkrácenou syntaxi je samozřejmě možné použít jen tehdy, pokud je použitá metoda jediná.

Situace u extension metod

Extension metody jsou definovány na statické třídě, nová using konstrukce tím pádem umožňuje jemnější „zpřístupňování“ extension metod jednotlivých statických tříd aniž bychom museli zpřístupnit celý namespace jako dosud.

using System.Linq.Enumerable; // Dotahujeme pouze jednu třídu extension-metod, ne celý namespace

class Program
{
    static void Main()
    {
        var range = Range(5, 17); // Ok: není extension metoda, ale běžná statická
        var odd = Where(range, i => i % 2 == 1); // Chyba, extension-metodu takto volat nelze
        var even = range.Where(i => i % 2 == 0); // Ok, extension metoda
    }
}

Using-konstrukce samozřejmě z extension metody neudělá běžnou statickou metodu, přímo zkrácenou syntaxí je tedy volat nelze.

Mimochodem dosud bylo možné bez obavy změnit běžnou statickou metodu na extension metodu a nemuseli jsme se obávat, že něco přestane fungovat. Nyní již si nemůžeme být jisti, protože pokud by někdo běžnou statickou metodu volal bez uvedení třídy (pomocí nového using static), tak změnou této metody na extension-metodu přestane takový kód být kompilovatelný.

Série článků o novinkách v C# 6.0:

  1. Auto-property initializers a getter-only (read-only) auto-properties
  2. Expression-bodied function members
  3. Using static
  4. Null-conditional operators (?., ?[], …)
  5. String inerpolation – zkrácený String.Format()
  6. nameof() expressions
  7. Index initializers – přehlednější inicializace slovníků
  8. Exception filters, await v catch/finally blocích
  9. Konstruktor struct bez parametrů
  10. Ostatní (extension-Add v initializers, overload resolution)

C# 6.0: Expression-bodied function members [2/10]

Expression-syntaxi s „lambda-šipkou“, kterou známe již z běžného kódu u lambda výrazů, je nyní možné ji použít i pro zápis těla metody, getteru nebo obdobné situace (např. operátoru).

Použití pro metody, operátory a typové konverze

public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public static implicit operator string(Person p) => p.First + " " + p.Last;

Výsledek je stejný, jako by metoda měla klasické tělo s blokem a v něm samotný return příkaz.

Syntaxi lze použít, o pokud metoda „vrací“ void, nebo u asynchronních metod vracejících Task, stejně jako u lambda-výrazů:

public void Print() => Console.WriteLine(First + " " + Last);

Použití pro getter property a indexer

Syntaxi lze použít i pro zkrácený zápis getteru property (property pak nemůže mít setter), nebo pro indexer:

public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);

Série článků o novinkách v C# 6.0:

  1. Auto-property initializers a getter-only (read-only) auto-properties
  2. Expression-bodied function members
  3. Using static
  4. Null-conditional operators (?., ?[], …)
  5. String inerpolation – zkrácený String.Format()
  6. nameof() expressions
  7. Index initializers – přehlednější inicializace slovníků
  8. Exception filters, await v catch/finally blocích
  9. Konstruktor struct bez parametrů
  10. Ostatní (extension-Add v initializers, overload resolution)

C# 6.0: Auto-property initializers a getter-only (read-only) auto-properties [1/10]

Preview Visual Studio 2015 a .NET 4.6 dnes vyšly, nastal tedy čas si v seriálu krátkých článků připomenout novinky v C# 6.0 (jednotlivé články zamýšlené série budou přibývat postupně):

RTM Update: Constructor struct bez parametrů byl z finální podoby C# 6.0 odstraněn.

  1. Auto-property initializers a getter-only (read-only) auto-properties
  2. Expression-bodied function members
  3. Using static
  4. Null-conditional operators (?., ?[], …)
  5. String inerpolation – zkrácený String.Format()
  6. nameof() expressions
  7. Index initializers – přehlednější inicializace slovníků
  8. Exception filters, await v catch/finally blocích
  9. Konstruktor struct bez parametrů – není součástí C# 6.0 RTM
  10. Ostatní (extension-Add v initializers, overload resolution)
  11. Primary constructors
  12. Declaration expression

Finální podoba C# 6.0 se může měnit, články vychází z informací z okamžiku vydání VS 2015 Preview – soupisu změn od Madse Torgersena, C# Language PM a ze stručného seznamu změn vedeného u projektu Roslyn.

V tuto chvíli k velkému smutku všech zúčastněných byly ze C# 6.0 odstraněny dvě oblíbené konstrukce, které již v CTP verzích fungovaly:

  1. Primary constructors  – public class Point(int x, int y)
  2. Declaration expressions – if (int.TryParse(input, out int output))

Dá se předpokládat, že cut-off v tomto případě znamená odklad do C# 7.0, i když může dojít i k zásadním změnám.

Initializers for auto-properties

Jde o syntaxi známou z běžných fieldů, jejíž použitelnost byla rozšířena na auto-properties:

public class Customer
{
    public string First { get; set; } = "Jane";
    public string Last { get; set; } = "Doe";
}

Ve skutečnosti dojde k inicializaci podkladového fieldu, na který se auto-property mapuje.

Getter-only auto-properties (readonly)

V předchozích verzích C# musela mít auto-property setter i getter. Nově lze definovat pouze getter a ve skutečnosti tím vznikne read-only podkladový field, který lze nastavit buď pomocí initializeru (viz výše) nebo z constructoru.

public class Customer
{
    public string First { get; } = "Jane";
    public string Last { get; } = "Doe";
}

Nabízí se zde použití pro immutable třídy, v nichž dosud zkrácenou syntaxi auto-properties nebylo možné využít.

ASP.NET MVC6 – Zápisky z MVP Summitu 2014 (non-NDA session)

Protože session o MVC6 na Microsoft MVP Summitu není pod NDA, vystavuji rovnou svoje neformální „raw“ zápisky.

Základní info

MVC6 = MVC + WebAPI + Web Pages (unifikace do jednoho společného API)

Build on ASP.NET 5

  • poběží na .NET core s jeho podporou side-by-side verzování
  • cross-platform
  • IIS/self-hosted

nativní Dependency Injection

  • unified abstraction

plně Async

command-line scaffolding

Enhanced Razor

  • @inject, @using, @inherits
  • async views
  • flush pointes
  • tag helpers

Get Started

project.json

přidat do sekce dependencies

  • „Microsoft.AspNet.Mvc“: „6.0.0-beta1“

Startup.cs

Configure(IApplicationBuilder app) – app.UseMvc(routes => routes.MapRoute(…))

ConfigureServices(IServiceCollection services)

services.AddMvc()

services.Configure<MvcOptions>(options => …)

  • options.Filters
  • options.InputFormatters
  • options.ModelViewBinders
  • options.OutputFormatters
  • options.ValueProviderFactories

Routes

  • default routes, constratints: „{area:exists}/{controller=HomeControler}/{action=Index}/{id?int?}“
  • all routes fall through to next route, if the action is not found
  • attribute routing enabled by default [Route], [HttpXxx], concat route pro controller a action, inherited
  • route tokes [controller], [action], …

Samples

Areas

[Area] atribut na controlleru, nemusí být ve složce Area

stává se pouze informací pro routing, kde se to musí potkat s {area}

Model binding, formatting

[FromBody[ – formatters

[FromQuery], [FromRoute], [FromForm], [FromHeader] – restrikce

[Produces] na action – restrikce media types výstupu

WebAPI

shim-package pro podporu legacy WebAPI projektů (např. konvence pojmenování action–method, atp.)

View Components !!

partial view s controller action

vrací View nebo formatted data

Async, DI

Dependency Injection

POCO controller bez dědění Controller třídy

[Activate] atribut k property-based injection, např [Activate] public ActionContext ActionContext

service filters: [ServiceFilter(typeof(MyFilter)]

type filters: [TypeFilter(typeof(MyFilter)]

Application Model, conventions

described through ActionDescriptorCollection

tweak conventions (ála EF)

  • IApplicationModelConvention
  • IControllerModelConvention

CS1647: An expression is too long or complex to compile (workaround)

Na jednom z projektů jsme po úpravě ASPX stránky s enormním objemem html kódu narazili na zajímavou chybu zobrazenou v kompilátorem: CS1647: An expression is too long or complex to compile. Velmi pozoruhodný je též popis chyby na MSDN a doporučené řešení.

Jako funkční workaround zafungovalo doporučení z blogu henrywrites a sice vložit do ASPX stránky serverový komentář, například

<%
// workaround pro CS1647: An expression is too long or complex to compile
%>

The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel

Mě touto hláškou obšťastnil sign-in dialog ve Visual Studiu v lab Virtual Machine, ale můžete ji potkat i jinde. V mém případě byl důvod v nepřiměřeně se rozcházejícím čase virtuálního stroje a času skutečného (na serverech MSFT).

Stejně tak například bez rozumného času nejde Windows Update.

Gesto pro „zavření“ aplikace na iPadu občas přestane fungovat

Gesto, kterým lze sevřením čtyř nebo pěti prstů na iPadu s iOS 8.0.2 zavřít otevřenou aplikaci, občas přestane fungovat.

Workaround je zavřít aplikaci tlačítkem a zobrazit a skrýt ovládací centrum. Tím začne být gesto opět funkční.

iPad control center

„Copy Local“ referencí ve Visual Studiu

Copy Local standardně zobrazuje hodnotu True, ale ve skutečnosti to znamená neuvedeno, protože v *.csproj souboru není nic uvedeno. Pokud běží build na stroji, který má assembly uložené v GAC, nebude knihovna zkopírována do složky bin.

2014-10-24_1711

Řešení je jednoduché, stačí hodnotu nastavit na False a zpět na True. Tím dojde k uložení informace do *.csproj souboru a sice v elementu Reference přibyde nový element Private s hodnotou True.

<Reference Include="Havit">
  <HintPath>...</HintPath>
  <Private>True</Private>
</Reference>

MSBuild v rámci TFS Build Service nevytváří Web Deployment Packages

Problém

V projektu máme webovou aplikaci, která má Publish Profile, který má vytvořit Web Deployment balíček. Balíček se úspěšně vytváří jak při spuštění MSBuildu z Visual Studia, tak z příkazové řádky na vývojářském počítači, tak při spuštění z příkazové řádky na počítači s TFS Build Service. Jenže při spuštění z TFS Build Service se balíček nevytvoří.

Proč to nefunguje

Podoba publish profile, který byl vyroben pomocí UI ve Visual Studio 2013 je (plus mínus) takováto:

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>Package</WebPublishMethod>
<DesktopBuildPackageLocation>TfsPublish\BalicekKteryChciVytvorit.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile>
...
</PropertyGroup>
</Project>

Důvodem, proč se balíček nevytváří je skutečnost, že Visual Studio do publish profilu vytvoří vlastnost DesktopBuildPackageLocation, jenže je očekávána hodnota vlastnosti PackageLocation.

A jak to, že v rámci VS a z příkazové řádky to funguje? Protože PackageLocation se v průběhu načítání C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.targets nastaví podle DestopBuildPackageLocation.

<PackageLocation Condition="'$(PackageLocation)'=='' and !(('$(OutDir)' != '$(OutputPath)') Or ('$(IsDesktopBuild)' == 'False')) ">$(DesktopBuildPackageLocation)</PackageLocation>

Jenže jen za podmínky, kdy IsDesktopBuild není false (druhou podmínku není ukázanou výše třeba řešit). Otázkou je, kde se nastavuje hodnota vlastnosti IsDesktopBuild. Odpověď se skrývá v témže souboru:

<IsDesktopBuild Condition="'$(IsDesktopBuild)'=='' And '$(TeamFoundationServerUrl)' != ''">False</IsDesktopBuild>

A problém je objasněn – TFS Build Service nastavuje hodnotu TeamFoundationServerUrl, čímž se build liší od spuštění z příkazové řádky.

Možnosti řešení

Nastavení vlastnosti PackageLocation bohužel nefunguje v rámci vlastního targetu, neboť to je již pozdě. Z vlastnosti se odvozují další vlastnosti během načítání target souborů.

  1. Natvrdo nastavit hodnotu IsDesktopBuild na True při spouštění MS Buildu. Nenašel jsem žádné jiné použití této vlastnosti, tedy alespoň prozatím jde o bezpečné řešení.
  2. Během studia zmíněného souboru s MSBuild targety jsem našel, že se MSBuild po importu PublishProfile souboru (pubxml) pokouší importovat ještě další targety, pokud existují. Šlo by tedy takový soubor vytvořit a v něm zkopírovat hodnotu z DesktopBuildPackageLocation do PackageLocation.
    Pokud se projekt jmenuje Web a ten obsahuje publish profile v Properties\PublishProfiles\TfsPublish.pubxml, pak se načítají
  • Web\Properties\PublishProfiles\TfsPublish.wpp.targets (viz vlastnost WebPublishProfileCustomizeTargetFile)
  • Web\*.wpp.targets (viz vlastnost WebPublishPipelineCustomizeTargetFile)
  • Web\..\wpp.deploysettings.targets (viz WebPublishPipelineSolutionTargetFile)

Advanced .NET Debugging – záznam, slides a dema [MS Fest Brno 2014]

Slides z mé přednášky 18.10.2014 pro konferenci MS Fest Brno:

Z přednášky jsem pořizoval záznam, který najdete na našem HAVIT YouTube Channelu: