Core ASP.NET e Docker. Una guida passo passo.

Nella seguente guida imparerai da zero le nozioni di base su ASP.NET core e Docker.

Prima le cose:

Che cos’è ASP.NET Core ?.

ASP.NET Core è un framework open source multipiattaforma ad alte prestazioni per la creazione di un’applicazione moderna, basata su cloud, connessa a Internet. Con ASP.Net Core, puoi creare app e servizi Web, app IoT e back-end mobili. Usa i tuoi strumenti di sviluppo preferiti su Windows, macOS e Linux. Distribuire sul cloud o on-permise ed eseguire su .NET core o. NET Framework.

E cos’è Docker?

Docker è uno strumento progettato per semplificare la creazione, la distribuzione e l’esecuzione di applicazioni mediante l’utilizzo di contenitori. I contenitori consentono a uno sviluppatore di impacchettare un’applicazione con tutte le parti di cui ha bisogno, come librerie e altre dipendenze, e spedire tutto come un pacchetto. In questo modo, grazie al contenitore, lo sviluppatore può essere certo che l’applicazione verrà eseguita su qualsiasi altra macchina Linux indipendentemente dalle impostazioni personalizzate che la macchina potrebbe avere che potrebbero differire dalla macchina utilizzata per scrivere e testare il codice.

Iniziare.

Questo esempio dimostra come creare, eseguire e ancorare una semplice applicazione Web ASP.NET Core.

Pre-requisiti:

  • Codice di Visual Studio
  • .NET Core SDK 2.2 o successivo
  • C # per Visual Studio Code versione 1.17.1 o successive
  • Docker (se stai provando questo su Windows 10 Home Edition, devi avere Docker ToolBox installato)

Per ulteriori informazioni su come installare questo utilizzare i seguenti collegamenti:

Codice visivo: https://code.visualstudio.com/docs
.NET Core: https://docs.microsoft.com/es-es/dotnet/core/
Docker: https://docs.docker.com/docker-for-windows/
Docker Toolbox: https://docs.docker.com/toolbox/toolbox_install_windows/

Crea la tua app

Apri un nuovo prompt dei comandi ed esegui i seguenti comandi:

> dotnet nuova webApp -o myWebApp

> cd myWebApp

Il comando dotnet crea una new applicazione di tipo webApp per te. Il parametro -o crea una directory denominata myWebApp cui è memorizzata l’app e la popola con i file richiesti. Il comando cd myWebApp ti porta nella directory dell’app appena creata.

Diversi file sono stati creati nella directory myWebApp , per darti una semplice applicazione web pronta per essere eseguita. Startup.cs contiene tutte le impostazioni e configurazioni. La myWebApp/Pages contiene alcune pagine Web per l’applicazione.

Nel prompt dei comandi, eseguire il comando seguente:

dotnet dev-certs https --trust

Il sistema operativo in uso potrebbe richiedere di verificare se si accetta di fidarsi del certificato di sviluppo. Seguire le istruzioni se si è d’accordo.

Questo certificato consente di eseguire l’app Web su HTTPS durante lo sviluppo sul computer.

Esegui la tua app

Nel prompt dei comandi, eseguire il comando seguente:

dotnet run

Una volta completato il comando, accedere a https://localhost:5001

Questa immagine è scaricata da un tutorial, non è mia.

Congratulazioni, hai creato ed eseguito la tua prima app Web .NET!

Ora ci stiamo spostando nelle pagine Razor:

  • Apri il terminale integrato.
  • Cambia le directory ( cd ) in una cartella che conterrà il progetto.
  • Esegui i seguenti comandi:

> dotnet nuova webapp -o RazorPagesMovie
> code -r RazorPagesMovie

Il dotnet new comando dotnet new crea un nuovo progetto Razor Pages nella cartella RazorPagesMovie .

Il comando code apre la cartella RazorPagesMovie in una nuova istanza di Visual Studio Code.

  • Viene visualizzata una finestra di dialogo con le risorse richieste da compilare e il debug mancante da ‘RazorPagesMovie’. Aggiungerli?
  • Seleziona
  • Premi Ctrl-F5 per eseguire senza il debugger.
  • Affidati al certificato di sviluppo HTTPS eseguendo il comando seguente:

dotnet dev-certs https --trust

  • Il comando precedente visualizza la seguente finestra di dialogo:

