Autor en Google+
Saltar al contenido

Variable not found. Artículos, noticias, curiosidades, reflexiones... sobre el mundo del desarrollo de software, internet, u otros temas relacionados con la tecnología. C#, ASP.NET, ASP.NET MVC, HTML, Javascript, CSS, jQuery, Ajax, VB.NET, componentes, herramientas...

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, noticias, curiosidades, reflexiones... sobre el mundo del desarrollo
de software, internet, u otros temas relacionados con la tecnología

¡Microsoft MVP!
martes, 5 de febrero de 2013
ASPNETMVCHace poco, en el post donde trataba la inyección de dependencias y desacoplamiento de Hubs de SignalR, el amigo Maxxx comentaba que podría estar bien ver cómo podríamos emplear las mismas técnicas con ASP.NET MVC.

Y ciertamente, me ha parecido muy interesante porque es un escenario que encuentro habitualmente en empresas de desarrollo: comprenden los beneficios de reducir el acoplamiento entre componentes, pero les parece algo demasiado complejo como para aplicar en su día a día porque desconocen cuáles son y cómo usar las herramientas de que disponemos para conseguirlo.

Por tanto, en este post vamos a ver, paso a paso y de forma totalmente práctica, cómo evolucionar desde un controlador MVC fuertemente acoplado a clases del modelo hasta otro totalmente desacoplado usando inyección de dependencias y contenedores de inversión de control.

Y aunque las técnicas y ejemplos que mostraremos están muy enfocados a controladores MVC, los conceptos tratados son aplicables en cualquier tipo de tecnología y arquitectura.

0. Punto de partida

Vamos a partir de la siguiente clase del modelo, de la que sólo mostramos las partes importantes:
public class MyAppServices: IDisposable
{
    public IEnumerable<Product> GetAllProducts() { ... }
    public IEnumerable<Product> GetProductsByCategory(int categoryId) { ... } 
    public void Dispose() { ... }
}
Y vemos ahora el siguiente controlador MVC, funcionalmente correcto, que utiliza la clase anterior para obtener datos con los que poblar las vistas. Como curiosidad, deciros que el código está basado en hechos reales:
public class ProductsController : Controller
{
    public ActionResult Index()
    {
        using (var services = new MyAppServices())
        {
            var data = services.GetAllProducts();
            return View(data);
        }
    }
    public ActionResult ByCategory(int categoryId)
    {
        using (var services = new MyAppServices())
        {
            var data = services.GetProductsByCategory(categoryId);
            return View(data);
        }
    }
}
Observad que en este controlador existe un acoplamiento total con la clase MyAppServices, que es instanciada en cada una de las acciones que hemos implementado. Mucho código repetido, una dependencia total respecto a la implementación de la clase MyAppServices, y la imposibilidad de realizar pruebas unitarias a los métodos.

A continuación, vamos a ir haciendo evolucionar este controlador hasta que alcancemos el punto donde queremos llegar: el desacoplamiento total, manteniendo intactas las funcionalidades proporcionadas.

1. Extraer código de creación y liberación de dependencias

Uno de los aspectos negativos que hemos notado en el controlador de partida es que el código de sus acciones es demasiado extenso, teniendo en cuenta que sólo deben retornar una vista con información obtenida desde el modelo. Esto rompe con el principio básico DRY (Don’t Repeat Yourself).

La utilización del bloque using es muy correcta, es importante asegurarse de que los recursos son liberados al finalizar el tratamiento de la petición. Sin embargo, la instanciación de la clase del modelo la estamos replicando en demasiados puntos… ¿Qué ocurriría si en el futuro no queremos que sea la clase MyAppServices, sino cualquier otra, la usada por las acciones? ¿O si hacemos que el constructor de dicha clase reciba un parámetro? Pues tendríamos que tocar demasiado código. Serían cambios con un impacto muy alto en todos los componentes cohesionados con esta clase.

Para minimizar este riesgo, una primera medida podría ser la refactorización del código, llevándonos las tareas comunes de instanciación y liberación de la clase del modelo a un lugar que pueda ser compartido por las acciones. El resultado podría ser el siguiente:
public class ProductsController : Controller
{
    private MyAppServices _services;
    public ProductsController()
    {
        _services = new MyAppServices();
    }

    public ActionResult Index()
    {
        var data = _services.GetAllProducts();
        return View(data);
    }

