Joshua's Docs - ASP.NET + Some C# Notes

Warning:

Most of this will be .NET core stuff, since that is where I am starting with my learning / first project. I tend to focus on web stuff, so notes will probably also be heavy on the ASP.NET MVC side of things vs Mono / apps.

I also tend to make a lot of comparisons to other frameworks, especially Laravel, as I see a lot of overlap (.NET CLI vs Artisan, Razor vs Blade, etc.)

Resources

What Type Link
My C# Cheatsheet Cheatsheet Link
.NET Videos Video Series .NET Learning Center
Breakdown of JSON config files in a .NET Core project Guide TalkingDotnet
Default .gitignore Documentation .gitignore
.NET Core MVC Overview Overview Guide MSDocs
awesome-dotnet-core Collection Github

How to run / where is my package.json?

Typically .NET apps have the parts of a normal node/JS package.json file broken up into different parts and files.

  • Dependencies
    • Managed through either {ProjectName}.csproj (project file) or packages.config
      • Within a .csproj file, NuGet packages are referenced by <PackageReference Include="" Version="" /> XML
    • obj/project.assets.json is equivalent to package-lock.json, but unlike the typical recommendation for NPM, MS recommends that you do not commit this file to VC.
  • Tasks
    • Things like building and launching are normally handled through the .NET CLI commands, and it would be up to you to integrate a task handler (like grunt) if you wanted to automate those commands
      • However Properties/launchSettings.json does affect how those CLI commands execute
      • Many IDE's will create their own task config files when it notices you are trying to run a C#/DotNet app. These files usually just automate the running of CLI commands. For example, VSCode will create two files:
        • .vscode/launch.json
        • .vscode/tasks.json
  • Version # / Meta information about your own project
    • Should be in your {ProjectName}.csproj (project file)
    • You can add tons of key pairs under PropertyGroup:
      <PropertyGroup>
      	<TargetFramework>netcoreapp2.2</TargetFramework>
      	<Authors>Larry Fine</Authors>
      	<Company>Howard, Howard, and Fine INC</Company>
      	<Copyright>Copyright 2019</Copyright>
      	<!-- etc -->
      </PropertyGroup>
    • Full list of respected metadata inputs here

An actual NPM package.json file might or might not exist in your project depending on how you scaffolded the project and what the stack looks like. If it was not generated / included, there is nothing stopping you from adding one yourself; just keep in mind how Core handles the stuff above.

Hot rebuilding / hot reloading

The new .NET core CLI includes a command for file watching and hot-rebuilding:

dotnet watch run

However, that only handles the live-rebuilding of the server-side stuff; it won't auto-refresh your browser window like other hot-reload tools. To do that, you need to add an external dependency, the recommended tool being browsersync. You can find instructions for this step here.

Scaffolding / creating solutions

Similar to other in-all-one frameworks like Laravel, .NET has a substantial amount of boilerplate scaffolding. If you are using Visual Studio (note: not VSCode), the recommended way to create new things is with the Solution Explorer. For example, if you are building a MVC app and wanted to add a new Controller, you would select Controllers > Add > Controller, and then pick a Add Scaffold type (empty, API controller, pre-wired to EF, etc.).

Without Visual Studio, for example if you are using VSCode, there are two possible ways to accomplish the same thing as above. The first is to just manually create your files by hand; this is what some of the official guide pages recommend (for example, to add a controller). However, this really is not the same thing as a scaffolding, now is it?

Another option is to install a special scaffolding CLI tool. The tool of choice seems to be aspnet-codegenerator, and a guide for its initial setup can be found here or here. Once it is installed and setup, you can call it from the command line and scaffold most of the same types that you would normally use the Solution Explorer for if you had Visual Studio installed. For example, to accomplish the task of adding a controller, we might use something like:

dotnet aspnet-codegenerator controller \
-name UserController \
-api \
[... more options]

.NET Core MVC or API

Example projects

Using .NET API as backend with SPA frontend

There is built-in scaffolding to build this out. For example, dotnet new react -au Individual will create React project with built-in authorization. See this page for details.

If you want to custom build everything yourself, you can still use .NET to serve the static SPA files. Know how to use these things:

  • services.AddSpaStaticFiles
  • app.UseStaticFiles
  • app.UseSpaStaticFiles
  • app.UseSpa

Here is a guide for getting this to work with Vue.

Guides:

EF Core

Guide- start page

General initial steps:

  • Install nuget packages (EF Core & the driver you need, such as SQLite)
  • Create DbContext based class to provide DB connection
  • Set connection string (either through DbContext or startup)
  • Add DbContext through Startup.cs -> services.addDbContext<{YourDbContextClass}>();
  • Make migration files
    • dotnet tool install --global dotnet-ef & dotnet add package Microsoft.EntityFrameworkCore.Design (one time install)
    • dotnet ef migrations add InitialCreate
  • Run initial migration: dotnet ef database update

