Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
.NET project structure
$/
  artifacts/
  build/
  docs/
  lib/
  packages/
  samples/
  src/
  tests/
  .editorconfig
  .gitignore
  .gitattributes
  build.cmd
  build.sh
  LICENSE
  NuGet.Config
  README.md
  {solution}.sln
  • src - Main projects (the product code)
  • tests - Test projects
  • docs - Documentation stuff, markdown files, help files etc.
  • samples (optional) - Sample projects
  • lib - Things that can NEVER exist in a nuget package
  • artifacts - Build outputs go here. Doing a build.cmd/build.sh generates artifacts here (nupkgs, dlls, pdbs, etc.)
  • packages - NuGet packages
  • build - Build customizations (custom msbuild files/psake/fake/albacore/etc) scripts
  • build.cmd - Bootstrap the build for windows
  • build.sh - Bootstrap the build for *nix
  • global.json - ASP.NET vNext only

.gitignore

[Oo]bj/
[Bb]in/
.nuget/
_ReSharper.*
packages/
artifacts/
*.user
*.suo
*.userprefs
*DS_Store
*.sln.ide

There's probably more things that go in the ignore file.

  • Update: Added docs folder
  • Added README.md and LICENSE - Critical if you're OSS, if not ignore it
  • Renamed test to tests
  • Added lib for things that CANNOT exist in nuget packages
  • Removed NuGet.config for people using packet :)
  • Added global.json for ASP.NET vnext
  • Added .editorconfig file in the root (x-plat IDE settings)
  • Added NuGet.config back because people were confused about it missing
@daveaglick
Copy link

daveaglick commented Jan 24, 2020

That breaks the ability to do things like place a directory.build.props and targets that apply to just tests or samples

+1 - having a dedicated test directory props has been awesome, especially when rigging up test coverage reports for all test projects:

<Project>
  <Import Project="../Directory.Build.props" />
  <PropertyGroup>
    <CodeAnalysisRuleSet>..\..\tests.ruleset</CodeAnalysisRuleSet>
    <IsPackable>false</IsPackable>
    <DefaultItemExcludes>$(DefaultItemExcludes);TestResults\**;coverage*</DefaultItemExcludes>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="coverlet.msbuild" Version="2.7.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="AzurePipelines.TestLogger" Version="1.0.3" />
    <PackageReference Include="nunit" Version="3.12.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
    <PackageReference Include="Shouldly" Version="3.0.2" />
  </ItemGroup>  
</Project>

@gsscoder
Copy link

gsscoder commented Jan 27, 2020

@davidfowl, this is a necessity I actually didn't experimented. But thank you for pointing it out.

@beef3333
Copy link

beef3333 commented Feb 3, 2020

@davidfowl, really like this structure. I am working on an application that uses helm for deployments and am trying to decide the best place to put the chart definitions. Maybe a deployment folder?

@davidfowl
Copy link
Author

davidfowl commented Feb 3, 2020

@beef3333 yes that sounds good

@gsscoder
Copy link

gsscoder commented Feb 4, 2020

@davidfowl, a scaffolding CLI tool too?

@gsscoder
Copy link

gsscoder commented Feb 16, 2020

I admit I was wrong putting everything on src, it doesn't suit to build using Azure Pipelines.

@jnm2
Copy link

jnm2 commented Feb 16, 2020

Azure Pipelines and src have been working fine for me.

@gsscoder
Copy link

gsscoder commented Feb 16, 2020

@jnm2, I mean everything... The solution file, the test and sample project along with the main one.

@jnm2
Copy link

jnm2 commented Feb 16, 2020

Yes, that's how I do it too and I haven't noticed an issue on Azure Pipelines. What are you seeing?

@gsscoder
Copy link

gsscoder commented Feb 16, 2020

It's a just a matter of comfort for defining glob patterns etc. Not a real obstacle, but sticking to this layout fits more natural to me.

And since I'm new to Azure development, I prefer keep things simple.

@kirkone
Copy link

kirkone commented Aug 17, 2020

@davidfowl I want to add two things:

  1. In my case I used pipelines instead of build. This will prevent some trouble with the default .gitignore file for Visual Studio.
  2. It would be very nice to have the compiled information of this discussion in a better visible place in the official docs.

Thanks,
KirK

@sharpninja
Copy link

sharpninja commented Aug 17, 2020

Is there a repo I can clone?

@tiny-dancer
Copy link

tiny-dancer commented Aug 20, 2020

+1 to @kirkone

@davidfowl, i think it's time to evolve into a full repo :) similar to https://github.com/golang-standards/project-layout

@TheAngryByrd
Copy link

TheAngryByrd commented Aug 20, 2020

@sharpnina @tiny-dancer Take a look at MiniScaffold creates a repo via dotnet template. It's starts with F# but you can move over to C# pretty easily.

@virzak
Copy link

virzak commented Aug 21, 2020

Pretty sure these two are extremely common:

  • CHANGELOG.md
  • Directory.Build.props

Less common are:

  • git-hooks/
  • package.json
    • For packages like husky to run commit hooks like dotnet format for c# code and xstyler for xaml

@D3MaxT
Copy link

D3MaxT commented Aug 26, 2020

