Skip to content

How Projects Work

Zingabopp edited this page Apr 8, 2021 · 2 revisions

Project Definition

The .NET project you work with in Visual Studio is actually comprised of several projects merged together behind the scenes. You have the common projects provided by Microsoft that do a lot of fancy things to make your project build (in older style projects, this comes from the line <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />, the newer SDK projects import something similar with <Project Sdk="Microsoft.NET.Sdk"> at the top of the project file). The project files you may work with are:

  • The csproj file in the project folder
    • Defines properties, references, and other things specific to your project.
  • Directory.Build.props and Directory.Build.targets
    • When the build system runs, it will automatically search up the directory tree until it finds these files (or reaches the root drive) and import them into the project if they are found.
    • The BeatSaberModdingTools templates make use of these to define the project properties and prebuild/postbuild targets that go into actions like copying the mod to your Beat Saber's Plugins directory and automatically creating zip files for Release builds.
      • These files were used for this so they don't pollute the csproj folder and make it easier to update them with new functionality or drop them into other projects.
  • The csproj.user file in the project folder
    • The build system automatically imports the <YOUR PROJECT NAME>.csproj.user file.
    • The csproj.user file can override most things in the csproj folder. It is commonly used to override properties that may be machine specific without affecting the project for other people (i.e. someone forking the project can change where the project looks for Beat Saber files without changing the project for the owner).
      • Used in most Beat Saber projects to override the BeatSaberDir property, which tells projects where to find the game assemblies (if they use this property and are correctly set up). You can see how the csproj.user file works here:

On top you have the csproj file. By default this project tries to use game assemblies that are in the directory Refs in the Solution folder. If Refs doesn't exist then BeatSaberDir is blank. When a csproj.user file (shown below) is loaded, it replaces BeatSaberDir with its own value, in this case I:\Steam\SteamApps\common\Beat Saber. Now all the references that use BeatSaberDir in the HintPath will be looking in the correct folder.


Project Structure

Projects are composed mainly of three things:

  • Properties
    • Defined inside a PropertyGroup.
    • Project variables that can be assigned values.
    • Referenced in the project using the format $(PropertyName).
  • Items
    • Defined in an ItemGroup.
    • Can have metadata in the form of attributes or child elements.
    • Grouped into collections according to their type.
    • Usually used to represent files.
    • The group is referenced using the format @(TypeName)
  • Targets
    • Defined under the Project element.
    • Represents a set of instructions for the build system to perform.
    • Must define at least one target to run before or after.
    • Can contain their own PropertyGroups and ItemGroups
<!-- 
    In this example we define a property 'TargetDirectory' with the value 'Output'.
    Then a collection of items with the type 'FileToCopy'.
    After the target 'Build' runs, our target, 'CopyFiles', will run where it will copy 'File1.txt' and 'File2.txt' to folder named 'Output'
    -->
<Project>
    <PropertyGroup>
        <TargetDirectory>Output</TargetDirectory>
    </PropertyGroup>
    <ItemGroup>
        <FileToCopy Include="File1.txt" />
        <FileToCopy Include="File2.txt" />
    </ItemGroup>
    <Target Name=CopyFiles AfterTargets="Build">
        <Copy SourceFiles="@(FileToCopy)" DestinationFolder="$(TargetDirectory)" />
    </Target>
</Project>

For a more detailed look at how projects work, you can see the Microsoft documentation Here.


Home