Странно, но крутая новая фишка Visual Studio 2012 проскочила практически мимо официальных анонсов.

Visual Studio 2012 научилась компилировать проекты в несколько потоков.

Сами по себе и Visual Studio 2010, и msbuild поддерживали параллельное построение уже достаточно давно. Но по какой-то неизвестной причине работали они “из коробки” только для проектов Visual C++. Для C# приходилось использовать обходные пути, вроде прикручивания mbuild через External Tools.

В Visual Studio 2012 ограничение “только для C++” убрали. Так что не удивляйтесь, увидев для своего проекта в output загадочные числа в начале каждой строки:

1>------ Rebuild All started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
2>------ Rebuild All started: Project: ClassLibrary2, Configuration: Debug Any CPU ------
2>  ClassLibrary2 -> C:Users...ClassLibrary2binDebugClassLibrary2.dll
1>  ClassLibrary1 -> C:Users...ClassLibrary1binDebugClassLibrary1.dll
========== Rebuild All: 2 succeeded, 0 failed, 0 skipped ==========

Количество одновременно собираемых проектов задается в Tools > Options > Projects and Solutions > Build and Run:

image

Опция глобальная, включена по умолчанию, и действует на все проекты (в том числе и на сконвертированные из предыдущих версий Visual Studio). Надеюсь, внезапно ускорившиеся билды и нелинейный output не станут для вас неприятным сюрпризом 😉

…по мотивам одной рассылки

Что выведет следующий код (при сборке под .NET 4.0 в 2010-й студии)?

using System;

class Base
{
   
public virtual bool Method1(bool value) { return true
; }
   
public virtual bool Method2(bool value) { return true
; }
}

class Derived : Base
{
   
public override bool Method1(bool value = true
)
    {
       
return
value;
    }

   
public override bool Method2(bool value = true
)
    {
       
return
Method1();
    }
}

class Program
{
   
static void Main(string
[] args)
    {
       
Derived a = new Derived
();

       
Console.WriteLine("Call to Method1, expected: True, got: {0}"
, a.Method1());
       
Console.WriteLine("Call to Method2, expected: True, got: {0}", a.Method2());
    }
}

Что выведет этот же код, если собрать его в Visual Studio 2012?

В .NET 4.5 многим стандарным классам были добавлены новые методы для поддержки async/await. В What’s New явно упомянут Asynchronous File I/O, но поиск выдает чуть больше новых методов.

Стандартные асинхронные методы появились так же в классах работы с сетью (dns/сокетами/почтой), базами данных и XML:

Namespace Type Methods
System.IO Stream и наследники FlushAsync
ReadAsync
WriteAsync
CopyToAsync
TextReader
StreamReader
StringReader
ReadAsync
ReadBlockAsync
ReadLineAsync
ReadToEndAsync
TextWriter
StringWriter
StreamWriter

WriteAsync
WriteLineAsync
FlushAsync

System.Threading SemaphoreSlim WaitAsync
System.Net Dns GetHostAddressesAsync
GetHostEntryAsync
HttpListener GetContextAsync
HttpListenerContext AcceptWebSocketAsync
HttpListenerRequest GetClientCertificateAsync
WebClient DownloadDataTaskAsync
DownloadFileTaskAsync
DownloadStringTaskAsync
OpenReadTaskAsync
OpenWriteTaskAsync
UploadDataTaskAsync
UploadFileTaskAsync
UploadStringTaskAsync
UploadValuesTaskAsync
System.Net.Mail SmtpClient SendMailAsync
System.Net.NetworkInformation IPGlobalProperties GetUnicastAddressesAsync
Ping SendPingAsync
System.Net.Security NegotiateStream
SslStream
AuthenticateAsClientAsync
AuthenticateAsServerAsync
System.Net.Sockets TcpClient ConnectAsync
TcpListener AcceptSocketAsync
AcceptTcpClientAsync
UdpClient ReceiveAsync
SendAsync
System.Net.WebSockets WebSocket
AspNetWebSocket
CloseAsync
CloseOutputAsync
ReceiveAsync
SendAsync
System.Data.Common DbCommand ExecuteNonQueryAsync
ExecuteReaderAsync
ExecuteScalarAsync
DbConnection OpenAsync
DbDataReader GetFieldValueAsync
IsDBNullAsync
NextResultAsync
ReadAsync
System.Data.SqlClient
(по сравнению с Common)
SqlBulkCopy WriteToServerAsync
SqlCommand ExecuteXmlReaderAsync
System.Net.Http HttpClient DeleteAsync
GetAsync
GetByteArrayAsync
GetStreamAsync
GetStringAsync
PostAsync
PutAsync
SendAsync
HttpContent CopyToAsync
LoadIntoBufferAsync
ReadAsByteArrayAsync
ReadAsStreamAsync
ReadAsStringAsync
System.ServiceModel.Description MetadataExchangeClient GetMetadataAsync
System.ServiceModel.Discovery AnnouncementClient AnnounceOfflineTaskAsync
AnnounceOnlineTaskAsync
System.Xml XmlReader GetValueAsync
MoveToContentAsync
ReadAsync
ReadContentAsAsync
ReadContentAsBase64Async
ReadContentAsBinHexAsync
ReadContentAsObjectAsync
ReadContentAsStringAsync
ReadElementContentAsAsync
ReadElementContentAsBase64Async
ReadElementContentAsBinHexAsync
ReadElementContentAsObjectAsync
ReadElementContentAsStringAsync
ReadInnerXmlAsync
ReadOuterXmlAsync
ReadValueChunkAsync
SkipAsync
XmlWriter FlushAsync
WriteAttributesAsync
WriteAttributeStringAsync
WriteBase64Async
WriteBinHexAsync
WriteCDataAsync
WriteCharEntityAsync
WriteCharsAsync
WriteCommentAsync
WriteDocTypeAsync
WriteElementStringAsync
WriteEndDocumentAsync
WriteEndElementAsync
WriteEntityRefAsync
WriteFullEndElementAsync
WriteNameAsync
WriteNmTokenAsync
WriteNodeAsync
WriteProcessingInstructionAsync
WriteQualifiedNameAsync
WriteRawAsync
WriteStartDocumentAsync
WriteStartElementAsync
WriteStringAsync
WriteSurrogateCharEntityAsync
WriteWhitespaceAsync
XmlDictionaryWriter WriteBase64Async
WriteValueAsync
XmlResolver и наследники GetEntityAsync

