IHttpModule with Unity

May 22, 2008 at 10:04 AM
Could I do the Property Injection with IHttpModule?
May 22, 2008 at 7:01 PM
You want to create an HttpModule that gets run through a container? Yes, you could, although you wouldn't be able to do constructor injection (since ASP.NET creates the module instances, not you). You'd need to have the module call the container's BuildUp method on itself.

There's also the question of where the container is - global object, application object, somewhere else? There's no one right answer for that one, so you'll have to decide how you want to do that.

May 23, 2008 at 6:31 AM
Thanks.  But how could I buildup with the IHttpmodule?

Currently, I have built a SecurityHttpModule which using IHttpModule.

However, it seems I don't have a "real" instance under my code?

How could I capture this instance and build up it? Thanks.
May 23, 2008 at 6:38 AM
Thanks.  But how could I buildup with the IHttpmodule?

Currently, I have built a SecurityHttpModule which using IHttpModule.

However, it seems I don't have a "real" instance under my code?

How could I capture this instance and build up it? Thanks.
May 23, 2008 at 7:08 AM
I'm sorry, I really don't understand what you're asking. Could you post some examples of what you're trying to do?

May 23, 2008 at 7:14 AM
I have create an HttpModule as follows and would like to the Dependency Injection on UserService. Howerver, it returns null :-


public class SecurityHttpModule : IHttpModule
{
    private ICacheManager cacheObj;

    //private UserService _userservice;

    //[Dependency]
    //public UserService UserServiceObj
    //{
    //    get { return _userservice; }
    //    set { _userservice = value; }
    //}

    public SecurityHttpModule()
    {
        cacheObj = CacheFactory.GetCacheManager();
    }

    public void Init(HttpApplication context)
    {
      context.AuthenticateRequest +=
          (new EventHandler(this.Application_AuthenticateRequest));
    }
   

    private void Application_AuthenticateRequest(Object source, EventArgs e)
    {

        if ((HttpContext.Current.User != null) && (HttpContext.Current.User.Identity.IsAuthenticated))
        {
            //HttpContext.Current.User.Identity
            if (cacheObj.GetData(HttpContext.Current.User.Identity.Name) == null)
            {
                UserService UserServiceObj = new UserService();

                User user= UserServiceObj.RetrieveUser(HttpContext.Current.User.Identity.Name);
                //TODO: Tempoarily assign null to user object
                UserPrincipal principal = new UserPrincipal(new UserIdentity(
                HttpContext.Current.User.Identity.Name, HttpContext.Current.User.Identity.AuthenticationType, true, user),
                new List<String>() { "Admin", "2" });

                HttpContext.Current.User = principal;               
                cacheObj.Add(HttpContext.Current.User.Identity.Name, principal);
            }           
        }
    }

    public void Dispose()
    {
    }

}

May 23, 2008 at 6:00 PM
I think you need to do something like the following.  You will have to ensure your container is initialized properly first.

Non-Unity related issue, I would recommend against referencing HttpContext.Current from an IHttpModule.  I believe the a better way to get the current HttpContext in a module is via the HttpApplication that is passed as the sender/source of your event handler.  If you dig into framework IHttpModules, you will see that HttpContext.Current is never referenced. 

        public SecurityHttpModule()
        {
            container.BuildUp<SecurityHttpModule>(this);

            cacheObj = CacheFactory.GetCacheManager();
        }

        public void Init(HttpApplication context)
        {
            context.AuthenticateRequest +=
                (new EventHandler(this.Application_AuthenticateRequest));
        }


        private void Application_AuthenticateRequest(Object source, EventArgs e)
        {
            // avoid using HttpContext.Current in modules
            HttpApplication application = source as HttpApplication;
            HttpContext context = application.Context;

            if ((context.User != null) && (context.User.Identity.IsAuthenticated))
            {
                //
            }
        }


hnchan wrote:
I have create an HttpModule as follows and would like to the Dependency Injection on UserService. Howerver, it returns null :-


public class SecurityHttpModule : IHttpModule
{
    private ICacheManager cacheObj;

    //private UserService _userservice;

    //[Dependency]
    //public UserService UserServiceObj
    //{
    //    get { return _userservice; }
    //    set { _userservice = value; }
    //}

    public SecurityHttpModule()
    {
        cacheObj = CacheFactory.GetCacheManager();
    }

    public void Init(HttpApplication context)
    {
      context.AuthenticateRequest +=
          (new EventHandler(this.Application_AuthenticateRequest));
    }
   

