.Net和.Net Core面试
1、Asp.net页面之间传递值的几种方式
QueryString,Cookie,Session,Application,Server.Transfer
https://blog.csdn.net/ba_wang_mao/article/details/118105359
2、解释.net core中间件
中间件是一种在请求管道中处理HTTP请求和响应的组件。它们可以执行各种任务,如身份验证、授权、日志记录等。每个中间件都有机会处理请求或将请求传递给下一个中间件。
https://www.cnblogs.com/xixi-in-summer/p/18081145
3、如何在ASP.NET Core应用程序中配置依赖注入(Dependency Injection)?
在ASP.NET Core中,可以通过Startup.cs文件中的ConfigureServices方法配置依赖注入。服务可以注册为Transient、Scoped或Singleton,并在控制器或其他类中通过构造函数注入使用这些服务。
查看代码
 public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 注册Transient服务
        services.AddTransient<IMyService, MyService>();
        // 注册Scoped服务
        services.AddScoped<IMyScopedService, MyScopedService>();
        // 注册Singleton服务
        services.AddSingleton<IMySingletonService, MySingletonService>();
        // 注册其他服务
        services.AddControllers();
    }
}
查看代码
 public class MyController : ControllerBase
{
    private readonly IMyService _myService;
    // 通过构造函数注入服务
    public MyController(IMyService myService)
    {
        _myService = myService;
    }
    [HttpGet]
    public IActionResult Get()
    {
        var result = _myService.DoSomething();
        return Ok(result);
    }
}
4、ASP.NET Core中的配置管理(Configuration Management)是如何工作的?
ASP.NET Core使用一个灵活的配置系统,可以从多个来源加载配置,如appsettings.json文件、环境变量、命令行参数等。配置值可以通过IConfiguration接口在代码中读取。
配置提供程序(Configuration Providers)用于从不同的来源(如 appsettings.json)加载配置数据。
查看代码
 public class Startup
{
    public IConfiguration Configuration { get; }//表示配置的接口,用于访问配置数据。
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public void ConfigureServices(IServiceCollection services)
    {
        // 从配置中读取值
        var mySetting = Configuration["MySetting"];
        var connectionString = Configuration.GetConnectionString("DefaultConnection");
        // 注册服务
        services.AddControllers();
    }
}
appsettings.json文件:
{
  "MySetting": "Hello, World!",
  "ConnectionStrings": {
    "DefaultConnection": "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"
  }
}
5、请解释ASP.NET Core中的路由(Routing)机制。
ASP.NET Core 中的路由机制用于将传入的 HTTP 请求映射到相应的控制器和操作方法。它决定了应用程序如何响应特定的 URL 请求。
在 ASP.NET Core 中,路由可以通过以下两种方式配置:
5.1、约定路由(Conventional Routing):
在 Startup.cs 文件的 Configure 方法中配置。
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});
这种方式适用于大多数 MVC 应用程序。
5.2、属性路由(Attribute Routing):
直接在控制器或操作方法上使用 [Route] 属性定义路由。
[Route("api/[controller]")]
public class ProductsController : Controller
{
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        // 处理请求
    }
}
///api/Products/Get/5
这种方式适用于 Web API 或需要更细粒度控制的场景。
6、如何在ASP.NET Core中实现身份验证(Authentication)?
可以使用ASP.NET Core Identity来实现身份验证,它提供用户注册、登录、角色管理等功能。此外,还可以使用Cookie、JWT(JSON Web Tokens)、OAuth等外部身份验证机制。
(1)配置认证服务
Identity
 public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
    services.AddControllersWithViews();
    services.AddRazorPages();
}
Cookie
 public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication("CookieAuth")
            .AddCookie("CookieAuth", options =>
            {
                options.Cookie.Name = "YourAppCookie";
                options.LoginPath = "/Account/Login"; // 登录页面路径
                options.AccessDeniedPath = "/Account/AccessDenied"; // 访问被拒绝页面路径
            });
    services.AddControllersWithViews();
}
JWT
 public void ConfigureServices(IServiceCollection services)
{
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSecretKey"));
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = "YourIssuer",
                    ValidAudience = "YourAudience",
                    IssuerSigningKey = key
                };
            });
    services.AddControllersWithViews();
}
(2)启用认证中间件
查看代码
 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?}");
        endpoints.MapRazorPages();
    });
}
(3) 注册和登录示例
Identity注册
 public class AccountController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }
    [HttpGet]
    public IActionResult Register()
    {
        return View();
    }
    [HttpPost]
    public async Task<IActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email, FullName = model.FullName };
            var result = await _userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return RedirectToAction("Index", "Home");
            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }
        return View(model);
    }
}
Cookie登录
 public class AccountController : Controller
{
    [HttpGet]
    public IActionResult Login()
    {
        return View();
    }
    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            // 验证用户凭据
            var user = AuthenticateUser(model.Username, model.Password);
            if (user != null)
            {
                var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, user.Username),
                    new Claim(ClaimTypes.Role, user.Role)
                };
                var claimsIdentity = new ClaimsIdentity(claims, "CookieAuth");
                var authProperties = new AuthenticationProperties
                {
                    IsPersistent = model.RememberMe
                };
                await HttpContext.SignInAsync("CookieAuth", new ClaimsPrincipal(claimsIdentity), authProperties);
                return RedirectToAction("Index", "Home");
            }
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
        }
        return View(model);
    }
    private User AuthenticateUser(string username, string password)
    {
        // 实现用户验证逻辑
        // 返回用户信息或 null
    }
}
JWT服务实现
 public class JwtService
{
    private readonly IConfiguration _configuration;
    public JwtService(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    public string GenerateToken(User user)
    {
        var securityKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        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: _configuration["Jwt:Issuer"],
            audience: _configuration["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddHours(1),
            signingCredentials: credentials
        );
        return new JwtSecurityTokenHandler().WriteToken(token);
        //登录可返回token
        //return Ok(new { token = _jwtService.GenerateToken(userInfo) });
    }
}
(4)授权特性使用
使用 [Authorize] 属性保护需要认证的控制器或操作。
[Authorize]  // 需要认证
public class SomeController : Controller
{
    [AllowAnonymous]  // 允许匿名访问
    public IActionResult PublicAction()
    {
        return View();
    }
    [Authorize(Roles = "Admin")]  // 需要Admin角色
    public IActionResult AdminOnly()
    {
        return View();
    }
    [Authorize(Policy = "RequireAdminRole")]  // 使用策略
    public IActionResult PolicyBasedAction()
    {
        return View();
    }
}
(5)配置自定义授权策略(可选)
可以在 ConfigureServices 方法中配置授权策略,以便更灵活地控制访问权限。
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
        options.AddPolicy("MemberOnly", policy => policy.RequireRole("Member"));
    });
    services.AddControllersWithViews();
}
然后在控制器或操作中使用这些策略:
[Authorize(Policy = "AdminOnly")]
public IActionResult Admin()
{
    return View();
}
7、请解释ASP.NET Core中的过滤器(Filters)。
过滤器是 ASP.NET Core MVC 或 Razor Pages 中的一种机制,用于在特定的 MVC 操作(Action)或页面处理生命周期中执行代码。它们可以作用于控制器、操作方法或全局。ASP.NET Core提供了多种内置过滤器,如授权过滤器、资源过滤器、动作过滤器和异常过滤器。还可以创建自定义过滤器来实现特定的业务逻辑。
ASP.NET Core 提供了以下类型的过滤器:
授权过滤器(Authorization Filters):用于处理身份验证和授权。
资源过滤器(Resource Filters):在模型绑定之前和之后执行,通常用于模型验证。
操作过滤器(Action Filters):在操作方法执行前后执行,用于日志记录。
结果过滤器(Result Filters):在操作结果执行前后执行。用于缓存。
异常过滤器(Exception Filters):用于处理操作或结果中的异常。
自定义操作过滤器示例:
public class CustomActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // 在操作方法执行之前执行
        Console.WriteLine("Before Action Execution");
    }
    public void OnActionExecuted(ActionExecutedContext context)
    {
        // 在操作方法执行之后执行
        Console.WriteLine("After Action Execution");
    }
}
在控制器或操作方法上应用过滤器:
[ServiceFilter(typeof(CustomActionFilter))]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}
全局过滤器:
在 Startup.cs 中注册全局过滤器:
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add(new CustomActionFilter());
    });
}
过滤器 vs 中间件
| 特性 | 中间件 | 过滤器 | 
|---|---|---|
| 作用范围 | 全局,作用于所有请求 | 局部,作用于特定的控制器或操作方法 | 
| 执行顺序 | 在请求管道的早期阶段执行 | 在 MVC 或 Razor Pages 生命周期中执行 | 
| 使用场景 | 全局异常处理、日志记录、身份验证等 | 身份验证、模型验证、缓存、异常处理等 | 
| 与 MVC 的关系 | 独立于 MVC,适用于所有请求 | 与 MVC 或 Razor Pages 紧密相关 | 
| 灵活性 | 更底层,直接操作 HTTP 上下文 | 更高级,与 MVC 生命周期集成 | 
总结
- 
中间件:适用于全局的请求处理,更接近底层,适合处理与 HTTP 上下文直接相关的任务。
 - 
