## Pourquoi Déployer .NET sur Azure ?
Dans un environnement moderne, l'importance d'une application Web performante et fiable ne peut être sous-estimée. Les développeurs ont besoin d'un environnement robuste qui offre des performances élevées, des hauteurs de disponibilité et la possibilité de s'échapper rapidement des problèmes techniques. Azure, avec sa plateforme PaaS (Platform as a Service), offre une solution idéale pour déployer des applications .NET. En déployant sur Azure, les développeurs peuvent bénéficier d'un service fiable, scalable et sécurisé.
Un cas concret de déploiement .NET sur Azure est lorsqu'une entreprise souhaite développer une application web interne qui nécessite un grand nombre de connexions utilisateurs simultanées. Avec Azure, l'entreprise peut facilement augmenter le nombre d'instances pour gérer la charge et assurer une disponibilité élevée.
## Prerequis
- Connaissance approfondie du langage C#
- Familiarité avec les frameworks .NET (ASP.NET Core est préféré)
- Compréhension des concepts de base de l'infrastructure en nuage
- Installation d'Azure CLI
- Création d'un compte Azure et de ressources associées (comme un groupe de ressources, une application web, etc.)
## Concepts fondamentaux
### 1. App Service
L'App Service est le service PaaS d'Azure pour héberger des applications Web. Il prend en charge les langages .NET Core et .NET Framework.
```bash
## Installez l'extension Azure App Service pour Azure CLI
az extension add --name webapp
2. Groupe de ressources
Un groupe de ressources est un conteneur logique qui permet d'organiser les ressources Azure en fonction des besoins.
## Créez un groupe de ressources Azure
az group create --name "MyResourceGroup" --location "eastus"
3. Application Web
L'application web est l'environnement dans lequel votre application .NET est déployée.
## Créez une application web Azure
az webapp create --resource-group "MyResourceGroup" --name "my-dotnet-app" --runtime "DOTNETCORE|3.1"
Mise en pratique : Projet fil rouge
Nous allons construire un gestionnaire de tâches simple en utilisant ASP.NET Core et déployer sur Azure App Service.
Étape 1 : Création du projet
Créez un nouveau projet ASP.NET Core.
## Créez un nouveau projet ASP.NET Core avec l'interface utilisateur Razor Pages
dotnet new webapp -n TaskManager --framework net6.0
cd TaskManager
Étape 2 : Configuration des modèles de données et d'accès aux données
Créez une classe pour le modèle de tâche et configurez la base de données.
// Task.cs
public class Task
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsCompleted { get; set; }
}
// ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Task> Tasks { get; set; }
}
Étape 3 : Configuration de la chaîne de connexion à la base de données
Ajoutez une chaîne de connexion à votre fichier appsettings.json.
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=TaskManagerDb;Trusted_Connection=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Étape 4 : Création de la base de données
Ajoutez les migrations pour créer la base de données.
## Ajoutez une migration
dotnet ef migrations add InitialCreate
## Appliquez la migration
dotnet ef database update
Étape 5 : Configuration du contôleur et des vues
Créez un contrôleur et des vues pour gérer les tâches.
// TaskController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
public class TaskController : Controller
{
private readonly ApplicationDbContext _context;
public TaskController(ApplicationDbContext context)
{
_context = context;
}
// GET: /Task/
public async Task<IActionResult> Index()
{
return View(await _context.Tasks.ToListAsync());
}
// GET: /Task/Create
[HttpGet]
public IActionResult Create()
{
return View();
}
// POST: /Task/Create
[HttpPost]
public async Task<IActionResult> Create([Bind("Id,Title,IsCompleted")] Task task)
{
if (ModelState.IsValid)
{
_context.Add(task);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(task);
}
// GET: /Task/Edit/5
[HttpGet]
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var task = await _context.Tasks.FindAsync(id);
if (task == null)
{
return NotFound();
}
return View(task);
}
// POST: /Task/Edit/5
[HttpPost]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,IsCompleted")] Task task)
{
if (id != task.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(task);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TaskExists(task.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(task);
}
private bool TaskExists(int id)
{
return _context.Tasks.Any(e => e.Id == id);
}
}
Étape 6 : Création des vues Razor
Créez les vues pour afficher, créer et modifier les tâches.
<!-- Index.cshtml -->
@model List<TaskManager.Models.Task>
<h2>Task Manager</h2>
<p><a asp-action="Create">Create New Task</a></p>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Completed</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.Title</td>
<td>@item.IsCompleted</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<!-- Create.cshtml -->
@model TaskManager.Models.Task
<h2>Create Task</h2>
<form asp-action="Create">
<div class="form-group">
<label asp-for="Title"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsCompleted" /> @Html.DisplayNameFor(model => model.IsCompleted)
</label>
</div>
<button type="submit" class="btn btn-primary">Create</button>
</form>
<!-- Edit.cshtml -->
@model TaskManager.Models.Task
<h2>Edit Task</h2>
<form asp-action="Edit">
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Title"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsCompleted" /> @Html.DisplayNameFor(model => model.IsCompleted)
</label>
</div>
<button type="submit" class="btn btn-primary">Update</button>
</form>
Étape 7 : Déploiement sur Azure
Déployez votre application sur Azure App Service.
## Configurez la chaîne de connexion dans Azure
az webapp config appsettings set --resource-group "MyResourceGroup" --name "my-dotnet-app" --settings "ConnectionStrings:DefaultConnection=Server=(localdb)\\mssqllocaldb;Database=TaskManagerDb;Trusted_Connection=True;"
## Déployez l'application sur Azure
dotnet publish -c Release -o ./publish
az webapp deployment local-publish -n "my-dotnet-app" --src-path "./publish"
Erreurs fréquentes et debugging
1. Erreur de connexion à la base de données
Message d'erreur :
System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server.
Code incorrect :
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Task> Tasks { get; set; }
}
Code correct :
public class ApplicationDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=TaskManagerDb;Trusted_Connection=True;");
}
}
public DbSet<Task> Tasks { get; set; }
}
2. Erreur d'authentification
Message d'erreur :
System.InvalidOperationException: IDX10223: Unable to obtain OpenID Connect Configuration from discovery document.
Code incorrect :
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "https://your-identity-provider.com";
options.Audience = "your-audience";
});
Code correct :
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "https://your-identity-provider.com";
options.Audience = "your-audience";
options.RequireHttpsMetadata = false; // Temporaire pour le développement
});
3. Erreur de configuration de l'application web
Message d'erreur :
System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Extensions.Hosting.Abstractions'.
Code incorrect :
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Code correct :
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Pour aller plus loin
1. Authentification et autorisation avec Azure Active Directory (Azure AD)
Intégrez votre application à Azure AD pour gérer les utilisateurs et les autorisations.
2. Utilisation de SignalR pour des communications en temps réel
Ajoutez la possibilité de mettre à jour les tâches en temps réel avec SignalR.
3. Optimisation des performances et des coûts sur Azure
Améliorez la performance de votre application et gérez efficacement les coûts en optimisant le déploiement et la configuration.
Défi pratique
Développez un petit service API RESTful pour gérer des utilisateurs avec ASP.NET Core. Créez les endpoints pour créer, lire, mettre à jour et supprimer des utilisateurs.