mirror of
https://github.com/m-lamonaca/dev-notes.git
synced 2025-04-06 19:06:41 +00:00
Merge branch 'main' of https://github.com/m-lamonaca/ProgrammingNotes
This commit is contained in:
commit
4817b5b939
5 changed files with 74 additions and 262 deletions
BIN
.images/dotnet_covariant_contravariant.png
Normal file
BIN
.images/dotnet_covariant_contravariant.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -127,8 +127,9 @@ find [start-position] -type f -name FILENAME # search for a file named "filenam
|
|||
find [start-position] -type d -name DIRNAME # search for a directory named "dirname"
|
||||
find [path] -exec <command> {} \; # execute command on found items (identified by {})
|
||||
|
||||
[ -f "path" ] # test if a file exists
|
||||
[ -d "path" ] # test if a folder exists
|
||||
[[ -f "path" ]] # test if a file exists
|
||||
[[ -d "path" ]] # test if a folder exists
|
||||
[[ -L "path" ]] # test if is symlink
|
||||
```
|
||||
|
||||
### Other
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
# ASP.NET Configuration
|
||||
|
||||
## `.csproj`
|
||||
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<!-- enable documentation comments (can be used for swagger) -->
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
|
||||
<!-- do not warn public classes w/o documentation comments -->
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
```
|
||||
|
||||
## `Program.cs`
|
||||
|
||||
```cs
|
||||
|
@ -84,6 +96,14 @@ namespace App
|
|||
services.AddScoped<ITransientService, ServiceImplementation>();
|
||||
services.AddTransient<ITransientService, ServiceImplementation>();
|
||||
|
||||
// add swagger
|
||||
services.AddSwaggerGen(options => {
|
||||
|
||||
// OPTIONAL: use xml comments for swagger documentation
|
||||
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -99,6 +119,7 @@ namespace App
|
|||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
|
||||
|
@ -106,6 +127,9 @@ namespace App
|
|||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
// MVC routing
|
||||
|
|
|
@ -1,181 +1,5 @@
|
|||
# ASP .NET REST API
|
||||
|
||||
## Startup class
|
||||
|
||||
- Called by `Program.cs`
|
||||
|
||||
```cs
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace <Namespace>
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers(); // controllers w/o views
|
||||
//or
|
||||
services.AddControllersWithViews(); // MVC Controllers
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## DB Context (EF to access DB)
|
||||
|
||||
NuGet Packages to install:
|
||||
|
||||
- `Microsoft.EntityFrameworkCore`
|
||||
- `Microsoft.EntityFrameworkCore.Tools`
|
||||
- `Microsoft.EntityFrameworkCore.Design` *or* `Microsoft.EntityFrameworkCore.<db_provider>.Design`
|
||||
- `Microsoft.EntityFrameworkCore.<db_provider>`
|
||||
|
||||
In `AppDbContext.cs`:
|
||||
|
||||
```cs
|
||||
using <Namespace>.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace <Namespace>.Repo
|
||||
{
|
||||
public class AppDbContext : DbContext
|
||||
{
|
||||
public AppDbContext(DbContextOptions<ProjectContext> options) : base(options)
|
||||
{
|
||||
|
||||
}
|
||||
//DBSet<TEntity> represents the collection of all entities in the context, or that can be queried from the database, of a given type
|
||||
public DbSet<Entity> entities { get; set; }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In `appsettings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"CommanderConnection" : "Server=<server>;Database=<database>;UID=<user>;Pwd=<password>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In `Startup.cs`:
|
||||
|
||||
```cs
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// SqlServer is the db used in this example
|
||||
services.AddDbContext<CommanderContext>(option => option.UseSqlServer(Configuration.GetConnectionString("CommanderConnection")));
|
||||
services.AddControllers();
|
||||
}
|
||||
```
|
||||
|
||||
### Migrations
|
||||
|
||||
- Mirroring of model in the DB.
|
||||
- Will create & update DB Schema if necessary
|
||||
|
||||
In Package Manager Shell:
|
||||
|
||||
```ps1
|
||||
add-migrations <migration_name>
|
||||
update-database # use the migrations to modify the db
|
||||
```
|
||||
|
||||
## Repository
|
||||
|
||||
In `IEntityRepo`:
|
||||
|
||||
```cs
|
||||
using <Namespace>.Model;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace <Namespace>.Repository
|
||||
{
|
||||
public interface IEntityRepo
|
||||
{
|
||||
IEnumerable<Entity> SelectAll();
|
||||
Entity SelectOneById(int id);
|
||||
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In `EntityRepo`:
|
||||
|
||||
```cs
|
||||
using <Namespace>.Model;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace <Namespace>.Repo
|
||||
{
|
||||
public class EntityRepo : IEntityRepo
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public EntityRepo(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IEnumerable<Entity> SelectAll()
|
||||
{
|
||||
return _context.Entities.ToList(); // linq query (ToList()) becomes sql query
|
||||
}
|
||||
|
||||
public Entity SelectOneById(int id)
|
||||
{
|
||||
return _context.Entities.FirstOrDefault(p => p.Id == id);
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Data Transfer Objects (DTOs)
|
||||
|
||||
A **DTO** is an object that defines how the data will be sent and received over the network (usually as JSON).
|
||||
|
@ -202,13 +26,13 @@ public void ConfigureServices(IServiceCollection services)
|
|||
}
|
||||
```
|
||||
|
||||
In `Entity<CrudOperation>DTO.cs`:
|
||||
In `EntityDTO.cs`:
|
||||
|
||||
```cs
|
||||
namespace <Namespace>.DTOs
|
||||
{
|
||||
// define the data to be serialized in JSON (can differ from model)
|
||||
public class EntityCrudOpDTO // e.g: EntityReadDTO, ...
|
||||
public class EntityDTO
|
||||
{
|
||||
// only properties to be serialized
|
||||
}
|
||||
|
@ -228,7 +52,7 @@ namespace <Namespace>.Profiles
|
|||
{
|
||||
public EntitiesProfile()
|
||||
{
|
||||
CreateMap<Entity, EntityCrudOpDTO>(); // map entity to it's DTO
|
||||
CreateMap<Entity, EntityDTO>(); // map entity to it's DTO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,35 +60,7 @@ namespace <Namespace>.Profiles
|
|||
|
||||
## Controller (No View)
|
||||
|
||||
Uses [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) to receive a suitable implementation of `IEntityRepo`,
|
||||
|
||||
### Service Lifetimes
|
||||
|
||||
- `AddSingleton`: same for every request
|
||||
- `AddScoped`: created once per client
|
||||
- `Transient`: new instance created every time
|
||||
|
||||
In `Startup.cs`:
|
||||
|
||||
```cs
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers();
|
||||
services.AddScoped<IEntityRepo, EntityRepo>(); // map the interface to its implementation, needed for dependency injection
|
||||
}
|
||||
```
|
||||
|
||||
### Request Mappings
|
||||
|
||||
```cs
|
||||
using <App>.Model;
|
||||
using <App>.Repo;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace <App>.Controllers
|
||||
{
|
||||
[Route("api/endpoint")]
|
||||
[ApiController]
|
||||
public class EntitiesController : ControllerBase // MVC controller w/o view
|
||||
|
@ -272,33 +68,32 @@ namespace <App>.Controllers
|
|||
private readonly ICommandRepo _repo;
|
||||
private readonly IMapper _mapper; // AutoMapper class
|
||||
|
||||
public EntitiesController(IEntityRepo repository, IMapper mapper) // injection og the dependency
|
||||
public EntitiesController(IEntityRepo repository, IMapper mapper)
|
||||
{
|
||||
_repo = repository;
|
||||
_mapper = mapper
|
||||
}
|
||||
|
||||
[HttpGet] // GET api/endpoint
|
||||
public ActionResult<IEnumerable<EntityCrudOpDTO>> SelectAllEntities()
|
||||
public ActionResult<IEnumerable<EntityDTO>> SelectAllEntities()
|
||||
{
|
||||
var results = _repo.SelectAll();
|
||||
|
||||
return Ok(_mapper.Map<EntityCrudOpDTO>(results)); // return an action result OK (200) with the results
|
||||
return Ok(_mapper.Map<EntityDTO>(results));
|
||||
}
|
||||
|
||||
// default binding source: [FromRoute]
|
||||
[HttpGet("{id}")] // GET api/endpoint/{id}
|
||||
public ActionResult<EntityCrudOpDTO> SelectOneEntityById(int id)
|
||||
public ActionResult<EntityDTO> SelectOneEntityById(int id)
|
||||
{
|
||||
var result = _repo.SelectOneById(id);
|
||||
|
||||
if(result != null)
|
||||
{
|
||||
return Ok(_mapper.Map<EntityCrudOp>(result)); // transform entity to it's DTO
|
||||
// transform entity to it's DTO
|
||||
return Ok(_mapper.Map<EntityDTO>(result));
|
||||
}
|
||||
|
||||
return NotFound(); // ActionResult NOT FOUND (404)
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -306,15 +101,6 @@ namespace <App>.Controllers
|
|||
## Controller (With View)
|
||||
|
||||
```cs
|
||||
using <App>.Model;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace <App>.Controllers
|
||||
{
|
||||
[Route("api/endpoint")]
|
||||
[ApiController]
|
||||
public class EntitiesController : Controller
|
||||
|
@ -332,5 +118,4 @@ namespace <App>.Controllers
|
|||
return Json(new { data = _db.Entities.ToList() }); // json view
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1439,10 +1439,10 @@ class Class
|
|||
set => _backingField = value;
|
||||
}
|
||||
|
||||
// access backing field with the field keyword [C# 10]
|
||||
// access backing field with the field keyword [C# 11?]
|
||||
public Type Property { get => field; set => field = value; }
|
||||
|
||||
// required property [C# 10], prop myst be set at obj init (in constructor or initializer)
|
||||
// required property [C# 11?], prop must be set at obj init (in constructor or initializer)
|
||||
public required Type Property { get; set; }
|
||||
|
||||
// EXPRESSION-BODIED READ-ONLY PROPERTY
|
||||
|
@ -2032,6 +2032,8 @@ Generic type parameters support covariance and contravariance to provide greater
|
|||
- **Contravariance**: Enables to use a more generic (less derived) type than originally specified.
|
||||
- **Invariance**: it's possible to use _only_ the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant.
|
||||
|
||||

|
||||
|
||||
**NOTE**: annotate generic type parameters with `out` and `in` annotations to specify whether they should behave covariantly or contravariantly.
|
||||
|
||||
```cs
|
||||
|
|
Loading…
Add table
Reference in a new issue