Ninject + .NET 4 + Integrated Pipeline results in NullReferenceException - asp.net

I have configured Ninject 2 in an ASP.NET 4.0 project (not MVC) however when I deploy the project to an IIS host it crashes with the following:
System.NullReferenceException: Object reference not set to an instance of an object.
[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.PipelineModuleStepContainer.GetEventCount(RequestNotification notification, Boolean isPostEvent) +30
System.Web.PipelineStepManager.ResumeSteps(Exception error) +1481
System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) +132
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +709
I have tested this again with a vanilla ASP.net Web Application and get the same crash with the following code:
protected override IKernel CreateKernel()
{
return Container;
}
private IKernel Container
{
get
{
IKernel kernel = new StandardKernel(new SiteModule());
var module = new OnePerRequestModule();
module.Init(this);
return kernel;
}
}
Has anyone else got Ninject working with ASP.net 4?
[UPDATE: 2010.11.03]
After doing some research it appears it may be something to do with the OnePerRequestModule() module, removing this however doesn't seem to resolve the problem I added it due at the suggestion of this question.

In Ninject 2, you use the Ninject.Web extension (see the complete set here) and dont do any explicit config as you have here around OnePerRequestModule etc.
You don't do any web.config stuff either IIRC (I'm using the MVC one and you don't there)

Related

Unit testing HttpContext Response.Redirect

