Questa è la versione .NET MVC dell'applicazione Todo list in AngularJS e NodeJs.

Lato client ( AngularJS 1 ) non cambia niente, quello che cambia sono le API lato server in quanto sono implementate in Web API MVC.
HomeHome

La struttura delle cartelle dell'applicazione è questa:
Text
/
  app                  ... l'applicazione SPA AngularJS 1
    controllers        ... tutti i controllers dell'applicazione
      modal            ... i controllers delle pagine modali
    directives         ... le eventuali direttive
    others             ... l'entry point della applicazione
    pages              ... le pagine dell'applicazione
        modal          ... le pagine modali
    services           ... i service/factory che si occupano dell'accesso ai dati
    app.js             ... entry point angular js dove viene definita la APP
  App_Data             ... contiene lo script sql
  App_Start            ... inizializzatori MVC
    RouteConfig.cs     ... viene ridefinita la route di default per usare le url senza hash #
  Code
    Manager.cs         ... la classe che accede al DB (per semplicità di porting da NodeJS ho usato ADO.NET)
  Contents
    css                ... i css di bootstra e quelli custo dell'applicazione
    fonts              ... i font di bootstrap
    images             ... eventuali immagini
    js                 ... javscript librerie AngularJS
  Controllers          ... le pagine js lato server di nodejs (pagine e API)
    HomeController.js  ... il controller dell'unica pagina C# MVC
    TodoController.js  ... le API C# MVC
  Models
    BO                 ... gli oggetti usati dalle Web API
  Views
    Home
      Index.html       ... l'unica pagina C# MVC che funge da "Master Page"
  Global.asax          ... dove viene impostata la formattazione JSON camelCase delle Web API
  Web.config           ... dove è definita la connection string al DB
Rispetto alla versione NodeJs, essendo C# tipizzato, ho dovuto creare una serie di oggetti che rappresentano i contenuti JSON inviati dalle Web API (/Models/BO).

Come mia regola tendo a intercettare tutti gli errori possibili in modo che le Web API non sollevino mai eccezioni difficilmente gestibili lato client in JavaScript. Quindi tutte le risposte sono "wrappate" in un oggetto ServiceStatus:
C#
using System;
using System.Collections.Generic;

namespace Sgart.MvcAngularJS.Models.BO
{
  public class ServiceStatus
  {
    private const int SUCCESS_SECONDS = 2;

    public ServiceStatus()
    {
      Success = false;
      Messages = new List<ServiceStatusErrorItem>();
      ReturnValue = -1;
      ErrorCount = 0;
    }
    public bool Success { get; set; }
    public List<ServiceStatusErrorItem> Messages { get; set; }
    public object ReturnValue { get; set; }
    public int ErrorCount { get; set; }

    public void AddError(string message, int seconds = 0)
    {
      Messages.Add(new ServiceStatusErrorItem(ServiceStatusErrorType.Error, message, seconds));
      Success = false;
      ErrorCount++;
    }
    public void AddError(Exception ex, int seconds = 0)
    {
      Messages.Add(new ServiceStatusErrorItem(ServiceStatusErrorType.Error, ex.Message, seconds));
      Success = false;
      ErrorCount++;
    }

    public void AddWarning(string message, int seconds = 0)
    {
      Messages.Add(new ServiceStatusErrorItem(ServiceStatusErrorType.Warning, message, seconds));

    }
    public void AddWarning(Exception ex, int seconds = 0)
    {
      Messages.Add(new ServiceStatusErrorItem(ServiceStatusErrorType.Warning, ex.Message, seconds));
    }
    public void AddSuccess(string message, int seconds = SUCCESS_SECONDS)
    {
      Messages.Add(new ServiceStatusErrorItem(ServiceStatusErrorType.Success, message, seconds));
    }
    public void AddInfo(string message, int seconds = 0)
    {
      Messages.Add(new ServiceStatusErrorItem(ServiceStatusErrorType.Info, message, seconds));
    }
  }

  public class ServiceStatus<T> : ServiceStatus
  {
    public T Data { get; set; }
  }

  public class ServiceStatusList<T> : ServiceStatus<List<T>>
  {
    public ServiceStatusList() : base()
    {
    }
  }
}
la proprietà Data, di tipo "generics", conterrà il tipo di oggetto in risposta.
Il metodo delle Web API sarà sempre fatto secondo questo modello:
C#
[HttpGet]
[Route("todo/search")]
public BO.ServiceStatusList<BO.TodoItem> Search([FromUri] BO.SearchInputItem param)
{
  BO.ServiceStatusList<BO.TodoItem> result = new Models.BO.ServiceStatusList<Models.BO.TodoItem>();
  result.Data = new List<Models.BO.TodoItem>();
  try
  {
    result.Data = Metodo.Carica.Dati.Da.DB ...;
 
    result.AddSuccess("eventuale messaggio di successo");
    result.Success = true;  // settare a true se tutto OK
  }
  catch (Exception ex)
  {
    result.AddError(ex);  // messaggio di errore, success=false
  }
  return result;
}
Perché tutto funzioni senza modificare la app AngularJS devo fare in modo che le Web API rispondano secondo gli standard JavaScript ovvero in notazione camleCase. Posso ottenere questo aggiungendo del codice nel metodo Application_Start del Global.asax:
C#
protected void Application_Start()
{
  ...
  // forzo la formattazione dei nomi in stile JavaScript, camelCase
  var formatters = GlobalConfiguration.Configuration.Formatters;
  var jsonFormatter = formatters.JsonFormatter;
  var settings = jsonFormatter.SerializerSettings;
  settings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
}
In questa versione ho apportato una piccola modifica lato AngularJS per fare in modo che le url del browser non contengano il carattere hash (#).
Questo lo si ottiene agendo sul file nel file /app/others/app-route.js (solo sui browser moderni):
JavaScript
// configure html5 to get links working
// you URLs will be sgart.it/home rather than sgart.it/#/home
$locationProvider.html5Mode({ enabled: true });
e impostando il tag base nell'head della pagina /Views/home/Index.cshtml:
HTML
<!DOCTYPE html>
<html data-ng-app="app" data-ng-cloak>
<head>
  ...
  <!-- base: necessario ad angular per gestire i path senza hash # -->
  <base href="/">
  ...
</head>
L'ultima modifica che ho apportato è a livello grafico, agendo solo sul CSS, per dare un diverso feedback all'utente durante le chiamate alle API:
waitwait

Il codice sorgente può essere scaricato da qui Download SgarMvcAngularJS o da GitHub. E può essere compilato e modificato con Visual Studio 2015 Community (versione gratuita). Se non funziona aggiorna i pacchetti NuGet.

Per funzionare è necessario che sulla macchina sia presente un database Microsoft SQL Server.
Fatto questo è necessario creare il database tramite lo script /App_data/schema.sql ed eventualmente cambiare i parametri di configurazione in nel Web.config


05/10/2019 Aggiunto i progetti su GitHub:
Potrebbe interessarti anche: