New Project doesn't work

Oct 3, 2008 at 5:21 PM
I created a small demo project using:
  • Unity 1.1
  • ObjectBuilder2
  • Common 4.0
... and I got it to work.  I have the sample application available at http://www.kingwilder.com on my Downloads page. I have a blog post on it.

But whenever I try to create a new project, with virually the exact same configuration, it doesn't work.  More specifically, the web site doesn't work, but the Unit Tests work fine.  I've create three different test projects trying to re-create what worked in my first project, and when it comes to making it work with the web site, it just doesn't. I've tried a WebSite, and a Web Application, and both methods come out with the same result, nothing works.

The problem appears to be that either the [Dependency] property or the [InjectionConstructor] constructors don't seem to be getting registered when the page is loading.

I'm using a PageBase example as described on pnpguidance.net by David Hayden.

Here's the PageBase class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using Microsoft.Practices.Unity;

namespace UnitySimpleTest2.Web
{
    /// <summary>
    /// We are wrapping up the Unity instantiation into a base page class for
    /// reuse in all derived pages.
    /// </summary>
    public class PageBase<T> : System.Web.UI.Page where T : class
    {


        protected override void OnPreInit(EventArgs e)
        {
            InjectDependencies();

            base.OnPreInit(e);
        }

        protected virtual void InjectDependencies()
        {
            HttpContext context = HttpContext.Current;

            if (context == null) return;

            IContainerAccessor accessor = context.ApplicationInstance as IContainerAccessor;

            if (accessor == null) return;

            IUnityContainer container = accessor.Container;
            if (container == null)
                throw new InvalidOperationException("Container on Global Application Class is Null.  Cannot perform BuildUp.");

            container.BuildUp(this as T);

        }

    }
}

This is the code-behind of the default page:

using System;
using System.Web.UI;

using UnitySimpleTest2.Facade;

using Microsoft.Practices.Unity;

namespace UnitySimpleTest2.Web
{
    public partial class _Default : PageBase<_Default>
    {
        // This doesn't work either!
        //[Dependency]
        //IFacade _facade { get; set; }

        IFacade _facade;

        public _Default()
        {

        }

        [InjectionConstructor]
        public _Default(IFacade facade)
        {
            this._facade = facade;
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                WriteMessage();
            }
        }

        private void WriteMessage()
        {
            lblMessage.Text = _facade.WriteMessage();
        }
    }
}

I'm also using the web.config for the types:

<section name="Unity"
    type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
    Microsoft.Practices.Unity.Configuration"/>


<Unity>
    <typeAliases>
        <typeAlias alias="IData"
            type="UnitySimpleTest2.DataObjects.IData,
                UnitySimpleTest2.DataObjects"></typeAlias>
        <typeAlias alias="Data"
            type="UnitySimpleTest2.DataObjects.Data,
                UnitySimpleTest2.DataObjects"></typeAlias>
       
        <typeAlias alias="IFacade"
            type="UnitySimpleTest2.Facade.IFacade,
                UnitySimpleTest2.Facade"></typeAlias>
        <typeAlias alias="Facade"
            type="UnitySimpleTest2.Facade.Facade,
                UnitySimpleTest2.Facade"></typeAlias>
    </typeAliases>
    <containers>
        <container>
            <types>
                <type type="IData" mapTo="Data"></type>
                <type type="IFacade" mapTo="Facade"></type>
            </types>
        </container>
    </containers>
</Unity>

The problem is the _facade variable is ALWAYS null.  Any ideas why?  Does anyone have a bullet-proof method of making this work?  I'm dead in the water on a project until I sort this out.

Thanks.
Oct 3, 2008 at 6:10 PM
Constructor injection doesn't happen for pages because ASP.NET is creating the pages and not using the container. So that'll never work.

The property injection isn't happening because Unity only injects public properties - your Facade property is private.

Oct 3, 2008 at 6:15 PM
By the way, you might want to look at using an HttpModule for DI instead of using a base page. It centralizes all your DI stuff and doesn't eat your base class.

Oct 3, 2008 at 6:31 PM
If you are interested in using an HttpModule, I published a screencast on that very subject:

Unity and ASP.NET Web Pages Dependency Injection Part II with Special Guests - Autofac and Ninject

Regards,

Dave

Oct 3, 2008 at 8:45 PM
>>Constructor injection doesn't happen for pages because ASP.NET is creating the pages and not using the container. So that'll never work.

>>The property injection isn't happening because Unity only injects public properties - your Facade property is private.

I wonder why it worked on my other project, that I posted on my web site.  Confusing.

>> By the way, you might want to look at using an HttpModule for DI instead of using a base page. It centralizes all your DI stuff and doesn't eat your base class.

I'll look into this.  I would want a centralized way of handling this.

>> If you are interested in using an HttpModule, I published a screencast on that very subject:

>> Unity and ASP.NET Web Pages Dependency Injection Part II with Special Guests - Autofac and Ninject

David, I've watched many of your videos, including this one.  I'll take another look at it.

I really don't want to NOT use Unity.  I like what it does, when it works.  :^)
Oct 4, 2008 at 12:21 AM
David, do you have the code from your screencast for the HttpModule example?  I was able to recreate your Unity.Integrations.Web project for the most part, but I think the UnityHttpApplication class is missing something since you didn't show that class.

When I run my project I'm still getting a null reference on my property in my code-behind even with the Dependency attribute.

This is my UnityHttpApplication class which I'm sure is not complete:

using System.Web;

using Microsoft.Practices.Unity;

namespace Unity.Integrations.Web
{
    public abstract class UnityHttpApplication : HttpApplication
    {
        protected abstract IUnityContainer CreateContainer();

        public void Application_Start()
        {
            IUnityContainer container = CreateContainer();
            IoC.Initialize(container);
            OnApplicationStarted();
        }

        public void Application_End()
        {
            OnApplicationEnded();
        }

        public virtual void OnApplicationStarted(){

        }

        public virtual void OnApplicationEnded()
        {

        }
    }
}

This is my Global.asax now:

using System.Configuration;

using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

using Unity.Integrations.Web;

namespace UnitySimpleTest2.Web
{

    public class Global : UnityHttpApplication
    {
        protected override IUnityContainer CreateContainer()
        {
            IUnityContainer container = new UnityContainer();

            UnityConfigurationSection section =
                (UnityConfigurationSection)ConfigurationManager.GetSection("Unity");
               
            section.Containers["defaultContainer"].Configure(container);

            return container;
        }
    }
}

This kind of thing is very necessary, since 99% of .Net developers are not building single page web sites, they're building web applications.  So encapsulating this functionality would be very useful.  And I for one, would be using it in every application I build.  Up to now, when I look back at my applications, they are tightly-coupled, since I didn't know anything about DI 3 months ago.

But now I see it's need but I need to use it in a multi-tiered application type of scenario.

I've uploaded my simple project on my site, http://www.kingwilder.com/Portals/0/Downloads/unitysimpletest2.zip.  I know it's alot to ask, but if you could take a look at it and see where I'm going wrong, it would be appreciated.  I will then post the code on my site for others.

Thanks for your help.
Oct 4, 2008 at 12:54 AM
FYI, in my uploaded zip file I forgot to make the properties public, so if you look at the code, just assume that I have.  But even when I changed them to public here locally, it still returned null.

I know I'm missing something in the UnityHttpApplication class.

I'm kind of surprised that a feature like this isn't already built into Unity.  I'm sure it's really needed.

Oct 4, 2008 at 12:58 AM
Ok, I got it to work!  I forgot to register the UnityHttpModule in the web.config.  Once I did that it worked.

But I'm still unsure if my UnityHttpApplication class is correct.  It's in two posts previous.  Can someone take a look at it and tell me if it's ok or does it need some tweaking.

Thanks.
Oct 4, 2008 at 5:41 PM
Ok, I'm back.  This does work, except for my UserControls.  They all return null, whether they are in the same folder as my page or in a different folder.

David, if you could put your sample application that you demo'd in your screencast on your web site, it would be helpful.  I seem to be doing exactly what you did in your screencast, but I'm obviously missing something.

