You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何替换已弃用的Microsoft.AspNetCore.Http及HttpContext

替代方案:使用ASP.NET Core现代请求处理方式

针对你原来基于Microsoft.AspNetCore.Http的请求处理逻辑,现在可以用ASP.NET Core的控制器或最小API来替代,这两种方式都是当前官方推荐的标准方案,完全替代旧的直接操作HttpContext的模式。

方案一:使用控制器(ControllerBase)

控制器是ASP.NET Core中结构化处理HTTP请求的主流方式,自动封装了请求响应的处理逻辑,无需直接操作原始HttpContext(如需获取,可通过HttpContextAccessor注入)。

转换后的示例代码

[ApiController]
[Route("your-route")]
public class YourController : ControllerBase
{
    private readonly ILogger<YourController> _log;
    private readonly IDictionary<string, IService> _serv;
    private readonly CancellationToken _hostCancellationToken;
    private readonly ICache _cache;
    private readonly IResponseBuilder _responseBuilder;
    private bool Started { get; set; }

    // 通过构造函数注入依赖
    public YourController(ILogger<YourController> log, 
                          IDictionary<string, IService> serv,
                          IHostApplicationLifetime hostLifetime,
                          ICache cache,
                          IResponseBuilder responseBuilder)
    {
        _log = log;
        _serv = serv;
        _hostCancellationToken = hostLifetime.ApplicationStopping;
        _cache = cache;
        _responseBuilder = responseBuilder;
    }

    [HttpGet]
    public async Task<IActionResult> HandleRequest([FromRoute] long version)
    {
        if (!Started)
        {
            return StatusCode((int)HttpStatusCode.ServiceUnavailable);
        }

        var format = GetAcceptedFormat(Request, _serv.Keys);
        if (!_serv.TryGetValue(format, out var serv))
        {
            return StatusCode((int)HttpStatusCode.NotImplemented, 
                $"Requested Content-Type {format} is not supported with current configuration.");
        }

        try
        {
            Response.ContentType = format;
            using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(_hostCancellationToken, HttpContext.RequestAborted);
            
            await Read(Response.Body, version, cancellationSource.Token);
            return Ok();
        }
        catch (ParameterException e)
        {
            return BadRequest(e.Message);
        }
        catch (KeyNotFoundException)
        {
            return NotFound("Not found");
        }
        catch (Exception e)
        {
            _log.LogError(e, "An exception occurred while writing the response");
            return StatusCode((int)HttpStatusCode.InternalServerError, e.ToString());
        }
    }

    public Task Read(Stream target, long version, CancellationToken ct)
    {
        return Task.Run(() =>
        {
            _cache.InTransaction(() =>
            {
                using var reader = _cache.GetReader();
                var (lastVersion, items) = (reader.GetVersion(), ReadByType(reader, version));
                _responseBuilder.WriteFrom(target, items, lastVersion, ct);
            });
        }, ct);
    }

    // 保留你的GetAcceptedFormat方法逻辑
    private string GetAcceptedFormat(HttpRequest request, IEnumerable<string> supportedFormats)
    {
        // 原逻辑实现
    }
}

关键替代点说明

  • 路由参数获取:用[FromRoute]特性直接绑定,替代context.GetRouteParameter<long>("version")
  • 响应状态码:使用ControllerBase提供的方法(如BadRequest()、NotFound()、StatusCode())替代自定义的FailWith扩展
  • 请求/响应访问:通过控制器的Request、Response属性访问,无需直接传入HttpContext
  • 依赖注入:通过构造函数注入所需服务(如日志、缓存),替代手动维护实例

方案二:使用最小API

如果你的业务逻辑简单,不需要复杂的控制器结构,可以用轻量的最小API,直接在Program.cs中定义端点:

转换后的示例代码

var builder = WebApplication.CreateBuilder(args);

// 注册依赖服务
builder.Services.AddSingleton<IDictionary<string, IService>>(yourServiceDictionary);
builder.Services.AddSingleton<ICache>(yourCache);
builder.Services.AddSingleton<IResponseBuilder>(yourResponseBuilder);

var app = builder.Build();
var hostCancellationToken = app.Lifetime.ApplicationStopping;
var log = app.Services.GetRequiredService<ILogger<Program>>();
var serv = app.Services.GetRequiredService<IDictionary<string, IService>>();
var cache = app.Services.GetRequiredService<ICache>();
var responseBuilder = app.Services.GetRequiredService<IResponseBuilder>();
bool started = false;

app.MapGet("your-route/{version:long}", async (HttpContext context, long version) =>
{
    if (!started)
    {
        return Results.StatusCode((int)HttpStatusCode.ServiceUnavailable);
    }

    var format = GetAcceptedFormat(context.Request, serv.Keys);
    if (!serv.TryGetValue(format, out var service))
    {
        return Results.StatusCode((int)HttpStatusCode.NotImplemented, 
            $"Requested Content-Type {format} is not supported with current configuration.");
    }

    try
    {
        context.Response.ContentType = format;
        using var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(hostCancellationToken, context.RequestAborted);
        
        await Read(context.Response.Body, version, cancellationSource.Token, cache, responseBuilder);
        return Results.Ok();
    }
    catch (ParameterException e)
    {
        return Results.BadRequest(e.Message);
    }
    catch (KeyNotFoundException)
    {
        return Results.NotFound("Not found");
    }
    catch (Exception e)
    {
        log.LogError(e, "An exception occurred while writing the response");
        return Results.StatusCode((int)HttpStatusCode.InternalServerError, e.ToString());
    }
});

app.Run();

// 提取Read方法为静态或注入服务
static Task Read(Stream target, long version, CancellationToken ct, ICache cache, IResponseBuilder responseBuilder)
{
    return Task.Run(() =>
    {
        cache.InTransaction(() =>
        {
            using var reader = cache.GetReader();
            var (lastVersion, items) = (reader.GetVersion(), ReadByType(reader, version));
            responseBuilder.WriteFrom(target, items, lastVersion, ct);
        });
    }, ct);
}

// 保留GetAcceptedFormat方法
static string GetAcceptedFormat(HttpRequest request, IEnumerable<string> supportedFormats)
{
    // 原逻辑实现
}

关键替代点说明

  • 端点定义:用MapGet等方法直接绑定路由和处理逻辑
  • 响应结果:使用Results静态类提供的方法返回标准HTTP响应
  • 依赖获取:通过app.Services获取已注册的服务,或直接在端点委托中注入

核心注意事项

  1. 取消令牌处理:两种方案都保留了CancellationTokenSource.CreateLinkedTokenSource的逻辑,结合主机停止令牌和请求中止令牌,确保请求能正确取消
  2. 错误处理:替代了自定义的FailWith,使用框架内置的响应方法,符合ASP.NET Core的标准错误处理流程
  3. 内容类型设置:仍然可以通过Response.ContentType设置响应的Content-Type,和原逻辑保持一致

内容的提问来源于stack exchange,提问作者user122222

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:16:20