@davidfowl
Hello David.
Where would you recommend putting a self-signed ROOT certificate that gets added to docker images in local development only? Would that go under build or something else?

Thank you.

@sharpninja
Copy link

sharpninja commented Aug 26, 2020

@davidfowl
Where would you recommend putting a self-signed ROOT certificate that gets added to docker images in local development only? Would that go under build or something else?

I would not put them in GIT, and GitHub may even block them. Instead, create a powershell script to create and register the cert and place it's path in an environment variable, then have the Dockerfile get the file path from the environment.

@D3MaxT
Copy link

D3MaxT commented Aug 26, 2020

@davidfowl
Where would you recommend putting a self-signed ROOT certificate that gets added to docker images in local development only? Would that go under build or something else?

I would not put them in GIT, and GitHub may even block them. Instead, create a powershell script to create and register the cert and place it's path in an environment variable, then have the Dockerfile get the file path from the environment.

Hello sharpninja,
I appreciate the response, but I am not sure this would work. This cert gets added to each image by using a dockerfile.dev and then the docker.compose file builds that docker dev file during local development only. So it uses a COPY instruction to copy the certificate into the image and a RUN instruction to run update-ca-certificates on the Debian Linux used by the container. As far as I know, you can't do this with PowerShell. Also, as far as I know, you can't use COPY with files outside of the docker build context, so you can't use files outside the directory where the docker files are.

I could not find a better way of getting a self-signed certificate into a docker image, so the certificate is included in the Solution (it's a public only side, no private key, so I don't mind putting into a Git repo).

Thank you.

@sharpninja
Copy link

sharpninja commented Aug 26, 2020

As far as I know, you can't do this with PowerShell.

There is quit literally nothing you cannot do with PowerShell. Read about New-SelfSignedCertificate which generates a cert you can keep locally and include in your Dockerfile.

@gigi81
Copy link

gigi81 commented Apr 2, 2021

Hi, I created a tool to automate this process https://github.com/gigi81/dotnet-newrepo/
It doesn't include everything mentioned here but most of it is there. I would appreciate anyone taking the time to try it and give some feedback. In short here is how to use it (more details on the readme of the project):

dotnet tool install dotnet-newrepo --global

#first create a directory host your repo
mkdir Organization.Project
cd Organization.Project
#then create the init.yml file (this file is used to specify a few settings like your github username/repo)
newrepo init
#customize the init.yml file with your custom settings
notepad init.yml
#then finally create the repo
newrepo

@agilenut
Copy link

agilenut commented Apr 19, 2021

@davidfowl - Curious if you still consider this current or if there are some lessons learned since it was created.

@ShreyasJejurkar
Copy link

ShreyasJejurkar commented Apr 30, 2021

I created a .NET CLI tool for this => https://github.com/MCCshreyas/Project

@tombohub
Copy link

tombohub commented May 22, 2021

how do you organize src folder?

@sarvasana
Copy link

sarvasana commented May 22, 2021

By dragging files and folders around until you are happy.

@fgimian
Copy link

fgimian commented Jul 12, 2021

This is a great starting point, thanks!

For generating the gitignore file, you can always use the dotnet CLI as follows;

dotnet new gitignore

Also, I think we should pretend batch scripts never existed and always assume that it will be a PowerShell script build.ps1 that starts the build 😄 PowerShell is a significantly more robust scripting language and well worth knowing IMHO.

I think it also would be good to clarify whether sub-directories should be present in src and tests if there's only one project. For example, dotnet-format places the project at the root of src and tests directories which may be appropriate if only one project is present, but is this a good approach?

Huge thanks for the gist 😄
Fotis

@ambrosektal
Copy link

ambrosektal commented Jul 27, 2021

Can someone help me understand this? What is an example of:
"lib - Things that can NEVER exist in a nuget package"?
I thought I could build a nuget package to hold anything?

@fvilches17
Copy link

fvilches17 commented Aug 3, 2021

Hi @davidfowl thanks for sharing. Where would you put pipeline-related files? (e.g. azure-pipelines.yaml, resource-group.bicep, etc.)

@jedjohan
Copy link

jedjohan commented Aug 19, 2021

Hi @davidfowl thanks for sharing. Where would you put pipeline-related files? (e.g. azure-pipelines.yaml, resource-group.bicep, etc.)

Sorry not David but a tip:

  • we put pipelines in /build (yaml pipes)
  • we put IaC (.bicep) in a folder named /infra

@fgimian
Copy link

fgimian commented Aug 19, 2021

I have a further thought too. I realise I'm in the absolute minority here, but I find it odd that we shorten source to src and libraries to lib yet there's no good reason to do this and we don't do this for any other folder. This really feels more historical than logical to me personally and doesn't make my OCD happy 😄

As such, I'm personally using source as my source folder ... does that make me a bit of an outcast? 😨

I personally put my azure-pipelines.yaml in the root folder but agree that it probably would be better in the build directory.

@fvilches17
Copy link

fvilches17 commented Aug 29, 2021

Hi @davidfowl thanks for sharing. Where would you put pipeline-related files? (e.g. azure-pipelines.yaml, resource-group.bicep, etc.)

Sorry not David but a tip:

  • we put pipelines in /build (yaml pipes)
  • we put IaC (.bicep) in a folder named /infra

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment