Ho trovato che c'è modo più ripetizioni di codice in un'applicazione WebForms che è immediatamente evidente. Ho battuto la testa con questo problema esatto, e ho trovato diversi rimedi.
ASCIUGGI I tuoi UserControls (e anche i modelli!)
Quando guardi ogni singola pagina, vedi tante differenze che non puoi immaginare che il codice venga ripetuto. Guarda i dati che stai salvando nel database. Su un'applicazione su cui lavoro, abbiamo circa 10 diverse forme che salvano tutti i record "persone" nel database con gli stessi campi, ma in ogni vista sono disponibili diversi campi. All'inizio pensavo che ci fosse troppo codice personalizzato, ma poi ho capito che sono tutti gli stessi dati nella stessa tabella. Ho creato un controllo utente generico per modificare oggetti "persone" - Compila i campi modulo in base a un modello di dominio e ripopola il modello di dominio in base ai campi modulo.
Ho anche creato un modello di visualizzazione che comprendeva la logica di visualizzazione e quindi l'utilizzo per influire sul controllo utente.
Modello di dominio persona
public enum PersonType
{
Applicant = 1,
Foo = 2
}
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string TaxId { get; set; }
public IEnumerable<PersonType> Types { get; private set; }
public bool IsApplicant
{
get { return Types.Contains(PersonType.Applicant); }
}
public bool IsSomethingElse
{
get { return Types.Contains(PersonType.Foo); }
}
public bool RequiresTaxId
{
get { return IsApplicant; }
}
}
Modello vista persona
public class PersonViewModel
{
public Person Person { get; private set; }
public bool ShowTaxIdField { get { return Person.RequiresTaxId; } }
public PersonViewModel(Person person)
{
Person = person;
}
}
(A Snippet Of) Il controllo utente
<p id="TaxIdField" runat="server">
<asp:Label ID="TaxIdLabel" runat="server" AssociatedControlID="TaxId">Tax Id:</asp:Label>
<asp:TextBox ID="TaxId" runat="server" />
</p>
Il codice C # dietro
public partial class PersonUserControl : System.Web.UI.UserControl
{
public void SetModel(PersonViewModel model)
{
TaxId.Text = model.Person.TaxId;
TaxIdField.Visible = model.ShowTaxIdField;
// ...
}
public PersonViewModel GetModel()
{
var model = new PersonViewModel(new Person()
{
TaxId = TaxId.Text.Trim(),
// ...
});
return model;
}
}
Push Business Logic nei modelli di dominio
Rimuovere il codice duplicato significa anche spostare la logica di business nei tuoi modelli di dominio. Questa "persona" richiede un codice fiscale? Bene, la classe Person
dovrebbe avere una proprietà o un metodo chiamato IsTaxIdRequired
. Guarda Creare modelli di domini malvagi per alcune idee aggiuntive.
Ma utilizzo i DataSet ...
Stop! Subito. Stai intimamente legando il tuo codice C # allo schema del database sottostante. Anche se devi scrivere a mano un livello di mappatura tra gli oggetti DataSet e i tuoi modelli di dominio, sarai ancora più avanti perché ora puoi raggruppare le regole di comportamento e aziendali con i tuoi dati in una classe pulita e ordinata. Usando DataSet, i tuoi file Design e Code-Behind implementano la logica di business! Ferma questo il prima possibile. Anche se il framework WebForms non aderisce strettamente al modello Model-View-Controller, il codice C # dovrebbe essere visto come "Controller" e il file Design dovrebbe essere visto come "View". L'unica cosa rimasta è il "Modello", che non dovrebbe essere un DataSet . Gli oggetti DataSet forniscono dati, ma nessun comportamento porta a una logica aziendale ripetuta.
Utilizza classi di supporto per inizializzare l'interfaccia utente
Tutto ciò che vedo spesso in 15 diversi UserControls:
public InitStateDropdownList()
{
ddlState.DataSource = ...
ddlState.DataBind();
ddlState.Items.Insert(0, new ListItem("Select", string.Empty));
}
Spingilo in una classe helper:
public static class DropDownListHelper
{
public static void InitStates(DrowDownList list)
{
list.DataSource = // get options from database or session
list.Items.Insert(0, new ListItem("Select", string.Empty));
list.DataBind();
}
}
E usalo:
DropDownListHelper.InitStates(ddlState);
Alcune persone si arrabbiano con le classi di "helper", ma è sicuramente meglio che scrivere quelle che sono essenzialmente le stesse 3 linee di codice in più punti. Anche se non puoi creare controlli utente super generici, elimina almeno il codice ripetitivo che inizializza i componenti al caricamento della pagina.
Quando BIG riscrive la risposta?
Quasi mai. Per tutte le mie lamentele riguardo al framework WebForms, questo in least compartimenta pagine e moduli, che è un'ottima impostazione per un lavoro di refactoring a lungo termine. La chiave è aggiungere copertura di prova . Ho avuto molto successo usando i Test CodedUI e SpecFlow per testare le applicazioni WebForms, dal momento che la maggior parte se non tutta la logica di business è sparsa tra C # e ASP in 19 file diversi. Almeno scrivi alcuni test per convalidare le regole di business esistenti non si rompano durante le molte sessioni di refactoring che hai nel tuo futuro.