c# asp.net-mvc generics dependency-injection structuremap

c# - ¿Cómo uso StructureMap con tipos genéricos no cerrados usando Scan con un constructor "codicioso"



asp.net-mvc generics (2)

Entre varias preguntas de desbordamiento de pila y publicaciones de blog hay una cantidad bastante razonable de documentación sobre el tema de genéricos abiertos y StructureMap. Desafortunadamente, me falta algo, ya que mis intentos de utilizar el scan para realizar la configuración junto con una implementación de clase que tiene un constructor "codicioso" aún funcionan.

Quiero que StructureMap capte una instancia de la clase inferior mediante referencias a su interfaz implementada. ToCsvService existe en un ensamblaje sin referencia llamado Infraestructura. IToCsvService existe en un conjunto referenciado llamado Core. Como puede ver, ToCsvService tiene un constructor "codicioso".

public class ToCsvService<TSource> : IToCsvService<TSource> { public ToCsvService(ICollection<TSource> collection) { } }

ToCsvService que StructureMap sepa sobre ToCsvService través del método ConnectImplementationsToTypesClosing .

ObjectFactory.Initialize(cfg => { cfg.Scan(scan => { scan.Assembly("Infrastructure"); scan.WithDefaultConventions(); // even with this call StructureMap cannot use ToCsvService // instance of IToCsvService (though wouldn''t expect it to) scan.ConnectImplementationsToTypesClosing (typeof(IToCsvService<>)); }); });

Desde el método ObjectFactory.WhatDoIHave() , parece que StructureMap conoce ToCsvService .

PluginType Name Description ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ IToCsvService`1 (IToCsvService`1) Scoped as: Transient 6202a7ee-89a4-4edd-831d-4867b7dd1a7e Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Sin embargo, cuando especifico IToCsvService<CustomerViewModel> en un constructor de Controller arroja la excepción

Código de excepción de StructureMap: 202 No se definió ninguna instancia predeterminada para PluginFamily Core.Services.IToCsvService`1 [[UI.Models.MachineForm, UI, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]], Core, Version = 1.0. 0.0, Culture = neutral, PublicKeyToken = null

Imagino que esto es porque StructureMap no tiene idea de qué entregar al constructor de ToCsvService "codicioso". ¿Hay algún modo en que pueda hacer que StructureMap sea capaz de jugar bien con este constructor? ¿Debo cambiar de un constructor y simplemente establecer la propiedad de recopilación después de la creación de instancias?

La pregunta StructureMap y los tipos genéricos detallan algo que estoy tratando de hacer, pero no utiliza un escaneo para hacerlo. La answer proporcionada por Joshua Flanagan utiliza la configuración For(x).Use(y) , que podría funcionar si no estuviera escaneando el ensamblado porque no tengo una referencia ToCsvService .

Editar

Quería ver si usar un mecanismo diferente para permitir que StructureMap identifique las instancias de ToCsvService<> tendría un efecto. Cambia lo que se informa en ObjectFactory.WhatDoIHave() y arroja una excepción diferente. Aquí hay un ejemplo de AddAllTypesOf usar AddAllTypesOf .

ObjectFactory.Initialize(cfg => { cfg.Scan(scan => { scan.Assembly("Infrastructure"); scan.WithDefaultConventions(); scan.AddAllTypesOf(typeof(IToCsvService<>)); }); });

Después de usar lo anterior, el volcado de ObjectFactory.WhatDoIHave() es

PluginType Name Description -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- IToCsvService`1 (IToCsvService`1) Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Scoped as: Transient Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- IToCsvService`1 (IToCsvService`1) Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Scoped as: Transient Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Con esta configuración arrojo esta excepción:

Código de excepción de StructureMap: 202 Ninguna instancia predeterminada definida para PluginFamily System.Collections.Generic.ICollection`1 [[UI.Models.MachineForm, UI, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]], mscorlib, Version = 4.0.0.0, Cultura = neutral, PublicKeyToken = b77a5c561934e089

Para mí, la excepción indica que StructureMap sabe que necesita un ICollection<MachineForm> para crear instancias de ToCsvService pero no sabe de dónde obtenerlo. Lo cual va al comentario de Jimmy''s de abajo sobre el uso de StructureMap y la inyección de setter Constructor . Sin embargo, esto no parece posible sin agregar una referencia explícita al ensamblaje de Infraestructura.

Preguntas sobre Desbordamiento de pila algo relacionadas en StructureMap y Generics

  • StructureMap y tipos genéricos
  • ¿Inyección de setter StructureMap en tipo genérico abierto?
  • StructureMap Registro automático para tipos genéricos usando Scan

Publicaciones de blogs relacionadas con StructureMap y genéricos


¿Hay implementaciones concretas de IToCsvService? ¿O solo el tipo abierto ToCsvService?

ConnectImplementationsToTypesClosing es para conectar algo como un CustomerViewModelToCsvService concreto a IToCsvService <>. Si desea conectar clases abiertas para abrir interfaces, necesitará:

For(typeof(IToCsvService<>)).Use(typeof(ToCsvService<>));

Aquí estoy conectando el tipo de interfaz abierta al tipo de clase abierta.


De hecho, en la versión actual debería ser muy simple. Todo lo que tiene que hacer es proporcionar el argumento cuando llame para obtener una nueva instancia del objeto. Para hacer esto, usa el método "Con" en el objectfactory.

Esto le permite usar el constructor codicioso. Sin embargo, también significa que debe saber que necesita la colección en este ejemplo. Por lo tanto, no es el método óptimo para inyectar el estado.

var newObject = ObjectFactory.With<ICollection<CustomerViewModel>>(SomeCollection) .GetInstance<IToCsvService<CustomerViewModel>>();