    public ActionResult Category(int categoryId)
    {
        var data = _services.GetProductsByCategory(categoryId);
        return View(data);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            _services.Dispose();
    }
}
Como podemos ver, los métodos de acción se han simplificado notablemente, eliminando todo el “ruido” que introducía el bloque using y la instanciación de la clase del modelo. Ahora estas acciones son más fáciles de leer y, por tanto, de modificar y mantener.

Siguiendo con el código anterior, la creación de la instancia nos la hemos llevado al constructor, por lo que si quisiéramos sustituir la clase del modelo por otra ya sólo tendríamos que tocar una línea de código en el controlador. Al llamar en un único punto el new, hemos eliminado casi completamente el pegamento que unía el componente instanciado con el instanciador.

Por último, seguimos manteniendo el control sobre el tiempo de vida de MyAppServices. Se instancia en el constructor del controlador, y se libera justo al acabar el proceso de la petición, aprovechando que podemos sobrescribir el método Dispose().

Vamos mejorando, pero aún hay mucho por hacer :-)

2. Abstracción de las clases del modelo

Aunque la refactorización anterior nos ha llevado a un código más limpio, aún seguimos teniendo un controlador muy acoplado a la clase MyAppServices. El próximo paso será romper esta cohesión abstrayéndonos mediante interfaces.

La idea es eliminar de nuestro controlador la referencia a la clase concreta del modelo que estamos usando. Para ello, realizaremos dos operaciones:
  • En primer lugar, extraeremos un interfaz con los miembros que nos interesen desde la clase MyAppServices, a la que llamaremos IAppServices. Y por supuesto, reflejamos en la clase del modelo que implementa ese interfaz, de forma que el asunto quedaría algo así:    
    public interface IAppServices: IDisposable
    {
        IEnumerable<Product> GetAllProducts();
        IEnumerable<Product> GetProductsByCategory(int categoryId);
    }
    public class MyAppServices: IAppServices
    {
        // ...
    }
      
  • En segundo lugar, modificamos el controlador, de forma que el miembro _services deje de ser del tipo MyAppServices y pase a usar el nuevo interfaz:    
    public class ProductsController : Controller
    {
        private IAppServices _services;
    
        public ProductsController()
        {
            _services = new MyAppServices();
        }
    
        // ... Action methods and Dispose
    }
Aunque pueda parecer lo contrario, lo que hemos hecho es realmente importante. Ahora, salvo en el constructor, no queda en nuestra clase controlador ninguna referencia a la clase concreta del modelo que estamos utilizando. De cara a la implementación de las acciones, nos da igual qué objeto se encuentre almacenado en _services, lo único que nos interesa es que cumpla el contrato definido por la interfaz IAppServices; el uso de esta abstracción es un paso más hacia el desacoplamiento total.

Veamos ahora cómo resolver ese “salvo en el constructor”…

3. Inyección de Dependencias

En este momento tenemos ya un código de controlador bastante limpio y desacoplado de la clase del modelo, pero aún seguimos teniendo un poco de “pegamento” en el constructor.

Si quisiéramos sustituir la implementación MyAppServices por otra, aún tendríamos que modificar todos los controladores que usaran esta técnica.

Tampoco seríamos capaces aún de realizar pruebas unitarias a las acciones, puesto que éstas implicarían la ejecución de código de MyAppServices. Y sabemos que esto no serían pruebas unitarias, sino de integración, ¿verdad?

Bien, ¿y cómo podríamos solucionar esto? Pues mediante la inyección de dependencias. Este principio de diseño sugiere la eliminación de dependencias rígidas de un componente (como la provocada por el uso del new en el constructor) haciendo que sea otro componente el que suministre al primero todos aquellos objetos que necesite para funcionar.

En otras palabras, si desde ProductsController necesitamos para funcionar una instancia de cualquier tipo que implemente las operaciones definidas en el interfaz IAppServices, simplemente debemos obligar a que alguien nos la suministre.

La implementación práctica de este principio en nuestro ejemplo se podría materializar de la siguiente forma, modificando ligeramente el constructor:
public class ProductsController : Controller
{
    private IAppServices _services;

    public ProductsController(IAppServices services)
    {
        _services = services;
    }

    // Action methods and Dispose
}
Observad que ahora el constructor de la clase exige que alguien le suministre las dependencias, u objetos que necesita para funcionar correctamente; no se podrá instanciar el controlador de otra forma. Y dado que tenemos ya definido el interfaz, no es necesario indicar un tipo concreto, simplemente el contrato que define las operaciones que usaremos desde el controlador, sea cual sea la clase que las implemente.

