0

To start, I know this can be done but as i was not involved in setting it up or implementing it i did not see how it was done.

At a former job, when i was helping support a web-application (MVC or Web-App), we had your usual EF design pattern. But when it came time to consume the EF Objects all we had to do was declare a property in the Page/Controller and we had access to the Repository/Service.

We did not have to do anything as far as declaring an explicity var prop1 = IOC.Resolve<Type>; after declaration, it would be auto populated. I assumed this was dependency injection but have not seen any write ups on how to make this possible.

Any help would be greatful.

Edit 2014-04-13

Attempted to do the Property Injection within the Global.asax file like such

protected void Application_Start( object sender , EventArgs e ) {
    App.Initialize( null );

    if( HttpContext.Current != null ) {
        var pg = base.Context.Handler as Page;
        if( pg != null ) {
            App.InjectProperties( pg );
        }
    }
}

I have tried do the if.... logic in Application_BeginRequest with no success on either.

App.cs

public class App {
    public static void Initialize( string log4netPath ) {
        var container = new WindsorContainer();

        container.Kernel.ComponentModelCreated += ( s => {
            if( s.LifestyleType == LifestyleType.Undefined ) {
                s.LifestyleType = LifestyleType.PerWebRequest;
            }
        } );

        container.Install(
            new DomainInstaller() ,
            new RepositoryInstaller() ,
            new ServiceInstaller()
            );

        container.Install( new SiteInstaller() );

        if( log4netPath != null || string.IsNullOrWhiteSpace( log4netPath ) )
            container.AddFacility( new LoggingFacility( LoggerImplementation.Log4net , log4netPath ) );

        CWC.Init( container );
    }

    public static void InjectProperties( Page pg ) {
        var type = pg.GetType();
        foreach( var prop in type.GetProperties() ) {
            if( CWC.IsInitialized ) {
                try {
                    var obj = CWC.Resolve(prop.PropertyType);
                    prop.SetValue( pg , obj , null );
                } catch( System.Exception ) {
                    //do nothing
                }
            }
        }

    }
}

DomainInstaller.cs (pretty much all the Installer classes are setup this way):

public class DomainInstaller : IWindsorInstaller {
    #region IWindsorInstaller Members

    public void Install( Castle.Windsor.IWindsorContainer container , Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store ) {
        container.Register( Types.FromAssembly( Assembly.GetExecutingAssembly() )
            .Where( t => t.Namespace.StartsWith( "Woodsoft.Domain" ) )
                .WithService.FirstInterface().LifestylePerWebRequest() 
        );
    }

    #endregion
}

So i think i may have found my problem, but i am unsure how to implement the solution, as both my Pages and MasterPages will contain properties that will need to be injected from my EF data-framework. Below is an example of an MVC implementation, but Page and MasterPage object do not have an immediate common derived Interface that i can use like i could for Controllers.

Another project, MVC pattern:

public class SiteInstaller : IWindsorInstaller {
    #region IWindsorInstaller Members

    public void Install( IWindsorContainer container , IConfigurationStore store ) {
        container.Register(
            Classes.FromThisAssembly()
                .BasedOn<IController>()
                    .LifestyleTransient()
        );
    }

    #endregion
}

Any help to modify this Installer from MVC to WebForms? WIth the intention of MasterPage's and Page's both having Properties that will need to be injected from the Windsor Container.

Community
  • 1
  • 1
GoldBishop
  • 2,820
  • 4
  • 47
  • 82

1 Answers1

0
  • Typically in MVC, the entry point is a controller action which renders the view.
  • By default, the MVC framework will instantiate a controller class and invoke the appropriate action (controller method)
  • When the controller is instantiated, MVC will try everything in its power to provide everything the controller needs to instantiate it. e.g.

now consider this MVC controller

public class MyController : Controller
{
 public MyController()
 {
  // mvc can easily instantiate this controller 
  // since this is a parameter less controller.
 }
}

now consider this:

public class MyController : Controller
{
 public MyController(IRepository repository)
 {
  // mvc cannot easily instantiate this controller 
  // unless it knows how to inject a concrete implementation
  // of the IRepository interface
 }
}

typically what teams do as part of infrastructure setup is provide a dependency resolver to the MVC framework.

e.g.

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

now what happens is when MVC wants to instantiate the controller, it needs a concrete IRepository and also sees that it can delegate the responsibility to a user-provided DI framework. in this case, Autofac.

it'll request Autofac to provide a IRepository type.

and what we typically do in Application Start is

ContainerBuilder builder = new ContainerBuilder();

// critical line
builder.Register(c => new EFRepository()).As<IRepository>();

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

as you can see, when the controller is instantiated it'll magically (well not magically, we did some ground work) get the IRepository type and the action method can do:

var results = this.repository.GetEmployees();

similar to how the IRepository is injected via the constructor, you can inject it via the property of the controller as well.

builder.Register(c => new MyType()).As<IType>().PropertiesAutowired();

for your page, you can also do

builder.RegisterType<YourPageType>().PropertiesAutowired();

The DI (Autofac here) will automatically populate the page property with the registered concrete type.

etc.

Raja Nadar
  • 9,409
  • 2
  • 32
  • 41
  • Yeah, but they didnt have the injection apart of the Constructor for the either Page or Controller. I would create a page (Web-Forms mostly), create a public Property `public IRepository Repository {get;set;}` in the code-behind and then i would have access to basically the `Repository` object. Part im trying to understand, was how did they do the Injection without tying it to the Constructor? – GoldBishop Apr 13 '14 at 00:58
  • You don't need the constructor and property. Either is good. They didn't use constructors. Just property. Just look for i repository registration – Raja Nadar Apr 13 '14 at 01:27
  • I assume `ContainerBuilder` is the Container? for me i have a static class that uses `IWindsorContainer`, as well have IWindsorInstallers for each of the Libraries for local instantiation handling, so i have `DomainInstaller`, `RepositoryInstaller`, and `ServiceInstaller`, for this current application. Have any good reads i can go through to get this pattern implemented? – GoldBishop Apr 13 '14 at 01:36
  • _ContainerBuilder_ is the place where you register the types with autofac, _Container_ is the result of the builder. What you call windsor installer, in autofac are called modules. What @raja wrote is what you need to use autofac. The docs for autofac have info on _module_ and how to integrate with asp.net (web forms and mvc). If you have a choice of tech, do yourself a favour and forget about web forms. – MikeSW Apr 13 '14 at 15:16