Pergunta

Estou configurando AutoMapper na Bootstrapper e eu chamo o Bootstrap() na Application_Start(), e eu tenho dito que isso é errado porque eu tenho que modificar minha classe Bootstrapper cada vez que eu tenho que adicionar um novo mapeamento, por isso estou violar o Princípio Open-Closed.

Como você acha, que eu realmente violar este princípio?

public static class Bootstrapper
{
    public static void BootStrap()
    {
        ModelBinders.Binders.DefaultBinder = new MyModelBinder();
        InputBuilder.BootStrap();
        ConfigureAutoMapper();
    }

    public static void ConfigureAutoMapper()
    {
        Mapper.CreateMap<User, UserDisplay>()
            .ForMember(o => o.UserRolesDescription,
                       opt => opt.ResolveUsing<RoleValueResolver>());
        Mapper.CreateMap<Organisation, OrganisationDisplay>();
        Mapper.CreateMap<Organisation, OrganisationOpenDisplay>();
        Mapper.CreateMap<OrganisationAddress, OrganisationAddressDisplay>();
    }    
}
Foi útil?

Solução

Eu diria que você está violando dois princípios:. Princípio da responsabilidade única (SRP) eo princípio aberto / fechado (OCP)

Você está violando a SRP porque a classe bootstrapping ter mais do que uma razão para a mudança:. Se você modelo alter vinculativa ou a configuração automática mapeador

Você seria violar a OCP se você fosse para adicionar código de inicialização adicionais para configurar uma outra sub-componente do sistema.

Como eu costumo lidar com isso é que eu defina o seguinte interface.

public interface IGlobalConfiguration
{
    void Configure();
}

Para cada componente do sistema que as necessidades bootstrapping eu iria criar uma classe que implementa essa interface.

public class AutoMapperGlobalConfiguration : IGlobalConfiguration
{
    private readonly IConfiguration configuration;

    public AutoMapperGlobalConfiguration(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void Configure()
    {
        // Add AutoMapper configuration here.
    }
}

public class ModelBindersGlobalConfiguration : IGlobalConfiguration
{
    private readonly ModelBinderDictionary binders;

    public ModelBindersGlobalConfiguration(ModelBinderDictionary binders)
    {
        this.binders = binders;
    }

    public void Configure()
    {
        // Add model binding configuration here.
    }
}

Eu uso Ninject para injetar as dependências. IConfiguration é a implementação subjacente da classe AutoMapper estática e ModelBinderDictionary é o objeto ModelBinders.Binder. Eu, então, definir uma NinjectModule que digitalizar o especificado montagem para qualquer classe que implementa a interface IGlobalConfiguration e adicionar essas classes a um compósito.

public class GlobalConfigurationModule : NinjectModule
{
    private readonly Assembly assembly;

    public GlobalConfigurationModule() 
        : this(Assembly.GetExecutingAssembly()) { }

    public GlobalConfigurationModule(Assembly assembly)
    {
        this.assembly = assembly;
    }

    public override void Load()
    {
        GlobalConfigurationComposite composite = 
            new GlobalConfigurationComposite();

        IEnumerable<Type> types = 
            assembly.GetExportedTypes().GetTypeOf<IGlobalConfiguration>()
                .SkipAnyTypeOf<IComposite<IGlobalConfiguration>>();

        foreach (var type in types)
        {
            IGlobalConfiguration configuration = 
                (IGlobalConfiguration)Kernel.Get(type);
            composite.Add(configuration);
        }

        Bind<IGlobalConfiguration>().ToConstant(composite);
    }
}

Eu, então, adicione o seguinte código para o arquivo global.

public class MvcApplication : HttpApplication
{
    public void Application_Start()
    {
        IKernel kernel = new StandardKernel(
            new AutoMapperModule(),
            new MvcModule(),
            new GlobalConfigurationModule()
        );

        Kernel.Get<IGlobalConfiguration>().Configure();
    }
}

Agora meus bootstrapping adere Código, tanto SRP e OCP. Posso facilmente adicionar código de inicialização adicional, criando uma classe que implementa a interface IGlobalConfiguration e minhas aulas de configuração global só tem uma razão para a mudança.

Outras dicas

Para tê-lo completamente fechado, você poderia ter um estático initializer por inscrição Mapping, mas isso seria um exagero.

Algumas coisas são realmente útil ter centralizado a um grau a partir do ponto de vista de ser capaz de fazer engenharia reversa embora.

Em ninject, há a noção de ter um Module per ou subsistema do projeto (conjunto de projectos), que parece um compromisso razoável.

Eu sei que este é um velho, mas você pode estar interessado em saber que eu criei uma biblioteca de código aberto chamado Bootstrapper que lida precisamente com esta questão. Você pode querer dar uma olhada. Para evitar a quebra do princípio da OC você precisa definir seus mapeadores em classes separadas que implementam IMapCreater. Boostrapper vai encontrar essas classes usando reflexão e irá inicializar todos os mapeadores na inicialização

Se alguma coisa o seu o princípio da responsabilidade única que está a violar, em que a classe tem mais de uma razão para a mudança.

Eu, pessoalmente, teria uma classe ConfigureAutoMapper que toda a minha configuração para AutoMapper foi feito com. Mas pode-se argumentar que é a escolha pessoal.

Omu, eu lutar com perguntas semelhantes quando se trata de bootstrapping um contêiner IoC na rotina de inicialização do meu aplicativo. Para IoC, a orientação que recebi aponta para a vantagem de centralizar sua configuração ao invés de aspersão-lo em todo o seu aplicativo como você adicionar mudanças. Para configurar AutoMapper, eu acho que a vantagem de centralização é muito menos importante. Se você pode obter o seu recipiente AutoMapper em seu contêiner IoC ou serviço Locator, Concordo com a sugestão de configurar os mapeamentos de uma vez por montagem ou em construtores estáticos ou algo descentralizadas de Ruben Bartelink.

Basicamente, eu vejo isso como uma questão de decidir se deseja centralizar a bootstrapping ou descentralizar-lo. Se você está tão preocupado com o Princípio aberto / fechado em sua rotina de inicialização, vá com descentralizando-lo. Mas a sua adesão a OCP pode ser marcado para baixo em troca do valor de todas as suas bootstrapping feito em um só lugar. Outra opção seria a de ter o bootstrapper digitalização certos conjuntos para registros, assumindo AutoMapper tem como conceito a.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top