En estos momentos ya hemos eliminado por completo el acoplamiento entre ProductsController y MyAppServices: de hecho, no queda ninguna referencias hacia la clase concreta del modelo que usamos en el controlador.

Otra ventaja de haber dado este paso es que nos permite ya realizar pruebas unitarias completas sobre nuestros métodos de acción. Desde el código de test podríamos instanciar la clase ProductsController, suministrarle una referencia hacia un objeto falso (que implemente el interfaz requerido) y comprobar el funcionamiento de las acciones, sin salir de su ámbito.

Ah, antes de continuar, permitidme un consejo que suelo dar a los equipos de desarrollo con los que trabajo:
Programa siempre tus componentes como si fueras a hacerles pruebas unitarias.
Aunque no las hagas.
Es decir, el hecho de no realizar pruebas unitarias no debe valer como excusa para no aplicar principios y buenas prácticas, como el desacoplamiento o la inyección de dependencias, cuyo uso sólo traerá beneficios a vuestras aplicaciones.

Por recapitular un poco, el código del controlador lo tendríamos en este momento de la siguiente forma:
public class ProductsController : Controller
{
    private IAppServices _services;

    public ProductsController(IAppServices services)
    {
        _services = services;
    }

    public ActionResult Index()
    {
        var data = _services.GetAllProducts();
        return View(data);
    }

    public ActionResult Category(int categoryId)
    {
        var data = _services.GetProductsByCategory(categoryId);
        return View(data);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            _services.Dispose();
    }
}
Sin embargo, si en estos momentos ejecutamos nuestra aplicación, veremos que no funciona: ASP.NET MVC es incapaz de crear un controlador ProductsController, puesto que no dispone de un constructor sin parámetros. Es totalmente lógico: el framework no puede llamar al constructor porque no sabe qué parámetro enviarle.

4. Suministrando dependencias al controlador con un Dependency Resolver

Ojo, que lo que vamos a ver en este punto es sólo por “cultura general”, para conocer los mecanismos que hay por detrás de ASP.NET MVC, pero no es estrictamente necesario. Las técnicas mostradas aquí son ampliamente superadas por las que utilizaremos en el siguiente epígrafe.

Bueno, antes hemos comentado que para instanciar un controlador del tipo ProductsController, “alguien” debe suministrarle las dependencias, es decir, llamar a su constructor pasándole como parámetro la instancia de la clase del modelo a utilizar. 

La instanciación del controlador es un proceso que se lleva a cabo desde el interior del framework, aunque existen varias fórmulas que permiten intervenir en este proceso. Una posibilidad es usar el Dependency Resolver, de forma similar a como describimos hablando de SignalR.

El Dependency Resolver es un mecanismo incluido en ASP.NET MVC que actúa como suministrador de instancias centralizado. Cuando el framework necesita crear un objeto de cualquier tipo, en primer lugar solicita la nueva instancia al Dependency Resolver, y sólo si éste no se la facilita, lo crea de forma manual.

Así, cuando ASP.NET MVC va a instanciar el controlador ProductsController, primero pregunta al Dependency Resolver si le puede proporcionar una instancia. Si tomamos el control en este punto, podríamos automatizar la inyección de dependencias en los controladores.

Para ello, debemos crear una clase que implemente el interfaz IDependencyResolver, e informar al framework que se trata del nuevo componente encargado de la resolución. El código simplificado de esta clase podría ser el siguiente:
public class MyDependencyResolver: IDependencyResolver
{
    public object GetService(Type serviceType)
    {
        if (serviceType == typeof (ProductsController))
            return new ProductsController(new MyAppServices());
        return null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return Enumerable.Empty<object>();
    }
}
Como seguro podéis intuir, el método GetService() será el llamado por ASP.NET MVC en el momento de instanciar el controlador. Por otra parte, es necesario registrar en el framework este componente, lo cual podemos conseguirlo mediante el siguiente código, ejecutado durante la inicialización de la aplicación (en el método Application_Start() del global.asax puede ser un buen lugar para hacerlo):
DependencyResolver.SetResolver(new MyDependencyResolver());
De esta forma, al ejecutar nuestra aplicación, veríamos que todo funciona de nuevo. El framework está llamando al nuevo Dependency Resolver, y nuestro controlador está siendo creado junto con las dependencias que necesita satisfacer, en este caso el objeto que implemente IAppServices.