I am using HttpSimulator for unit testing. I am testing one method that has deeper in code chain call Response.Redirect. I am facing here with problem. I'm getting
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message= Object reference not set to an instance of an object.
Source=System.Web
StackTrace:
at System.Web.HttpApplication.CompleteRequest()
at System.Web.HttpResponse.End()
at System.Web.HttpResponse.Redirect(String url, Boolean endResponse, Boolean permanent)
at System.Web.HttpResponse.Redirect(String url, Boolean endResponse)
Then I reflected HttpApplication type and found mentioned method :
public void CompleteRequest()
{
this._stepManager.CompleteRequest();
}
I am initializing HttpApplication on one of the following ways :
HttpContext.Current.ApplicationInstance = new HttpApplication();
// or with Mock framework
var httpApplicationMock = new Mock<HttpApplication>()
var applicationInstance = httpApplicationMock.Object;
As I got from ASP documentation, _stepManager is in charge for Module and Handler execution order and harmonization. This field is initialized depends on whether application is under Classic or Integrated mode.
Then I have called in my test :
object stepManager = typeof(HttpApplication).GetField("_stepManager", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(HttpContext.Current.ApplicationInstance);
I got that stepManager is null, that is expected from above exception. StepManager is initialized within method :
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
So, from this I am not having control how to ensure stepManager to be initialized.
Then I have tried second scenario. In this scenario I have tried to initialize ApplicationInstance on other way.
From following link AppHost.cs
I have tried to initialize ApplicationInstance like this :
private static HttpApplication GetApplicationInstance()
{
var writer = new StringWriter();
var workerRequest = new SimpleWorkerRequest("", "", writer);
var httpContext = new HttpContext(workerRequest);
return (HttpApplication)getApplicationInstanceMethod.Invoke(null,
new object[] { httpContext });
}
and I got on lat method's line :
InnerException: System.InvalidOperationException
HResult=-2146233079
Message=This method cannot be called during the application's pre-start initialization phase.
Source=System.Web
StackTrace:
at System.Web.Compilation.BuildManager.EnsureTopLevelFilesCompiled()
at System.Web.Compilation.BuildManager.GetGlobalAsaxTypeInternal()
at System.Web.Compilation.BuildManager.GetGlobalAsaxType()
at System.Web.HttpApplicationFactory.CompileApplication()
at System.Web.HttpApplicationFactory.Init()
at System.Web.HttpApplicationFactory.EnsureInited()
at System.Web.HttpApplicationFactory.GetApplicationInstance(HttpContext context)
I have tried the third scenario. I have created custom Response derived from HttpResponseBase that has overrided Redirect method. But I am facing with problem, how to assign created HttpContextBase to the HttpContext.Current. I saw tip on Sergei's blog :
HttpContext httpContext = httpContextBase.ApplicationInstance.Context;
But it is not possible to set Context on ApplicationInstance. It is null.
Is it possible to solve one of these 3 cases or to take another idea/approach to unit test my scenario.
Thank you,
Rastko

HttpContext.GetService in Mono

I've got the following code (lifted from here), and I'm trying to run it on a linux server w/ mono 2.10.5.
private static HttpContext GetCurrentContext(ControllerContext context) {
var currentApplication = (HttpApplication)context.HttpContext.GetService(typeof(HttpApplication));
if (currentApplication == null) {
throw new NullReferenceException("currentApplication");
}
return currentApplication.Context;
}
When running on mono, I get the following exception, which is straightforward enough:
System.NotImplementedException: The requested feature is not
implemented. at System.Web.HttpContextWrapper.GetService
(System.Type serviceType) [0x00000] in <filename unknown>:0
Is there a known workaround I can use to accomplish the same result on mono?
Not sure about the GetService method in Mono but the code you have lifted could be shortened like this:
private static HttpContextBase GetCurrentContext(ControllerContext context) {
return context.HttpContext;
}
You don't really need to go through the Application in order to fetch the HttpContext when you have direct access to it. I have also changed the return type to HttpContextBase instead of HttpContext because in ASP.NET MVC it is recommended to always work with abstractions. It makes your code more weakly coupled and unit testable.
Or if for some unknown to me reason you want to work with an actual HttpContext (no idea why someone would like to tie his code to it) you could try the following:
private static HttpContext GetCurrentContext(ControllerContext context) {
return context.HttpContext.ApplicationInstance.Context;
}
But as you can see in both cases the existence of this GetCurrentContext static method becomes quite questionable.

using the same cache for web site and web services over IIS

my application is composed of several modules: a web site, and a few services that receive requests from client apps.
since all these modules manipulate pretty much the same data, I would like to have the same cache for all of them.
I'm using a static class to reference nHibernate's 2nd level cache (the SessionFactory object), and I've set up the web site and the web services within the same website on IIS.
however, the static SessionFactory variables are different between the web site and web service.
Here is the code for the static SessionManager class:
public static class SessionManager
{
private static ISessionFactory _sessionFactory = null;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
if (System.Web.HttpContext.Current != null)
{
log4net.Config.XmlConfigurator.Configure();
log4net.ILog log = log4net.LogManager.GetLogger("General");
log.InfoFormat("creating a new session factory for process: {0} (id = {1}), \n stack trace is: {2}",
System.Diagnostics.Process.GetCurrentProcess().ProcessName, System.Diagnostics.Process.GetCurrentProcess().Id,
new System.Diagnostics.StackTrace().ToString());
_sessionFactory = DAOBase.GetSessionFactory();
}
else
{
_sessionFactory = DAOBase.GetSessionFactoryForWin();
}
}
return _sessionFactory;
}
}
public static void BindSessionToRequest()
{
ISession session = SessionManager.SessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(session);
}
public static void UnbindSession()
{
ISession session = NHibernate.Context.CurrentSessionContext.Unbind(SessionManager.SessionFactory);
if (session != null && session.IsOpen)
{
session.Close();
}
}
public static ISession GetCurrentSession()
{
return SessionFactory.GetCurrentSession();
}
}
and the resulting logs:
for the web site:
2011-01-05 10:54:54 INFO General - creating a new session factory for process: aspnet_wp (id = 7892),
stack trace is: at Managers.SessionManager.get_SessionFactory()
at Managers.SessionManager.BindSessionToRequest()
at Managers.SessionPerRequestHttpModule.Context_BeginRequest(Object sender, EventArgs e)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
at System.Web.HttpApplication.ApplicationStepManager.ResumeSteps(Exception error)
at System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)
at System.Web.HttpRuntime.ProcessRequestNoDemand(HttpWorkerRequest wr)
at System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr ecb, Int32 iWRType)
and for the web service:
10:55:20 INFO General - creating a new session factory for process: aspnet_wp (id = 7892),
stack trace is: at Managers.SessionManager.get_SessionFactory()
at Managers.SessionManager.BindSessionToRequest()
at Managers.SessionPerRequestHttpModule.Context_BeginRequest(Object sender, EventArgs e)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
at System.Web.HttpApplication.ApplicationStepManager.ResumeSteps(Exception error)
at System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)
at System.Web.HttpRuntime.ProcessRequestNoDemand(HttpWorkerRequest wr)
at System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr ecb, Int32 iWRType)
I'm using IIS5 (yuck, I know), and i've tried about every configuration option I could think of. I've created the site and service as virtual directories under the same site, i've set their protection level to 'Low (IIS process)' etc., but to no avail.
anyone got an idea?
thanks in advance,
Jhonny
If the web app and the service are running in the same process/assembly, I'd imagine they might both have access to the application's application cache. When the SessionFactory gets initialized, if you happen to be storing the SessionFactory in the runtime cache by name (perhaps a dictionary/hash), you should be able to retrieve it by name from either the web app or the web service. The SharpArchitecture guys have a well built solution to caching the sessionfactory, although their approach was in order to solve multiple database scenarios. The source has inclusions for services as well and I think you'd be able to modify what they've built to suit your needs. If the web app and service have to live separately (different assemblies) you might not be able to accomplish this.

