Setting up new .Net projects

Intro

I have been a developer for somewhere around 30 years now. In my time I have created a few thousand projects of varying sizes, and for every new iteration I try to improve slightly on my previous. I also see a lot of code from others, and most what I see don’t seem care much about project setup. So I thought I would share how I set up new .Net projects.

This is not a guide in proper architecture or camel casing, and my preferences may vary from yours. You may even find some expert who did a lot of thinking and wrote a book on the subject that disagrees with me. That is fine, you should combine what you learn and find what suits you. The goal here is to have a clean consistent setup. I will try to give the reasoning for why I do it the way I do, staring with some background.

So is this important? Well, failing to name a project properly will usually not break your code. But other people may come into the project later, and having an intuitive easy setup will make their life easier. And making the right decision on platform and initial split of code can save you some refactoring down the road.

Background

At the time of writing we are half-way through 2018 and .Net 4.7.2 is out, .Net Core has matured into the clearly preferred choice for many projects. .Net Core WPF and WinForms support on Windows will be released soon. .Net Standard 2.0 is widely supported.

.Net Standard

.Net Standard is a standardization of .Net frameworks. It is not actual interfaces, but it may help to think of it as a set of common interfaces every .Net implementation must offer. A minimum and uniform set of features all .Net implementations must provide.

This means that if you write a project for .Net Standard 2.0 it will work on all platforms that support .Net Standard 2.0. For example .Net on Windows, Mono, Unity, Xamarin (Android and iOS) and UWP. See here for a detailed list.

A cool feature is that we get binary compatible files. Authors of NuGet packages only need to keep their package within .Net Standard and compile once to support all the platforms. For example when Entity Framework Core was released for .Net Core, it can run on .Net 4.6.1. Want NLog for your Unity 3D project? No problem.

So if you are writing a class library, why not just make it .Net Standard? Well, you could end up needing to pull in dependencies that are not .Net Standard. But that is not a problem, you can change target from .Net Standard to .Net or .Net Core at any time.

Start with .Net Standard on any new library project.

.Net Core

It’s cross platform, fast(!) and generally better in many ways. Community driven and a chance to start fresh and drop a lot of old .Net legacy. If you are starting a new project then most likely this is what you want to use. For example, one of the latest cool features allows you you compile a stand-alone .exe which contains the .Net Core framework and your own code in a single .exe. So the computer running it doesn’t need .Net installed.

With .Net Core a new csproj format was introduced that gives some advantages over the old one. First of all you get a “Edit csproj” mneu item when you right-click it, you can edit it directly. This is nice since it allows you to easily compare and copy-paste for example references from other projects. It also supports implicit include of files (“*.cs”), automatically loads references projects (you load business.csproj, which automatically loads database.csproj), better support for NuGet references and automatically resolves their references.  Generally this translates to less stuff to think of for you. But note that currently it doesn’t support WPF, Windows Forms, ASP.Net Web Forms/ASP.Net 4, etc…

If you need .Net 4.x due to references, interop or whatever then simply change the target. Open csproj file and change from netcoreapp to net. See here for a list of supported targets.

The cool thing about .Net Core framework stuff on NuGet is that its also compiled for .Net Standard, so yes, you can use new .Net Core features in .Net 4.7.

Start with .Net Core on any new ASP.Net or Console project. 

Create new solution

This always starts with creating a new project. I name the solution only “Customer.Solution“, and I name the project “Customer.Solution.Project“. To me this is pretty obvious, but I would guess nearly all of the projects I have seen are named either “Website” (or “WebSite”), or something cryptic like “DynaBo” or “DFN”, that only those in the inner circles know what means. If customer name is long I usually shorten it, three to eight letters is fine.

Giving the project this full name also sets the namespace to the same name, and puts it in a folder named the same. This makes it consistent and very easy to understand what belongs where, especially if I end up pulling in a library from another solution. There are several ways to go to achieve this, but I prefer this because of the simplicity of it.

Notice that the location is set to “C:\Source\<solution>”, and solution name is set to “src” (yes, contrary to what I just said about solution names).

Click OK an a wizard will ask you what project type you want. I often start with WebApi or MVC.

First thing now is to rename “src” to “Tedd.TestProject”. Right click solution and click Rename.

Once this is done I am following a standard folder layout in line with the giants such as ASP.Net, .Net Core, jQuery, Node.js, and many, many more. The reason for this is that Visual Studio will simply create a folder for the solution and a subfolder for each project. This is fine for many projects, but with source control and the need to add more folders and files it is nice that the projects are not in the root folder. I don’t always to though though.

Since our root folder now only contains “src” there is plenty of room for other folders such as “docs”, “tools”, “thirdparty”, etc…

ThirdParty-folder

Sometimes I need to add references to assemblies that are not available on NuGet or we need to add some source code from GitHub.

Some developers reference a file on their own disk, such as “C:\Program Files\SomeVendor\assemblies\SomeFile.dll” and say “you must install vendor package to run this project”. That is almost always wrong, and that .dll-file with its dependencies (or even the whole folder) can be put into the ThirdParty-folder.