Questa immagine è scaricata da un tutorial, non è mia.
  • Selezionare se si accetta di fidarsi del certificato di sviluppo.
  • Vedere Affidabilità del certificato di sviluppo HTTPS ASP.NET Core per ulteriori informazioni.
  • Visual Studio Code avvia Kestrel, avvia un browser e passa a http://localhost:5001 . La barra degli indirizzi mostra localhost:port# e non qualcosa come example.com . Questo perché localhost è il nome host standard per il computer locale. Localhost serve solo richieste web dal computer locale.
  • Nella home page dell’app, selezionare Accetta per consentire il tracciamento.
  • Questa app non tiene traccia delle informazioni personali, ma il modello di progetto include la funzione di consenso nel caso in cui sia necessario per conformarsi al Regolamento generale sulla protezione dei dati dell’Unione Europea (GDPR).

L’immagine precedente mostra l’app dopo aver dato il consenso al tracciamento

Esamina i file di progetto

Ecco una panoramica delle principali cartelle e file di progetto con cui lavorerai nelle esercitazioni successive.

Cartella Pagine

Contiene pagine Razor e file di supporto. Ogni pagina Razor è una coppia di file:

Un file .cshtml che contiene markup HTML con codice C # utilizzando la sintassi Razor.

Un file .cshtml.cs che contiene codice C # che gestisce gli eventi della pagina.

I file di supporto hanno nomi che iniziano con un trattino basso. Ad esempio, il file _Layout.cshtml configura gli elementi dell’interfaccia utente comuni a tutte le pagine. Questo file imposta il menu di navigazione nella parte superiore della pagina e l’informativa sul copyright nella parte inferiore della pagina. Per ulteriori informazioni, vedere Layout in ASP.NET Core.

cartella wwwroot

Contiene file statici, come file HTML, file JavaScript e file CSS. Per ulteriori informazioni, consultare File statici in ASP.NET Core.

appSettings.json

Contiene dati di configurazione, come stringhe di connessione. Per ulteriori informazioni, consultare Configurazione in ASP.NET Core.

Program.cs

Contiene il punto di ingresso per il programma. Per ulteriori informazioni, consultare ASP.NET Core Web Host.

Startup.cs

Contiene codice che configura il comportamento dell’app, ad esempio se richiede il consenso per i cookie. Per ulteriori informazioni, consultare Avvio dell’app in ASP.NET Core.

Pagine di rasoio

Razor Pages è abilitato in Startup.cs :

 public class Startup 
{
public void ConfigureServices(IServiceCollection services)
{
// Includes support for Razor Pages and controllers.
services.AddMvc();
}
  public void Configure(IApplicationBuilder app) 
{
app.UseMvc();
}
}

Considera una pagina di base:

 @page 
 

Hello, world!


The time on the server is @DateTime.Now

Il codice precedente assomiglia molto a un file di visualizzazione Razor. Ciò che lo rende diverso è la direttiva @page . @page trasforma il file in un’azione MVC, il che significa che gestisce le richieste direttamente, senza passare attraverso un controller. @page deve essere la prima direttiva Razor in una pagina. @page influenza il comportamento di altri costrutti Razor.

Gli appunti:

  • Il runtime cerca i file Razor Pages nella cartella Pages per impostazione predefinita.
  • Index è la pagina predefinita quando un URL non include una pagina.

Razor Pages è progettato per semplificare l’implementazione di modelli comuni utilizzati con i browser Web durante la creazione di un’app. L’associazione dei modelli, gli helper tag e gli helper HTML funzionano tutti con le proprietà definite in una classe Pagina Razor.

Per gli esempi in questo documento, DbContext è inizializzato nel file Startup.cs.

 using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesContacts.Data;
 namespace myWebApp 
{
public class Startup
{
public IHostingEnvironment HostingEnvironment { get; }
  public void ConfigureServices(IServiceCollection services) 
{
services.AddDbContext(options =>
options.UseInMemoryDatabase("name"));

services.AddMvc();
}
  public void Configure(IApplicationBuilder app) 
{
app.UseMvc();
}
}
}

Il modello di dati:

 using System.ComponentModel.DataAnnotations; 
 namespace myWebApp 
{
public class Customer
{
public int Id { get; set; }
  [Required, StringLength(100)] 
public string Name { get; set; }
}
}

Il contesto db:

 using Microsoft.EntityFrameworkCore; 
 namespace myWebApp 
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options)
: base(options)
{
}
  public DbSet Customers { get; set; } 
}
}