Además, en el Dispose() del controlador seguimos manteniendo la liberación de recursos de nuestra clase del modelo, por lo que todo seguirá funcionando correctamente.

Pero esto es demasiado trabajo, ¿no? Pensad que podemos tener controladores con dependencias hacia varios objetos, y que incluso éstos podrían tener, a su vez, dependencias con otros objetos, por lo que la instanciación manual del controlador podría ser bastante tediosa. También deberíamos introducir en los controladores la llamada a la liberación de recursos de las dependencias, y es bastante fácil que se nos olviden algunos…

5. Usar Contenedores de Inversión de Control

La solución definitiva a nuestros problemas pasa por el uso de los llamados contenedores de inversión de control (IoC Containers), que, entre otras cosas, son componentes especializados en la creación de instancias de objetos, así como en la gestión del ciclo de vida de éstas. En cierto sentido son similares a los dependency resolvers que hemos comentado anteriormente, pero van más allá y nos lo pondrán todo bastante más fácil.

Muy resumidamente, un contenedor IoC mantiene un registro de asociaciones entre interfaces y clases concretas. Cuando un componente externo solicita al contenedor una instancia de un tipo determinado, éste utiliza su registro para satisfacer las dependencias que sean requeridas en cada momento.

Así, si alguien solicita al container una instancia de la clase “X” cuyo constructor requiere como parámetro una instancia del interfaz “I”, el contenedor buscará en su registro la clase asociada a dicho interfaz y obtendrá automáticamente una instancia de ésta. Una vez la tenga, instanciará la clase “X” pasándole como parámetro a su constructor el objeto creando anteriormente.

Existen gran cantidad de contenedores de inversión de control (Ninject, Unity, Automapper, Autofac, Windsor, etc.), y la elección de uno u otro es muchas veces sólo cuestión de preferencias personales. Además, dado que se trata de componentes estándar y válidos para casi cualquier tipo de proyecto, se pueden encontrar extensiones que facilitan su integración en ASP.NET MVC, por lo que es conveniente siempre elegir uno que ya esté preparado para este framework.

Todos los contenedores son conceptualmente iguales; para un uso básico simplemente notaremos que hay entre ellos diferencia de sintaxis, por lo que vamos a centrarnos en uno de los más populares: Unity.

Unity (http://unity.codeplex.com/) es un potente contenedor promovido por  la iniciativa de Patterns & Practices de Microsoft. Como otros, dispone de extensiones específicas para ASP.NET MVC y se puede instalar muy fácilmente a través de Nuget usando el package “Unity.Mvc3” (ojo, que a pesar de su desafortunado nombre es válido también para la versión 4 del framework):
PM> Install-Package unity.mvc3
Una vez instalado, el siguiente paso es registrar en el contenedor las asociaciones entre interfaces y clases concreta en el archivo bootstrapper.cs que la instalación habrá dejado en el raíz de nuestro proyecto. Como la ubicación por defecto de este archivo es terrible, os recomiendo moverla a App_Start, puesto que el registro de clases se debe ejecutar durante el arranque de la aplicación y así seguimos las convenciones de ubicación de archivos.

En nuestro caso, lo único que tenemos que indicar es que cuando alguien solicite al contenedor una instancia para el interfaz IMyServices, se debe obtener y retornar un objeto de la clase concreta MyAppServices. Además, vamos a indicar que su tiempo de vida se limitará a la petición actual, es decir, que debe ser liberada cuando la petición haya sido procesada; el framework detectará que implementa IDisposable e invocará su método Dispose() de forma automática.

Todo esto se consigue en Unity introduciendo en bootstrapper.cs la siguiente línea:
// File: bootstrapper.cs:
public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
        container.RegisterType<IAppServices, MyAppServices>(
            new HierarchicalLifetimeManager()
        );
        return container;
    }
}
Nota: si sois de los que preferís remangaros y hacer las cosas por vosotros mismos, os recomiendo que leáis este brutal post de Eduard donde trata sobre la inyección de dependencias y cómo conseguir que las instancias tengan un tiempo de vida per-request. Muy aconsejable.

Volviendo al código, observad que si en el futuro queremos sustituir en la aplicación la implementación de MyAppServices por otra cualquiera que implemente el interfaz IAppServices, sólo tendríamos que modificar el registro en el contenedor IoC. El controlador no se vería afectado de ninguna forma.

