Frage

Ich Konfiguration AutoMapper in dem Bootstrapper und ich rufe die Bootstrap() im Application_Start(), und ich habe gesagt, dass dies falsch ist, weil ich meine Bootstrapper Klasse jedes Mal, wenn ich eine neue Zuordnung hinzufügen muß, haben zu ändern, so dass ich bin das Open-geschlossen-Prinzip zu verletzen.

Wie denken Sie, ich verletzen wirklich dieses Prinzip?

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>();
    }    
}
War es hilfreich?

Lösung

Ich würde behaupten, dass Sie zwei Prinzipien verletzen. Das einzige Verantwortung Prinzip (SRP) und das offene / geschlossene Prinzip (OCP)

Sie verletzen die SRP, da die Bootstrap-Klasse mehr als einen Grund haben zu ändern. Wenn Sie Modell ändern Bindung oder die Auto-Mapper-Konfiguration

Sie würden die OCP verletzen, wenn Sie zum Konfigurieren eines anderen Teilkomponente des Systems zusätzliche Bootstrap-Code hinzufügen waren.

Wie kann ich dies in der Regel handhaben ist, dass ich die folgende Schnittstelle zu definieren.

public interface IGlobalConfiguration
{
    void Configure();
}

Für jede Komponente im System, die Bootstrapping benötigt würde ich eine Klasse, die diese Schnittstelle implementiert.

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.
    }
}

Ich benutze Ninject die Abhängigkeiten zu injizieren. IConfiguration ist die zugrunde liegende Implementierung der statischen AutoMapper ModelBinderDictionary Klasse und ist das Objekt ModelBinders.Binder. Ich würde dann eine NinjectModule definieren, die die angegebene Assembly für jede Klasse scannen würde, der die IGlobalConfiguration-Schnittstelle implementiert und diese Klassen zu einem Verbund hinzuzufügen.

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);
    }
}

Ich würde dann den folgenden Code in die Datei Global.asax hinzufügen.

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

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

Nun mein Bootstrap Code haftet sowohl auf SRP und OCP. Ich kann leicht zusätzlichen Bootstrap Code hinzufügen, indem Sie eine Klasse erstellen, die die IGlobalConfiguration Schnittstelle und meine globalen Konfigurationsklassen implementiert nur einen Grund habe zu ändern.

Andere Tipps

Um es zu haben vollständig geschlossen ist, eine statische Initialisierer pro Mapping Registrierung haben könnte, aber das wäre übertrieben.

Einige Dinge tatsächlich nützlich sind aus der Sicht zu einem gewissen Grad zentralisierte in der Lage zu sein, Reverse Engineering though.

In ninject gibt es die Vorstellung, einen Module pro Projekt oder Subsystem (Satz von Projekten) zu haben, die einen vernünftigen Kompromiss zu sein scheint.

Ich weiß, das ist eine alte, aber Sie könnten daran interessiert zu wissen, dass ich eine Open-Source-Bibliothek erstellt haben genannt Bootstrapper , die genau mit diesem Thema beschäftigt. Vielleicht möchten Sie es heraus überprüfen. Um zu vermeiden, das OC-Prinzip zu brechen Sie benötigen, um Ihre Mapper in getrennten Klassen zu definieren, die IMapCreater implementieren. Boostrapper werden diese Klassen mit Reflexion finden und wird alle Mapper beim Start initialisieren

Wenn etwas sein das einzige Prinzip Verantwortung, dass Sie verletzt wird, dass die Klasse mehr als einen Grund hat zu ändern.

Ich persönlich würde eine ConfigureAutoMapper Klasse hat, die alles meine Konfiguration für AutoMapper mit getan wurde. Aber es könnte argumentiert werden, dass es die persönliche Wahl.

Omu, ringe mich mit ähnlichen Fragen, wenn es in meinem App-Startroutine zu Bootstrapping einen IoC-Container kommt. Für IoC, die Führung Ich habe Punkte zum Vorteil der Zentralisierung der Konfiguration gegeben, anstatt alles über Ihre App Beregnung, wenn Sie Änderungen hinzuzufügen. Für die Konfiguration AutoMapper, ich denke, der Vorteil der Zentralisierung ist viel weniger wichtig. Wenn Sie Ihren AutoMapper Behälter in Ihrem IoC-Container oder Service Locator zu bekommen, bin ich mit Ruben Bartelink Vorschlag die Zuordnungen der Konfiguration einmal pro Baugruppe oder in statischen Konstruktoren oder dezentral etwas.

Im Grunde genommen, ich sehe es als eine Frage der Entscheidung, ob Sie die Bootstrapping oder dezentralisieren es zentralisieren möchten. Wenn Sie das besorgt über das Öffnen / Geschlossen-Prinzip auf dem Startroutine sind, geht mit ihm zu dezentralisieren. Aber Ihre Einhaltung OCP kann im Austausch für den Wert aller Ihrem Bootstrapping an einem Ort durchgeführt wird gewählt unten. Eine andere Möglichkeit wäre die Bootstrap-Scan bestimmte Baugruppen für Register haben sein, vorausgesetzt, AutoMapper ein solches Konzept hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top