Reputation: 2038
I have an ASP.NET Core project that has a type IDataService that is generated by a T4 template. If I manually make Visual Studio generate the corresponding.cs file, and then build the project, everything is fine: various classes that implement IDataService can find the interface's type and everything is okay.
Because it's tedious and error-prone to transform all these templates by hand (for instance, after cloning the solution from source control) I modified the .csproj file to transform all t4 templates before every build. This works: when I build the project, all the T4 templates will produce up-to-date .cs files.
However, when IDataService.cs does not yet exist, and I build the project, I can see IDataService.cs being created in the build output (and the actual file appears in the folder as well), but then the build fails because the type or namespace IDataService could not be found. If I then re-run the build, IDataService.cs is already there from the previous build, and everything builds just fine.
What is going wrong here? Why can't msbuild find IDataService.cs despite having generated it on that very build?
Here's the build output (with normal verbosity):
Restoring NuGet packages...
To prevent NuGet from restoring packages during build, open the Visual Studio Options dialog, click on the NuGet Package Manager node and uncheck 'Allow NuGet to download missing packages during build.'
Committing restore...
Assets file has not changed. Skipping assets file writing. Path: C:\Users\Bar\source\repos\FooBar\Foo.WebApp\obj\project.assets.json
Restore completed in 246,75 ms for C:\Users\Bar\source\repos\FooBar\Foo.WebApp\Foo.WebApp.csproj.
1>------ Build started: Project: Foo.WebApp, Configuration: Debug Any CPU ------
1>Build started 20-10-2018 12:24:25.
1>Target TransformDuringBuild:
1> Target ExecuteTransformations:
1> Performing incremental T4 transformation
1> Calculating whether transformed output is out of date...
1> All outputs are up-to-date.
1> Calculating whether transformed output is out of date...
1> All outputs are up-to-date.
1> Calculating whether transformed output is out of date...
1> All outputs are up-to-date.
1> Calculating whether transformed output is out of date...
1> All outputs are up-to-date.
1> Calculating whether transformed output is out of date...
1> All outputs are up-to-date.
1> Calculating whether transformed output is out of date...
1> Transforming template Services\IDataService.tt...
1> Performing incremental T4 preprocessing
1>Target _GetProjectReferenceTargetFrameworkProperties:
1>Target ResolveProjectReferences:
1>Target _HandlePackageFileConflicts:
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Collections.Immutable.dll' and 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.collections.immutable\1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll'. NETSDK1036: Choosing 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Collections.Immutable.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Diagnostics.DiagnosticSource.dll' and 'Reference:C:\Users\Bar\.nuget\packages\system.diagnostics.diagnosticsource\4.5.1\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll'. NETSDK1033: Choosing 'Reference:C:\Users\Bar\.nuget\packages\system.diagnostics.diagnosticsource\4.5.1\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll' because AssemblyVersion '4.0.3.1' is greater than '4.0.3.0'.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Linq.Parallel.dll' and 'Reference:C:\Users\Bar\.nuget\packages\system.linq.parallel\4.3.0\ref\netstandard1.1\System.Linq.Parallel.dll'. NETSDK1033: Choosing 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Linq.Parallel.dll' because AssemblyVersion '4.0.3.0' is greater than '4.0.0.0'.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Reflection.Metadata.dll' and 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.reflection.metadata\1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll'. NETSDK1036: Choosing 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Reflection.Metadata.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Runtime.Serialization.Xml.dll' and 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.runtime.serialization.xml\4.3.0\ref\netstandard1.3\System.Runtime.Serialization.Xml.dll'. NETSDK1033: Choosing 'Reference:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Runtime.Serialization.Xml.dll' because AssemblyVersion '4.1.4.0' is greater than '4.1.1.0'.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:Microsoft.Win32.Registry.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.win32.registry\4.5.0\lib\netstandard2.0\Microsoft.Win32.Registry.dll'. NETSDK1036: Choosing 'Platform:Microsoft.Win32.Registry.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Collections.Immutable.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.collections.immutable\1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll'. NETSDK1036: Choosing 'Platform:System.Collections.Immutable.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Diagnostics.DiagnosticSource.dll' and 'Runtime:C:\Users\Bar\.nuget\packages\system.diagnostics.diagnosticsource\4.5.1\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll'. NETSDK1033: Choosing 'Runtime:C:\Users\Bar\.nuget\packages\system.diagnostics.diagnosticsource\4.5.1\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll' because AssemblyVersion '4.0.3.1' is greater than '4.0.3.0'.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Linq.Parallel.dll' and 'Runtime:C:\Users\Bar\.nuget\packages\system.linq.parallel\4.3.0\lib\netstandard1.3\System.Linq.Parallel.dll'. NETSDK1033: Choosing 'Platform:System.Linq.Parallel.dll' because AssemblyVersion '4.0.3.0' is greater than '4.0.2.0'.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Reflection.Metadata.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.reflection.metadata\1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll'. NETSDK1036: Choosing 'Platform:System.Reflection.Metadata.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Runtime.Serialization.Xml.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.runtime.serialization.xml\4.3.0\lib\netstandard1.3\System.Runtime.Serialization.Xml.dll'. NETSDK1033: Choosing 'Platform:System.Runtime.Serialization.Xml.dll' because AssemblyVersion '4.1.4.0' is greater than '4.1.2.0'.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.AccessControl.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.accesscontrol\4.5.0\lib\netstandard2.0\System.Security.AccessControl.dll'. NETSDK1036: Choosing 'Platform:System.Security.AccessControl.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.Cryptography.Cng.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.cryptography.cng\4.5.0\lib\netcoreapp2.1\System.Security.Cryptography.Cng.dll'. NETSDK1036: Choosing 'Platform:System.Security.Cryptography.Cng.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.Principal.Windows.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.principal.windows\4.5.0\lib\netstandard2.0\System.Security.Principal.Windows.dll'. NETSDK1036: Choosing 'Platform:System.Security.Principal.Windows.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:Microsoft.Win32.Registry.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.win32.registry\4.5.0\runtimes\unix\lib\netstandard2.0\Microsoft.Win32.Registry.dll'. NETSDK1036: Choosing 'Platform:Microsoft.Win32.Registry.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:Microsoft.Win32.Registry.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.win32.registry\4.5.0\runtimes\win\lib\netstandard2.0\Microsoft.Win32.Registry.dll'. NETSDK1036: Choosing 'Platform:Microsoft.Win32.Registry.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.AccessControl.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.accesscontrol\4.5.0\runtimes\win\lib\netcoreapp2.0\System.Security.AccessControl.dll'. NETSDK1036: Choosing 'Platform:System.Security.AccessControl.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.Cryptography.Cng.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.cryptography.cng\4.5.0\runtimes\win\lib\netcoreapp2.1\System.Security.Cryptography.Cng.dll'. NETSDK1036: Choosing 'Platform:System.Security.Cryptography.Cng.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.Principal.Windows.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.principal.windows\4.5.0\runtimes\unix\lib\netcoreapp2.0\System.Security.Principal.Windows.dll'. NETSDK1036: Choosing 'Platform:System.Security.Principal.Windows.dll' because it comes from a package that is preferred.
1> C:\Program Files\dotnet\sdk\2.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets(41,5): message NETSDK1041: Encountered conflict between 'Platform:System.Security.Principal.Windows.dll' and 'Runtime:C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.security.principal.windows\4.5.0\runtimes\win\lib\netcoreapp2.0\System.Security.Principal.Windows.dll'. NETSDK1036: Choosing 'Platform:System.Security.Principal.Windows.dll' because it comes from a package that is preferred.
1>Target GenerateTargetFrameworkMonikerAttribute:
1> Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
1>Target _CoreGenerateRazorAssemblyInfo:
1> Skipping target "_CoreGenerateRazorAssemblyInfo" because all output files are up-to-date with respect to the input files.
1>Target CoreGenerateAssemblyInfo:
1> Skipping target "CoreGenerateAssemblyInfo" because all output files are up-to-date with respect to the input files.
1>Target CoreCompile:
1> Using shared compilation with compiler from directory: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Roslyn
1> Services\DiagramDataService.cs(19,47,19,59): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Services\TestDataService.cs(9,36,9,48): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\CharacterController.cs(22,36,22,48): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\CharacterController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\AuthorController.cs(22,33,22,45): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\AuthorController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\DiagramController.cs(22,34,22,46): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\StorylineController.cs(22,36,22,48): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\DiagramController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> Controllers\GeneratedControllers\StorylineController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Done building target "CoreCompile" in project "Foo.WebApp.csproj" -- FAILED.
1>
1>Done building project "Foo.WebApp.csproj" -- FAILED.
1>
1>Build FAILED.
1>
1>Services\DiagramDataService.cs(19,47,19,59): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Services\TestDataService.cs(9,36,9,48): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\CharacterController.cs(22,36,22,48): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\CharacterController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\AuthorController.cs(22,33,22,45): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\AuthorController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\DiagramController.cs(22,34,22,46): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\StorylineController.cs(22,36,22,48): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\DiagramController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1>Controllers\GeneratedControllers\StorylineController.cs(20,26,20,38): error CS0246: The type or namespace name 'IDataService' could not be found (are you missing a using directive or an assembly reference?)
1> 0 Warning(s)
1> 10 Error(s)
1>
1>Time Elapsed 00:00:12.29
========== Build: 0 succeeded, 1 failed, 2 up-to-date, 0 skipped ==========
And this is the .csproj file:
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.Web" />
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<!-- Set this to true if you enable server-side prerendering -->
<BuildServerSideRenderer>false</BuildServerSideRenderer>
</PropertyGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<ItemGroup>
<T4ParameterValues Include="SolutionDir">
<Value>$(SolutionDir)</Value>
<Visible>False</Visible>
</T4ParameterValues>
<T4ParameterValues Include="Configuration">
<Value>$(Configuration)</Value>
<Visible>False</Visible>
</T4ParameterValues>
</ItemGroup>
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Compile Remove="ClientApp\dist\**" />
<Content Remove="$(SpaRoot)**" />
<Content Remove="ClientApp\dist\**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="ClientApp\dist\**" />
<None Remove="ClientApp\dist\**" />
</ItemGroup>
<ItemGroup>
<None Remove="ClientApp\src\app\diagram-types.ts" />
<None Remove="foobar.db" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Foo.WebApp.Database\Foo.WebApp.Database.csproj" />
<ProjectReference Include="..\Foo\Foo.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="ClientApp\src\app\diagram-types.ts" />
</ItemGroup>
<ItemGroup>
<None Update="Services\IDataService.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>IDataService.cs</LastGenOutput>
</None>
<None Update="Services\DiagramDataService.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>DiagramDataService.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Compile Update="Services\IDataService.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>IDataService.tt</DependentUpon>
</Compile>
<Compile Update="Services\DiagramDataService.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DiagramDataService.tt</DependentUpon>
</Compile>
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
<DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.Web" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
</Project>
Upvotes: 4
Views: 1283
Reputation: 2038
I've since managed to get it working, but I'm not quite sure why. I assumed that msbuild gathers the files to build, then transforms the t4 templates, then compiles the files it gathered, thus not including the files that were generated as part of the T4 transforms.
The project file listed a <Compile> element for each generated file, with the file name in an "Update" attribute. Changing that attribute to "Include" would cause the files to be included in the build, but this introduced a new problem: now the build would work if the files did not yet exist, but on subsequent builds, the files would be included implicitly by MSBuild on account of being in the project directory, and explicitly via the project file, causing a build error.
I've now used the Condition attribute on each of these elements to check if the file already exists: if it does, the file does not get included (because msbuild will already have done that implicitly), if it doesn't, it will get included (because msbuild won't know about it). This is the resulting .csproj file:
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.Web" />
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<!-- Set this to true if you enable server-side prerendering -->
<BuildServerSideRenderer>false</BuildServerSideRenderer>
</PropertyGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<ItemGroup>
<T4ParameterValues Include="SolutionDir">
<Value>$(SolutionDir)</Value>
<Visible>False</Visible>
</T4ParameterValues>
<T4ParameterValues Include="Configuration">
<Value>$(Configuration)</Value>
<Visible>False</Visible>
</T4ParameterValues>
</ItemGroup>
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Compile Remove="ClientApp\dist\**" />
<Content Remove="$(SpaRoot)**" />
<Content Remove="ClientApp\dist\**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="ClientApp\dist\**" />
<None Remove="ClientApp\dist\**" />
</ItemGroup>
<ItemGroup>
<None Remove="ClientApp\src\app\diagram-types.ts" />
<None Remove="foobar.db" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Foo.WebApp.Database\Foo.WebApp.Database.csproj" />
<ProjectReference Include="..\Foo\Foo.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="ClientApp\src\app\diagram-types.ts" />
</ItemGroup>
<ItemGroup>
<None Update="Services\IDataService.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>IDataService.cs</LastGenOutput>
</None>
<None Update="Services\DiagramDataService.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>DiagramDataService.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Compile Condition="!Exists('Services\IDataService.cs')" Include="Services\IDataService.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>IDataService.tt</DependentUpon>
</Compile>
<Compile Condition="!Exists('Services\DiagramDataService.cs')" Include="Services\DiagramDataService.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DiagramDataService.tt</DependentUpon>
</Compile>
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
<DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.Web" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
</Project>
Now I can clone the project from Git, build, and rebuild as much as I want, and everything will automatically get generated and included in the build.
Upvotes: 4