Hi experts,
I have an Asp.Net Core 2.1 web application running on Windows Server 2008 R2.
Everyone have access to this web app but only one person gets "System.NullReferenceException: Object reference not set to an instance of an object." forHttpContext
Weird this is, he can access the same application that running on test server which is same Windows Server 2008 R2
I indicated the line where error out in
yellow highlight in Session class code.
I spent many days to fix it, but no luck yet.
Please help, and thank you in advance.
Here is my Startup.cs:
public class Startup {
static public IConfigurationRoot Global { get; set; }
public IHostingEnvironment HostingEnvironment { get; }
public IConfiguration Configuration { get; }
public Startup(IHostingEnvironment env, IConfiguration configuration) {
try
{
HostingEnvironment = env;
Configuration = configuration;
this.SetGlobals(HostingEnvironment);
}catch(Exception ex)
{
//If failed in here, it needs special error handler
Helper.errorMsg msg = new Helper.errorMsg();
Helper.CreateRfs_LostHosting(ex, -1, msg).Wait();
}
}
public void ConfigureServices(IServiceCollection services) {
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromHours(12);
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
} else {
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Session.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
}
}
I have a Session Class:
public class Session
{
private static IHttpContextAccessor _httpContextAccessor;
public static void Configure(IHttpContextAccessor httpContextAccessor) {
_httpContextAccessor = httpContextAccessor;
}
public static void Initialize() {
var sessionUser = Session.GetSessionObj<SessionUser>("SessionUser");
if (sessionUser == null) {
sessionUser = new SessionUser();sessionUser.Initialize(HttpContext);
Session.SetSessionObj("SessionUser", sessionUser);
}
}
public static HttpContext HttpContext { get { return _httpContextAccessor.HttpContext; } }
public static SessionUser SessionUser { get { return Session.GetSessionObj<SessionUser>("SessionUser"); } }
public static bool UserValidated { get {
if (SessionUser == null)
{
Initialize();
}
return SessionUser.Validated;
} }
public static void SetSessionVar(string key, string value) {
_httpContextAccessor.HttpContext.Session.SetString(key, value);
}
public static void SetSessionObj(string key, object value) {
_httpContextAccessor.HttpContext.Session.SetObject(key, value);
}
public static T GetSessionObj<T>(string key) {
var sessionObj = _httpContextAccessor.HttpContext.Session.GetObject<T>(key);
return sessionObj;
}
}
here is SessionUser class:
public class SessionUser
{
public void Initialize(HttpContext httpContext) {
string userName = null;
var identity = httpContext.User.Identity;
if (identity.IsAuthenticated) {
userName = identity.Name;
} else {
var basicCredentials = new BasicAuthenticationHeader(httpContext);
userName = basicCredentials.UserName;
}
}
}
Added on 7/25/2018:--------------------------------------------------------------------------------------
here is BasicAuthenticationHeader.cs:
public class BasicAuthenticationHeader
{
private readonly string _authenticationHeaderValue;
private string[] _splitDecodedCredentials;
public bool IsValidBasicAuthenticationHeaderValue { get; private set; }
public string UserName { get; private set; }
public BasicAuthenticationHeader(HttpContext context)
{
var basicAuthenticationHeader = context.Request.Headers["Authorization"]
.FirstOrDefault(header => header.StartsWith("Basic", StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(basicAuthenticationHeader))
{
_authenticationHeaderValue = basicAuthenticationHeader;
if (TryDecodeHeaderValue())
{
ReadAuthenticationHeaderValue();
}
}
}
}
Detail Error message from asp.net built in error log:
System.NullReferenceException: Object reference not set to an instance of an object.
at Models.SessionUser.Initialize(HttpContext httpContext) in Models\SessionUser.cs:line 24
at Models.Session.Initialize() in Models\Session.cs:line 21
at Controllers.BaseController..ctor() in Models\BaseController.cs:line 16
here is BaseController.cs:
public class BaseController : Controller
{
public BaseController() {
try
{
Startup.UpdateGlobals(Session.HttpContext.Request);
Session.Initialize();
if (!Session.UserValidated)
{
ViewData["Error"] = "Unable to validate user permission.";
}
}
catch (Exception ex)
{
Helper.errorMsg msg = new Helper.errorMsg();
Helper.CreateRfs(ex, -1, msg).Wait();
}
}
}
##################################################---Added on 08/02/2018---##################################################
I changed the way accessing httpcontext by adding kind of middleware interface "UserRepositroy.cs". I don't have static httpcontextaccesor anymore.
It works for other people, but one specific user still appears to be null out on HttpContextAccessor though..
Here is the error message:
System.NullReferenceException: Object reference not set to an instance of an object.
at UserRepository.GetUserNetworkId() in UserRepository.cs:line 78
at UserRepository.GetUserPhoneKey() in UserRepository.cs:line 97
at UserRepository..ctor(IHttpContextAccessor httpContextAccessor) in UserRepository.cs:line 18
at lambda_method(Closure , ServiceProviderEngineScope )
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Models.ErrorHandlingMiddleware.Invoke(HttpContext context) in Models\ErrorHandlingMiddleware.cs:line 25 --- 8/2/2018 3:06:25 AM
Here is UserRepository.cs:
public class UserRepository : IUserRepository
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserRepository(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
Startup.UpdateGlobals(_httpContextAccessor.HttpContext.Request); <----------------Still httpContextAccessor is null from the user.
Startup.Global["UserPhoneKey"] = GetUserPhoneKey().ToString();
}
public bool IsUserValidated()
{
string userName = null;
string NetworkId = null;
int PhoneKey;
bool Validated = false;
var identity = _httpContextAccessor.HttpContext.User.Identity;
if (identity.IsAuthenticated)
{
userName = identity.Name;
}
else
{
var basicCredentials = new BasicAuthenticationHeader(_httpContextAccessor.HttpContext);
userName = basicCredentials.UserName;
}
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development"&& Environment.GetEnvironmentVariable("USER_NETWORK_ID") != null) // used for testing in development by setting overriding environmental varibles
{
NetworkId = Environment.GetEnvironmentVariable("USER_NETWORK_ID");
}
else
{ // assume production
NetworkId = userName.Split("\\").Last();
}
if (NetworkId.Contains("@"))
{
Validated = false;
}
else
{
var userInfo = UserInfo.GetUserInfo(NetworkId);
PhoneKey = userInfo.userPhoneKeyId;
Validated = PhoneKey > 0;
}
return Validated;
}
public string GetUserNetworkId()
{
string userName = null;
string NetworkId = null;
var identity = _httpContextAccessor.HttpContext.User.Identity;
if (identity.IsAuthenticated)
{
userName = identity.Name;
}
else
{
var basicCredentials = new BasicAuthenticationHeader(_httpContextAccessor.HttpContext);
userName = basicCredentials.UserName;
}
if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development"&& Environment.GetEnvironmentVariable("USER_NETWORK_ID") != null) // used for testing in development by setting overriding environmental varibles
{
NetworkId = Environment.GetEnvironmentVariable("USER_NETWORK_ID");
}
else
{ // assume production
NetworkId = userName.Split("\\").Last();
}
return NetworkId;
}
public int GetUserPhoneKey()
{
var userInfo = UserInfo.GetUserInfo(GetUserNetworkId());
int PhoneKey = userInfo.userPhoneKeyId;
return PhoneKey;
}
}
Here is how I added HttpContextAccessor and interface UserRepository in the Startup.cs:
public void ConfigureServices(IServiceCollection services) {
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromHours(12);
});
services.AddHttpContextAccessor(); //core 2.1
services.AddTransient<IUserRepository, UserRepository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
} else {
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}