Как использовать StructureMap с открытыми незакрытыми типами, используя Scan с "жадным" конструктором
Между различными вопросами и сообщениями в блоге имеется довольно разумная документация по теме открытых дженериков и StructureMap. К сожалению, я должен упустить что-то, поскольку мои попытки использовать scan
для выполнения конфигурации вместе с реализацией класса, у которой есть "жадный" конструктор, еще не работают.
Я хочу, чтобы StructureMap захватил экземпляр класса ниже через ссылки на его реализованный интерфейс. ToCsvService
существует в unreferenced сборке под названием Infrastructure. IToCsvService
существует в ссылочной сборке под названием Core. Как вы видете
ToCsvService
имеет "жадный" конструктор.
public class ToCsvService<TSource> : IToCsvService<TSource>
{
public ToCsvService(ICollection<TSource> collection)
{
}
}
Я могу сообщить StructureMap о ToCsvService
с помощью метода 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<>));
});
});
Из метода ObjectFactory.WhatDoIHave()
кажется, что StructureMap знает 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
Однако, когда я указываю IToCsvService<CustomerViewModel>
в конструкторе контроллера, он генерирует исключение
Код исключения StructureMap: 202 Нет экземпляра по умолчанию, определенного для 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
Я предполагаю, что это потому, что StructureMap не имеет понятия, что передать "жадному" конструктору ToCsvService
. Есть ли что-то, что я могу сделать StructureMap способным хорошо играть с этим конструктором? Нужно ли мне переключаться с конструктора и просто устанавливать свойство коллекции после создания экземпляра?
Вопрос Structuremap и общие типы детализирует несколько, я пытаюсь сделать, но не использует сканирование для этого. В ответе , предоставленном Джошуа Фланаганом, используется конфигурация For(x).Use(y)
, которая может работать, если я не сканирую сборка, потому что у меня нет ссылки ToCsvService
.
Изменить
Я хотел посмотреть, будет ли использование другого механизма, позволяющего StructureMap идентифицировать экземпляры ToCsvService<>
. Он изменяет то, что сообщается в ObjectFactory.WhatDoIHave()
, и выдает другое исключение. Вот пример использования AddAllTypesOf
.
ObjectFactory.Initialize(cfg =>
{
cfg.Scan(scan =>
{
scan.Assembly("Infrastructure");
scan.WithDefaultConventions();
scan.AddAllTypesOf(typeof(IToCsvService<>));
});
});
После использования выше дамп из ObjectFactory.WhatDoIHave()
равен
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
В этой конфигурации я бросаю это исключение:
Код исключения StructureMap: 202 Нет экземпляра по умолчанию для 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, Culture = нейтральный, PublicKeyToken = b77a5c561934e089
Для меня исключение указывает, что StructureMap знает, что ему требуется ICollection<MachineForm>
для создания экземпляра ToCsvService
, но не знает, откуда его получить. Которая идет в комментарий Джимми от ниже об использовании StructureMap и Встраивание конструктора set. Однако это не представляется возможным без добавления явной ссылки на сборку инфраструктуры.
Несколько связанных вопросов в StructureMap и Generics
Сообщения в блогах, касающиеся StructureMap и Generics
Ответы
Ответ 1
Существуют ли какие-либо конкретные реализации IToCsvService? Или просто открытый тип ToCsvService?
ConnectImplementationsToTypesClosing предназначен для подключения чего-то вроде конкретного CustomerViewModelToCsvService к IToCsvService < > . Если вы хотите подключить открытые классы для открытия интерфейсов, вам понадобится:
For(typeof(IToCsvService<>)).Use(typeof(ToCsvService<>));
Здесь я подключаю открытый тип интерфейса к классу открытого класса.
Ответ 2
На самом деле в текущей версии это должно быть очень просто. Все, что вам нужно сделать, это предоставить аргумент, когда вы вызываете, чтобы получить новый экземпляр объекта. Для этого вы используете метод "С" на объекте.
Это позволяет использовать жадный конструктор. Однако это также означает, что вы должны знать, что вам нужна коллекция в этом примере. Таким образом, это не оптимальный метод инъекционного состояния.
var newObject = ObjectFactory.With<ICollection<CustomerViewModel>>(SomeCollection)
.GetInstance<IToCsvService<CustomerViewModel>>();