Il presente articolo è stato tradotto automaticamente.

Modelli di esercitazione

Convenzione su configurazione

Jeremy Miller

Contenuto

Impatto di innovazione del linguaggio
Si supponga una sola volta e solo una sola volta
Impostazioni predefinite determinante
Convenzione tramite configurazione
Passaggi successivi

Sono sempre considerato sull'quanto tempo al progetto viene impiegato per i problemi principali e il tempo che trascorso wrestling con problemi tecnici esclusivamente? Alcuni potrebbe pronunciare che l'obiettivo più importante di tutte le nuove tecnologie di software e tecniche consiste nel ridurre la distanza tra intenzione dello sviluppatore del software e la realizzazione di tale tipo nel codice. E il settore continuamente ha generato il livello di astrazione consentono agli sviluppatori di dedicare più tempo funzionalità e meno infrastruttura di basso livello scrittura tempo, ma sono ancora lungo consente di accedere.

Considerare questo per un minuto. Se fosse necessario visualizzare il codice per i rappresentanti del business, presupponendo che fossero effettivamente disposti a leggere il codice con te, ovvero la quantità di codice sarebbe interessano? Tali business rappresentanti verrà probabilmente solo attenzione sul codice che esprime la funzionalità di business del sistema. Tale codice è l'essenza del sistema. Al contrario, probabilmente non presentano l'interesse slightest codice ad esempio le dichiarazioni di tipo, le impostazioni di configurazione blocchi try/catch e vincoli generici. Tale codice è l'infrastruttura o "Cerimonia", che è, lo sviluppatore necessario scorrere solo per il codice di spedizione.

In rate precedente di questo articolo È stato gran parte analizzate concetti fondamentali della progettazione e principi, più di cui sono stati parte della struttura di canon molto tempo. Questo tempo circa, si desidera esaminare alcune tecniche più recenti che è possibile adottare per ridurre la quantità di cerimonia nel codice. Alcuni dei concetti possono essere nuovi si ma ritiene che che tutto ciò sarà essere parte di .NET destinati in pochi anni.

Impatto di innovazione del linguaggio

Il primo fattore che vorrei considerare è la scelta di programmazione di lingua e alle modalità di utilizzo linguaggi di programmazione. Per illustrare l'impatto di un linguaggio di programmazione sull'importo della cerimonia nel codice, diamo un po'detour in pagine musty della cronologia.

Più indietro in questo decennio è stato creando un sistema di grandi dimensioni in Visual Basic 6.0. Ciascun metodo sarebbe simile illustrato nella Figura 1 . Ogni singolo bit di che il codice è cerimonia.

Figura 1 piedi nel cerimonia

Sub FileOperations()
    On Error Goto ErrorHandler

    Dim A as AType
    Dim B as AnotherType

    ' Put some code here

    Set A = Nothing
    Set B = Nothing
    ErrorHandler:
        Err.Raise Err.Number, _
            "FileOperations" & vbNewLine & Err.Source, _
            Err.Description, _
            Err.HelpFile, _
            Err.HelpContext
Exit Sub

Utilizzato una notevole quantità di standard in ogni metodo per creare un equivalente di un'analisi dello stack per il debug più semplice. Anche disponeva risolvere le variabili all'interno del metodo (un set = Nothing) per rilasciare gli oggetti. HO avuto uno standard rigoroso per revisioni del codice solo verificare che la pulitura di gestione e l'oggetto di errore è stata codificata correttamente in ogni metodo. Il codice effettivo, l'essenza di sistema, mobile in un punto qualsiasi all'interno di tutti i che cerimonia.

Memoria flash Avanti per oggi e contemporaneo linguaggi di programmazione quali C# o Visual Basic. NET. Oggi, la procedura di garbage collection eliminata la maggior parte della pulitura della memoria esplicita che hai utilizzato per l'immagine nella programmazione di Visual Basic 6.0. Analisi dello stack in eccezioni sono incorporate in Microsoft .NET Framework, in modo da a tale scopo per se stessi. Se si pensa tutto il codice rote standard che è stato eliminato quando passa a .NET Framework, è possibile dire che le lingue compatibile con .NET sono più produttivi e leggibile da Visual Basic 6.0 causa di questa limitazione nel codice cerimonia.

