Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No default Instance is registered and cannot be automatically determined for type

The definition of my interface is as follows:

public interface IApplicationSettings
{
   string LoggerName { get; }
   string NumberOfResultsPerPage { get; }
   string EmailAddress { get; }
   string Credential { get; }
}

The implementation of this interface is given below:

public class WebConfigApplicationSettings : IApplicationSettings
    {
        public string LoggerName
        {
            get { return ConfigurationManager.AppSettings["LoggerName"]; }
        }

        public string NumberOfResultsPerPage
        {
            get { return ConfigurationManager.AppSettings["NumberOfResultsPerPage"]; }
        }

        public string EmailAddress
        {
            get { return ConfigurationManager.AppSettings["EmailAddress"]; }
        }

        public string Credential
        {
            get { return ConfigurationManager.AppSettings["Credential"]; }
        }
    }

I also created a factory class to obtain the instance of the concrete implementation of WebConfigSettings as follows:

public class ApplicationSettingsFactory
    {
        private static IApplicationSettings _applicationSettings;

        public static void InitializeApplicationSettingsFactory(
                                      IApplicationSettings applicationSettings)
        {
            _applicationSettings = applicationSettings;
        }

        public static IApplicationSettings GetApplicationSettings()
        {
            return _applicationSettings;
        }
    }

Then I resolved dependency as follows:

public class DefaultRegistry : Registry {

        public DefaultRegistry() {
            Scan(
                scan => {
                    scan.TheCallingAssembly();
                    scan.WithDefaultConventions();
                    scan.With(new ControllerConvention());
                });


             For<IApplicationSettings>().Use<WebConfigApplicationSettings>();

             ApplicationSettingsFactory.InitializeApplicationSettingsFactory
                                   (ObjectFactory.GetInstance<IApplicationSettings>());

        }
    }

Now when i running my application it throw me following exception:

Exception has been thrown by the target of an invocation.

and the Inner Exception is

No default Instance is registered and cannot be automatically determined for type 'Shoppingcart.Infrastructure.Configuration.IApplicationSettings'\r\n\r\nThere is no configuration specified for Shoppingcart.Infrastructure.Configuration.IApplicationSettings\r\n\r\n1.) Container.GetInstance(Shoppingcart.Infrastructure.Configuration.IApplicationSettings)\r\n

I am using StructureMap for MVC5

like image 479
Mojammel Haque Avatar asked Apr 10 '15 04:04

Mojammel Haque


2 Answers

The reason your code isn't working is because when you call ObjectFactory.GetInstance<IApplicationSettings>(), your registry hasn't been registered and thus, StructureMap's configuration is incomplete.

I believe what you're trying to do is the following (tested and works):

public class ApplicationSettingsFactory
{
    public ApplicationSettingsFactory(WebConfigApplicationSettings applicationSettings)
    {
        _applicationSettings = applicationSettings;
    }

    private static IApplicationSettings _applicationSettings;

    public IApplicationSettings GetApplicationSettings()
    {
        return _applicationSettings;
    }
}

With your registry configured like this:

public DefaultRegistry() {

    Scan(scan => {
         scan.TheCallingAssembly();
         scan.WithDefaultConventions();
         scan.With(new ControllerConvention());
    });

    this.For<IApplicationSettings>().Use(ctx => ctx.GetInstance<ApplicationSettingsFactory>().GetApplicationSettings());

}
like image 198
Joseph Woodward Avatar answered Oct 09 '22 04:10

Joseph Woodward


I can't really tell you why your registration fails in StructureMap, but if you allow me, I would like to feedback on your design.

Your design and code violates a few basic principles:

  1. You are violating the Interface Segregation Princple (ISP).

    The ISP describes that interfaces should be narrow (role interfaces) and should not contain more members than a consumer uses. You however defined an application wide IApplicationSettings interface and your intention is to inject into any consumer that needs some configuration settings. Changes are really slim however that there is a consumer that actually needs all settings. This forces the consumer to depend on all members, it makes the API more complex, while it just needs one.

  2. You are violating the Open/Closed Principle (OCP).

    The OCP describes that it should be possible to add new features without making changes to existing classes in the code base. You will however find yourself updating the IApplicationSettings interface and its implementations (you will probably have a fake/mock implementation as well) every time a new setting is added.

  3. Configuration values aren't read at startup, which makes it harder to verify the application's configuration.

    When a consumer makes a call to a property of your IApplicationSettings abstraction, you are forwarding the call to the ConfigurationManager.AppSettings. This means that if the value isn't available or incorrectly formatted, the application will fail at runtime. Since some of your configuration values will only be used in certain cases, this forces you to test every such case after you deployed the application to find out whether the system is configured correctly.

Solution

The solution to these problems is actually quite simple:

  1. Load configuration values at start-up.
  2. Inject configuration values directly into a component that needs that exact value.

Loading the configuration values directly at start-up, allows the application to fail fast in case of a configuration error, and prevents the configuration from being read over and over again needlessly.

Injecting configuration values directly into a component, prevents that component from having to depend on an ever-changing interface. It makes it really clear what a component is depending upon, and bakes this information in during application start-up.

This doesn't mean though that you can't use some sort of ApplicationSettings DTO. Such DTO is exactly what I use in my applications. This basically looks as follows:

public static Container Bootstrap() {
    return Bootstrap(new ApplicationSettings
    {
        LoggerName = ConfigurationManager.AppSettings["LoggerName"],
        NumberOfResultsPerPage = int.Parse(
            ConfigurationManager.AppSettings["NumberOfResultsPerPage"]),
        EmailAddress = new MailAddres(
            ConfigurationManager.AppSettings["EmailAddress"]),
        Credential = ConfigurationManager.AppSettings["Credential"],
    });
}

public static Container Bootstrap(ApplicationSettings settings) {
    var container = new Container();

    container.RegisterSingle<ILogger>(
        new SmtpLogger(settings.LoggerName, settings.EmailAddress));

    container.RegisterSingle<IPagingProvider>(
        new PagingProvider(settings.NumberOfResultsPerPage));

    // Etc

    return container;
}

In the code above you'll see that the creation of the ApplicationSettings DTO is split from the configuration of the container. This way I can test my DI configuration inside an integration test, where the start-up projects configuration file is not available.

Also note that I supply the configuration values directly to the constructors of components that require it.

You might be skeptic, because it might seem to pollute your DI configuration, because you have dozens of objects that require to be set with the same configuration value. For instance, your application might have dozens of repositories and each repository needs a connection string.

But my experience is that is you have many components that need the same configuration value; you are missing an abstraction. But don't create an IConnectionStringSettings class, because that would recreate the same problem again and in this case you aren't really making an abstraction. Instead, abstract the behavior that uses this configuration value! In the case of the connection string, create an IConnectionFactory or IDbContextFactory abstraction that allows creation of SqlConnection's or DbContext classes. This completely hides the fact that there is a connection string from any consumer, and allows them to call connectionFactory.CreateConnection() instead of having to fiddle around with the connection and the connection string.

My experience is that makes the application code much cleaner, and improves the verifiability of the application.

like image 26
Steven Avatar answered Oct 09 '22 05:10

Steven