Handling application-wide events without Global.asax - asp.net

My project has no "global.asax" for various reasons and I can't change that (it's a component). Also, I have no access to web.config, so an httpModule is also not an option.
Is there a way to handle application-wide events, like "BeginRequest" in this case?
I tried this and it didn't work, can someone explain why? Seems like a bug:
HttpContext.Current.ApplicationInstance.BeginRequest += MyStaticMethod;

No, this is not a bug. Event handlers can only be bound to HttpApplication events during IHttpModule initialization and you're trying to add it somewhere in the Page_Init(my assumption).
So you need to register a http module with desired event handlers dynamically. If you're under .NET 4 there is a good news for you - there is PreApplicationStartMethodAttribute attribute (a reference: Three Hidden Extensibility Gems in ASP.NET 4):
This new attribute allows you to have
code run way early in the ASP.NET
pipeline as an application starts up.
I mean way early, even before
Application_Start.
So the things left are pretty simple: you need to create your own http module with event handlers you want, module initializer and attribute to your AssemblyInfo.cs file . Here is a module example:
public class MyModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
public void Dispose()
{
}
void context_BeginRequest(object sender, EventArgs e)
{
}
}
To register module dynamically you could use DynamicModuleUtility.RegisterModule method from the Microsoft.Web.Infrastructure.dll assembly:
public class Initializer
{
public static void Initialize()
{
DynamicModuleUtility.RegisterModule(typeof(MyModule));
}
}
the only thing left is to add the necessary attribute to your AssemblyInfo.cs:
[assembly: PreApplicationStartMethod(typeof(Initializer), "Initialize")]

Related

Proper Page.Loaded event in Xamarin.Forms

For the past 2 month I have been searching tirelessly for a way to implement a proper Page.Loaded event when using Xamarin.Forms but I couldn't implement or find a way to do it.
Most people suggest overriding Page.OnAppearing or adding an event handler for Page.Appearing both of which are not the answers or the proper way to achieve the desired effect and don't event behave as a real Page.Loaded event would.
I would like to know the following:
Why doesn't Xamarin.Forms have a built-in Page.Loaded event?
Is there's a work around?
Can I implement it from the native side?
Edit:
What I mean by "proper Page.Loaded" event is:
It must be called ONCE AND ONLY ONCE the page has loaded all of it's controls, laid them out, initialized them and rendered them for the first time.
It must NOT be called when returning from modal pages.
1.Why not load the data/controls in the constructor of the ContentPage? The constructor method is call only once and it is also called before Page.OnAppearing.
Can I implement it from the native side?
Yes, I think you can.
In iOS, override the ViewDidLoad method in custom renderer:
[assembly:ExportRenderer (typeof(ContentPage), typeof(MyPageRenderer))]
namespace App487.iOS
{
public class MyPageRenderer : PageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
//call before ViewWillAppear and only called once
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
}
}
}
In Android, try to override the OnAttachedToWindow method:
[assembly: ExportRenderer(typeof(ContentPage), typeof(MyPageRenderer))]
namespace App487.Droid
{
public class MyPageRenderer : PageRenderer
{
public MyPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
}
}
}
Currently Xamarin.Forms doesn't not provide a proper/complete life cycle events to fulfill all specific requirements, but things are improving, the Dev team is currently working on to address this issue, below mentioned issues and recent pull request on the official GitHub Repos (you may follow, get ideas and maybe implement it yourself before they even ship it), they will for sure provide that in the future, although it is not clear when it will be ready.
Specification: Enhancement Add better life cycle events #2210.
Issue: LifeCycle events for controls #556.
Pull request: Life cycle events for controls
GitHub Branch where currently working on.
MAUI repo (Next evolution of Xamarin) Cross-Platform LifeCycle.
Specification Add Loaded/Unloaded to VisualElement.

How to register delegating handlers in a MVC Application? (not Web API)

How do I register a global message handler in a MVC application?
I tried registering it in my Global.asax.cs, but this handler never gets called whenever I access any of my endpoints in all my controllers that inherit from System.Web.Mvc.Controller.
However, it does get called when I access routes all my controllers that inherit from System.Web.Http.ApiController.
This is what I put in my Global.asax.cs:
protected void Application_Start()
{
//other initializing stuff here
**GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthenticationHandler());**
}
I believe you're looking for Filters. You could build something like this:
public class MyAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
// do your work here
}
}
and then add it to the global filters list in Application_Start:
GlobalConfiguration.Configuration.Filters.Add(new MyAuthorizationFilter());

