AspNet Core e Angular App - parte 1

in ASPNET Core, Informatica

AspNet Core e Angular App – parte 1

Reading Time: 4 minutes

Questo post proviene da una serie di demo che ho utilizzato durante uno degli incontri di qualche mese fa con la community DotNet Tortona. Ho deciso di pubblicarlo perchè contiene alcuni spunti interessanti nello sviluppo di applicazioni web basate di Angular. L’esempio di questo post è basato su ASPNET Core 2.2.

La realizzazione di Angular App è legata all’implementazion di due elementi:

  • WebApi che consentono di gestire l’accesso ai dati, ad esempio per poter effettuare operazioni CRUD
  • Angular App per l’interfacciamento alle WebApi

DotNet Core consente di creare agevolmente questo tipo di soluzioni .

In questo post realizzeremo una semplice applicazione Angular per la gestione di un blog.

Creazione Api

Il primo elemento che andremo a realizzare sarà un progetto di tipo WebApi: in Visual Studio 2019 creiamo un nuovo progetto di tipo API.

Create a new ASP.NET Core Web Application prompt

Definiamo quindi la classe Model che dovrà essere utilizzata per creare i post del blog. Posizioneremo questa classe all’interno della cartella Model e la chiameremo BlogPost:

public class BlogPost
{
	[Key]
	public int PostId { get; set; }
	
	[Required]
	public string Creator { get; set; }
	
	[Required]
	public string Title { get; set; }
	
	[Required]
	public string Body { get; set; }
	
	[Required]
	public DateTime Dt { get; set; }
}

dove tramite Annotation definiamo come chiave il campo PostId e tutti i campi richiesti. A questo punto possiamo creare la struttura delle api utilizzando lo scaffolding di Visual Studio: cliccando con il pulsante destro del mouse sulla cartella Controller, selezioniamo Aggiungi -> Controller e quindi Api Controller con EntityFramework ed impostando il modello nel seguente modo:

Add API controller with actions prompt

A questo punto, Visual Studio creerà per noi tutto l’occorrente per persistere i dati all’interno del database. In particolare, il context:

public class BlogPostsContext : DbContext
{
    public BlogPostsContext (DbContextOptions<BlogPostsContext> options)
        : base(options)
    {
    }

    public DbSet<BlogPost> BlogPosts { get; set; }
}

con la definizione della tabella BlogPosts con record di tipo BlogPost (la classe creata in precedenza). Per semplicità, le API non avranno ulteriori livelli di astrazione: per progetti piu’ complessi è molto utile suddividere il progetto a due (o più livelli), introducendo un layer di repository.

Il nostro API Controller sarà :

[Route("api/[controller]")]
[Produces("application/json")]
[ApiController]
public class BlogPostsController : ControllerBase
{
    private readonly BlogPostsContext _context;

    public BlogPostsController(BlogPostsContext context)
    {
        _context = context;
    }

    // GET: api/BlogPosts
    [HttpGet]
    public async Task<ActionResult<IEnumerable<BlogPost>>> GetBlogPost()
    {
        return await _context.BlogPosts.ToListAsync();
    }

    // GET: api/BlogPosts/5
    [HttpGet("{id}")]
    public async Task<ActionResult<BlogPost>> GetBlogPost(int id)
    {
        var blogPost = await _context.BlogPosts.FindAsync(id);

        if (blogPost == null)
        {
            return NotFound();
        }

        return blogPost;
    }

    // PUT: api/BlogPosts/5
    [HttpPut("{id}")]
    public async Task<IActionResult> PutBlogPost(int id, BlogPost blogPost)
    {
        if (id != blogPost.PostId)
        {
            return BadRequest();
        }

        _context.Entry(blogPost).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!BlogPostExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return NoContent();
    }

    // POST: api/BlogPosts
    [HttpPost]
    public async Task<ActionResult<BlogPost>> PostBlogPost(BlogPost blogPost)
    {
        _context.BlogPosts.Add(blogPost);
        await _context.SaveChangesAsync();

        return CreatedAtAction("GetBlogPost", new { id = blogPost.PostId }, blogPost);
    }

    // DELETE: api/BlogPosts/5
    [HttpDelete("{id}")]
    public async Task<ActionResult<BlogPost>> DeleteBlogPost(int id)
    {
        var blogPost = await _context.BlogPosts.FindAsync(id);
        if (blogPost == null)
        {
            return NotFound();
        }

        _context.BlogPosts.Remove(blogPost);
        await _context.SaveChangesAsync();

        return blogPost;
    }

    private bool BlogPostExists(int id)
    {
        return _context.BlogPosts.Any(e => e.PostId == id);
    }
}

Si può notare come le API utilizzano la sintassi del protocollo HTTP per la definzione dei metodi: GET ottenere la lista dei dati, POST per aggiungere nuovi dati, PUT per aggiornare dati esistenti, e DELETE per cancellarli.

Cors e applicazione WebApi

Il Cors, è spesso fonte di problemi nell’accesso dei dati nelle applicazioni web. AspNet Core, permette di gestire in maniera agevole il cors, modificando la classe Startup.cs, ed in particolare all’interno del metodo ConfigureServices .

public void ConfigureServices(IServiceCollection services)
{
  ...
  services.AddCors(options =>
  {
      options.AddPolicy("CorsPolicy",
          builder => builder.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader()
              .AllowCredentials());
  });
  ...
}

Utilizzando services.AddCors(…) possiamo definire le regole di accesso alle nostre api, in questo caso tutte le orgini sono consentite, tutti i metodi, tutti gli header e tutte le credenziali. Ovviamente, per applicazioni in produzione, è necessario, restringere l’accesso aumentando il grado di sicurezza.

A questo punto è necessario modificare anche il metodo Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  ...
  app.UseCors("CorsPolicy");
  ...
}

Creazione del Database

A questo punto è necessario procedere con la creazione del database. Abbiamo predisposto tutto, ma è ancora necessario utilizzare EntityFramework Core per la creazione della tabella. Il primo step riguarda la creazione della stringa di connessione all’interno del file file appSettings.json:

"ConnectionStrings": {
  "BlogPostsContext": "Server=(localdb)\\mssqllocaldb;Database=BlogPostContext-d08fc301-dc66-44e2-8e02-b408c55da2cf;Trusted_Connection=True;MultipleActiveResultSets=true"
}

All’interno di ConnectionStrings è stata definita la stringa di connessione chiamata BlogPostsContext. A questo punto siamo pronti per eseguire la “migration” e far creare direttamente ad entity framework la tabella. Dalla package manager console di Visual Studio ( Tools->NuGet Package Manager->Package Manager Console) eseguiamo il seguente comando:

Add-Migration Initial

Entity Framework ha quindi creato la prima migrazione che include la nuova tabella. Con il comando:

Update-Database

possiamo effettuare l’aggiornamento della struttura del database, creando di fatto la tabella. Ed anche il database è stato sistemato.

API Test

Rimane ancora da effettuare il test delle api realizzate: in particolare la creazione di un post all’interno del blog. Seguendo la struttura che abbiamo definito in precedenza, l’API /api/blogposts consente di ricedere dati in formato json, tramite HTTP POST e di salvarsi sul database. Per testarla, possiamo creare un semplice json così impostato:

{
  "dt": "2019-09-12T18:18:02.190Z",
  "creator": "Andrea",
  "title": "Blog Test",
  "body": "Testing body"
}

ed effettura la submit tramite un client, come ad esempio postman.

Nel prossimo articolo, realizzeremo una semplice UI in angular 8 che permetterà di interagire con le API appena realizzate.