Одна из мелких фич, упомянутых в What’s New in the .NET Framework 4.5 Beta в разделе Networking – Support for Email Address Internationalization. Ссылка из What’s New оптимистично ведет в MSDN по System.Net.Mail, где про EAI, естественно, упоминаний уже нет.

Суть фичи на самом деле – новое свойство SmtpClient.DeliveryFormat, позволяющее включить поддержку UTF-8 в заголовках, в соответствии с RFC 5336 RFC 6531.

SmtpClient client = new SmtpClient();
client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;

client.PickupDirectoryLocation = @"d:tempsmtptest";
Directory.CreateDirectory(client.PickupDirectoryLocation);
client.Send("Василий <test@example.com>", "Павел <test2@example.com>", "тема", "тело");

client.DeliveryFormat = SmtpDeliveryFormat.International;
client.Send("Василий <test@example.com>", "Павел <test2@example.com>", "тема", "тело");

Результат вызова со старым форматом доставки:

X-Sender: =?utf-8?Q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9?=
 <test@example.com>
X-Receiver: =?utf-8?Q?=D0=9F=D0=B0=D0=B2=D0=B5=D0=BB?= <test2@example.com>
MIME-Version: 1.0
From: =?utf-8?Q?=D0=92=D0=B0=D1=81=D0=B8=D0=BB=D0=B8=D0=B9?=
 <test@example.com>
To: =?utf-8?Q?=D0=9F=D0=B0=D0=B2=D0=B5=D0=BB?= <test2@example.com>
Date: 16 Apr 2012 21:32:53 +0300
Subject: =?utf-8?B?0YLQtdC80LA=?=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64

0YLQtdC70L4=

С новым форматом доставки:

X-Sender: "Василий" <test@example.com>
X-Receiver: "Павел" <test2@example.com>
MIME-Version: 1.0
From: "Василий" <test@example.com>
To: "Павел" <test2@example.com>
Date: 16 Apr 2012 21:32:53 +0300
Subject: тема
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64

0YLQtdC70L4=

P.S. Пост для себя, на всякий случай, чтобы не вспоминать в следующий раз “что такое DeliveryFormat и EAI?” :)

Одна из фич, незаметно попавших в ASP.NET 4.5 – встроенная поддержка минификации контента. Упаковщик живет в пространстве имен System.Web.Optimization.

Упаковка контента включена по умолчанию в шаблонах ASP.NET MVC 4/.NET 4.5 в Visual Stidio 11 Beta, и, надеюсь, останется включенной по умолчанию в релизной версии.

Хоть фича и упоминается как новшество в ASP.NET 4.5, она доступна для проектов на базе .NET 4.0 и ASP.NET MVC 3. Сам по себе упаковщик доступен в виде пререлизного пакета nuget.

После установки пакета придется сделать еще несколько изменений:

1. Добавить вызов EnableDefaultBundles на старте приложения, в global.asax.cs:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    System.Web.Optimization.BundleTable.Bundles.EnableDefaultBundles();
}

2. Заменить явное подключение скриптов и стилей в _Layout.cshtml на

<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" rel="stylesheet" type="text/css" />
<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")" type="text/javascript"></script>

После этого все css и все скрипты будут подтянуты двумя файлами:

Untitled

Скриншот выше снят для стандартного шаблона ASP.NET MVC 3. Все скрипты в шаблоне весят достаточно много, отсюда и полумегабайтный размер выходного файла. Достаточно удалить лишние файлы из Scripts, и размер пакета станет более приемлимым :)

Кроме очевидного “собрать все в один большой файл”, System.Web.Optimization делает еще несколько вещей:

  • Игнорирует файлы .intellisense.js, -vsdoc.js, .debug.js.
  • Подхватывает уже минимизированные файлы – min.js, и подключает их “как есть”.
  • Учитывает порядок подключения скриптов для JQuery/UI/Validate, modernizr, dojo, mootools, prototype и ext.js

    Дополнительная плюшка, котороя не слишком заметна в документации – возможность подключения своих трансформаций для выходных файлов, на случай если стандартных JsMinify и CssMinify не хватит. Список уже готовых трансформаций виден в поиске на nuget. И в нем уже есть Less и CoffeeScript.