En este mismo punto incluiríamos todas las dependencias necesarias para que puedan construirse los objetos. Si, por ejemplo, MyAppServices depende a su vez de una clase que implementa IDataContext, debemos registrar también una asociación para dicho interfaz, de forma que el contenedor tenga toda la información necesaria para satisfacer las dependencias necesarias y construir el grafo de objetos completo.

En cualquier caso, una vez registradas todas las asociaciones en el método BuildUnityContainer(), sólo nos faltaría introducir una llamada a Bootstrapper.Initialize() en el método Application_Start() del global.asax, de forma que se ejecute durante la inicialización del sistema.

Además, dado que hemos indicado al contenedor que la instancia creada debe ser liberada al finalizar la petición, su método Dispose() será ejecutado automáticamente, por lo que ya podemos eliminar del controlador la implementación de Dispose(), desde donde antes realizábamos esta operación de forma manual.

Y hechos estos dos últimos ajustes, podemos decir que hemos terminado :-)

6. Resumiendo

Como podemos ver a continuación, hemos conseguido que nuestro controlador quede bastante limpio y testeable, y sus acciones muy concisas y centradas en sus objetivos funcionales. Además, su constructor deja clarísimas las dependencias del mismo, y se mantiene un total desacoplado de las clases del modelo utilizadas:
public class ProductsController : Controller
{
    private IAppServices _services;

    public ProductsController(IAppServices services)
    {
        _services = services;
    }

    public ActionResult Index()
    {
        var data = _services.GetAllProducts();
        return View(data);
    }

    public ActionResult Category(int categoryId)
    {
        var data = _services.GetProductsByCategory(categoryId);
        return View(data);
    }
}
Hemos eliminado también el código de liberación de dependencias, y hemos delegado al contenedor la instanciación, a veces compleja, de todos los componentes usados.

Aunque al hacerlo paso a paso el post ha quedado un poco extenso y podría llegar a parecer complejo, nada más lejos de la realidad. Lo único que tenemos que hacer y tener en cuenta para conseguir este tipo de controladores es, a modo de resumen:
  • Detectar cuáles son los objetos de los que depende nuestro controlador, es decir, determinar las dependencias que vamos a eliminar.
  • Preparar el constructor para recibir las dependencias, siempre en forma de interfaces, y almacenarlas en miembros privados.
  • Desde las acciones, usar los componentes externos a través los miembros privados en los que los hemos almacenado en el constructor.
  • Instalar un contenedor IoC y registrar en él las asociaciones entre las interfaces y clases, con objeto de que los controladores puedan ser instanciados automáticamente, siempre teniendo en cuenta la gestión del tiempo de vida de los objetos.
  • Si las dependencias así lo requieren, implementar en ellas el interfaz IDisposable, de forma que el container se encargue de liberar sus recursos al finalizar el proceso de la petición.
Podéis descargar el proyecto que hemos implementado en este post desde mi Skydrive.

Espero que os sea útil, y los que todavía no habéis dado el salto a este tipo de diseño os animéis a probarlo. Os aseguro que no os vais a arrepentir :-)

Publicado en Variable not found.

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

18 Comentarios:

Juan Pablo Párraga Cubells dijo...

Muy, muy interesante y didáctico. Muchas gracias

chkduke dijo...

Muy buen post, me ha parecido que esta muy bien explicado y resulta muy comprensible todo el tema de desacoplamiento, IoC y contenedores, incluso para usarlo en cualquier otro tipo de desarrollo que no sea MVC.

JoseTeques dijo...

Excelente post! Creo que es una de las mejores explicaciones en castellano que he encontrado sobre la inyeccion de dependencias y con el plus de que muestra paso a paso el como implementarla. Felicitaciones y gracias por contribuir con contenido de tanta calidad.

José M. Aguilar dijo...

Muchas gracias! :-)

Carlos Díez dijo...

Como siempre, muy buen post. Aplicable 100x100 a los proyectos reales. Gracias!!!

Javier dijo...

Un artículo buenísimo. El mejor ejemplo que he visto sobre cómo escribir el código para evitar las dependencias y sobre cómo usar los contenedores.

Está explicado de una forma tan sencilla y concisa que a pesar de conocer perfectamente todo lo que has expuesto he optado por guardarlo en mi ordenador para que forme parte de mis artículos de referencia.

José M. Aguilar dijo...

Uuf, me vais a subir los colores ;)

Muchas gracias por vuestros comentarios!

