Object reference error during custom session state provider initialization - asp.net

I have written a custom session state provider which works fine in debug mode but once deployed on the server (IIS 6) i get the following error:
Event code: 3008
Event message: A configuration error has occurred.
Event time: 10/7/2011 3:05:02 PM
Event time (UTC): 10/7/2011 9:35:02 AM
Event ID: 00e2c8b1368b45608bb062eb2ba9d0db
Event sequence: 2
Event occurrence: 1
Event detail code: 0
Application information:
Application domain: /LM/W3SVC/1/Root/bizapp-1-129624536989844520
Trust level: Full
Application Virtual Path: ...
Application Path: ...
Machine name: ...
Process information:
Process ID: 7556
Process name: w3wp.exe
Account name: ...
Exception information:
Exception type: ConfigurationErrorsException
Exception message: Object reference not set to an instance of an object. (E:\Program Files\BizAPP\WebClient\web.config line 282)
Request information:
Request URL: http://localhost:8080/bizapp/login.aspx
Request path: /bizapp/login.aspx
User host address: 127.0.0.1
User:
Is authenticated: False
Authentication Type:
Thread account name: ...
Thread information:
Thread ID: 1
Thread account name: ...
Is impersonating: False
Stack trace: at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
at System.Web.SessionState.SessionStateModule.InitCustomStore(SessionStateSection config)
at System.Web.SessionState.SessionStateModule.InitModuleFromConfig(HttpApplication app, SessionStateSection config)
at System.Web.SessionState.SessionStateModule.Init(HttpApplication app)
at System.Web.HttpApplication.InitModulesCommon()
at System.Web.HttpApplication.InitModules()
at System.Web.HttpApplication.InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
at System.Web.HttpApplicationFactory.GetNormalApplicationInstance(HttpContext context)
at System.Web.HttpApplicationFactory.GetApplicationInstance(HttpContext context)
at System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)
EDIT
line 282 is from web.config having the provider info, 3rd line below
<sessionState mode="Custom" customProvider="SessionStateStoreProvider" timeout="180">
<providers>
<add name="SessionStateStoreProvider" type="type full name" />
</providers>
</sessionState>

It means the "Object reference not set to an instance of an object" exception happens in one of your provider's methods (for example in the Initialize method). There's a bug in that code.
So you can either put a breakpoint in there and debug, or surround overridden methods with a try catch that can transform the exception in text, like this:
public class YourSessionState : SessionStateStoreProviderBase
{
public override void Initialize(string name, NameValueCollection config)
{
try
{
// your original Initialize code here
}
catch (Exception e)
{
throw new Exception("Error in initialize: " + e);
}
}
}
If you put the .PDB files aside the .DLL, you should now see the error line number.

You're not specifying the type correctly in your configuration.
Example:
<sessionState mode="Custom" customProvider="SessionStateStoreProvider">
<providers>
<add name="SessionStateStoreProvider"
type="Namespace.To.Your.SessionStateStoreClass" />
</providers>
</sessionState>
Unless you intentionally omitted the type.

Related

.NET Core 2.0 IOptions appsettings null issue