过滤器:适用于 MVC 或 Razor Pages 的特定生命周期阶段,适合处理与业务逻辑相关的任务。
 
在实际开发中,中间件和过滤器可以结合使用,以实现更灵活和强大的请求处理机制。例如,可以使用中间件处理全局身份验证,而使用过滤器处理特定控制器的授权或日志记录。
8、如何在ASP.NET Core中实现缓存?
ASP.NET Core 提供了多种缓存机制,包括内存缓存、分布式缓存和响应缓存。内存缓存适用于单节点应用,分布式缓存适用于多节点或集群环境。
8.1、内存缓存(In-Memory Cache)
内存缓存是将数据存储在应用程序的内存中,适用于单服务器场景。
(1)配置内存缓存服务
在 Startup.cs 的 ConfigureServices 方法中注册内存缓存服务:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache(); // 注册内存缓存服务
    services.AddControllersWithViews();
}
(2)使用内存缓存
在控制器或服务中注入 IMemoryCache 并使用缓存。
查看代码
 using Microsoft.Extensions.Caching.Memory;
public class HomeController : Controller
{
    private readonly IMemoryCache _memoryCache;
    public HomeController(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }
    public IActionResult Index()
    {
        // 尝试从缓存中获取数据
        if (!_memoryCache.TryGetValue("CachedTime", out DateTime cachedTime))
        {
            // 如果缓存中没有数据,则生成数据并存入缓存
            cachedTime = DateTime.Now;
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromSeconds(30)); // 设置滑动过期时间
            _memoryCache.Set("CachedTime", cachedTime, cacheEntryOptions);
        }
        ViewBag.CachedTime = cachedTime;
        return View();
    }
}
(3)缓存选项
var cacheEntryOptions = new MemoryCacheEntryOptions()
    .SetAbsoluteExpiration(TimeSpan.FromMinutes(10)) // 绝对过期时间
    .SetSlidingExpiration(TimeSpan.FromSeconds(30))  // 滑动过期时间
    .SetPriority(CacheItemPriority.High)            // 缓存优先级
    .RegisterPostEvictionCallback((key, value, reason, state) =>//缓存回调
    {
        Console.WriteLine($"Cache entry {key} was evicted: {reason}");
    });