Ecco il file di visualizzazione Pages / Create.cshtml :

 @page 
@model myWebApp.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
  


Enter your name.




Name:




Il modello di pagina Pages / Create.cshtml.c :

 using System.Threading.Tasks; 
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
 namespace myWebApp.Pages 
{
public class CreateModel : PageModel
{
private readonly AppDbContext _db;
  public CreateModel(AppDbContext db) 
{
_db = db;
}
  [BindProperty] 
public Customer Customer { get; set; }
  public async Task OnPostAsync() 
{
if (!ModelState.IsValid)
{
return Page();
}
  _db.Customers.Add(Customer); 
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
}
}
}

Per convenzione, la classe PageModel si chiama Model ed è nello stesso spazio dei nomi della pagina.

La classe PageModel consente la separazione della logica di una pagina dalla sua presentazione. Definisce i gestori di pagina per le richieste inviate alla pagina e i dati utilizzati per il rendering della pagina. Questa separazione consente di gestire le dipendenze delle pagine tramite l’iniezione delle dipendenze e di testare l’unità delle pagine.

La pagina ha un metodo del gestore OnPostAsync , che viene eseguito su richieste POST (quando un utente pubblica il modulo). È possibile aggiungere metodi di gestione per qualsiasi verbo HTTP. I gestori più comuni sono:

  • OnGet Inizializza lo stato necessario per la pagina.
  • OnPost per gestire l’invio di moduli.

Il suffisso di denominazione Async è facoltativo ma viene spesso utilizzato dalla convenzione per le funzioni asincrone. Il codice OnPostAsync nell’esempio precedente è simile a quello che si scriverebbe normalmente in un controller. Il codice precedente è tipico per Razor Pages. La maggior parte delle primitive MVC come il modello associato, la convalida e i risultati dell’azione sono condivisi.

Il precedente metodo OnPostAsync :

 public async Task OnPostAsync() 
{
if (!ModelState.IsValid)
{
return Page();
}
  _db.Customers.Add(Customer); 
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
}

Il flusso di base di OnPostAsync :

Verifica errori di convalida.

  • Se non ci sono errori, salva i dati e reindirizza.
  • In caso di errori, mostra di nuovo la pagina con i messaggi di convalida. La convalida lato client è identica alle tradizionali applicazioni MVC ASP.NET Core. In molti casi, gli errori di convalida vengono rilevati sul client e non vengono mai inviati al server.

Quando i dati vengono immessi correttamente, il metodo del gestore OnPostAsync chiama il metodo di supporto RedirectToPage per restituire un’istanza di RedirectToPageResult . RedirectToPage è un nuovo risultato dell’azione, simile a RedirectToAction o RedirectToRoute , ma personalizzato per le pagine. Nell’esempio precedente, reindirizza alla pagina dell’indice radice ( /Index ). RedirectToPage è dettagliato nella sezione Generazione URL per Pagine.

Quando il modulo inviato presenta errori di convalida (che vengono passati al server), il metodo del gestore OnPostAsync chiama il metodo helper Page . Page restituisce un’istanza di PageResult . La Page ritorno è simile al modo in cui le azioni nei controller restituiscono View . PageResult è il tipo di ritorno predefinito per un metodo gestore. Un metodo handler che restituisce void rende la pagina.

La proprietà Customer utilizza l’attributo [BindProperty] per optare per l’associazione del modello.

 public class CreateModel : PageModel 
{
private readonly AppDbContext _db;
  public CreateModel(AppDbContext db) 
{
_db = db;
}
  [BindProperty] 
public Customer Customer { get; set; }
  public async Task OnPostAsync() 
{
if (!ModelState.IsValid)
{
return Page();
}
  _db.Customers.Add(Customer); 
await _db.SaveChangesAsync();
return RedirectToPage("/Index");
}
}

Razor Pages, per impostazione predefinita, associa le proprietà solo ai verbi non GET. L’associazione alle proprietà può ridurre la quantità di codice che devi scrivere. Il bind riduce il codice usando la stessa proprietà per eseguire il rendering dei campi modulo ( ) e accetta l’input.

La home page ( Index.cshtml ):

 @page 
@model myWebApp.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
 

Contacts











@foreach (var contact in Model.Customers)
{





}

ID Name
@contact.Id @contact.Name
edit
<button type="submit" asp-page-handler="delete"
asp-route-id="@contact.Id">delete
  Create 

