ASP.NET Core – Best practices (tips and tricks) – an opinionated approach – Part 2
Introduction
In the last post, we talked about tips and tricks, different strategies and approaches to make your code and project easier to maintain.
This post is the second part in the series.
Avoid HTML Helpers – Use Tag Helpers
We should avoid using HTML Helpers in favour of Tag Helpers.
Tag Helpers are also processed and rendered on the server. However, they are more HTML friendly, and they remind of Angular’s directives.
They can be either attributes or elements. We can extend existing HTML elements with our own custom Tag Helpers as well.
We talked about Tag Helpers on several occasions, so if you are interested in it, you can check out the series on TagHelpers.
Use View Components
View Components are another new feature of ASP.NET Core MVC.
In old ASP.NET MVC, if we wanted to extract a part of the view to another reusable view, we could use partial views. However, that was only possible if it was using the same model as its parent view. However, if you want to extract and render a chunk of HTML that uses another model you would have to use @Html.Action
And that would callback into controller action as a child request. And it worked most of the time. However, in some situations, child actions would get very weird.
Child actions are not present in ASP.NET Core MVC. However, we can use View Components instead.
Use Webpack
If you ever worked with client-side, you had to bundle and minify your files. One of the great solutions for this was Grunt, then came Gulp and that was even better. Both are a built on top of Node and used as Node packages (npm). Then Webpack came. The rise in usage of ES2015 and ES modules increased the need for module loaders and bundlers. There is Browserfiy, which lets you write modules like you would do in old Node-style (require, export) or ES6 modules and make them browser ready for all browsers. Then there was Webpack
Then there was Webpack, which is in core module bundler and it will bundle all your JS, CSS. Anything you throw at it, Webpack will treat as a module. You can use all kind of plugins with it and work with React, Angular, TypeScript and almost anything that you could need.
The recommendation is to use multiple configuration files with Webpack. We could use one configuration for vendor code and one configuration for our application’s code that is changing all the time.
Use Karma as a Test Runner
Originally written for AngularJS by Angular Team. However, it is probably the best Test Runner for JavaScript out there which requires minimal configuration.
Use ConEmu or cmder for Windows
When you are working with command-line tools, and you try it on Linux or Mac, you never really get to feel like at home when you are inside of Windows built-in command line. My unhappiness was even bigger once I tried Mac’s iTerm in combination with Oh My Zsh. After that, whenever I used cmd or PowerShell for dotnet and JS I was heartbroken.
Yes, there is Git Bash, but that’s just basic. I also tried HyperJS, but it never worked as I wanted it.
Then I tried cmder and ConEmu, and that’s when I finally found something good enough. If you are on Windows 10, there are also ways to use built-in Linux Bash with Cmder or ConEmu.
If you are using Windows and have not tried ConEmu yet, I would advise you to do so.
NuGet and npm Only
The recommendation is to use npm only for your client-side and for server-side there is NuGet. Microsoft developers have been encouraged to use bower over last few years, especially since the bower support first came with VS 2015. However, bower has been deprecated and almost any package that you used and had bower support, it probably .” npm as well. With webpack and npm you won’t be needing bower.
Another reason for this is that TypeScript team decided to use npm packages as a source for TypeScript type definitions. TypeScript compiler will now look inside of npm installed modules to see if there are matching types for the library that you are using.
TypeScript
If you are doing client-side development and you have not tried TypeScript for projects, I would recommend you to go for it!
For smaller projects that are not going to grow and will not be too consuming, quite often the effort to set up the TypeScript on the project is not worth it. But on larger projects, it pays off!
I have been using TypeScript on and off on my projects, for few times in periods of few months, and I can definitely say it makes a lot of things easier and more enjoyable. At least for me.
Benefits are huge. Some of the main advantages that come to the mind are:
- Types of course! Static type checking is helpful!
- IntelliSense
- Interfaces
- Building on previous ones there is – Tooling Support
- Strict null check – this checks every possible solution where your code and your objects could be null, and you will get a compiler error if you are trying to use a property of something that can be null and you haven’t checked it.
- Control flow based type analysis
- Generics
Strict null check examples:
Control flow based type analysis example:
function foo(x: string | number | boolean) { if (typeof x === "string") { x; // type of x is string here x = 1; x; // type of x is number here } x; // type of x is number | boolean here } function bar(x: string | number) { if (typeof x === "number") { return; } x; // type of x is string here }
Regarding types and auto-completion: Yes, WebStorm and other great editors have auto-completion support, and they will help you a lot, but they also show tons of other stuff. And when you have tons of related files it is not so precise and accurate, and you can quite often mismatch a property name.
Client-side code folders
You should have your original code (JavaScript modules, or not TypeScript files in your client-side folder) in Client or some other folder. And the output/compilation/bundle of those files should go to wwwroot.
As Scott says “wwwroot is your bin\ folder”.
Tests
For open source libraries or larger applications that have a lot of unit tests, one test project for every project is probably what you will do. For business applications that do not have such requirements having one Test Project and organizing the tests into folders is not a bad idea.
Recommend framework for unit tests is xUnit. It is extensible, flexible, open source and has a good vocabulary. It is quite easy to get started with it.
If you wanna to test the code inside of your Startup class, something that is forming and processing middleware you should check out ASP.NET Core Test Host.
ASP.NET Core includes a test host that can be added to test projects and used to host ASP.NET Core applications, serving test requests without the need for a real web host.
EF Core In-Memory provider
EF Core In-Memory provider will keep all the data in memory while letting you to do almost anything that you usually do with Entity Framework.
The in-memory provider is especially useful for tests. Another usage would be for smaller applications where you just want to demo something.
It is important to note that every DbContext that you create will use the same instance of the in-memory database. However, you could set up your DbContext constructor to create a new instance of in-memory DB every time.
Entity Framework Core In-Memory provider is not to meant to be used in production!
Don’t use the Async suffix
This one is debatable.
For extending the old (legacy) code, adding Async suffix is sometimes mandatory since in C# you can not overload a method based on its return type. Also, when adding an async method on API that already has the same synchronous method, it makes sense to name the new with Async suffix.
Scott recommends to not use Async suffix for methods of new APIs and libraries that you are building. I agree with this. This mostly goes for libraries that usually go full async and have almost all of the methods on API exposed as async methods.