.NET Framework era un passaggio di grandi dimensioni, ma non terminato ancora l'evoluzione in lingue. Consideriamo che una proprietà semplice in C# implementata la modalità classica del prospetto:

public class ClassWithProperty {
  // Higher Ceremony
  private string _name;
  public string Name {
    get { return _name; }
    set { _name = value; }
  }
}

L'essenza di questo codice è semplicemente che la classe ClassWithProperty ha una proprietà di stringa denominata Name. Si veloce Avanti per C# 3.0 ed eseguire la stessa operazione con una proprietà automatica:

public class ClassWithProperty {
  // Lower Ceremony
  public string Name { get; set; }
}

Questo codice ha lo scopo di stesso esatto della proprietà di stile classico, ma è necessario notevolmente meno codice "del compilatore rumore".

In genere, tuttavia, gli sviluppatori di software non sono necessario controllare assoluto di linguaggi di programmazione. Mentre in modo definito, RITENGO che che è necessario sfruttare nuovo innovazioni linguaggio di programmazione o lingue anche alternative, è possibile parlare di idee di progettazione è possibile utilizzare oggi con destinati C# e Visual Basic.

Convalida al centro del dominio

.NET Framework rende quasi semplice aggiungere la convalida a livello di campo dichiarativo nell'interfaccia utente con strumenti quali i controlli di convalida ASP.NET. Gli stessi, ritengo che utile per posizionare la logica di convalida sulle classi del modello di dominio effettivo o almeno Chiudi per Servizi di dominio, per questi motivi:

  1. Logica di convalida è un problema di logica aziendale e preferisce che tutte le regole di business essere contenuta nelle classi di logica di business.
  2. Inserire la logica di convalida nel modello di dominio o Servizi di dominio disconnessi dall'interfaccia utente potenzialmente consente di ridurre la duplicazione attraverso le schermate e consente la stessa logica di convalida essere utilizzata nei servizi di interfaccia utente non (servizi Web, ad esempio) esposti dall'applicazione che informa volta e una sola volta, ancora più.
  3. È molto più semplice scrivere i test di unità e l'accettazione contro logica di convalida nel modello piuttosto che verificare tale stessa logica implementato come parte dell'interfaccia utente.

Si supponga una sola volta e solo una sola volta

Che cosa succede se si scopre midway tramite un progetto che qualcosa della definizione di un singolo campo dati deve essere modificata? In troppo numerosi casi, tale piccola modifica al database verrà ripple tramite l'applicazione quando si apporta una modifica analoga a varie parti di livello intermedio, codice di accesso ai dati e anche nel livello di interfaccia utente per adattare una singola logica modificare.

In un datore di lavoro precedenti, viene chiamato che rippling effetto da un campo dati piccoli cambia il Anti-Pattern il tunnel spaziale. Si desidera ottenere dalla necessità di una piccola modifica in un'unica fase teleported tutto attraverso i livelli. Possono rallentare l'effetto di tunnel spaziale riducendo livelli non necessari e che il primo passaggio. Il passaggio più difficile, ma più rewarding consiste nel trovare un modo per dire una volta e una sola volta.

I Say si volta e solo una volta modalità stati devono essere presente solo un'origine autorevole singola per qualsiasi dei fatti o di un criterio nel sistema stesso. Verranno eseguire l'esempio di generazione di un'applicazione Web con creazione, leggere, aggiornare ed eliminare funzionalità (CRUD). Questo tipo di sistema è la modifica e l'archiviazione dei campi dati rivestono gran parte importanza prioritaria. Questi campi devono essere modificati in schermate, convalida sul server, memorizzati nel database e probabilmente convalidato sul client per un'esperienza migliore, ma si desidera specificare che "in questo campo è obbligatorio e/o il campo deve essere più di 50 caratteri" nel codice una sola volta.

Esistono due diversi approcci che potrebbe richiedere. È Impossibile creare lo schema del database la definizione di schema e generare codice livello intermedio e presentazione utente dallo schema. È anche possibile definiscono i campi dei dati sorta di archiviazione di metadati esterne, ad esempio un file XML, quindi utilizzare generazione del codice per generare lo schema del database, gli oggetti di livello intermedio e le schermate di interfaccia utente. Personalmente, non sono una ventola di generazione di codice su larga scala, in modo che il team scelto un altro orientamento.