La classe PageModel associata ( Index.cshtml.cs ):

 using System.Threading.Tasks; 
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
 namespace myWebApp.Pages 
{
public class IndexModel : PageModel
{
private readonly AppDbContext _db;
  public IndexModel(AppDbContext db) 
{
_db = db;
}
  public IList Customers { get; private set; } 
  public async Task OnGetAsync() 
{
Customers = await _db.Customers.AsNoTracking().ToListAsync();
}
  public async Task OnPostDeleteAsync(int id) 
{
var contact = await _db.Customers.FindAsync(id);
  if (contact != null) 
{
_db.Customers.Remove(contact);
await _db.SaveChangesAsync();
}
  return RedirectToPage(); 
}
}
}

Il file Index.cshtml contiene il seguente markup per creare un collegamento di modifica per ciascun contatto:

 edit 

Anchor Tag Helper ha utilizzato l’ asp-route-{value} per generare un collegamento alla pagina Modifica. Il collegamento contiene i dati del percorso con l’ID contatto. Ad esempio, http://localhost:5000/Edit/1 .

Il file Pages / Edit.cshtml :

 @page "{id:int}" 
@model myWebApp.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
 @{ 
ViewData["Title"] = "Edit Customer";
}
 

Edit Customer - @Model.Customer.Id
















La prima riga contiene la @page "{id:int}" . Il vincolo di routing "{id:int}" indica alla pagina di accettare richieste alla pagina che contengono dati di route int . Se una richiesta alla pagina non contiene dati di route che possono essere convertiti in un int , il runtime restituisce un errore HTTP 404 (non trovato). Per rendere l’ID facoltativo, aggiungere ? al vincolo del percorso:

 @page "{id:int?}" 

Il file Pages / Edit.cshtml.cs :

 using System; 
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
 namespace myWebApp.Pages 
{
public class EditModel : PageModel
{
private readonly AppDbContext _db;
  public EditModel(AppDbContext db) 
{
_db = db;
}
  [BindProperty] 
public Customer Customer { get; set; }
  public async Task OnGetAsync(int id) 
{
Customer = await _db.Customers.FindAsync(id);
  if (Customer == null) 
{
return RedirectToPage("/Index");
}
  return Page(); 
}
  public async Task OnPostAsync() 
{
if (!ModelState.IsValid)
{
return Page();
}
  _db.Attach(Customer).State = EntityState.Modified; 
  try 
{
await _db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
throw new Exception($"Customer {Customer.Id} not found!");
}
  return RedirectToPage("/Index"); 
}
}
}

Il file Index.cshtml contiene anche markup per creare un pulsante Elimina per ogni cliente:

 <button type="submit" asp-page-handler="delete" 
asp-route-id="@contact.Id">delete

Quando il pulsante Elimina è reso in HTML, la sua formaction include parametri per:

  • L’ID contatto cliente specificato dall’attributo asp-route-id .
  • Il handler specificato dall’attributo asp-page-handler .

Ecco un esempio di pulsante di eliminazione renderizzato con un ID contatto cliente pari a 1 :

  

Quando il pulsante è selezionato, viene inviata una richiesta POST al server. Per convenzione, il nome del metodo del gestore viene selezionato in base al valore del parametro del handler base allo schema OnPost[handler]Async .

Poiché il handler viene delete in questo esempio, il metodo del gestore OnPostDeleteAsync viene utilizzato per elaborare la richiesta POST . Se il asp-page-handler è impostato su un valore diverso, ad esempio remove , viene selezionato un metodo del gestore della pagina con il nome OnPostRemoveAsync .

 public async Task OnPostDeleteAsync(int id) 
{
var contact = await _db.Customers.FindAsync(id);
  if (contact != null) 
{
_db.Customers.Remove(contact);
await _db.SaveChangesAsync();
}
  return RedirectToPage(); 
}

Il metodo OnPostDeleteAsync :

  • Accetta l’ id dalla stringa di query.
  • Interroga il database per il contatto del cliente con FindAsync .
  • Se viene trovato il contatto del cliente, vengono rimossi dall’elenco dei contatti del cliente. Il database è aggiornato.
  • Chiama RedirectToPage per reindirizzare alla pagina dell’indice radice ( /Index ).

Dockerizzazione della nostra app Web .Net Core.