Resolving HttpRequestScoped services in ASMX with Autofac 2.1.12

The Description I had a legacy type that is HttpRequestScoped and a legacy web service consuming that service. To resolve services in legacy concerns, I have a global resolver. This was all working well in 1.4, and now that I'm using 2.1.12 I'm experiencing DependencyResolutionException.
The Code In 2.1.12, my Global.asax.cs:
builder.Register(c => new SomeLegacyType(HttpContext.Current)) // note: it relies on HttpContext.Current
.As<SomeLegacyType>()
.HttpRequestScoped();
_containerProvider = new ContainerProvider(builder.Build()); // this is my app's IContainerProvider
Setup.Resolver = new AutofacResolver(_containerProvider.ApplicationContainer);
Setup.Resolver is a singleton, and it is being set to AutofacResolver which looks something like this:
public class AutofacResolver : IResolver
{
private readonly IContainer _container;
public AutofacResolver(IContainer container)
{
_container = container;
}
public TService Get<TService>()
{
return _container.Resolve<TService>();
}
}
The web service looks like this:
[WebService]
public LegacyWebService : WebService
{
[WebMethod(EnableSession=true)]
public String SomeMethod()
{
var legacyType = Setup.Resolver.Get<SomeLegacyType>();
}
}
The Exception The following exception when Setup.Resolver.Get<SomeLegacyType>() is called:
Autofac.Core.DependencyResolutionException: No scope matching the expression 'value(Autofac.Builder.RegistrationBuilder`3+<>c__DisplayClass0[SomeAssembly.SomeLegacyType,Autofac.Builder.SimpleActivatorData,Autofac.Builder.SingleRegistrationStyle]).lifetimeScopeTag.Equals(scope.Tag)' is visible from the scope in which the instance was requested.
at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope)
at Autofac.Core.Resolving.ComponentActivation..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope)
at Autofac.Core.Resolving.ResolveOperation.Resolve(ISharingLifetimeScope activationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Lifetime.LifetimeScope.Resolve(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Container.Resolve(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolve(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
Side Question Is there a better way to have properties injected in ASMX, the same way my ASPX pages are injected (rather than use Setup.Resolver)? I use the AttributedInjectionModule because of legacy concerns. It doesn't appear that the module works on ASMX.
If you configure your 'resolver' to use the RequestLifetime rather than ApplicationContainer all should work as expected.
This means your IContainer parameter will have to change to ILifetimeScope.
I'm not sure about a better way to inject ASMX dependencies, there may be one but I don't think Autofac supports it.

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