sabato 25 febbraio 2023

Creare un progetto asp .net core che usi Northwind ed a cui venga aggiunto Identity in un momento successivo

 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”.

Crittografia e WCF per passare una password ( od una qualsiasi altra stringa (xml,json, etc.etc.) ) da un applicazione ad un' altra in relativa sicurezza

 Il codice che segue è da considerarsi in alpha e da non utilizzare in un ambiente di produzione , qui potete trovare il  "progetto&quo...