Automatically nest files in .csproj class libary (DependentUpon) - c#

I have a number of C# files I am generating. I would like them to automatically be nested under the matching C# file inside the Visual Studio solution explorer. For example, Foo.Generated.cs and Bar.Generated.cs would be nested under Foo.cs and Bar.cs, respectively.
If possible I'd like to be able to manage this in my Directory.Build.props file, so all the class libraries in my solution will have the same behavior.
Versions
.NET Core 3.1
Visual Studio 2019 (16.5.3)
Failed Attempt A:
<Compile Update="**\*Generated.cs">
<DependentUpon>$([System.String]::Copy(%(Filename)).Replace('.Generated', '.cs'))</DependentUpon>
</Compile>
Failed Attempt B:
<Compile Update="**\*Generated.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
Failed Attempt C:
<Compile Update="**\*Generated.cs">
<DependentUpon>%(Filename).cs</DependentUpon>
</Compile>
The above approaches have also been tried with:
<ItemGroup>
<ProjectCapability Include="DynamicDependentFile" />
<ProjectCapability Include="DynamicFileNesting" />
</ItemGroup>

If possible I'd like to be able to manage this in my
Directory.Build.props file, so all the class libraries in my solution
will have the same behavior.
First, I think you should use Directory.Build.targets rather than Directory.Build.props. As this document shows, Directory.Build.props is imported very early in Microsoft.Common.props and Itemgroup elements are recognized after MSBuild Properties, so when you add items in Directory.Build.props, these elements will not be recognized by MSBuild.
However, Directory.Build.targets is imported very late which MSBuild already starts to recognize them at that time and with it, you can add any items that can be recognized in that file.
Solution
1) change your file to Directory.Build.targets
2) add these(yours) in it:
<Compile Update="**\*Generated.cs">
<DependentUpon>$([System.String]::Copy(%(Filename)).Replace('.Generated', '.cs'))</DependentUpon>
</Compile>
And it works in my side and hope it could help you.

Related

Why can't I delete *.Designer.cs files?

I've got a simple project which contains resources (localization/globaliztion).
The part of *.csproj file looks like this:
<ItemGroup>
<EmbeddedResource Update="Resources\ErrorMessages.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>ErrorMessages.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\ErrorMessages.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ErrorMessages.resx</DependentUpon>
</Compile>
</ItemGroup>
So, as far as I understand ErrorMessages.Designer.cs file should always be compiled, but when I try to delete it and build the project this file is never compiled (created) and build fails.
I assumed that I could freely add those files to .gitignore but as far as I understand my thought process was incorrect, wasn't it?
The designer files are (re)created, when the file that they represent as C# code does change (is saved/updated, etc.). In this case, the file is only regenerated when the ErrorMessages.resx file is saved/changed/updated. This doesn't happen during a build, but only when the user actively does that. You need to keep the designer files (also in source control) or your build will fail - as you have discovered.
(Note this is not to be confused with Roslyn Source Generators, where the generated files are (generally) not to be kept or checked into source control)

App.config for different environments folder structure

I have multiple config files for the different environments for my C# application. They appear as subitems under App.config. The problem is I want to add a new option, in this case JMTelcom, but it appears outside the folder structure. The file seems to be working fine at compile time, but how do I make it appear next to its siblings?
<ItemGroup>
<Compile Update="App.*.config">
<DependentUpon>App.config</DependentUpon>
</Compile>
</ItemGroup>
Add/append above lines to your .csproj file should do the trick. (Assuming your project is using .net core)

Avalonia exception "Unable to find view for <class name>"

I have a VS solution with the following projects so that I can share UI code between iOS and Windows:
MyApp.UI.Avalonia - a .NET Standard Class Library with Avalonia nuget package
contains XAML/CS files for UI
MyApp.iOS - a Xamarin iOS project, with Avalonia and Avalonia.iOS nuget packages
Depends on
MyApp.Windows - a Windows Application project created from the Avalonia project template (with XAML files deleted)
When I run the Windows application, I get an exception in my App class at the call to AvaloniaXamlLoader.Load(this): System.IO.FileNotFoundException: 'Unable to find view for MyApp.App
It looks like it is failing when trying to find App.xaml, the corresponding XAML file to the App.cs file. It does so by looking for resource with URL something like "avares:/!AvaloniaResourceXamlInfo". When I debug this process in the Avalonia solution's ControlCatalog project, it does find a resource by this name in the shared ControlCatalog class library assembly, and inside that resource it finds all of the XAML files and Assets.
A difference I notice between my project and theirs is that when I right click the project and select Add -> Item -> User Control (Avalonia), it creates a XAML file wrapping a CS file in their project, but in my project it creates the two files merely side-by-side. What project setup am I missing to get the XAML files into this magical "!AvaloniaResourceXamlInfo" resource?
Update:
While I still get the same error, I was able to get the xaml.cs files to encapsulate the corresponding .cs files (so apparently that isn't the only issue) by adding the following to my .csproj file manually (which I found in the ControlCatalog sample project):
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
</ItemGroup>
Have you tried changing the property of the file?
Make sure to align Namespaces with paths in this project.
Avalonia seems to be a bit picky about it.
Despite .Net allows Namespaces and paths to be something different
The project ran without error once I manually added the following to the .csproj file of the .NET Standard library project shared by the Windows and iOS application projects:
<ItemGroup>
<Compile Update="**\*.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>
</AvaloniaResource>
<AvaloniaResource Include="Assets\*" />
<AvaloniaResource Include="Assets\Fonts\*" />
</ItemGroup>
Looks like that <Compile ... tag encapsulates the cs filese into the xaml.cs files, and the rest embeds the xaml files as resources which can be found by Avalonia.

Is there a DependentUpon option in a .net core app?

In my .net core application, I would like to have my partial files put under a given file like it was with a .net framework application using the tag DependentUpon in the csproj.
As shown in a picture, I would like all Program.*.cs files to be under Program.cs.
However, in the .csproj file, I do not see the file listed:
Is there a way to do that in a .net core app?
Yes, you just put an entry in an ItemGroup to update the implicit Compile elements from globbing. I'd personally use a separate ItemGroup element for this, away from your dependencies:
<ItemGroup>
<Compile Update="Program.*.cs">
<DependentUpon>Program.cs</DependentUpon>
</Compile>
</ItemGroup>

T4MVC is generating T4MVC.cs and T4MVC1.cs

VS2017 15.4.1
ASP.NET MVC 5.2.3
T4MVC 4.0.0
AutoT4MVC 1.5.3
Resharper
I have been using T4MVC] for many months in this project without issue. However today each time I change a controller method it is generating two T4MVC files:
instead of updating T4MVC.cs which ultimately means the project wont't compile and I have to delete T4MVC1.cs.
Has anyone seen this behaviour or has some ideas of a fix?
Here's the steps I do to fix it:
Delete T4MVC1.cs file.
Unload your project.
Edit the .csproj file.
Check the following tag:
<Compile Include="T4MVC.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>T4MVC.tt</DependentUpon>
</Compile>
Make sure there's only one of these and it's T4MVC.cs. Remove T4MVC1.cs block if you have it.
Check the following tag:
<None Include="T4MVC.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>T4MVC.cs</LastGenOutput>
</None>
Make sure the <LastGenOutput> is T4MVC.cs. If not, edit it to be T4MVC.cs.
Save the .csproj file.
Reload the project.
Rebuild
Make sure to check in that code so won't cause any trouble in the future.

Categories