Reputation: 13440
We've been using StructureMap for Dependency Injection in our ASP.Net MvC 3 web apps with C#, but today I'm unable to inject a needed type into a C# CustomResolver I've built.
Here is the code in our StructureMapInitialization.cs file:
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;
}
}
}
And here is a snippet of the code from our AutoMapperProfile.cs file:
Mapper.CreateMap<AbstractOrganization, DashboardDetails>()
.ForMember(dashboard => dashboard.AlertsDictionary,
member => member.ResolveUsing<OrganizationAlertResolver>()
.ConstructedBy(() => new OrganizationAlertResolver(
ObjectFactory.GetInstance<ICustomerRepository>(), ObjectFactory.GetInstance<IEnumerable<IAlertGenerator<Customer>>>())));
And here is my CustomResolver code:
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;
}
}
}
So, I'm trying to use StructureMap to inject the IEnumerable of IAlertGenerator of type Customer into my CustomResolver, but I get a StructureMap 202 Exception saying that there was no default instance of that type found, even though I created the instance of it in the last entry in the StructureMap initialization file.
Here is a copy of the error message I'm getting when I run it:
StructureMap Exception Code: 202 No Default Instance defined for PluginFamily System.Collections.Generic.IEnumerable
1[[Core.Domain.Alerts.IAlertGenerator
1[[Core.Domain.Model.Customer, Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Can anyone help with suggestions on how to fix this problem?
Upvotes: 2
Views: 3409
Reputation: 26504
In addition to what Mike has pointed out this issue can be caused by multiple instances closing the type. Based on your code:
ObjectFactory.GetInstance<IEnumerable<IAlertGenerator<Customer>>>()
I'm guessing that is what is happening.
It should be as simple as changing the above to:
ObjectFactory.GetAllInstances<IAlertGenerator<Customer>>()
which will find all instances which close IAlertGenerator<Customer>
.
Upvotes: 2
Reputation: 67898
I'm not 100% certain what's going on here but I've seen two different issues in StructureMap when getting this error. The first is that the class being instantiated needs a parameterless constructor, so Customer
may not have one.
The second is that even though a parameterless constructor exists, StructureMap tries to use the most fully-qualified constructor, and I've seen that with classes like SqlConnection
. Below is an example of how to work around that.
x.ForRequestedType<IDbConnection>()
.CacheBy(InstanceScope.Singleton)
.TheDefault.Is.ConstructedBy(ctor => new SqlConnection("connection string"));
Note that I had to use the .TheDefault.Is.ConstructedBy
construct to get it to use the right constructor. Before resorting to this I had tried to just pass the parameter using the .Ctor
construct but just couldn't get it to work.
I hope this helps point you in the right direction.
Upvotes: 0