I have a .NET Core 2.0 application that injects configuration sections using IOptions<> into my various services. Works fine if I run the app in visual studio and in most environments (stage/production etc). For some reason, running the built application locally on my machine causes an error in which it appears as though the injected config classes have NULL values.
Code:
Startup.cs (uses structuremap to inject other services)
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Configuration);
services.AddOptions();
services.Configure<RedisCacheConfiguration>(c => Configuration.GetSection("RedisCacheConfiguration").Bind(c));
return ConfigureIoC(services);
}
private IServiceProvider ConfigureIoC(IServiceCollection services)
{
var container = new Container();
container.Configure(config =>
{
config.Scan(_ =>
{
_.AssemblyContainingType(typeof(Startup));
_.WithDefaultConventions();
});
});
container.Populate(services);
return container.GetInstance<IServiceProvider>();
}
// 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.UseMvc();
}
}
appsettings.json
{
"RedisCacheConfiguration": {
"RedisAddress": "redis.server:6379"
}
}
RedisCacheConnectionFactory.cs
public class RedisCacheConnectionFactory
{
private readonly ConnectionMultiplexer _connection;
public RedisCacheConnectionFactory(IOptions<RedisCacheConfiguration> configAssessor)
{
var configuration = configAssessor.Value;
var redisAddress = configuration.RedisAddress;
if (_connection == null || !_connection.IsConnected || !_connection.GetDatabase().IsConnected(default(RedisKey)))
{
var addressChunks = redisAddress.Split(':');
var address = addressChunks[0];
var port = int.Parse(addressChunks[1]);
var configurationOptions = new ConfigurationOptions
{
AbortOnConnectFail = false,
ConnectTimeout = 600,
};
configurationOptions.EndPoints.Add(new DnsEndPoint(address, port));
_connection = ConnectionMultiplexer.Connect(configurationOptions);
}
}
public ConnectionMultiplexer Connection => _connection;
}
The Error
Hosting environment: Development
Content root path: C:\Work\MyApi\MyApi
Now listening on: http://localhost:57070
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 POST http://localhost:57070/outboundpayload application/json 1141
info: MyApi.Authentication.MyApiAuthHandler[8]
AuthenticationScheme: MyApi was successfully authenticated.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
Authorization was successful for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action MyApi.Controllers.OutboundPayloadController.Post (MyApi) in 170.5965ms
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
An unhandled exception has occurred while executing the request
StructureMap.Building.StructureMapBuildException: Error while building type MyApi.Infrastructure.Factories.RedisCacheConnectionFactory. See the inner exception for details
1.) new RedisCacheConnectionFactory(*Default of IOptions<RedisCacheConfiguration>*)
2.) MyApi.Infrastructure.Factories.RedisCacheConnectionFactory
3.) Instance of MyApi.Infrastructure.Factories.RedisCacheConnectionFactory
4.) new RedisCacheProvider(*Default of RedisCacheConnectionFactory*, *Default of IOptions<RedisCacheConfiguration>*)
5.) MyApi.Infrastructure.Providers.RedisCacheProvider
6.) Instance of MyApi.Domain.Contracts.Providers.ICacheProvider (MyApi.Infrastructure.Providers.RedisCacheProvider)
7.) new EncryptedLeadCacheManager(*Default of ICacheProvider*, *Default of IEnvironmentWrapper*, *Default of IAesCryptographyService*)
8.) MyApi.Domain.Managers.EncryptedLeadCacheManager
9.) Instance of MyApi.Domain.Contracts.Managers.ICacheManager (MyApi.Domain.Managers.EncryptedLeadCacheManager)
10.) new OutboundLeadService(*Default of IUidService*, *Default of ICacheManager*)
11.) MyApi.Domain.Services.OutboundLeadService ('MyApi.Domain.Services.OutboundLeadService, MyApi.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null')
12.) Instance of MyApi.Domain.Contracts.Services.IOutboundLeadService ('MyApi.Domain.Services.OutboundLeadService, MyApi.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null')
13.) new OutboundPayloadFactory(*Default of ICertificateRepository*, *Default of IAes128Encryptor*, *Default of IQueryStringHelper*, *Default of IOutboundLeadService*, *Default of ILogger*, *Default of IMapProcessedLeadToIssuerLeadDto*)
14.) MyApi.Domain.Factories.OutboundPayloadFactory ('MyApi.Domain.Factories.OutboundPayloadFactory, MyApi.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null')
15.) Instance of MyApi.Domain.Contracts.Factories.IOutboundPayloadFactory ('MyApi.Domain.Factories.OutboundPayloadFactory, MyApi.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null')
16.) Container.GetInstance(MyApi.Domain.Contracts.Factories.IOutboundPayloadFactory)
17.) Container.TryGetInstance(MyApi.Domain.Contracts.Factories.IOutboundPayloadFactory)
---> System.NullReferenceException: Object reference not set to an instance of an object.
at MyApi.Infrastructure.Factories.RedisCacheConnectionFactory..ctor(IOptions`1 configAssessor) in C:\Work\MyApi\MyApi\MyApi.Infrastructure\Factories\RedisCacheConnectionFactory.cs:line 19
at lambda_method(Closure , IBuildSession , IContext )
--- End of inner exception stack trace ---
at lambda_method(Closure , IBuildSession , IContext )
at StructureMap.Building.BuildPlan.Build(IBuildSession session, IContext context)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at StructureMap.SessionCache.GetObject(Type pluginType, Instance instance, ILifecycle lifecycle)
at StructureMap.SessionCache.GetDefault(Type pluginType, IPipelineGraph pipelineGraph)
at StructureMap.Container.GetInstance(Type pluginType)
at StructureMap.Container.TryGetInstance(Type pluginType)
at Microsoft.Extensions.Internal.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.<CreateActivator>b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeInnerFilterAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
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>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 474.7396ms 500 text/html; charset=utf-8
The IOptions seems to be injected but has null values, see the Inner Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at MyApi.Infrastructure.Factories.RedisCacheConnectionFactory..ctor(IOptions`1 configAssessor) in C:\Work\MyApi\MyApi\MyApi.Infrastructure\Factories\RedisCacheConnectionFactory.cs:line 19
Once I put in null handling in this class the error changes to the next instance of using the IOptions<> injected configuration.
Anyone know why I'm getting this behavior?