Common commands- see EF Core Tools CLI reference

  • Help
    • dotnet ef -h

Data Context Class & Objects

Docs:

As I understand it, a Data Context is a short-lived instance (aka session) that represents the connection established between a database (such as SQL) and the running code itself. A Data Context Class is what defines the generic parameters of this context, and does so by implementing the system.IDisposable interface, or in the case of EF6, implements DbContext which implements system.IDisposable.

It exposes direct methods to use the DB, such as executeQuery(), or certain framework components, such as Entity Framework, wrap the connection in further methods and exposed interfaces.

This is pretty similar to other languages and frameworks; it is very common with databases to have a class that abstracts the startup and teardown process of handling a DB connection.

ORM

Most of the docs and solutions will point you towards using EF (Entity Framework) as your ORM. However, most people will recommend that, if you are concerned about performance, you switch to using Dapper (built by StackExchange).

See this,and this, and Dapper's own performance measurements here.

Authentication

Pretty much anything having to do with .NET Core auth is going to involve the Microsoft.AspNetCore.Identity namespace and dependencies, and this is the general starting spot.

If you want to use automatic scaffolding, you can either do it while setting up a brand new project, or use the solutions explorer -> add -> identity.

Some standard considerations:

  • The user model should extend IdentityUser
  • Startup.Configure should call app.UseAuthentication()
    • Also app.UseIdentityServer() if using OpenID
  • Startup.Services should call
    • services.AddDefaultIdentity or services.AddIdentity
    • .AddEntityFrameworkStores
  • No matter how you scaffolded (or didn't) identity, you will also need to make EF migrations:
    • dotnet ef migrations add CreateIdentitySchema
    • dotnet ef database update

See this, this, and this for guides on manual overrides.

API controllers and routing

Returning JSON

public JsonResult get(int id){
	return Json(new {
		keyAlpha = "valueAlpha",
		keyBeta = "valueBeta"
	});
}

Reading POST form data

The default syntax for using [FromBody] is rather misleading...

[HttpPost]
public void Post([FromBody] string name) {
	User user = new User { Name = name };
}

If you make a typical POST with a JSON body that looks like this:

{
	"name": "Mad Hatter"
}

The value of name will actually be null! This is because, if there is only one parameter taken in via FromBody, .NET expects that the body of the POST is not json, but instead is just the value. See this S/O.

So how do you accept complex bodies? You have a few options...

Use a model

Assuming you have a model setup to mirror the body, you can map the POST body to the model easily:

[HttpPost]
public void Post([FromBody] User userFromPost) {
	// No code needed! `userFromPost` is ready to use!
}

Be very careful about this sort of direct model binding though; this allows all properties of the bound model to be set via API request, whereas you might want certain things (user.isAdmin) to be read-only via API. In this case, use one of the solutions outlined here, or manually instantiate a new object and map the input:

[HttpPost]
public void Post([FromBody] User data) {
	User user = new User { Name = data.Name };
}

Manual parsing

If you don't declare any arguments, you can read off raw things from the request, like Request.Body, or Request.Headers, and so on.

Example:

using Newtonsoft.Json;
using System.Text;
// ...
[HttpPost]
public async void Post() {
	using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
	{
		string bodyText = await reader.ReadToEndAsync();
		User userJson = JsonConvert.DeserializeObject<User>(bodyText);
		User user = new User { Name = userJson.Name };
	}
}

See this in-depth post that explains this in detail.


Accessing appsettings.json values inside classes

See StackOverflow (1) and MSDocs

Dependency Injection (DI)

Dependency Injection, often just referred to as DI, is a concept common both in and outside of .NET and C#. Please see my notes here

Logging

Usually, if you are starting with a scaffolded app, VisualStudio will have already included the standard MS logging packages, such as Microsoft.Extensions.Logging.

To use the standard logging library, you need to add the namespace, and either take an instance of the logger via DI, or via LoggerFactory instantiation.

public class HomeController : Controller {
	private readonly ILogger _logger;
	public HomeController(ILogger<HomeController> logger) {
			_logger = logger;
	}
}

Visual Studio stuff

Moving .sln (solution) file

  • Open the file and edit the path string
  • Delete any .suo files in dir (they will be hidden files, and will rebuild on relaunch)

CLI

Troubleshooting

Use -v "verbose" flag with many commands for more details, such as failed migrations

Markdown Source Last Updated:
Mon Mar 29 2021 05:56:27 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Mon Sep 09 2019 00:33:36 GMT+0000 (Coordinated Universal Time)
© 2024 Joshua Tzucker, Built with Gatsby
Feedback