Il supporto docker per VS Code è fornito da un’estensione. Per installare l’estensione Docker, apri la vista Estensioni premendo Ctrl + Maiusc + X e cerca la docker per filtrare i risultati. Seleziona l’estensione Microsoft Docker.

Dockerfiles

Con Docker, è possibile creare immagini specificando i comandi passo per passo necessari per creare l’immagine in un file Dockerfile . Un file Docker è solo un file di testo che contiene le istruzioni di compilazione.

VS Code comprende la struttura dei Dockerfile e il set di istruzioni disponibili, in modo da ottenere un’ottima esperienza durante la creazione di questi file.

  1. Crea un nuovo file nell’area di lavoro chiamato Dockerfile
  2. Premi Ctrl + Spazio per visualizzare un elenco di frammenti corrispondenti a comandi Dockerfile validi. Premendo il pulsante ‘i’ Altre informazioni sulla destra verrà visualizzato un riquadro a comparsa con i dettagli e un collegamento alla documentazione Docker Online.

Dato che stiamo creando un contenitore Linux, questo è il Dockerfile che useremo.

  DA microsoft / dotnet: base AS 2.2-aspnetcore-runtime 
WORKDIR / app
ESPOSI 80
  DA microsoft / dotnet: build AS 2.2-sdk 
WORKDIR / src
COPIA ["myWebApp.csproj", "./"]
RUN dotnet restore "./myWebApp.csproj"
COPIA . .
WORKDIR "/ src /."
Esegui dotnet build "myWebApp.csproj" -c Rilascio -o / app
  DA compilare come pubblicare 
Esegui dotnet pubblica "myWebApp.csproj" -c Rilascio -o / app
  DA base COME finale 
WORKDIR / app
COPIA --da = pubblica / app.
ENTRYPOINT ["dotnet", "myWebApp.dll"]

E questo è il Dockerfile che dovresti usare per i contenitori Windows.

 FROM microsoft/dotnet:sdk AS build-env 
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "myWebApp.dll"]

Per ridurre al .dockerignore il contesto di compilazione, aggiungi un file .dockerignore alla cartella del tuo progetto e copia in esso quanto segue.

  node_modules 
NPM-debug.log
Dockerfile *
finestra mobile-comporre *
.dockerignore
.idiota
.gitignore
.env
*/bidone
* / Obj
README.md
LICENZA
.vscode

Per semplificare le cose, l’estensione Docker include molte righe di comando che ti aiuteranno in questo.

nel codice di Visual Studio: Ctrl + Maiusc + P, quindi digita ” Docker :” e vedrai le diverse linee di comando a tua disposizione. Useremo Docker: Aggiungi i file Docker a myWebApp. Apparirà una nuova scheda che chiede di selezionare la piattaforma applicativa: ASP.Net Core. Quindi selezioneremo il sistema operativo: Linux e quale porta ascolterà la nostra App, la terremo su 80. È l’impostazione predefinita. Siamo pronti per partire. Ora abbiamo a disposizione il Dockerfile già creato e il file .dockerignore.

Ora dobbiamo creare i nostri contenitori e immagini per poter eseguire la nostra app. Possiamo farlo nel prompt dei comandi ma dato che siamo nel codice di Visual Studio, lo faremo qui. Nel codice di Visual Studio: Ctrl + Maiusc + p , quindi digitare “Docker: build”. VS Code seleziona automaticamente l’ultima immagine creata, ma puoi scegliere quella che ti serve, in questo esempio è: myWebApp: latest.

Ora eseguiremo l’app:

  1. Ctrl + Maiusc + P
  2. Docker: Esegui.

Visualizza la pagina Web in esecuzione da un contenitore

  • Vai a localhost: 8080 per accedere alla tua app in un browser web.
  • Se stai utilizzando il Nano Windows Container e non hai aggiornato Windows Creator Update, c’è un bug che influenza il modo in cui Windows 10 comunica con i contenitori tramite “NAT” (Network Address Translation). Devi colpire direttamente l’IP del contenitore. È possibile ottenere l’indirizzo IP del proprio contenitore con i seguenti passaggi:
  1. Esegui docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" myWebApp
  2. Copia l’indirizzo IP del contenitore e incollalo nel tuo browser. (Ad esempio 172.16.240.197 )

O se hai installato Kitematic puoi farlo in un modo più interattivo. Vai su Le mie immagini, seleziona quello che ti serve, in questo caso è myWebApp, fai clic su Crea e il gioco è fatto.

È semplice!