È in genere progettare le classi del modello di dominio prima e Microsoft considera la logica di convalida per la responsabilità delle classi di entità del modello di dominio. Per regole di convalida semplici, ad esempio campi obbligatori e le regole di lunghezza massima della stringa, è necessario decorare le proprietà con attributi di convalida ad esempio la classe indirizzo illustrata nella Figura 2 .

Nella figura 2 mediante attributi di convalida

public class Address : DomainEntity {
  [Required, MaximumStringLength(250)]
  public string Address1 { get; set; }

  [Required, MaximumStringLength(250)]
  public string City { get; set; }

  [Required]
  public string StateOrProvince { get; set; }

  [Required, MaximumStringLength(100)]
  public string Country { get; set; }

  [Required, MaximumStringLength(50)]
  public string PostalCode { get; set; }

  public string TimeZone { get; set; }
}

Utilizzo degli attributi è una tecnica semplice e piuttosto comune per specificare le regole di convalida. Inoltre sono in grado di dire che, poiché le regole di convalida sono espressi in modo dichiarativo invece implementata con codice imperativo, si hanno superato il test essenza rispetto a cerimonia.

A questo punto, tuttavia, è necessario replicare le regole per i campi obbligatori e lunghezza massima della stringa del database. Nel caso il team, è possibile utilizzare NHibernate per il meccanismo di persistenza. Una delle potenti funzionalità di NHibernate è per generare codice DDL (language) di dati definizione dai mapping NHibernate che potrà essere utilizzato per creare lo schema del database e mantenere sincronizzati con il modello di dominio (questa strategia ovviamente risulta più adatta nei nuovi progetti). Affinché questa strategia di generare il database dal modello di dominio sia utile, è stato necessario per noi aggiungere ulteriori informazioni per i mapping NHibernate per contrassegnare i campi non null e specificare la lunghezza di stringa.

È utilizzato il nuovo meccanismo NHibernate Fluent per definire il mapping di oggetto. Nel nostro codice di installazione NHibernate Fluent, viene definita convenzioni automatiche nel mapping insegnare NHibernate Fluent come gestire la presenza dell'[Required] e i [MaximumStringLength] attributi in classi il modello con il codice illustrato nella Figura 3 .

Nella Figura 3 Gestione degli attributi in NHibernate

public class MyPersistenceModel : PersistenceModel {
  public MyPersistenceModel() {
    // If a property is marked with the [Required]
    // attribute, make the corresponding column in
    // the database "NOT NULL"
    Conventions.ForAttribute<RequiredAttribute>((att, prop) => {
      if (prop.ParentIsRequired) {
        prop.SetAttribute("not-null", "true");
      }
    });

    // Uses the value from the [MaximumStringLength]
    // attribute on a property to set the length of 
    // a string column in the database
    Conventions.ForAttribute<MaximumStringLengthAttribute>((att, prop) => {
      prop.SetAttribute("length", att.Length.ToString());
    });
  }
}

Queste convenzioni ora verranno applicate a tutti i mapping nel progetto. Per la classe di indirizzo, verifica semplicemente NHibernate Fluent vengono mantenute le proprietà:

public class AddressMap : DomainMap<Address> {
  public AddressMap() {
    Map(a => a.Address1);
    Map(a => a.City);
    Map(a => a.TimeZone);
    Map(a => a.StateOrProvince);
    Map(a => a.Country);
    Map(a => a.PostalCode);
  }
}

Ora che È stato dedicare NHibernate Fluent sugli attributi di convalida, È possibile generare DDL per la tabella indirizzi (vedere la Figura 4 ). Si noti in SQL nella Figura 4 che la lunghezza di stringa corrisponde alla definizione dagli attributi nella classe indirizzo [MaximumStringLength]. Analogamente, il null/seguire dagli attributi [Required] non valori NULL della classe di indirizzo.

Nella figura 4 la generazione di codice DDL