Httphandler for WebDav requests

I am trying to write a asp.net httphandler for handling webdav requests with IIS.
I am extending the IHttpHandler interface and implementing the ProcessRequest.
public class clsMyHandler : IHttpHandler
{
public void ProcessRequest(System.Web.HttpContext context)
{
StreamWriter sw = new StreamWriter(#"C:\requestLog.txt",true);
sw.WriteLine("Got a request at " + DateTime.Now.ToString());
sw.Close();
}
public bool IsReusable
{
get
{
return true;
}
}
}
It's a simple handler for my test purpose to just log into a file when I get the webdav request for a file of given name. I can see the handler listed in the Handler mappings.
This is the web.config
<handlers>
<add name="testhandler" verb="*" path="*e.txt" type="MyPipeLine.clsMyHandler, MyPipeLine" />
</handlers>
It works fine when the request is a http from browser. My handler gets executed and logs in the file. But when the request is webdav(I have enabled webdav with IIS and mapped the website root as a network drive) editing a file of the pattern *e.txt fails which I would expect as I am overriding the webdav handler, but I do not see it getting logged in my file.
I am not sure if there is a server log that I can check to get some clue as to whether or not the handler was invoked and if there is an error in the handler. I am new to this.
I am not finding much materials/guides online regarding httphandlers for webdav.
Appreciate any help.

Health Monitoring is not logging errors when CustomError is set to "On" or "RemoteOnly"

I am using Health Monitoring for catching all errors and sending them to email. While it works in the development environment it did not when I deploy it in Prod. The only difference being the "customerrors" set to "on/off". So, I verified it again and it seems it will not log when the custom errors is set to "On/RemoteOnly". Below is part of my configuration in question.
Is there a workaround to this issue? Thanks.
<healthMonitoring enabled="true">
<eventMappings>
<clear />
<add name="All Errors" type="System.Web.Management.WebBaseErrorEvent"
startEventCode="0" endEventCode="2147483647" />
</eventMappings>
<providers>
<clear />
<add
name="SimpleMailWebEventProvider"
type="System.Web.Management.SimpleMailWebEventProvider"
to="dev#net"
from="de#net"
buffer="false"
/>
</providers>
<rules>
<clear />
<add name="All Errors Default" eventName="All Errors" provider="SimpleMailWebEventProvider"
profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" />
</rules>
</healthMonitoring>
--update
This is MVC3 project
In an ASP.NET MVC 3 project you will have a global HandleError action filter registered by default in global.asax.cs:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
This attribute gets applied to every controller action and if customErrors are set to On only the custom error page is displayed and the exception that occured in a controller action is marked as handled. ASP.NET Health Monitoring doesn't see this exception anymore and can't log it.
An approach to use Health Monitoring together with the HandleError attribute and a custom error page is described here and here and here:
You create a custom error attribute derived from HandleError:
public class HandleErrorHealthMonitoringAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
// Do the default, i.e. show custom error page if custom errors are on
base.OnException(filterContext);
// Suppress raising the health monitoring event below if custom errors
// are off. In that case health monitoring will receive the exception
// anyway and raise the event
if (!filterContext.HttpContext.IsCustomErrorEnabled)
return;
// Raise health monitoring event
var errorEvent = new GenericWebRequestErrorEvent(
"Unhandled exception occurred.", this,
WebEventCodes.WebExtendedBase + 1, filterContext.Exception);
errorEvent.Raise();
}
}
And then register this attribute instead of default HandleError:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorHealthMonitoringAttribute());
}
The GenericWebRequestErrorEvent is a custom error event derived from the base WebRequestErrorEvent. It doesn't do anything custom and only exists because WebRequestErrorEvent doesn't have any public constructors, so we can't use var errorEvent = new WebRequestErrorEvent(...):
public class GenericWebRequestErrorEvent : WebRequestErrorEvent
{
public GenericWebRequestErrorEvent(string message, object eventSource,
int eventCode, Exception exception) :
base(message, eventSource, eventCode, exception)
{
}
public GenericWebRequestErrorEvent(string message, object eventSource,
int eventCode, int eventDetailCode, Exception exception) :
base(message, eventSource, eventCode, eventDetailCode, exception)
{
}
}
Note, that you will receive an email titled with MyNamespace.GenericWebRequestErrorEvent and not with System.Web.Management.WebRequestErrorEvent and the event code will always be 100001 (= WebEventCodes.WebExtendedBase + 1).

