一、基础概念
1. 什么是 ASP.NET Core?
答案:
ASP.NET Core 是一个跨平台、高性能的开源 Web 框架,用于构建现代的、基于云的互联网应用。它是 ASP.NET 的重新设计,支持 Windows、Linux、macOS,可以部署到 IIS、Nginx、Docker、Azure 等多种环境。
关键特点:
- 跨平台
- 高性能
- 开源
- 统一的 MVC 和 Web API 框架
- 内置依赖注入
- 模块化中间件管道
2. ASP.NET Core 和 ASP.NET 的区别?
| 特性 | ASP.NET | ASP.NET Core |
|---|---|---|
| 平台 | 仅 Windows | 跨平台(Win/Linux/macOS) |
| 性能 | 较慢 | 更快 |
| 部署 | IIS | 多种(Docker、Nginx、IIS) |
| 依赖注入 | 需要第三方 | 内置 |
| 配置 | Web.config | appsettings.json + 环境变量 |
| 包管理 | NuGet + GAC | 仅 NuGet |
| 编译 | 运行时编译 | JIT + AOT |
3. ASP.NET Core 的启动流程?
csharp
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 1. 配置服务(依赖注入)
builder.Services.AddControllers();
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
var app = builder.Build();
// 2. 配置中间件管道
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// 3. 配置终结点
app.MapControllers();
// 4. 运行应用
app.Run();
关键步骤:
- 创建
WebApplicationBuilder - 注册服务(DI)
- 构建
WebApplication - 配置中间件
- 配置路由
- 运行应用
二、依赖注入(DI)
4. 什么是依赖注入?ASP.NET Core 如何实现?
答案:
依赖注入是一种设计模式,通过外部注入依赖对象,而不是在类内部创建。ASP.NET Core 内置了轻量级的 DI 容器。
三种服务生命周期:
csharp
// Transient:每次请求都创建新实例
builder.Services.AddTransient<IMyService, MyService>();
// Scoped:每个 HTTP 请求一个实例
builder.Services.AddScoped<IMyService, MyService>();
// Singleton:整个应用程序生命周期一个实例
builder.Services.AddSingleton<IMyService, MyService>();
使用场景:
Transient:轻量级、无状态的服务Scoped:有状态的服务,每个请求独立(如 DbContext)Singleton:全局共享的服务(如配置、缓存)
5. 如何在控制器中使用 DI?
csharp
public class HomeController : ControllerBase
{
private readonly IMyService _myService;
private readonly ILogger<HomeController> _logger;
// 构造函数注入
public HomeController(IMyService myService, ILogger<HomeController> logger)
{
_myService = myService;
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
var result = _myService.GetData();
_logger.LogInformation("Data fetched");
return Ok(result);
}
}
三、中间件(Middleware)
6. 什么是中间件?中间件的执行顺序?
答案:
中间件是一个处理 HTTP 请求和响应的组件,按顺序组成管道。每个中间件可以:
- 决定是否传递给下一个中间件
- 在请求和响应之前/之后执行逻辑
中间件顺序很重要!
csharp
var app = builder.Build();
// 1. 异常处理(应该在最外层)
app.UseExceptionHandler("/error");
// 2. HTTPS 重定向
app.UseHttpsRedirection();
// 3. 静态文件
app.UseStaticFiles();
// 4. 路由
app.UseRouting();
// 5. 认证
app.UseAuthentication();
// 6. 授权
app.UseAuthorization();
// 7. 终结点
app.MapControllers();
app.Run();
7. 如何创建自定义中间件?
方式一:内联中间件
csharp
app.Use(async (context, next) =>
{
// 请求处理前
Console.WriteLine($"请求: {context.Request.Path}");
await next();
// 请求处理后
Console.WriteLine($"响应状态: {context.Response.StatusCode}");
});
方式二:中间件类
csharp
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine($"请求: {context.Request.Path}");
await _next(context);
Console.WriteLine($"响应状态: {context.Response.StatusCode}");
}
}
// 扩展方法
public static class LoggingMiddlewareExtensions
{
public static IApplicationBuilder UseLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoggingMiddleware>();
}
}
// 使用
app.UseLogging();
四、MVC 和 Web API
8. MVC 和 Web API 的区别?
在 ASP.NET Core 中,MVC 和 Web API 已经统一了,都使用 ControllerBase 基类。
主要区别:
- MVC:返回视图(HTML),用于 Web 应用
- Web API:返回数据(JSON/XML),用于 RESTful API
示例:
csharp
// MVC Controller
public class HomeController : Controller
{
public IActionResult Index()
{
return View(); // 返回 HTML 视图
}
}
// API Controller
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok(new { Name = "张三" }); // 返回 JSON
}
}
9. 什么是 RESTful API?如何在 ASP.NET Core 中实现?
RESTful API 原则:
- 使用 HTTP 动词(GET、POST、PUT、DELETE)
- 无状态
- 统一接口
- 资源导向
示例:
csharp
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
// GET api/products
[HttpGet]
public ActionResult<IEnumerable<Product>> GetAll()
{
return Ok(_context.Products.ToList());
}
// GET api/products/5
[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
return Ok(product);
}
// POST api/products
[HttpPost]
public ActionResult<Product> Create(Product product)
{
_context.Products.Add(product);
_context.SaveChanges();
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
// PUT api/products/5
[HttpPut("{id}")]
public IActionResult Update(int id, Product product)
{
var existing = _context.Products.Find(id);
if (existing == null)
return NotFound();
existing.Name = product.Name;
existing.Price = product.Price;
_context.SaveChanges();
return NoContent();
}
// DELETE api/products/5
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
_context.Products.Remove(product);
_context.SaveChanges();
return NoContent();
}
}
五、Entity Framework Core
10. 什么是 ORM?EF Core 的优势?
答案:
ORM(对象关系映射)是一种技术,将关系数据库映射到面向对象模型。
EF Core 优势:
- 不需要写 SQL 语句
- LINQ 查询,类型安全
- 数据库迁移
- 支持多种数据库(SQL Server、MySQL、PostgreSQL 等)
- 变更跟踪
11. DbContext 是什么?如何配置?
csharp
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置实体关系
modelBuilder.Entity<Product>()
.HasOne(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);
}
}
// 注册 DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
12. 什么是迁移(Migration)?如何使用?
答案:
迁移是管理数据库架构变更的工具,将代码模型同步到数据库。
bash
# 安装 EF Core 工具
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
# 创建迁移
dotnet ef migrations add InitialCreate
# 查看迁移 SQL
dotnet ef migrations script
# 应用迁移
dotnet ef database update
# 回滚迁移
dotnet ef database update 0
13. 如何优化 EF Core 查询性能?
1. 使用 AsNoTracking
csharp
// 只读查询,不跟踪变更
var products = _context.Products
.AsNoTracking()
.ToList();
2. 使用 Include 加载关联数据
csharp
// 预先加载
var products = _context.Products
.Include(p => p.Category)
.Include(p => p.OrderItems)
.ToList();
3. 分页
csharp
var products = _context.Products
.Skip(pageSize * (pageNumber - 1))
.Take(pageSize)
.ToList();
4. 选择性加载
csharp
var products = _context.Products
.Select(p => new { p.Id, p.Name, p.Price }) // 只查询需要的字段
.ToList();
六、身份验证和授权
14. Authentication 和 Authorization 的区别?
| Authentication(认证) | Authorization(授权) | |
|---|---|---|
| 定义 | 验证用户身份 | 验证用户权限 |
| 问题 | "你是谁?" | "你能做什么?" |
| 示例 | 登录、JWT Token | 角色访问控制 |
15. 如何在 ASP.NET Core 中实现 JWT 认证?
csharp
// 1. 安装包
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
// 2. 配置 JWT
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Audience,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
};
});
// 3. 使用
app.UseAuthentication();
app.UseAuthorization();
// 4. 生成 Token
public string GenerateToken(User user)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, user.Role)
};
var token = new JwtSecurityToken(
issuer: _jwtSettings.Issuer,
audience: _jwtSettings.Audience,
claims: claims,
expires: DateTime.Now.AddHours(24),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
16. 如何使用授权?
csharp
// 基于角色的授权
[Authorize(Roles = "Admin")]
public IActionResult AdminOnly()
{
return Ok("管理员才能访问");
}
// 基于策略的授权
// 配置策略
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("MinimumAge", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(18));
});
// 使用策略
[Authorize(Policy = "MinimumAge")]
public IActionResult AdultOnly()
{
return Ok("18岁以上才能访问");
}
// 获取当前用户信息
[HttpGet]
public IActionResult GetCurrentUserId()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return Ok(userId);
}
七、配置和日志
17. ASP.NET Core 如何管理配置?
csharp
// appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=mydb;"
},
"JwtSettings": {
"SecretKey": "your-secret-key",
"Issuer": "yourdomain.com",
"Audience": "yourdomain.com"
}
}
// 读取配置
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();
// 使用选项模式
builder.Services.Configure<JwtSettings>(
builder.Configuration.GetSection("JwtSettings"));
18. 如何使用日志?
csharp
public class ProductService
{
private readonly ILogger<ProductService> _logger;
public ProductService(ILogger<ProductService> logger)
{
_logger = logger;
}
public void Create(Product product)
{
_logger.LogInformation("Creating product: {Name}", product.Name);
try
{
// 创建逻辑
_logger.LogInformation("Product created successfully");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating product");
throw;
}
}
}
日志级别:
Trace:最详细的调试信息Debug:开发调试信息Information:一般信息Warning:警告信息Error:错误信息Critical:严重错误
八、性能优化
19. 如何提高 ASP.NET Core 应用性能?
1. 使用异步方法
csharp
// 好的做法
public async Task<IActionResult> Get()
{
var products = await _context.Products.ToListAsync();
return Ok(products);
}
// 不好的做法(同步阻塞)
public IActionResult Get()
{
var products = _context.Products.ToList(); // 同步
return Ok(products);
}
2. 使用缓存
csharp
builder.Services.AddMemoryCache();
public class ProductService
{
private readonly IMemoryCache _cache;
public async Task<Product> GetProductAsync(int id)
{
if (!_cache.TryGetValue(id, out Product product))
{
product = await _context.Products.FindAsync(id);
_cache.Set(id, product, TimeSpan.FromMinutes(30));
}
return product;
}
}
3. 使用响应压缩
csharp
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
});
app.UseResponseCompression();
4. 使用 CDN 和静态文件缓存
csharp
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append("Cache-Control",
"public,max-age=31536000");
}
});
20. 什么是 Kestrel?为什么比 IIS 快?
答案:
Kestrel 是 ASP.NET Core 内置的跨平台 Web 服务器。
优势:
- 轻量级、高性能
- 跨平台
- 专为 ASP.NET Core 优化
- 支持异步 I/O
典型部署架构:
Internet → Nginx/IIS → Kestrel → ASP.NET Core
Nginx/IIS 作为反向代理,处理 SSL、静态文件、负载均衡。
九、常见面试代码题
21. 实现一个简单的缓存装饰器
csharp
public interface IProductService
{
Task<Product> GetProductAsync(int id);
}
public class CachedProductService : IProductService
{
private readonly IProductService _innerService;
private readonly IMemoryCache _cache;
public CachedProductService(
IProductService innerService,
IMemoryCache cache)
{
_innerService = innerService;
_cache = cache;
}
public async Task<Product> GetProductAsync(int id)
{
string cacheKey = $"product_{id}";
if (_cache.TryGetValue(cacheKey, out Product cachedProduct))
{
return cachedProduct;
}
var product = await _innerService.GetProductAsync(id);
_cache.Set(cacheKey, product, TimeSpan.FromMinutes(30));
return product;
}
}
22. 实现全局异常处理中间件
csharp
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
public GlobalExceptionMiddleware(
RequestDelegate next,
ILogger<GlobalExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "未处理的异常");
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
var error = new
{
Message = "服务器内部错误",
Details = context.Request.Headers.ContainsKey("X-Debug")
? ex.Message : null
};
await context.Response.WriteAsJsonAsync(error);
}
}
}
// 使用
app.UseMiddleware<GlobalExceptionMiddleware>();
十、进阶话题
23. 什么是 SignalR?
答案:
SignalR 是一个实时通信库,用于向连接的客户端推送内容。
使用场景:
- 聊天应用
- 实时通知
- 实时更新(股票、游戏)
- 协作编辑
示例:
csharp
// Hub
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
// 客户端调用
await hubConnection.InvokeAsync("SendMessage", "张三", "你好");
// 监听消息
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
Console.WriteLine($"{user}: {message}");
});
24. 什么是健康检查?
csharp
// 安装包
dotnet add package Microsoft.AspNetCore.Diagnostics.HealthChecks
dotnet add package AspNetCore.HealthChecks.NpgSql
// 配置
builder.Services.AddHealthChecks()
.AddNpgSql(connectionString)
.AddRedis(redisConnectionString);
// 端点
app.MapHealthChecks("/health");
// 响应内容
app.MapHealthChecks("/health-detailed", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
context.Response.ContentType = "application/json";
var result = JsonSerializer.Serialize(report);
await context.Response.WriteAsync(result);
}
});
25. 什么是 BackgroundService?
csharp
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(5000, stoppingToken);
}
}
}
// 注册
builder.Services.AddHostedService<Worker>();
十一、面试准备建议
重点复习内容:
- ✅ DI 生命周期和应用场景
- ✅ 中间件管道和顺序
- ✅ RESTful API 设计原则
- ✅ EF Core 基础和性能优化
- ✅ JWT 认证和授权
- ✅ 异步编程
- ✅ 缓存策略
- ✅ 日志记录
实践建议:
- 创建一个完整的 CRUD API
- 实现 JWT 认证
- 使用 EF Core + 数据库迁移
- 添加单元测试
- 部署到 Docker
常见追问:
- "如何处理并发问题?"
- "如何实现分布式缓存?"
- "如何处理大数据量查询?"
- "如何实现 API 版本控制?"
- "如何处理循环依赖?"
祝面试顺利! 🎉