8.2、分布式缓存(Distributed Cache)
分布式缓存适用于多服务器场景,数据存储在共享的外部存储中(如 Redis、SQL Server 等)。
(1)配置分布式缓存服务
以 Redis 为例,安装 NuGet 包:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
在 Startup.cs 中注册 Redis 分布式缓存服务:
public void ConfigureServices(IServiceCollection services)
{
    services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = "localhost:6379"; // Redis 连接字符串
        options.InstanceName = "SampleInstance";  // 实例名称
    });
    services.AddControllersWithViews();
}
(2)使用分布式缓存
在控制器或服务中注入 IDistributedCache 并使用缓存。
查看代码
 using Microsoft.Extensions.Caching.Distributed;
using System.Text;
public class HomeController : Controller
{
    private readonly IDistributedCache _distributedCache;
    public HomeController(IDistributedCache distributedCache)
    {
        _distributedCache = distributedCache;
    }
    public async Task<IActionResult> Index()
    {
        var cacheKey = "CachedTime";
        var cachedTime = await _distributedCache.GetStringAsync(cacheKey);
        if (cachedTime == null)
        {
            cachedTime = DateTime.Now.ToString();
            var options = new DistributedCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromSeconds(30));
            await _distributedCache.SetStringAsync(cacheKey, cachedTime, options);
        }
        ViewBag.CachedTime = cachedTime;
        return View();
    }
}
8.3、响应缓存(Response Cache)
响应缓存用于缓存 HTTP 响应,适用于缓存整个页面或 API 响应。
(1)配置响应缓存服务
在 Startup.cs 中注册响应缓存服务:
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCaching(); // 注册响应缓存服务
    services.AddControllersWithViews();
}
在 Configure 方法中启用响应缓存中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseResponseCaching(); // 启用响应缓存中间件
    // 其他中间件
}
(2)使用响应缓存
在控制器或操作方法上使用 [ResponseCache] 特性。
[ResponseCache(Duration = 60)] // 缓存 60 秒
public class HomeController : Controller
{
    [ResponseCache(Duration = 30)] // 缓存 30 秒
    public IActionResult Index()
    {
        ViewBag.CurrentTime = DateTime.Now.ToString();
        return View();
    }
}
(3)缓存选项
/*Duration:缓存持续时间(秒)。
Location:缓存位置(Any、Client、None)。
VaryByHeader:根据 HTTP 头变化缓存。
VaryByQueryKeys:根据查询字符串变化缓存。*/
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client, VaryByHeader = "User-Agent")]
public IActionResult Index()
{
    ViewBag.CurrentTime = DateTime.Now.ToString();
    return View();
}
9、如何在ASP.NET Core中进行性能调优?
可以通过使用缓存、优化数据库查询、减少不必要的中间件、使用异步编程、内存优化、减少视图的复杂性、压缩和缩小静态资源等方法来进行性能调优。
9.1、使用异步编程
使用 async 和 await 关键字处理 I/O 操作(如数据库查询、文件读写、网络请求等),避免阻塞线程,提高并发处理能力。
查看代码
 public class OptimizedController : Controller
{
    private readonly IProductService _productService;
    private readonly IOrderService _orderService;
    [HttpGet]
    public async Task<IActionResult> GetDashboardData()
    {
        // 并行执行多个独立的异步操作
        var tasks = new[]
        {
            _productService.GetProductsAsync(),
            _orderService.GetOrdersAsync()
        };
        await Task.WhenAll(tasks);
        return Ok(new
        {
            Products = tasks[0].Result,
            Orders = tasks[1].Result
        });
    }
    // 避免使用async void
    [HttpPost]
    public async Task<IActionResult> ProcessData()
    {
        try
        {
            await _productService.ProcessAsync();
            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理数据时出错");
            return StatusCode(500);
        }
    }
    
    //使用 Task.Run 将同步方法包装为异步方法。
    public async Task<IActionResult> GetData()
    {
        var data = await Task.Run(() => _syncService.GetData());
        return Ok(data);
    }
}
9.2、数据库优化
- 使用索引,为常用的查询字段创建索引
 
CREATE INDEX IX_Users_Name ON Users (Name);
- 批量操作,减少数据库往返次数
 
_dbContext.Users.AddRange(users);
await _dbContext.SaveChangesAsync();
- 使用分页,避免一次性加载过多数据
 
public async Task<(List<Product> Items, int Total)> GetPagedProductsAsync(
    int page, 
    int pageSize)
{
    var query = _context.Products.AsNoTracking();
    
    var total = await query.CountAsync();
    var items = await query
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToListAsync();
    return (items, total);
}
- 优化 LINQ 查询,减少数据库查询的开销
 
public async Task<List<Product>> GetProductsOptimizedAsync()
{
    return await _context.Products
        .AsNoTracking() // 禁用实体跟踪
        .Select(p => new Product 
        {
            Id = p.Id,
            Name = p.Name
            // 只选择需要的字段
        })
        .ToListAsync();
}
                    
                
                
            
        
浙公网安备 33010602011771号