I'm trying to upgrade a .NET Core 2.1 project to .NET 6.0+.
I see some different behavior in both versions.
Error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
WebRequestContext.Localization.get returned null.
I would like to understand if is it expected. In the past migrated from ASP.NET MVC on .NET 4.8 to .NET Core 2.1 and used this answer code @Html.Action in ASP.NET Core.
Everything works fine in .NET Core 2.1, but now I'm upgrading the project to .NET 6.0 my project is not working for certain functionality.
Here is my code reference for WebRequestContext
:
public class WebRequestContext
{
private readonly IHttpContextAccessor _httpContextAccessor;
public WebRequestContext(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
Current = this;
}
public static WebRequestContext Current { get; private set; }
public Localization Localization
{
get
{
return (Localization)GetFromContextStore("Localization");
}
set
{
AddToContextStore("Localization", value);
}
}
protected object GetFromContextStore(string key)
{
return _httpContextAccessor.HttpContext?.Items[key];
}
protected object AddToContextStore(string key, object value)
{
if (_httpContextAccessor.HttpContext == null) return value;
_httpContextAccessor.HttpContext.Items[key] = value;
return value;
}
}
I have initialized this in ServiceCollection
like this.
services.AddSingleton<WebRequestContext, WebRequestContext>();
services.AddHttpContextAccessor();
services.AddTransient<IActionContextAccessor, ActionContextAccessor>();
In my project many places in the View and also in the HtmlHelperExtensions
trying to access this value. At the start of the application, these values are getting stored as expected. I can see this value is accessible at the controller level. In the view if I try to access the @Html.DxaRegion("Header")
custom extension action after calling this RenderActionAsync
method this original _httpContextAccessor.HttpContext
value is getting reset to null. This behavior is not happening in .NET Core 2.1
Because in many places I have used to access Localization, this value actually stored in the _httpContextAccessor.HttpContext.Items[key]
getting null.
WebRequestContext.Current.Localization.CultureInfo
This is the code block setting the current HTTPContext value to null. but that same works fine in .NET Core 2.1:
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
// fetching required services for invocation
var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
// creating new action invocation context
var routeData = new RouteData();
foreach (var router in helper.ViewContext.RouteData.Routers)
{
routeData.PushState(router, null, null);
}
routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);
//get the actiondescriptor
RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
var candidates = actionSelector.SelectCandidates(routeContext);
var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
var originalActionContext = actionContextAccessor.ActionContext;
var originalhttpContext = httpContextAccessor.HttpContext;
try
{
var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
{
newHttpContext.Items.Remove(typeof(IUrlHelper));
}
newHttpContext.Response.Body = new MemoryStream();
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
actionContextAccessor.ActionContext = actionContext;
var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
await invoker.InvokeAsync();
newHttpContext.Response.Body.Position = 0;
using (var reader = new StreamReader(newHttpContext.Response.Body))
{
return new HtmlString(reader.ReadToEnd());
}
}
catch (Exception ex)
{
return new HtmlString(ex.Message);
}
finally
{
actionContextAccessor.ActionContext = originalActionContext;
httpContextAccessor.HttpContext = originalhttpContext;
if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
{
helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
}
}
}
}
Did anyone face a similar issue? Any help would be much appreciated.