Your help would be appreciated.

Thanks.
Oct 4, 2008 at 6:54 PM
What does "they all return null" mean? Is the user control itself null, or some service you're trying to inject into the control?

In general, you won't be able to inject controls via the container - there's too much dependency on the ASP.NET page lifecycle. You've got to add them in code from your codebehind.

If you're trying to inject values into the controls, just like with pages, ASP.NET creates the control instances, so you can't do constructor injection. And the properties need to be public. I don't know if you're using my module or David's, but I know mine does properly inject into controls. I haven't looked at David's so I can't say one way or the other.

-Chris
Oct 4, 2008 at 9:50 PM
Edited Oct 4, 2008 at 10:09 PM
Chris,

Sorry, when I refer to "null" being returned, it's on the Dependency property in the UserControl that is typed as an interface for the facade object.  It never gets injected, so it never gets resolved to it's concrete class or anything.

Here's my UserControl class:

namespace UnitySimpleTest2.Web
{
    public partial class MyUserControl : System.Web.UI.UserControl
    {
        [Dependency]
        public IFacade Facade { get; set; }  // <-- This is always null

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                WriteMessage();
            }
        }

        private void WriteMessage()
        {
            lblMessage.Text = Facade.WriteMessage("Hi, from the UserControl!");
        }
    }
}

>>In general, you won't be able to inject controls via the container - there's too much dependency on the ASP.NET page lifecycle. You've got to add them in code from your codebehind.

But isn't this what the UnityHttpModule example is supposed to address?  I guess I'm confused about that response because I thought Unity was made to work with ASP.NET.  I've seen many examples that work with ASP.NET, although I think they are not realistic examples.  Not to put any of the authors down who created those examples, I think many developers would prefer to see an example of it in action in a more real world example, you know, with a multi-tier application, folders separating aspects of the application, different projects for each layer of the application, that kind of thing.  I don't think anyone that would be using Unity, would be building a one page web site.

I'm presently using a version (my version) of David Hayden's HttpModule and HttpApplication example (since I couldn't find his code anywhere) and while it works, when I stepped through it, it enters the UnityHttpModule --> Init method, but it never fires the OnPreRequestHandlerExecute method and then it doesn't call the method to recursively walk through all UserControls on the page and inject those controls.  So I know I'm missing something from David's original example, and I haven't figured out what that is yet.

I have made all the properties public, so that part of it works, but it doesn't get further than the page.  No user controls in the page are injected.

I will try your HttpModule/HttpApplication extension example and see how that does.

Essentially what I need, and I think all developers need who may be using Unity, is an easy way of plugging Unity into a web application and having it handle injections transparently for all parts of the application.  It would be nice if a future release of Unity would have this integrated.

Don't get me wrong, I think what you've done with Unity is great.  I like it so much that I've built a little code generator using MyGeneration to build the web.config Unity section in one-click, which saves tons of time.  If I knew more about it, I would love to contribute, but I don't think I'm at that skill level yet.

Thanks for your response.

Oct 4, 2008 at 11:07 PM
Chris,

I built a small multi-tiered application using your (and the guy who's web site you pointed me to) Application extension method and the HttpModule and it worked!  Even with the UserControl!!!

I think this is something I can use in my enterprise application.  Are there any issues you might know of that would prevent me from using this custom assembly, like performance issues, etc?  I'm in the beginning stages of a very large enterprise application and I would like to use some DI component that would not over burden the application.

Are there any cautions that come to mind?

Thanks again,

King Wilder (kahanu)
Oct 6, 2008 at 8:38 PM
I just want to thank Chris Tavares and David Hayden for their help on this.

I've built a small multi-tiered ASP.NET application that works with either a Boostrapper (registering types via C# code) or the web.config.  You can read about how it works and download the example from my blog.

http://www.kingwilder.com/Blog/tabid/54/EntryID/9/Default.aspx

I'm still fairly new to Unity, so if anyone sees anything that I've done wrong or could be done easier, by all means let me know on my blog.

Again thanks to everyone who helped.

King Wilder