    private void Application_AuthenticateRequest(Object source, EventArgs e)
    {

        if ((HttpContext.Current.User != null) && (HttpContext.Current.User.Identity.IsAuthenticated))
        {
            //HttpContext.Current.User.Identity
            if (cacheObj.GetData(HttpContext.Current.User.Identity.Name) == null)
            {
                UserService UserServiceObj = new UserService();

                User user= UserServiceObj.RetrieveUser(HttpContext.Current.User.Identity.Name);
                //TODO: Tempoarily assign null to user object
                UserPrincipal principal = new UserPrincipal(new UserIdentity(
                HttpContext.Current.User.Identity.Name, HttpContext.Current.User.Identity.AuthenticationType, true, user),
                new List<String>() { "Admin", "2" });

                HttpContext.Current.User = principal;               
                cacheObj.Add(HttpContext.Current.User.Identity.Name, principal);
            }           
        }
    }

    public void Dispose()
    {
    }

}




May 24, 2008 at 6:04 AM
Thank you very much. BTW, one more question.

Currently, I init the container as a local variable from the Application_Start function under Global.asa.

    protected void Application_Start(object sender, EventArgs e)
        {

            IUnityContainer container = new UnityContainer();
            /.../    
         }

According to your sample, do I need to change the container as the global variable? Thanks again!!
        

May 24, 2008 at 7:42 AM

You could, but I think that would suck. :-)  How about something like this,

 

// in global.asax.cs
protected
void Application_Start(object sender, EventArgs e) {
   
IUnityContainer container = new UnityContainer();
    // initialize the container
   
Application["UnityContainer"] = container; // save the container for later
}

 

// in SecurityHttpModule.cs
public class SecurityHttpModule : IHttpModule {
   
public void Init(HttpApplication context) {
        context.AuthenticateRequest += Application_AuthenticateRequest;
       
IUnityContainer container = context.Application["UnityContainer"] as IUnityContainer;
       
if (container == null)
           
throw new ConfigurationErrorsException("UnityContainer is not setup correctly.");
        container.BuildUp(
this);
    }

   
private void Application_AuthenticateRequest(object sender, EventArgs e) { }
   
public void Dispose() { }
}

 

Or, you could setup a singleton to hold your container as shown in this post.

hnchan wrote:
Thank you very much. BTW, one more question.

Currently, I init the container as a local variable from the Application_Start function under Global.asa.

    protected void Application_Start(object sender, EventArgs e)
        {

            IUnityContainer container = new UnityContainer();
            /.../    
         }

According to your sample, do I need to change the container as the global variable? Thanks again!!
        




May 24, 2008 at 8:03 AM

If your application depends on singletons, you should avoid using 

    Application["UnityContainer"] = container;

as your web application will have one AppDomain with a pool of HttpApplication objects. An individual HttpApplication object is created to handle each simultaneous HTTP request. See this article for an explaination.  This post I referenced last time uses the AppDomain to store the configured Unity container and would only create one.


hnchan wrote:
Thank you very much. BTW, one more question.

Currently, I init the container as a local variable from the Application_Start function under Global.asa.

    protected void Application_Start(object sender, EventArgs e)
        {

            IUnityContainer container = new UnityContainer();
            /.../    
         }

According to your sample, do I need to change the container as the global variable? Thanks again!!
        




May 24, 2008 at 11:43 AM
Thanks. It works now!!
May 24, 2008 at 5:36 PM

Not being satisfied with my own understanding of the AppDomain / HttpApplication pool issue, I did some more digging.  For those who are interested, read in the NET Framework Developer's Guide Working with HttpApplication Instances page. A couple of key points:

  • Application_OnStart is raised only once during an application's lifetime, on the first instance of HttpApplication. Use Application_OnStart only to create or modify states shared by all pipeline instances, such as the use of the ApplicationState object
  • Application_OnEnd is raised only once during an application's lifetime, on the last instance of HttpApplication that is torn down. Use Application_OnEnd only to clean up states or resources shared by all pipeline instances, such as the use of the ApplicationState object.

 So my comment on singletons was not correct.

Phil


pbolduc wrote:

If your application depends on singletons, you should avoid using 

    Application["UnityContainer"] = container;

as your web application will have one AppDomain with a pool of HttpApplication objects. An individual HttpApplication object is created to handle each simultaneous HTTP request. See this article for an explaination.  This post I referenced last time uses the AppDomain to store the configured Unity container and would only create one.