Manuel Rodríguez Pérez dijo...

Excelente articulo.

Anónimo dijo...

Hola, excelente artículo, me parace que dada la "muy buena" explicación valío la pena que fuera tan largo. Gracias!

Anton dijo...

Muy buen articulo, conciso y didactico, hace que se entienda facil el concepto.
Gracias!

MELEK dijo...

Excelente post y todo para poner en practica en mis nuevos proyectos

Anónimo dijo...

Gracias! La mejor explicación en español que he encontrado para ioc en asp mvc.

Te añado a mis favoritos ;)

Jaume dijo...

Hola JM, Soy Jaume González, me conoces a través de uno de tus clientes de Barcelona, aunque quizás ahora no caigas.

Hoy he estudidado este tema en profundidad, el caso es que yo entendia el concepto de DI pero no de IOC, he tenido dos problemas:

Todas mis controladoras heredan de una controlador base, y según parece Unity llama a los constructores de las controladoras que tienen por parámetro la interfaz, pero no al constructor de la controladora base, por lo tanto en este escenario no sé como aplicarlo para la controladora base.

Después he estado intentando aplicar IoC con Unity a otras clases (no controladoras), hasta que he caido que, segun creo, unity solo instancia controladoras, por tanto, o busco otro contenedor IoC, o utilizo el Dependency Resolver, ¿Correcto? ¿Qué opción me recomiendas?

Gracias y saludos

Jaume dijo...

Solución a los problemas anteriores:

Con esto, utilizo el concepto IoC fuera de los controladores, aunque supongo que estoy reinventando la rueda.

public static class FactoryObjects_InterfaceX
{
public static InterfaceX GetObject(string ObjectName)
{
switch (ObjectName){
case "ClaseX":
return new ClaseX();
default:
break;
}

return null;
}
}

Por lo que veo Unity aplica IoC pero solo en el contexto de las controladoras, Dependency Resolver también es solo para controladoras.
Automapper se utiliza en otro contexto diferente (Reflexión, DTO -> Model, etc..), así que supongo que los otros que citas quizás se pueden utilizar para el contexto que comento.

Lo de reinventar la rueda ya sé que no está bien, pero sirve aveces cómo ejercicio didáctico para asimilar conceptos.

Jaume dijo...

Hola de nuevo,
He echado un vistazo a un artículo sobre Ninject y parece que se ajusta a lo que necesitaría, aunque con el ejemplo que he pegado antes ya me vale.

José M. Aguilar dijo...

Hola, Jaume! Claro que sé quién eres :)

Unity permite hacer todo eso que quieres, no hay necesidad de reinventar la rueda (salvo por aprender o divertirse ;). De hecho, el ejemplo que planteas es una implementación "artesana" de service locator, que es un patrón implementado por todos los contenedores IoC.

Por supuesto, puedes usar Unity (o Ninject o el que quieras) en todo tipo de componentes. Todos los conceptos tratados en este post son válidos.

Y en cuanto a la ejecución de constructores, no sé si he llegado a comprender el problema, pero hasta lo que he entendido, creo que es normal: Unity te instanciará la clase que le hayas indicado, eres tú el responsable de llamar al constructor base desde el constructor de la clase hija (el controller, en este caso). Pero eso no es algo que tenga que ver con Unity, es lo normal cuando usamos herencia y queremos asegurar que se ejecuta código constructor de las clases de las que heredamos.

Saludos.





Jaume dijo...

rápida contestación, gracias!!

respecto, a usarlo para clases del modelo y no para controladoras, lo he intentado sin éxito, algo habré hecho mal, al definir la relación Interfaz/Objeto desde unity me instancia automáticamente la clase del controlador, pero no la del modelo, y lo hago igual. En cualquier caso ya lo volveré a intentar, con mi clase "artesana" ya me vale de momento, siempre peco de reinventar cosas, no obstante creo que muchas cosas que sé, las sé gracias a ese pecado.

Respecto a la aplicación en la herencia, ya te he entendido, pero es un rollo tener que crear un constructor en todas las subclases para llamar a la clase padre..., bueno no te molestes, quizás en un futuro en alguno de los cursos que nos haces lo veamos "in situ"

Otra cosa, he rellenado el formulario de solicitud de colaboración para artículos en el blog, ¿no te ha llegado?. Saludos!!

José M. Aguilar dijo...

Precisamente te estoy escribiendo un mail justo en este momento :)