Structuremap – Profiles

In the StrcutureMap concept, profiles are just named child containers. Because of existence of profiles in StructureMap is just to give configuration changing ability for development and testing environment registrations. Using profiles is giving you to resolving services in different ways in different application modes actually. Profiles also have registrations which are defined in container. Profile concept works like inheritance aspects of OOP. If some registrations are defined in current container, profiles created in current container also have these registrations and could give you to ability to override these defined registrations. To explain this concept, lets move on some examples.

Let’s imagine we have a service consuming some abilities from remote location. In testing scenarios, remote location are expected to be interchangeable. We do not want to connect real remote services in testing scenario sometimes. Especially if we want to test our business logic. In this case, we just want the IoC container to inject test remote service into business services.

Let’s start coding. I want to introduce with IServiceConfiguration interface which I want to use this for changing remote service location etc.

 
public interface IServiceConfiguration
{
    string ServiceURL { get; }
    int Port { get; }
    string Username { get; }
    string Password { get; }
}

Then, let’s define testing and production concrete service configurations like below;

 
public class TestServiceConfig : IServiceConfiguration
{
    public string ServiceURL { get; private set; }
    public int Port { get; private set; }
    public string Username { get; private set; }
    public string Password { get; private set; }

    public TestServiceConfig()
    {
        ServiceURL = "http://localhost/myApp/testService";
        Port = 1534;
        Username = "admin";
        Password = "admin";
    }
}

public class ProdServiceConfig : IServiceConfiguration
{
    public string ServiceURL { get; private set; }
    public int Port { get; private set; }
    public string Username { get; private set; }
    public string Password { get; private set; }

    public ProdServiceConfig()
    {
        ServiceURL = "http://services.mysystem.com/testService";
        Port = 1534;
        Username = "admin";
        Password = "prodPassword";
    }
}

Consumer service needs IServiceConfiguration to connect the remote service.

 
public interface IConsumerService
{
    IServiceConfiguration ServiceConfiguration { get; }
    void Consume();
}

public class SomeConsumerService : IConsumerService
{
    public IServiceConfiguration ServiceConfiguration { get; private set; }

    public SomeConsumerService(IServiceConfiguration serviceConfiguration)
    {
        ServiceConfiguration = serviceConfiguration;
    }

    public void Consume()
    {
        Console.WriteLine("I am consuming the service with the given configurations below:");
        Console.WriteLine("\tServiceURL: {0}", ServiceConfiguration.ServiceURL);
        Console.WriteLine("\tPort: {0}", ServiceConfiguration.Port);
        Console.WriteLine("\tUsername: {0}", ServiceConfiguration.Username);
        Console.WriteLine("\tPassword: {0}", ServiceConfiguration.Password);
    }
}

After defining all requirements of system, let’s define a container which has profiles having ability to change service configurations.

 
class Program
{
    static void Main(string[] args)
    {
        // for testing profile name
        string testing = "testing";

        // for prod profile name
        string prod = "prod";

        var container = new Container(_ =>
        {
            // this registration is common on all profiles declared below
            // because it is in the container level
            _.For<IConsumerService>().Use<SomeConsumerService>();

            _.Profile(testing, p =>
            {
                p.For<IServiceConfiguration>().Use<TestServiceConfig>();
            });

            _.Profile(prod, p =>
            {
                p.For<IServiceConfiguration>().Use<ProdServiceConfig>();
            });
        });

        var testProfile = container.GetProfile(testing);
        var testConsumer = testProfile.GetInstance<IConsumerService>();
        testConsumer.Consume();

        Console.WriteLine("------------------------------------------------------------------------");
        Console.WriteLine("------------------------------------------------------------------------");

        var prodProfile = container.GetProfile(prod);
        var prodConsumer = prodProfile.GetInstance<IConsumerService>();
        prodConsumer.Consume();
    }
}

In here, we don’t need to define registration for each profile which are already defined in container. I mean;

 
_.For<IConsumerService>().Use<SomeConsumerService>();

IConsumerService registration will be applied for all profiles in this container. But as you can see, we could also override registrations. In this example, we override the IServiceConfiguration registration for each profile. Let’s run the application and check the results

As you can see, we are able to change registrations using with StructureMap’s profile concept. See you next post.