CREATE TABLE [dbo].[Address](
  [id] [bigint] IDENTITY(1,1) NOT NULL,
  [StateOrProvince] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
  [Country] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
  [PostalCode] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
  [TimeZone] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
  [Address1] [nvarchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
  [Address2] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
  [City] [nvarchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
PRIMARY KEY CLUSTERED 
(
  [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

È stato investito alcuni dell'infrastruttura che deriva la struttura del database dagli attributi di convalida negli oggetti del modello di dominio di, ma è ancora dispone la questione di convalida sul lato client e l'aspetto di lato client. Vorremmo eseguire convalide semplice inpue all'interno del browser e contrassegnare gli elementi di campo obbligatorio in qualche modo per un'esperienza migliore.

La soluzione team arrivato a era quello di rendere il rendering di HTML di elementi di input tenere presenti gli attributi di convalida. (Per contesto, si utilizza il controller di visualizzazione del modello di ASP.NET, o un MVC, Framework Beta1 con il motore di Web Form come il motore di visualizzazione.) viene nella figura 5 illustrato l'il codice potrebbe aspetto di una visualizzazione di indirizzi nel nostro sistema.

Nella figura 5 indirizzo Visualizza tag

<div class="formlayout_body">
  <p><%= this.TextBoxFor(m => m.Address1).Width(300)%></p>
  <p><%= this.TextBoxFor(m => m.Address2).Width(300) %></p>
  <p>
    <%= this.TextBoxFor(m => m.City).Width(140) %>
    <%= this.DropDownListFor(m => 
        m.StateOrProvince).FillWith(m => m.StateOrProvinceList) %>
  </p>
  <p><%= this.TextBoxFor(m => m.PostalCode).Width(80) %></p>        
  <p><%= this.DropDownListFor(m => 
         m.Country).FillWith(m => m.CountryList) %></p>
  <p><%= this.DropDownListFor(m => 
         m.TimeZone).FillWith(m => m.DovetailTimeZoneList) %></p>
</div>

TextBoxFor e DropDownListFor sono poco gli helper HTML nella visualizzazione di base comune che vengono utilizzati per tutte le visualizzazioni nel nostro Architettura MVC. La firma di TextBoxFor è illustrata di seguito:

public static TextBoxExpression<TModel> TextBoxFor< TModel >(
  this IViewWithModel< TModel > viewPage, 
  Expression<Func< TModel, object>> expression)

  where TModel : class {
    return new TextBoxExpression< TModel >(
    viewPage.Model, expression);
  }

La cosa importante tenere presente in questo codice è che l'argomento di input è un'espressione (espressione < Func < TModel, oggetto >> per la precisione). Durante la costruzione il codice HTML effettivo per la casella di testo, la classe TextBoxExpression consente di:

  1. Analizzare l'espressione e trovare esattamente PropertyInfo stesso oggetto per la proprietà associata.
  2. Consente di interrogare che PropertyInfo per verificare l'esistenza degli attributi di convalida.
  3. Il rendering di conseguenza il codice HTML per la casella di testo.

Abbiamo semplicemente aggiunto una classe chiamata necessario per tutti gli elementi HTML sono associati a proprietà contrassegnate con l'attributo [Required]. Analogamente, se viene trovata [MaximumStringAttribute] su una proprietà associata, è impostare l'attributo maxlength della casella di testo HTML per corrisponde all'attributo e limitare la lunghezza di input per consentito utente. Il codice HTML risultante simile al seguente:

<p><label>Address:</label>
<input type="text" name="Address1" value="" 
       maxlength="250" style="width: 300px;" 
       class="required textinput" /></p>

L'aspetto di campi obbligatori è facile da controllo semplicemente modificando l'aspetto della classe CSS richiesta (è impostare il colore dei campi obbligatori sullo schermo una blu chiaro). Abbiamo la convalida lato client effettivo con jQuery convalida plug-in, che, opportunamente sufficiente, semplicemente Cerca l'esistenza della classe necessaria per gli elementi di input. Impostando semplicemente l'attributo maxlength gli elementi di input viene applicata la lunghezza massima di un elemento di testo.

Non significa ha questo un'implementazione completa. L'implementazione effettiva nel tempo di generazione non era difficile che. La parte difficile è stato pensando tramite consentono di eliminare metadati ripetitivi e codifica nei livelli più. Sto che che molti team non saranno bello su quella che il team ha generato il database dal modello di oggetti ma OK poiché mio obiettivo reale è sufficiente per fornire alcune idee sulla modalità di potrebbe Utilizzo il Say una sola volta e solo una volta principale per semplificare il risultato delle proprie attività di sviluppo.

Impostazioni predefinite determinante

Nella sezione precedente È illustrato un esempio molto piccolo (tramite una classe AddressMap) di esprimere la relazione tra oggetti mapping ORM (con NHibernate Fluent. Ecco un esempio leggermente più complesso che esprime un riferimento da una classe di sito a oggetti di indirizzo:

public SiteMap() {
  // Map the simple properties
  // The Site object has an Address property called PrimaryAddress
  // The code below sets up the mapping for the reference between
  // Site and the Address class
  References(s => s.PrimaryAddress).Cascade.All();
  References(s => s.BillToAddress).Cascade.All();
  References(s => s.ShipToAddress).Cascade.All();
}

Quando si configurano strumenti ORM, è in genere necessario:

  1. Specificare il nome di tabella in cui una classe Entity esegue il mapping.
  2. Specificare il campo chiave primaria di un'entità e in genere inoltre specificare sorta di strategia per l'assegnazione di valori di chiave primaria. (È una sequenza di numero/database automatico? O verrà assegnati dal sistema i valori di chiave primaria? Oppure si è utilizzare i GUID per la chiave primaria?)
  3. Mappare le proprietà dell'oggetto o campi a colonne della tabella.
  4. Quando si effettua una "in una" relazione da un oggetto con un altro (ad esempio il mapping tra siti a indirizzo), è necessario specificare la colonna chiave esterna che possibile utilizzare lo strumento ORM per unire i record padre e figlio.

Che è in genere necessità. Si tratta di cerimonia che è necessario eseguire per ottenere ORM per mantenere gli oggetti. È per fortuna, può eliminare parte il tedium incorporando alcune impostazioni predefinite determinante nel nostro codice (si noti la presenza di lettere maiuscole).

Si noterà che non ha specificato un nome di tabella, una strategia di chiave primaria, oppure i nomi di campo chiave esterna o gli esempi di mapping. Nella superclasse di mapping NHibernate Fluent il team, è possibile impostare alcuni valori predefiniti per il mapping:

public abstract class DomainMap<T> : ClassMap<T>, 
  IDomainMap where T : DomainEntity {

  protected DomainMap() {
    // For every DomainEntity class, use the Id property
    // as the Primary Key / Object Identifier
    // and use an Identity column in SQL Server,
    // or an Oracle Sequence
    UseIdentityForKey(x => x.Id, "id");
    WithTable(typeof(T).Name);
  }
}

Software opinionated

È possibile notareche descritto l'adozione delle convenzioni come "restrittiva". Parte la filosofia dietro convenzione sulla configurazione è rendere "opinionated software" che consente di creare vincoli fittizi per il progetto.

Un framework opinionated prevede agli sviluppatori di eseguire operazioni in un determinato modo quasi al punto di eliminazione flessibilità.Proponents del software opinionated ritiene che questi vincoli ottimizzare sviluppo rimuovendo le decisioni dagli sviluppatori e promozione di coerenza.

Un'opinione utilizzato dal team è che tutte le classi di modelli dominio completamente sono identificate da una singola proprietà lunga denominata ID:

public virtual long Id { get; set; }

Si tratta di una regola semplice, ma è aveva un numero di efficaci impatto sulla progettazione.Poiché tutte le classi di entità vengono individuate nello stesso modo, sono stati in grado utilizzare una classe singolo archivio invece di scrivere specializzato archivio classi per ogni entità principale.Di conseguenza stesso, URL gestione in un'applicazione Web è coerente tra le classi di entità, senza dover registrare speciali regole di routing per ogni entità.

Dopo questa opinione riduce i costi dell'infrastruttura per l'aggiunta di un nuovo tipo di entità.Lo svantaggio di questo approccio è che sarebbe molto difficile per contenere la chiave di naturale o anche una chiave composta o un GUID per un identificatore di oggetto.Non un problema per il team, ma è possibile bloccare facilmente un altro team dall'adozione l'opinione.

A questo punto, come si è applicare le opinioni?Il primo passaggio semplicemente è creazione di un comune comprensione e contratto all'interno di un team su questi opinioni.Gli sviluppatori informati trovarsi la possibilità di migliore di utilizzare in modo efficiente le scelte di progettazione opinionated a proprio vantaggio.Convenzione sulla configurazione in modo analogo, è può essere a una situazione di emergenza quasi che se gli sviluppatori non ha familiarità con le convenzioni esistente o le convenzioni sono confusione.

È possibile, inoltre, utilizzare uno strumento di analisi del codice statico come parte della build di continuous integration per applicare automaticamente le convenzioni del progetto.

In questo codice che si sta impostando un criterio che tutte le classi che sottoclasse Domain­Entity verrà essere identificato dalla proprietà ID assegnato con la strategia di identità. Il nome della tabella verrà considerato uguale a corrispondere al nome della classe. Ora, è sempre possibile ignorare queste scelte in base alla classe, ma sono raramente avevamo eseguire questa operazione (una classe denominata utenti deve essere mappato a una tabella denominata utenti solo per evitare un conflitto con una parola riservata in SQL Server). Nello stesso modo NHibernate Fluent presuppone un nome di chiave esterno basato sul nome di proprietà che fa riferimento a un'altra classe.

Concessa, questo non salva molte righe di codice per la classe di mapping, ma rende le parti del mapping che variano semplice a letto da ridurre il codice non significative generale il mapping.

Convenzione tramite configurazione

Gli sviluppatori di software hanno cercato ottenere più la produttività e rendere più dinamico sistemi spostando comportamento all'esterno di codice imperative e dichiarative XML di configurazione. Molti sviluppatori ritenute proliferazione di configurazione XML causa troppo che è stato diventare una pratica dannosa. La strategia di valori predefiniti tramite configurazione esplicita è detto anche convenzione sulla configurazione.

Convenzione sulla configurazione è una filosofia di progettazione e la tecnica che tenta di applicare le impostazioni predefinite possono essere implicite dalla struttura del codice invece di richiedere codice esplicito. L'idea è per semplificare lo sviluppo, consentendo allo sviluppatore di preoccuparsi solo le parti unconventional dell'applicazione e architettura.

Ora per a destra, molte persone sono rapido riproduzione con il framework di MVC ASP.NET e sperimentare diverse modalità di utilizzarlo. Nel modello MVC di sviluppo Web Esistono un paio di origini di codice ripetitivo che potrebbe essere un'opportunità grande per applicare le convenzioni sulla configurazione.

Ecco cinque passaggi nel flusso di base di una singola richiesta nel modello MVC:

  1. Ricevuto un URL dal client. Il sottosistema di routing verrà l'URL di analizzare e determinare il nome del controller di gestione di questo URL.
  2. Dal nome del controller di base del sottosistema di routing, creare o individuare l'oggetto controller appropriato.
  3. Richiamare il metodo controller corretto.
  4. Selezionare la visualizzazione appropriata e il marshalling di dati del modello generati dal metodo controller per questa visualizzazione.
  5. Eseguire il rendering della visualizzazione.

All'esterno della casella, è alcuni cerimonia ripetitiva in Creazione di pagine Web con ASP.NET MVC Framework che è possibile ridurre dall'adozione di alcune convenzioni restrittive.

La prima è necessario connettersi un URL in ingresso al sito Web con la classe controller appropriato. Nella libreria di routing in .NET Framework MVC possibile interrogare un URL e determinare il nome del controller di. .NET Framework MVC quindi verrà richiesto l'oggetto IControllerFactory registrato per l'oggetto controller che corrisponda il controller che corrisponde al nome controller determinato DALL'URL in ingresso.

Molti team semplicemente delegare costruzione controller per un'inversione dello strumento di controllo (IOC). Nei casi il team, è possibile utilizzare lo strumento StructureMap open source per risolvere le istanze del controller per nome:

public class StructureMapControllerFactory 
  : IControllerFactory {

  public IController CreateController(
    RequestContext requestContext, string controllerName) {

    // Requests the named Controller from the 
    // StructureMap container
    return ObjectFactory.GetNamedInstance<IController>(
      controllerName.ToLowerInvariant());
  }
}

Richiedere che il controller è abbastanza semplice, ma prima occorre registrare tutte le classi controller per nome con il contenitore IOC. Attendere. Non È che aggiungere alcuni cerimonia l'architettura? Un anno o due fa che sarebbe sono plunged in anticipo con configurazione IOC esplicita delle classi controller come questo:

public static class ExplicitRegistration {
  public static void BootstrapContainer() {
    ObjectFactory.Initialize(x => {
      x.ForRequestedType<IController>().AddInstances(y => {
        y.OfConcreteType<AddressController>().WithName("address");
        y.OfConcreteType<ContactController>().WithName("contact");

        // and so on for every possible type of Controller
      });
    });
  }
}

Questo codice rappresenta tedium pure e cerimonia esiste per alcun motivo rispetto ai feed lo strumento IOC. Se si osserva più vicina al codice di registrazione, si noterà che di seguito uno schema coerenza. AddressController è registrato come indirizzo e Contact­Controller viene registrato come contatto. Invece di configurare in modo esplicito ogni controller, è possibile creare semplicemente una convenzione per determinare automaticamente il nome di routing di ogni classe controller.

Fortunatamente, c'supporto diretto di StructureMap per la registrazione in base convenzione, è possibile creare un nuovo ControllerConvention che registra automaticamente qualsiasi tipo concreto di IController:

public class ControllerConvention : TypeRules, ITypeScanner {
  public void Process(Type type, PluginGraph graph) {
    if (CanBeCast(typeof (IController), type)) {
      string name = type.Name.Replace("Controller", "").ToLower();
      graph.AddType(typeof(IController), type, name);
    }
  }
}

Successivamente, è necessario codice avvio il contenitore StructureMap con convenzione di nuovo, come illustrato nella Figura 6 . Una volta ControllerConvention nuovo nel luogo e parte del contenitore IOC avvio automatico, le nuove classi di controller di aggiungere all'applicazione vengono aggiunti automaticamente alla registrazione IOC senza alcuna configurazione esplicita parte dello sviluppatore. Pertanto sono presenti più errori e bug poiché uno sviluppatore dimenticato aggiungere nuovi elementi di configurazione per nuovi screening dei.

Figura 6 convenzioni di nuove per StructureMap

/// <summary>
/// This code would be in the same assembly as 
/// the controller classes and would be executed
/// in the Application_Start() method of your
/// Web application
/// </summary>
public static class SampleBootstrapper {
  public static void BootstrapContainer() {
    ObjectFactory.Initialize(x => {
      // Directs StructureMap to perform auto registration
      // on all the Types in this assembly
      // with the ControllerConvention
      x.Scan(scanner => {
        scanner.TheCallingAssembly();
        scanner.With<ControllerConvention>();
        scanner.WithDefaultConventions();
      });
    });
  }
}

Come una nota di lato, che si desidera spiegare che questa strategia di registrazione automatica è possibile in tutti i contenitori IOC sto tenere in considerazione per .NET Framework, purché il contenitore IOC espone una registrazione a livello di programmazione DELL'API.

Passaggi successivi

In conclusione, si tratta tutte le informazioni sulla riduzione la distanza e friction tra l'intento e il codice che rende tale intenzione verificarsi.Numerose tecniche che È stato illustrato in questa colonna stanno realmente consentendo il codice "solo scoprire " utilizzando le convenzioni di denominazione anziché codice esplicito o ricerca consentono di evitare la duplicazione di informazioni nel sistema.Utilizzato anche alcune tecniche di riflessione per riutilizzare le informazioni sepolto negli attributi per ridurre lo sforzo meccanico.

Tutte le idee di progettazione possono ridurre la cerimonia dello sforzo di sviluppo ripetitiva, ma si tratta di un prezzo.Detractors della convenzione sulla configurazione si lamentano chiave intrinseci dell'approccio.Incorporamento opinioni in codice o in framework verrà sottratta dal potenziale riutilizzo in nuovi scenari in cui le opinioni non come favorevole.

Non vi sono numerosi altri argomenti che era Impossibile soddisfare questa volta che può soddisfare in una colonna successiva.In modo definito si desidera esaminare come del linguaggio orientato programmazione; alternativi lingue quali il F #, IronRuby e IronPython; e il linguaggio specifici del dominio interno Utilizzo interessa il processo di progettazione software.

Inviare domande e commentimmpatt@Microsoft.com.

Jeremy Miller, un Microsoft MVP per C#, è inoltre autore di open sourceStructureMapstrumento per la dipendenza Infiltrazione con .NET e il forthcomingStrumento storyTellerPer supercharged FIT test in .NET.Visitare il suo blogPer gli sviluppatori sulla struttura, parte del sito CodeBetter.