ASP.NET handler not running on IIS7

I've wrote a simple handler:
public class ImageHandler : IHttpHandler, IRequiresSessionState
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
byte[] imgData = context.Session["Data"] as byte[];
if (imgData != null)
{
context.Response.CacheControl = "no-cache";
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.ContentType = "image/png";
context.Response.BinaryWrite(imgData);
context.Response.Flush();
}
}
}
And setup the web.config:
<system.web>
<httpHandlers>
<add verb="GET" path="image.png" type="TestWeb.Handlers.ImageHandler, TestWeb" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="Image" verb="GET" path="image.png" type="TestWeb.Handlers.ImageHandler, TestWeb" />
</handlers>
</system.webServer>
If I run the code allowing VS start a new IIS service and open a new tab it reaches the breakpoint on the handler.
If I set don't open a page. Wait for request from an external application it never reaches the handler.
It is not just the breakpoint, no code from the handler executes when I run the website configured on IIS. It only works if I start from VS.
What did I miss when configuring IIS7 ?
I had to switch the Application Pool to Integrated mode, it was using classic.
And I had to remove the handler configuration from <system.web> because it was giving me error 500.23.
HTTP Error 500.23 - Internal Server
Error An ASP.NET setting has been
detected that does not apply in
Integrated managed pipeline mode.
you need to attach to the asp.net worker process. go to tools/attach to process and choose the w3p process.

Why can't my host (softsyshosting.com) support BeginRequest and EndRequest event handlers?

I heard good things about Softsys Hosting and so I decided to move my ASP.NET MVC solution over to them. But it would not run on them. I was able to pinpoint the problem to my BeginRequest event handlers. If I had them I'd get an error. Here is my code.
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
void MvcApplication_EndRequest(object sender, EventArgs e)
{
}
void MvcApplication_BeginRequest(object sender, EventArgs e)
{
}
I could reproduce the problem by just creating the default ASP.NET MVC application and adding the above code. The strange thing is this code worked fine on my old host and it only crashes on my new (shared) host. If I have these event handlers in my code I get this error:
Server Error in '/' Application.  
Object reference not set to an
instance of an object. Description:
An unhandled exception occurred during
the execution of the current web
request. Please review the stack trace
for more information about the error
and where it originated in the code.
Exception Details:
System.NullReferenceException: Object
reference not set to an instance of an
object.
Source Error: An unhandled exception
was generated during the execution of
the current web request. Information
regarding the origin and location of
the exception can be identified using
the exception stack trace below.
Stack Trace:
[NullReferenceException: Object
reference not set to an instance of an
object.]
System.Web.PipelineModuleStepContainer.GetStepArray(RequestNotification
notification, Boolean isPostEvent) +27
System.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification
notification, Boolean isPostEvent) +11
System.Web.PipelineStepManager.ResumeSteps(Exception
error) +205
System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext
context, AsyncCallback cb) +91
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest
wr, HttpContext context) +514
I tried troubleshooting this with Softsys, but they were not very helpful, basically they just confirmed that I had turned on the "ASP.NET Pipeline (MVC)" functionality within my admin control panel.
Can someone:
Tell me if I've coded something wrong
Show me a work-around
Explain to me why this error is occuring on one host and not the other.
You need register your handlers in each HttpApplication instance. There may be several pooled instances of HttpApplication. Application_Start is called only once (for IIS 6 and IIS 7 in classic mode - on the first request, for IIS 7 integrated mode - on web app start, just before any request). So to get all working you need to add events handlers in overrided Init method of HttpApplication or in constructor of it. If you add them in constructor - these handlers will be invoked first, even before the handlers of registered modules.
So your code should look like this:
public class MySmartApp: HttpApplication{
public override void Init(){
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
protected void Application_Start(){
RegisterRoutes(RouteTable.Routes);
}
}
or like this:
public class MySmartApp: HttpApplication{
public MySmartApp(){
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
protected void Application_Start(){
RegisterRoutes(RouteTable.Routes);
}
}
Looks to me like you went from IIS 6 or IIS 7 Classic mode to IIS 7 Integrated mode. In IIS 7 integrated mode, the Request processing was decoupled from application start. This article explains the why's and wherefores.
To fix it, you'll need to move your code to Application_BeginRequest instead.

Resources