IHttpModule is not being called for my WebMethod

Ok, so I have an existing application to which I have added a custom HttpModule. I'm registering two events in the Init() method (PreRequestHandlerExecute and PostRequestHandlerExecute). The HttpModule gets called for every 'normal' request. But not I have created an .aspx containing a few WebMethods that are being called for ajaxifying some UI components. The WebMethod gets called nicely, but the trouble is that my HttpModule does NOT get called at all (no events, no init, even no constructor) when accessing the WebMethod. The module gets called nicely when accessing the .aspx in question as a 'normal' request. But it refuses to be called when calling the WebMethod.
My .aspx looks like this:
public partial class SelectionListService : System.Web.UI.Page
{
[WebMethod]
[ScriptMethod]
public static RadComboBoxData GetItemsAsRadComboBoxData(RadComboBoxContext context)
{
...
}
}
My HttpModule look like this:
public class MyModule : IHttpModule, IRequiresSessionState
{
public MyModule ()
{
}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(Application_PreRequestHandlerExecute);
context.PostRequestHandlerExecute += new EventHandler(Application_PostRequestHandlerExecute);
}
private void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
...
}
private void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
...
}
}
I have been digging into this for quite some time now, but I just can't get it to work. Any ideas?
PS1: the BeginRequest, etc in global.asax.cs do get called when accessing the WebMethod.
PS2: I'm running IIS7 on Windows7.
since PageMethods must be static, an instance of the Page class with all it's events and the ASP.NET pipeline never happens. You simply get the result of your PageMethod call, and that is all.
I have a project that had the same problem. We found that the first event in the pipeline that we could get to fire for the WebMethods was the AcquireRequestState event. We hooked into that with our HttpModule in order to do the authorization checking required for the application.
I don't know what your pre and post request handlers do, but maybe you could shift some of the logic into the AcquireRequestState event handler.

Ninject.Web.PageBase still resulting in null reference to injected dependency

I have an ASP.NET 3.5 WebForms application using Ninject 2.0. However, attempting to use the Ninject.Web extension to provide injection into System.Web.UI.Page, I'm getting a null reference to my injected dependency even though if I switch to using a service locator to provide the reference (using Ninject), there's no issue.
My configuration (dumbed down for simplicity):
public partial class Default : PageBase // which is Ninject.Web.PageBase
{
[Inject]
public IClubRepository Repository { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var something = Repository.GetById(1); // results in null reference exception.
}
}
...
//global.asax.cs
public class Global : Ninject.Web.NinjectHttpApplication
{
/// <summary>
/// Creates a Ninject kernel that will be used to inject objects.
/// </summary>
/// <returns>
/// The created kernel.
/// </returns>
protected override IKernel CreateKernel()
{
IKernel kernel =
new StandardKernel(new MyModule());
return kernel;
}
..
...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IClubRepository>().To<ClubRepository>();
//...
}
}
Getting the IClubRepository concrete instance via a service locator works fine (uses same "MyModule"). I.e.
private readonly IClubRepository _repository = Core.Infrastructure.IoC.TypeResolver.Get<IClubRepository>();
What am I missing?
[Update] Finally got back to this, and it works in Classic Pipeline mode, but not Integrated. Is the classic pipeline a requirement?
[Update 2] Wiring up my OnePerRequestModule was the problem (which had removed in above example for clarity):
protected override IKernel CreateKernel()
{
var module = new OnePerRequestModule();
module.Init(this);
IKernel kernel = new StandardKernel(new MyModule());
return kernel;
}
...needs to be:
protected override IKernel CreateKernel()
{
IKernel kernel = new StandardKernel(new MyModule());
var module = new OnePerRequestModule();
module.Init(this);
return kernel;
}
Thus explaining why I was getting a null reference exception under integrated pipeline (to a Ninject injected dependency, or just a page load for a page inheriting from Ninject.Web.PageBase - whatever came first).
This is fairly puzzling because from what I can tell it appears that you have everything configured correctly. From the fact that you are getting a Null Reference Exception instead of an ActivationException, it would seem that the page level injection does not appear to be happening. Typically this is due to the protection level of the property being injected, but based on your code there is no issue there. Here are some things you can try to help track down what this issue is:
The call to Kernel.Inject(this), which initiates the property injection for Ninject is done in the OnInit method of the PageBase class. If for some reason this method is not getting executed it could result in the issue your seeing. You can do some further investigation by overriding the RequestActivation() method, which is the method called to do the actual injection (be sure to call base.RequestActivation()). If your override is never called, then there is an issue with the OnInit.
The InjectAttribute is set up in the default kernel configuration, so there should not be any need to specify it, however if you wanted to be extra certain, you could set up the attribute mapping in your kernel set up by doing something like:
IKernel kernel = new StandardKernel(new NinjectSettings { InjectAttribute = typeof(InjectAttribute) },new MyModule());
The kernel instance used by the PageBase class for the injection (and likewise the one that should be instantiated by your CreateKernel override in your Global.asax.cs) is stored in a service locator type object in Ninject.Web.KernelContainer. I would make sure you can see the Kernel property on KernelContainer and that it is not null from your Page_Load method.
Thats all I've got at the moment as far as insight. Like I said it appears from here that you have all of your ducks dressed and put in rows, so they should be working....
Good luck tracking down the issue.
This may not be specific to Ninject. I can get the same exception running in integrated mode with no IoC. I just have a simple asp.net app that just contains one aspx page with no logic.
In my global.asax file i have the following:
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
this.EndRequest += new EventHandler(Global_EndRequest);
}
void Global_EndRequest(object sender, EventArgs e)
{
// do stuff
}
Basically subscribing to an event in the application_start causes this exception for me when running in integrated pipeline mode. Switching to classic pipeline or removing the event subscription and handler makes the error go away. I'm running IIS 7.5 on Win7 Enterprise 64bit.
This may not solve your specific problem but i'm posting here as this is the only page that came up when i pasted the exception into google! I'll move my answer into a separate question when i'm allowed to ask one. I have no stackoverflow kudos yet :(