Others put the file directly into the bin-folder (yes, the transient compile output folder) and wonder why solution is not working after I go over and clean up the SVN or Git ignores.

Often libraries are shared by multiple projects in a solution So I use a place, outside the solution itself, to put third party files. That is also a good place to keep a copy of the license for these files.

Git or SVN ignore

When using source code repositories there are a lot of “junk” files I don’t want committed/pushed/checked in. For example being asked to check in all binary files every single time can be a hassle, and checking them in does nothing more than waste space and lead to merge conflicts. They are recreated every time I compile, so there is no point in saving them. The same goes for user settings file, Visual Studio temp folder, ReSharper-folder, etc…

If I am using Git I simply google github visual studio ignore, grab https://github.com/github/gitignore/blob/master/VisualStudio.gitignore and save it as .gitignore inside src-folder. If I add source files in ThirdParty-folder I may also want to copy it to those source folders too.

If I am using SVN I’ll need to manually add ignore of a few files and folders. For each project you want minimum to ignore the bin and obj-folders, and any .suo. Look at the .gitignore for the rest.

Experiment: Run ASP.Net Core on >=.Net 4.6.1

I did this so you can do it if you need to. Run your project and see that it works on .Net Core.

This is just to demonstrate that it is possible. Unless you have a very good reason to run ASP.Net Core on .Net you should not do this.

As I mentioned earlier, .Net Standard is good. ASP.Net Core is written highly modular, where much of the key components are downloaded over NuGet. And most of these components target .Net Standard 2.0. This means that they run just fine on .Net 4.6.1 and up. We will use .Net 4.7.2, which is the latest at time of writing.

Right click the project (Tedd.TestProject.WebUi) and select “Edit Tedd.TestProject.WebUi.csproj”.

As expected the target framework is “netcoreapp2.1”, which translates to .Net Core 2.1.

Replace “netcoreapp2.1” with “net472” (from this list). (Note that .Net Standard can’t be used for executable such as web or console.)

The package “Microsoft.AspNetCore.App” (which recently replaced “Microsoft.AspNetCore.All” to help lower third party dependencies) is a combined package containing all packages needed to do ASP.Net development on .Net Core. It does not target .Net Standard because the package contains a few packages that are .Net Core specific, mainly the .Net Core runtime and libuv. Libuv is a native library used by Kestrel web server, it will soon replaced by managed sockets library. We can download “Microsoft.ASpNetCore.App” and add the packages manually, removing the two that doesn’t work. The config we end up with then is:

I had to “Upgrade” (force download) all components to make them work, since the already downloaded version is for .Net Core. Something like “UpdatePackage reinstall Project Tedd.TestPRoject.WebUi” from Package Manager Console should work. And with this config we are running on .Net 4.7.2. Fantastic. That was fun. Now reset it back to .Net Core by copying the initial config back.

Adding libraries

I usually don’t put all my code one project, unless its a small project with clear and limited scope. I allow myself to be a bit pragmatic in my choices, so I don’t go for a full architecture for everything. But when I do, there are some guidelines I follow. I will get back to them in a later blog post, so for now just a few samples.

Database

First out in our example is the database project.

Again I name it with its full namespace. This time i use .Net Standard Class Library. As I demonstrated in the experiment above, you can easily change this to .Net 4.6.1 or above, or .Net Core. The difference is that a library doesn’t use the “Microsoft.AspNetCore.App” so you don’t have to create all those references. Since .Net Standard can only reference .Net Standard, changing it doesn’t even require re-downloading any packages.

Notice after adding the .Net Standard library that it is using the new csproj, it can be edited to use a new target. And if we add Entity Framework Core through NuGet we see that it also uses .Net Standard 2.0.

Models

Sometimes models must live in their own project to make dependencies work. Other times they can be split between Database and main project. This depends on the project. Either way I almost always put models into a project or folder named Models, possible with subfolders if the project is big enough. Separation of data and logic doesn’t seem to be very clear to many, and I see a lot of projects that mix this. I say always, because there are many reasons why I do it differently. But for a vanilla web project I think clarity and least surprise is important.

Enums

I do the same for enums, where I put them in a separate folder. The reason is that I usually don’t navigate much to enums, and when I do its through F12/ctrl-click or similar. The reason for defining an enum is usually to share it between mutliple parts of the code, so it doesn’t necessarily make sense to put them along with the code files.

Other things…

  • One class per file, even enums.
  • Namespace always matches folder structure.

Summary

  • Naming convention such as Customer.Solution.Project should be followed. The projects name is the same as the root namespace is the same as the folder name. Clear and consistent.
  • A standard folder structure makes it easier to navigate the project.
  • .Net Core projects are preferred, and can run under .Net 4.6.1 and up.
  • .Net Standard libraries are preferred, and can easily be changed into another target if required.

1 thought on “Setting up new .Net projects”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Tedds blog

Subscribe now to keep reading and get access to the full archive.

Continue reading