Инъекция зависимостей C# с StructureMap

Мы использовали StructureMap для внедрения зависимостей в наших веб-приложениях ASP.Net MvC 3 с C#, но сегодня я не могу внедрить необходимый тип в созданный C# CustomResolver.

Вот код в нашем файле StructureMapInitialization.cs:

namespace UI.DependencyResolution
{
/// <summary>
/// Class Structure Map IOC intialization
/// </summary>
public static class StructureMapIocInitialization
{
    /// <summary>
    /// Initialize Method for Structure Map IOC Initialization
    /// </summary>
    /// <returns>an IContainer for Services and Repository</returns>
    public static IContainer Initialize()
    {
        ObjectFactory.Initialize(cfg =>
        {
            cfg.Scan(scan =>
            {
                scan.Assembly("Infrastructure");
                scan.Assembly("Core");
                scan.WithDefaultConventions();
                scan.ConnectImplementationsToTypesClosing(typeof(IAlertGenerator<>));
                scan.ConnectImplementationsToTypesClosing(typeof(IValidationRule<>));
            });

            cfg.For<IFilterProvider>().Use<StructureMapFilterProvider>();
            cfg.For<IControllerActivator>().Use<StructureMapControllerActivator>();

            cfg.SetAllProperties(c =>
            {
                c.WithAnyTypeFromNamespaceContainingType<ICustomerRepository>();
                c.WithAnyTypeFromNamespaceContainingType<IMachineRepository>();
                c.WithAnyTypeFromNamespaceContainingType<ICurrentUserService>();
                c.WithAnyTypeFromNamespaceContainingType<ICircuitRegistrationRepository>();
                c.WithAnyTypeFromNamespaceContainingType<IWorkflowRequestInformationRepository>();
                c.WithAnyTypeFromNamespaceContainingType<IEnumerable<IAlertGenerator<Customer>>>();

            });

        });

        return ObjectFactory.Container;
    }
}

}

А вот фрагмент кода из нашего файла AutoMapperProfile.cs:

Mapper.CreateMap<AbstractOrganization, DashboardDetails>()
    .ForMember(dashboard => dashboard.AlertsDictionary,
    member => member.ResolveUsing<OrganizationAlertResolver>()
    .ConstructedBy(() => new OrganizationAlertResolver(
        ObjectFactory.GetInstance<ICustomerRepository>(), ObjectFactory.GetInstance<IEnumerable<IAlertGenerator<Customer>>>())));

А вот мой код CustomResolver:

namespace UI.Models.CustomResolvers
{
    public class OrganizationAlertResolver : ValueResolver<Organization, Dictionary<string,   string>>
    {
        private readonly ICustomerRepository _customerRepository;

        /// <summary>
        /// Storage for customer alert generator.
        /// </summary>
        private readonly IEnumerable<IAlertGenerator<Customer>> _customerAlertGenerators;


        public OrganizationAlertResolver(ICustomerRepository customerRepository, 
            IEnumerable<IAlertGenerator<Customer>> customerAlertGenerators)
        {
            _customerRepository = customerRepository;
            _customerAlertGenerators = customerAlertGenerators;
        }

        protected override Dictionary<string,string> ResolveCore(Organization organization)
        {
            var customers = _customerRepository.GetActiveCustomersByOrgNumber(organization.OrgNumber);
            foreach (var generator in _customerAlertGenerators)
            {
                generator.PopulateAlerts(customers);
            }

        Dictionary<string, string> alertsDictionary = new Dictionary<string, string>();

            foreach (var customer in customers)
            {
                foreach (var alert in customer.Alerts)
                {
                    if(alertsDictionary.ContainsKey(alert.ToString()))
                    {
                        alertsDictionary[alert.ToString()] = alert.Message;
                    }
                    else
                    {
                        alertsDictionary.Add(alert.ToString(), alert.Message);
                    }
                }
            }
            return alertsDictionary;
        }
    }
}

Итак, я пытаюсь использовать StructureMap для вставки IEnumerable IAlertGenerator типа Customer в мой CustomResolver, но я получаю исключение StructureMap 202, в котором говорится, что не найдено ни одного экземпляра по умолчанию этого типа, хотя я создал его в последняя запись в файле инициализации StructureMap.

Вот копия сообщения об ошибке, которое я получаю при запуске:

Код исключения StructureMap: 202 Нет экземпляра по умолчанию, определенного для PluginFamily System.Collections.Generic.IEnumerable1[[Core.Domain.Alerts.IAlertGenerator1 [[Core.Domain.Model.Customer, Core, версия =1.0.0.0, культура = нейтральная, PublicKeyToken= ноль]], ядро, версия =1.0.0.0, культура = нейтральная, PublicKeyToken= ноль]], mscorlib, версия =4.0.0.0, Культура = нейтральная, PublicKeyToken=b77a5c561934e089

Может кто-нибудь помочь с предложениями о том, как решить эту проблему?

2 ответа

Решение

В дополнение к тому, на что указал Майк, эта проблема может быть вызвана несколькими экземплярами, закрывающими тип. На основании вашего кода:

ObjectFactory.GetInstance<IEnumerable<IAlertGenerator<Customer>>>()

Я предполагаю, что это то, что происходит.

Это должно быть так же просто, как изменить выше:

ObjectFactory.GetAllInstances<IAlertGenerator<Customer>>()

который найдет все экземпляры, которые закрываются IAlertGenerator<Customer>,

Я не уверен на 100%, что здесь происходит, но я видел две разные проблемы в StructureMap при получении этой ошибки. Во-первых, для экземпляра класса требуется конструктор без параметров, поэтому Customer может не иметь.

Во-вторых, несмотря на то, что существует конструктор без параметров, StructureMap пытается использовать наиболее квалифицированный конструктор, и я видел это с такими классами, как SqlConnection, Ниже приведен пример того, как обойти это.

x.ForRequestedType<IDbConnection>()
    .CacheBy(InstanceScope.Singleton)
    .TheDefault.Is.ConstructedBy(ctor => new SqlConnection("connection string"));

Обратите внимание, что я должен был использовать .TheDefault.Is.ConstructedBy построить, чтобы заставить его использовать правильный конструктор. Прежде чем прибегнуть к этому, я попытался просто передать параметр, используя .Ctor построить, но просто не мог заставить его работать.

Я надеюсь, что это поможет вам в правильном направлении.

Другие вопросы по тегам