Programmatically register HttpModules at runtime

I'm writing an app where 3rd party vendors can write plugin DLLs and drop them into the web app's bin directory. I want the ability for these plugins to be able to register their own HttpModules if necessary.
Is there anyway that I can add or remove HttpModules from and to the pipeline at runtime without having a corresponding entry in the Web.Config, or do I have to programmatically edit the Web.Config when adding / removing modules? I know that either way is going to cause an AppDomain restart but I'd rather be able to do it in code than having to fudge the web.config to achieve the same effect.
It has to be done at just the right
time in the HttpApplication life cycle
which is when the HttpApplication
object initializes (multiple times,
once for each instance of
HttpApplication). The only method
where this works correct is
HttpApplication Init().
To hook up a module via code you can
run code like the following instead of
the HttpModule definition in
web.config:
public class Global : System.Web.HttpApplication
{
// some modules use explicit interface implementation
// by declaring this static member as the IHttpModule interface
// we work around that
public static IHttpModule Module = new xrnsToashxMappingModule();
public override void Init()
{
base.Init();
Module.Init(this);
}
}
All you do is override the HttpApplication's Init() method and
then access the static instance's Init
method. Init() of the module hooks up
the event and off you go.
Via Rick Strahl's blog
Realize this is an old question, but asp.net 4 provides some new capabilities that can help here.
Specifically, ASP.NET 4 provides a PreApplicationStartMethod capability that can be used to add HttpModules programmatically.
I just did a blog post on that at http://www.nikhilk.net/Config-Free-HttpModule-Registration.aspx.
The basic idea is you create a derived HttpApplication that provides ability to add HttpModules dynamically at startup time, and it then initializes them into the pipeline whenever each HttpApplication instance is created within the app-domain.
The dll Microsoft.Web.Infrastructure.dll has a method for this inside the class DynamicModuleUtility.
The dll is shipped with WebPages 1.0
public static class PreApplicationStartCode
{
private static bool _startWasCalled;
public static void Start()
{
if (_startWasCalled) return;
_startWasCalled = true;
DynamicModuleUtility.RegisterModule(typeof(EventTriggeringHttpModule));
}
}
This worked for me for dynamic registration.
RegisterModule(typeof(RequestLoggerModule));
public class RequestLoggerModule : IHttpModule
{ ... }
https://learn.microsoft.com/en-us/dotnet/api/system.web.httpapplication.registermodule?view=netframework-4.7.2
In new versions of ASP MVC you can use Package Manager to add a reference to WebActivatorX and then do something like this
using WhateverNameSpacesYouNeed;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(YourApp.SomeNameSpace.YourClass), "Initialize")]
namespace YourApp.SomeNameSpace
{
public static void Initialize()
{
DynamicModuleUtility.RegisterModule( ... the type that implements IHttpModule ... );
}
}

Resources