When publishing an ASP.NET Core 6 web application with C# 10's <ImplicitUsings />
enabled to an Azure App Service from a Visual Studio 2022 publishing profile, the publishing build fails due to missing using
statements.
C# 10 introduces the new implicit usings feature, where certain using
directives are treated as global using
directives based on the SDK. This can be enabled with the following csproj
configuration:
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
This works exactly as expected with a local build. E.g., when targeting the Microsoft.NET.Sdk.Web
SDK, I'm able to remove using
directives for System
, System.Collections.Generic
, System.Linq
, &c.
When publishing to an Azure App Service from a Visual Studio 2022 publishing profile, however, the build output shows errors such as the following:
C:\Code\MyWebApp\MyClass.cs(41,25): Error CS0246: The type or namespace name 'IEnumerable<>' could not be found (are you missing a using directive or an assembly reference?)
This can be seen below as part of an expanded context:
Build started...
1>------ Build started: Project: MyWebApp, Configuration: Release Any CPU ------
1>Done building project "MyWebApp.csproj".
2>------ Publish started: Project: MyWebApp, Configuration: Release Any CPU ------
Determining projects to restore...
All projects are up-to-date for restore.
C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\Roslyn\csc.exe /noconfig /unsafe- /checked- /nowarn:1701,1702,1701,1702,2008 /fullpaths /nostdlib+ /platform:x64 /errorreport:prompt /warn:6 /define:TRACE;RELEASE;NET;NET6_0;NETCOREAPP;NET5_0_OR_GREATER;NET6_0_OR_GREATER;NETCOREAPP1_0_OR_GREATER;NETCOREAPP1_1_OR_GREATER;NETCOREAPP2_0_OR_GREATER;NETCOREAPP2_1_OR_GREATER;NETCOREAPP2_2_OR_GREATER;NETCOREAPP3_0_OR_GREATER;NETCOREAPP3_1_OR_GREATER /errorendlocation /preferreduilang:en-US /highentropyva+ /reference: /debug+ /debug:portable /filealign:512 /optimize+ /out:obj\Release\net6.0\win-x64\MyWebApp.dll /refout:obj\Release\net6.0\win-x64\ref\MyWebApp.dll /target:exe /warnaserror- /utf8output /deterministic+ /langversion:10.0 /analyzerconfig:… /analyzer:"C:\Program Files\dotnet\sdk\6.0.100\Sdks\Microsoft.NET.Sdk.Web\analyzers\cs\Microsoft.AspNetCore.Analyzers.dll" /additionalfile:Areas\MyArea\Index.cshtml … /warnaserror+:NU1605
C:\Code\MyWebApp\MyClass.cs(41,25): Error CS0246: The type or namespace name 'IEnumerable<>' could not be found (are you missing a using directive or an assembly reference?)
2>Build failed. Check the Output window for more details.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Publish: 0 succeeded, 1 failed, 0 skipped ==========
I assume this has something to do with the csc.exe
command generated by the publishing profile.
Unfortunately, it's not immediately obvious to me how to remedy this within my pubxml
file, which is pretty straight-forward:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<ResourceId>/subscriptions/77e95f68-ed69-4bfe-9bbe-0b4d3910722e/resourceGroups/ResourceGroup/providers/Microsoft.Web/sites/MyWebApp</ResourceId>
<PublishProvider>AzureWebSite</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<ProjectGuid>77e95f68-ed69-4bfe-9bbe-0b4d3910722e</ProjectGuid>
<MSDeployServiceURL>mywebapp.scm.azurewebsites.net:443</MSDeployServiceURL>
<DeployIisAppPath>MyWebApp</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>False</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<EnableMSDeployBackup>True</EnableMSDeployBackup>
<UserName>$MyWebApp</UserName>
<_SavePWD>True</_SavePWD>
<_DestinationType>AzureWebSite</_DestinationType>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<InstallAspNetCoreSiteExtension>False</InstallAspNetCoreSiteExtension>
<EnableMsDeployAppOffline>True</EnableMsDeployAppOffline>
</PropertyGroup>
</Project>
(Note: ResourceId
, ProjectGuid
, &c. have been anonymized and don't refer to an actual property.)
Acknowledging this is a new feature in a new version of Visual Studio, this could be a bug. That said, are there any pubxml
properties that are needed to enable the <ImplicitUsing />
feature? Or is there something else that's needed to enable this feature with Visual Studio publishing profiles?
First of all, it appears that this was a false alarm. I apparently neglected to finish rebooting my workstation after installing the release version of Visual Studio 2022. After restarting, I am now able to publish with full support for implicit usings. Whoops.
That said, this does provide a good opportunity to offer some insight into what I discovered after the fact, which may help future readers with similar types of issues—and certainly helped me better understand the integration between the various command-line tools.
Notably, there doesn't appear to be any command-line parameters for handling implicit usings built into any of the following tools:
dotnet.exe
)csc.exe
)msbuild.exe
)Instead, this is handled via the Microsoft Build Engine (msbuild.exe
) when working off of a C# project file (*.csproj
), at which point it generates the following intermediate file at:
/{BaseIntermediateOutputPath}/{Configuration}/net6.0/{MyWebApp}.GlobalUsings.g.cs
e.g., by default:
/obj/Release/net6.0/MyWebApp.GlobalUsings.g.cs
This file contains global using
directives that are specific to the configured SDK:
// <auto-generated/>
global using global::Microsoft.AspNetCore.Builder;
global using global::Microsoft.AspNetCore.Hosting;
…
In turn, this file is appended to the underlying call to the C# Compiler (csc.exe
).
Note: The .NET 6.0 SDK—i.e.,
dotnet.exe
—provides a wrapper aroundmsbuild.exe
as part of either thebuild
orpublish
commands, and thus offers the same functionality. Further, by default, the .NET SDK will persist the intermediate files in the/obj
folder, whereasmsbuild.exe
immediately deletes them.
Given this, the implicit usings feature isn’t actually part of C# 10 per se—despite being advertised as such—but is rather a bit of tooling built into the Microsoft Build Engine (msbuild.exe
). The C# 10 compiler (csc.exe
) does supports global using
directives, but has no awareness of implicit usings.
Ultimately, this isn't too surprising, as the C# compiler (csc.exe
) isn't actually aware of C# project files (*.csproj
) themselves—those are an artifact of the Microsoft Build Engine, with pass-through support via the .NET SDK.
It's unclear why local builds worked successfully with this prior to a full reboot, while calls using Visual Studio 2022's publishing profiles failed. I assume this has something to do with how Visual Studio assembles the arguments for the C# Compiler (csc.exe
) as part of the publishing process. Regardless, it's an easy solution to just reboot the workstation after installation. Otherwise, this post will hopefully help demystify the overall process.