Asp.Net Core 5中直接使用HttpContext时WebMarkupMin压缩异常
场景复现
在Asp.Net Core 5项目中使用WebMarkupMin库压缩cshtml文件,同时为了全局便捷使用HttpContext添加了HttpContextHelper工具类。配置完成后出现ArgumentNullException: Value cannot be null. (Parameter 'destination')异常,移除HttpContext相关配置后视图恢复正常显示。
相关代码
Startup.cs配置
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddWebMarkupMin( options => { options.AllowMinificationInDevelopmentEnvironment = true; options.AllowCompressionInDevelopmentEnvironment = true; }) .AddHtmlMinification( options => { options.MinificationSettings.RemoveRedundantAttributes = true; options.MinificationSettings.RemoveHttpProtocolFromAttributes = true; options.MinificationSettings.RemoveHttpsProtocolFromAttributes = true; options.MinificationSettings.MinifyInlineJsCode = true; options.MinificationSettings.RemoveHtmlComments = true; options.CssMinifierFactory.CreateMinifier(); options.JsMinifierFactory.CreateMinifier(); }) .AddHttpCompression(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddHttpContextAccessor(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseWebMarkupMin(); HttpContextHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>()); } }
HttpContextHelper工具类
public class HttpContextHelper { private static IHttpContextAccessor m_httpContextAccessor; public static HttpContext Current => m_httpContextAccessor.HttpContext; public static string AppBaseUrl => $"{Current.Request.Scheme}://{Current.Request.Host}{Current.Request.PathBase}"; internal static void Configure(IHttpContextAccessor contextAccessor) { m_httpContextAccessor = contextAccessor; } }
异常信息
ArgumentNullException: Value cannot be null. (Parameter 'destination')
System.IO.StreamHelpers.ValidateCopyToArgs(Stream source, Stream destination, int bufferSize)
System.IO.MemoryStream.CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
System.IO.Stream.CopyToAsync(Stream destination)
WebMarkupMin.AspNetCore5.BodyWrapperStreamBase.InternalFinishAsync()
WebMarkupMin.AspNetCore5.BodyWrapperStreamWithResponseBodyFeature.FinishAsync()
WebMarkupMin.AspNetCore5.WebMarkupMinMiddleware.InvokeCore(HttpContext context, bool useMinification, bool useCompression)
WebMarkupMin.AspNetCore5.WebMarkupMinMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
解决方案
1. 修复IHttpContextAccessor重复注册问题
services.AddHttpContextAccessor()内部已经完成了IHttpContextAccessor的单例注册,手动添加的services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>()属于重复注册,会导致上下文访问器实例冲突。删除手动注册代码,仅保留:
services.AddHttpContextAccessor();
2. 调整中间件初始化顺序
将HttpContextHelper.Configure的调用移至app.UseWebMarkupMin()之前,确保WebMarkupMin中间件执行时,HttpContextAccessor已经完成初始化:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); // 先初始化HttpContextHelper HttpContextHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>()); // 再启用WebMarkupMin app.UseWebMarkupMin(); }
3. 为HttpContextHelper添加空值检查
在访问HttpContext相关属性时增加空值判断,避免在无上下文场景下抛出异常:
public class HttpContextHelper { private static IHttpContextAccessor m_httpContextAccessor; public static HttpContext Current => m_httpContextAccessor?.HttpContext; public static string AppBaseUrl { get { var context = Current; return context == null ? string.Empty : $"{context.Request.Scheme}://{context.Request.Host}{context.Request.PathBase}"; } } internal static void Configure(IHttpContextAccessor contextAccessor) { m_httpContextAccessor = contextAccessor ?? throw new ArgumentNullException(nameof(contextAccessor)); } }
4. 移除WebMarkupMin冗余配置代码
HtmlMinification配置中的options.CssMinifierFactory.CreateMinifier()和options.JsMinifierFactory.CreateMinifier()属于冗余调用,会提前创建实例但未正确关联,可能导致流处理异常,直接删除这两行代码即可。
完成以上调整后,WebMarkupMin可正常处理响应流,同时HttpContextHelper也能全局正常使用HttpContext。
内容的提问来源于stack exchange,提问作者Mohamad Hasan Salmaaniyaan

