ASP.NET Core 面试题汇总

一、基础概念

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();

关键步骤:

  1. 创建 WebApplicationBuilder
  2. 注册服务(DI)
  3. 构建 WebApplication
  4. 配置中间件
  5. 配置路由
  6. 运行应用

二、依赖注入(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>();

十一、面试准备建议

重点复习内容:

  1. ✅ DI 生命周期和应用场景
  2. ✅ 中间件管道和顺序
  3. ✅ RESTful API 设计原则
  4. ✅ EF Core 基础和性能优化
  5. ✅ JWT 认证和授权
  6. ✅ 异步编程
  7. ✅ 缓存策略
  8. ✅ 日志记录

实践建议:

  • 创建一个完整的 CRUD API
  • 实现 JWT 认证
  • 使用 EF Core + 数据库迁移
  • 添加单元测试
  • 部署到 Docker

常见追问:

  • "如何处理并发问题?"
  • "如何实现分布式缓存?"
  • "如何处理大数据量查询?"
  • "如何实现 API 版本控制?"
  • "如何处理循环依赖?"

祝面试顺利! 🎉

相关推荐
独断万古他化2 小时前
【抽奖系统开发实战】Spring Boot 抽奖系统全链路总结:从架构到落地的实践复盘
java·spring boot·后端·架构·系列总结
小江的记录本2 小时前
【HashMap】HashMap 系统性知识体系全解(附《HashMap 面试八股文精简版》)
java·前端·后端·容器·面试·hash·哈希
咚为2 小时前
告别 lazy_static:深度解析 Rust OnceCell 的前世今生与实战
开发语言·后端·rust
bugcome_com2 小时前
ASP.NET Web Pages 教程 —— Razor 语法全面指南
前端·asp.net
代码探秘者2 小时前
【大模型应用】5.深入理解向量数据库
java·数据库·后端·python·spring·面试
逍遥德2 小时前
Postgresql explain执行计划详解
数据库·后端·sql·postgresql·数据分析
清汤饺子2 小时前
$20 的 Cursor Pro 额度,这样用一个月都花不完
前端·javascript·后端
WZTTMoon2 小时前
Spring Boot 启动报错:OpenFeign 隐性循环依赖,排查了整整一下午
java·spring boot·后端·spring cloud·feign
波波0075 小时前
ASP.NET MVC 中的返回类型全集详解
后端·asp.net·mvc