Creiamo un progetto App Web Asp .Net Core MVC ,una volta creato il progetto scrivete
nella “Console di Gestione Pacchetti ":
Install-Package
Microsoft.EntityFrameworkCore.Tools
vi consiglio di usare il seguente comando per visualizzare le funzionalità proprie del package appena installato :
per saperne di più digitate nella console di gestione pacchetti "Get-Help about_EntityFrameworkCore" e premete invio :-) ,
considerato che nell'esempio useremo
Sql Server con lo Scaffold DB Context dobbiamo installare il
pacchetto Microsoft.EntityFrameworkCore.SqlServer ed a tal fine
eseguiamo il seguente comando
Install-Package
Microsoft.EntityFrameworkCore.SqlServer
in seguito
eseguite il comando Scaffold-DbContext per creare il dbcontext che
verrà utilizzato dall'applicazione , questo modo di creare il
dbcontext è detto “Database First” ovvero si parte dal db
esistente per creare le entità dell'applicazione,
supponiamo
di utilizzare il database Northwind
https://github.com/Microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs ,apritelo
con Sql Management Studio e cliccate su
Execute ,ora
dovremmo avere il database Northwind popolato.
A questo
punto possiamo eseguire con successo il comando :
Scaffold-DbContext
"Data Source=(localdb)\mssqllocaldb;Initial
Catalog=Northwind;Integrated Security=True"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir
Context -Context NorthwindContext
Come
risultato avremo una directory Context dentro la quale troveremo il
file NorthwindContext.cs ,esso
contiene la “mappatura” del database fisico nelle entità,avremo inoltre una nuova directory Models che contiene le classi che rappresentano le tabelle del db
,
in models troviamo le classi relative alle tabelle del db , qui sotto
la lista non completa :
Per
vedere l'utilizzo pratico di quanto appena fatto andiamo sulla dir
controller ,tasto destro-> aggiungi-> controller:
clicchiamo
su Aggiungi
scegliamo
,ad esempio Customer come classe e NorthwindContext come contesto
,clicchiamo su Aggiungi ,eseguita la procedura di Scaffolding da
parte di Visual Studio andiamo a vedere la directory Controllers
all'interno della cartella troviamo un
nuovo controller riferito alla gestione dei Customers ,prima di vedere il controller in azione
spostiamo la nostra attenzione al file Program.cs e troviamo
questo metodo definisce le regole di
route ,se non settiamo nessun percorso (oltre al nome del server)
verranno usati i default ,ovvero verrà selezionato il controller
Home e l'action Index del controller Home ,se nel path di route
abbiamo solo Customers (il nome del controller) verrà chiamata
l'azione di default ovvero Index
se andiamo sotto la directory
Views/Home/ troveremo il file Index.cshtml che contiene il messaggio
di Welcome.
Nel file Program dobbiamo
aggiungere il dbcontext :
builder.Services.AddDbContext<NorthwindContext>(options
=>options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
il valore DefaultConnection è ricavato
dalla sezione ConnectionStrings valore della chiave
“DefaultConnection” del file appsettings.json che vedete qua
sotto:
{
"Logging":
{
"LogLevel":
{
"Default":
"Information",
"Microsoft.AspNetCore":
"Warning"
}
},
"ConnectionStrings":
{
"DefaultConnection":
"Data Source=(localdb)\\mssqllocaldb;Initial Catalog=Northwind;Integrated
Security=True"
},
"AllowedHosts":
"*"
}
Mandiamo in esecuzione il programma
cliccando su Esegui o premendo F5 , proviamo ora a chiamare il
CustomersController aggiungendo alla barra dell'indirizzo “Customers”
, così :
https://localhost:7074/Customers
ed otteniamo:
in pratica lo scaffolding crea per noi
le funzioni base per interagire con le entità che possono esser
create oppure modificate oppure andare a vederne il dettaglio oppure
cancellate , il routing ha aggiunto Index nel comporre l'indirizzo da
chiamare perchè è il suo valore predefinito nel MapControllerRoute
.
Osserviamo
le action dentro il controller :
l'action
Create senza parametri è chiamata da un anchor tag helper dentro la
pagina Index.cshtml sotto Views/Customers , il codice è <a
asp-action="Create">Create
New</a>
, l'attributo asp-controller è stato omesso poiché se non viene
specificato nessun controller è chiamato il controller di default
che chiama la vista corrente,avremmo potuto scrivere <a
asp-controller="Customers"
asp-action="Create">Create
New</a>
ed ottenuto lo stesso risultato.La prima create si occupa quindi di
reinviarci alla view dove inseriremo i dati del nuovo customer , la
seconda create raccoglie i dati inseriti e crea un nuovo customer sul
db. Il primo Create riceve una richiesta get da un link , il secondo
riceve una richiesta di tipo post da un form ,il method non è
specificato poiché di default vale “post” : <form
asp-action="Create">
è
quindi equivalente ad <form
asp-action="Create"
method="post">
Aggiungiamo
Identity al progetto :
se
partiamo con un progetto nuovo in fase di creazione del progetto con
Visual Studio possiamo scegliere “Account Individuali” oppure da
riga di comando “dotnet new mvc –auth Individual --use-local-db”
per aggiungere Identity.Per
aggiungere Identity in un progetto esistente dobbiamo invece seguire
una procedura:
1)
installiamo i seguenti due package:
Install-Package
Microsoft.AspNetCore.Identity.EntityframeworkCore
Install-Package
Microsoft.AspNetCore.Identity.UI
2)
dobbiamo far derivare NorthwindContext da IdentityDbContext
ovvero:
public
class NorthwindContext : IdentityDbContext
{
...….......
…..............
}
3) configuriamo i servizi di Identity
aggiungendoli ai services della classe Program:
builder.Services.AddDefaultIdentity<IdentityUser>() .AddEntityFrameworkStores<NorthwindContext >();
in
questo modo NorthwindContext erediterà il mapping specifico di
Identity e sarà possibile gestire i dati relativi agli utenti
utilizzando le tabelle a questo preposte,
per
utilizzare il mapping aggiungiamo la chiamata al metodo
base.OnModelCreating (builder) all'interno del metodo OnModelCreating (che potete trovare nella classe NorthwindContext) ,in pratica :
protected
override
void
OnModelCreating(ModelBuilder modelBuilder)
{ base.OnModelCreating(modelBuilder);
//qui
segue il nostro codice di mapping
}
è
chiaro quindi che viene chiamato il metodo OnModelCreating della
classe IdentityDbContext passandogli il modelBuilder ,essendo
aspnetcore opensource
possiamo andare a vedere dove Identity definisce la struttura delle
identità che lo vanno a definire:
https://github.com/dotnet/aspnetcore/blob/main/src/Identity/EntityFrameworkCore/src/IdentityUserContext.cs
4)
per continuare la nostra procedura dobbiamo aggiungere due middleware
:
app.UseAuthentication();
app.UseAuthorization();
i
middleware devono essere aggiunti nel punto “giusto” ,al
contrario dei services , un punto adatto potrebbe essere dopo il
routing :
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
5)poichè
la UI di Identity usa le razor pages dobbiamo abilitare le razor
pages aggiungendo il servizio RazorPages nel file Program così :
builder.Services.AddRazorPages()
ed
il middleware MapRazorPages nel seguente modo prima di app.Run():
app.MapRazorPages();
app.Run();
6)
il modello concettuale ora contiene anche le identità di Identity ,
per allinearlo con il database dobbiamo creare una migration usando
il comando Add-Migration scegliendo un nome significativo per la
migration ad esempio Add-Migration Identity , eseguiamo il comando a
cui facciamo seguire il comando “Update-Database” che porta le
modifiche sul database fisico
7) aggiungiamo
la partial view _LoginPartial.cshtml ,dobbiamo chiamare questa
LoginPartial nel file _Layout.cshtml
<div
class="navbar-collapse
collapse d-sm-inline-flex justify-content-between">
<ul
class="navbar-nav
flex-grow-1">
<li
class="nav-item"><a
class="nav-link
text-dark"
asp-area=""
asp-controller="Home"
asp- action="Index">Home</a></li>
<li
class="nav-item">
<a
class="nav-link
text-dark"
asp-area=""
asp-controller="Home"
asp-action="Privacy">Privacy</a>
</li>
</ul>
<partial
name="_LoginPartial"
/>
</div>
Vediamo
cosa contiene la LoginPartial fornita da Identity :
@using
Microsoft.AspNetCore.Identity
@inject
SignInManager<IdentityUser>
SignInManager
@inject
UserManager<IdentityUser>
UserManager
<ul
class="navbar-nav">
@if
(SignInManager.IsSignedIn(User))
{
<li
class="nav-item">
<a
id="manage"
class="nav-link
text-dark"
asp-area="Identity"
asp- page="/Account/Manage/Index"
title="Manage">Hello
@UserManager.GetUserName(User)!</a>
</li><li
class="nav-item">
<form
id="logoutForm"
class="form-inline"
asp-area="Identity"
asp-page="/Account/Logout"
asp-route-returnUrl="@Url.Action("Index",
"Home",
new
{ area = ""
})"><button
id="logout"
type="submit"
class="nav-link
btn btn-link text-dark border-0">Logout</button></form>
</li>
} else {
<li
class="nav-item">
<a
class="nav-link
text-dark"
id="register"
asp-area="Identity"
asp- page="/Account/Register">Register</a>
</li>
<li
class="nav-item">
<a
class="nav-link
text-dark"
id="login"
asp-area="Identity"
asp- page="/Account/Login">Login</a>
</li>
}
</ul>
grazie
all'if che utilizza il valore booleano ritornato dal metodo
IsSignedIn(User) la partial view fornisce due coppie di link ,nel
caso l'utente sia loggato oppure no ,nel primo caso il primo link è
alla pagina di gestione dell'account ovvero “/Account/Manage/Index”
,il
secondo è un button link dentro un form che punta ad
“/Account/Logout” ,viene passato anche un returnUrl alla Index
della Home . Nel caso l'utente non sia loggato la partial view
restituisce due altri link , il primo invia alla pagina di
registrazione “/Account/Register” il secondo manda alla pagina di
Login “/Account/Login”.