Neither the Page class nor the presenters should have to deal directly with managing the construction or lifecycle of any of its dependencies - that should all be handled by your container. Since constructor injection does not work with WebForms, you will need to expose any needed dependencies as properties on the class. For example, you could change your class to:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public _DefaultPresenter Presenter { get; set; }
}
The page should not need any reference to the repository, as it will be injected into the presenter.
The rest of this answer is specific to StructureMap - details may differ for other containers.
To enable setter injection, you need to tell StructureMap which properties to populate. One way is to apply the [SetterProperty] attribute to the property itself. However, this can feel a bit invasive to have StructureMap details within your classes. Another way is to configure StructureMap so that it knows which property types to inject. For example:
protected void Application_Start(object sender, EventArgs e)
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid);
x.SetAllProperties(set => set.WithAnyTypeFromNamespaceContainingType<IRepository>());
});
}
The SetAllProperties method allows you to tell StructureMap how to recognize the properties it should populate. In this case, I'm telling StructureMap to inject all presenters (assuming they are all in the same namespace).
You still need to perform the setter injection on each request. With StructureMap, you use the BuildUp() method to inject dependencies into an existing instance. You could do it in the Init or Load events of each page or a page base class, but again, that feels invasive. To keep the container out of your page classes completely, you can use the PreRequestHandlerExecute event of the application (in global.asax or an IHttpModule):
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var page = application.Context.CurrentHandler as Page;
if (page == null) return;
ObjectFactory.BuildUp(page);
}
Finally, if you want to explicitly Dispose of your IRepository, you could handle that in the EndRequest event:
protected void Application_EndRequest(object sender, EventArgs e)
{
var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable;
if (disposable != null) disposable.Dispose();
}
Note that this works properly because in the initialization we told StructureMap to cache IRepository by Hybrid, which means "give me the same instance for each HTTP Request (or thread, if not running within a website)". When you retrieve the IRepository in EndRequest, you will receive the same one used throughout the request, and you can dispose it.