Ni la clase Page ni los presentadores deberían tener que encargarse directamente de la gestión de la construcción o el ciclo de vida de cualquiera de sus dependencias; todo esto debe ser manejado por su contenedor. Como la inyección de constructor no funciona con WebForms, deberá exponer las dependencias necesarias como propiedades en la clase. Por ejemplo, usted podría cambiar su clase a:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public _DefaultPresenter Presenter { get; set; }
}
La página no debería necesitar ninguna referencia al repositorio, ya que se inyecta en el presentador.
El resto de esta respuesta es específica de StructureMap; los detalles pueden diferir para otros contenedores.
Para habilitar la inyección del colocador, debe decirle a StructureMap qué propiedades debe rellenar. Una forma es aplicar el atributo [SetterProperty] a la propiedad en sí. Sin embargo, esto puede parecer un poco invasivo para tener detalles de StructureMap dentro de sus clases. Otra forma es configurar StructureMap para que sepa qué tipos de propiedades inyectar. Por ejemplo:
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>());
});
}
El método SetAllProperties permite indicar a StructureMap cómo reconocer las propiedades que debe rellenar. En este caso, le estoy diciendo a StructureMap que inyecte a todos los presentadores (suponiendo que todos estén en el mismo espacio de nombres).
Aún necesita realizar la inyección del colocador en cada solicitud.Con StructureMap, utiliza el método BuildUp() para inyectar dependencias en una instancia existente. Podrías hacerlo en los eventos Init o Load de cada página o una clase base de página, pero una vez más, eso parece invasivo. Para mantener el recipiente fuera de sus clases de página por completo, se puede utilizar el evento PreRequestHandlerExecute de la aplicación (en Global.asax o un 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);
}
Por último, si quieres explícitamente se deshaga de la IRepository, se pudiera manejar que en el caso EndRequest:
protected void Application_EndRequest(object sender, EventArgs e)
{
var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable;
if (disposable != null) disposable.Dispose();
}
Tenga en cuenta que esto funciona correctamente porque en la inicialización le dijimos StructureMap para almacenar en caché IRepository por híbrido, que significa "dame la misma instancia para cada solicitud HTTP (o hilo, si no se ejecuta dentro de un sitio web) ". Cuando recupere el IRepository en EndRequest, recibirá el mismo que utilizó durante la solicitud, y puede deshacerse de él.
¡Perdón por no mirar el código o las etiquetas en su pregunta! Lo he reelaborado ahora, ¡espero que eso mejore! Eliminará esto si elimina el suyo ... –