ASP.NET Core Program.cs 設定實務

2022-10-29

.NET 6 將以往 .NET 專案中存在的 Program.cs 以及 Startup.cs 進行整合,只留下 Program.cs,本文將筆記在 .NET 6 使用各種服務以及環境設定所需要於 Program.cs 的設定。

logo

說明

初始專案

專案類型使用 Razor Pages 的預設組態。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

依賴注入服務

using CodeRestaurant.Services;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSingleton<ISuggestion, Suggestion>();
var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

如果是 Razor Pages 的專案類型,就可以在 cs 當中進行使用注入的服務,詳細的注入方式可以參考 ASP.NET Core Constructor Depedency Injection (DI)

使用 Windows 驗證

using Microsoft.AspNetCore.Authentication.Negotiate;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
   .AddNegotiate();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

_ViewImports.cshtml

@using ProjectName
@namespace ProjectName.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

_Layout.cshtml

使用的方式與 MVC 相當類似,只要配合 Razor 語法使用 User 就可以取得相關識別資訊。

@User.Identity?.Name!

API & Swagger

.NET 6 預設原生支援 Swagger,只需要在 Program.cs 服務中加入 AddControllersAddEndpointsApiExplorer 以及 AddSwaggerGen

並且在 app 加上 UseSwagger 以及 UseSwaggerUI 就可以藉由 Swagger 的路由來檢視 API。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
}
else
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
// https://localhost:port/swagger/index.html


app.UseHttpsRedirection();
app.UseStaticFiles();
app.MapRazorPages();
app.MapControllers();

app.Run();

而要提供 API 必須使用 MVC 的 Controller,由 Controller 扮演 API 的回應路由。

SuggestController.cs

[Route("api/[controller]")]
[ApiController]
public class SuggestController : ControllerBase
{
    [HttpGet]
    public string Get()
    {
        return "Hello Wolrd";
    }
}

在 View (或者是 Client 端) 的使用則以 Ajax 進行呼叫。此外利用了 appsettings.json 管理環境參數,讓 API 的網址集中管理。

appsettings.json

{
  "APIUri": "api/Suggest"
}

Index.cshtml.cs

public class IndexModel : PageModel
{
    public IndexModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration{ get; set; }

    public void OnGet()
    {

    }
}

Index.cshtml

$(() => {
    $.ajax({
        url: '@Model.Configuration["APIUri"]'
    }).done(data => $('#elementID').text(data));
})

EntityFramework Core Code First

搭配使用 Repository Pattern,使用依賴注入的方式來連線資料庫。

使用 UseLazyLoadingProxies 能夠讓 EF 搭配導覽屬性達到需要關聯資料的時候,才去做讀取。

builder.Services.AddDbContextPool<RestaurantContext>(
        options => options
            .UseLazyLoadingProxies()
            .UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddScoped<IRestaurantRepository, DbRestaurantRepository>();

Routing Rules

調整所支援的路由規則 LowercaseUrlsLowercaseQueryStrings,讓 Tag Helper 所渲染的 Url 以及 Query Strings 路由全採小寫。

如果在 Url 結尾需要固定加入斜線,則可以加入 AppendTrailingSlash

builder.Services.Configure<RouteOptions>(
    options =>
    {
        options.LowercaseUrls = true;
        options.LowercaseQueryStrings = true;
        options.AppendTrailingSlash = true;
    }
);