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>>();