2010-09-09 11 views
6

Per molti anni ho fatto ASP.NET moduli web sviluppo mi è stato rovinato da una libreria proprietaria, che mi ha permesso di fare cose come:modello Binder in ASP.NET WebForms

UpdateToObject(ControlsCollection, obj) 
    UpdateFromObject(ControlsCollection, obj) 

codice Concettualmente ha fatto qualcosa di molto simile a ciò che fa MVC Model Binder, vale a dire dati i valori postati del modulo come input popolerebbe l'oggetto personalizzato. Fondamentalmente è liberato sviluppatore di fare codice scimmia come

employee.Name = txtName.Text; 
employee.DOB = DateTime.Parse(txtDOB.Text); 

e così via ..

Ora, questa libreria proprietaria non è disponibile sul nuovo progetto sono coinvolto con, ed è un progetto di moduli Web . Quindi mi chiedo se c'è un modo di utilizzare System.Web.Mvc.DefaultModelBinder nel contesto dei moduli Web. L'obiettivo è raggiungere una popolazione semplice e facile di controlli dagli oggetti del dominio e viceversa, idealmente con le annotazioni di validazione prese in considerazione. Se ciò non è possibile, qualcuno potrebbe indicarmi una soluzione open source per rispondere a questa esigenza. Non ho davvero voglia di riscrivere questo codice.

Grazie in anticipo.

risposta

1

Sherlock, si verificheranno alcuni problemi durante il tentativo di utilizzare ModelBinder da MVC poiché si basano su ControllerContext.

Ho risposto a una domanda simile in precedenza ChangeType, Convert - Converting from one type to another ma è davvero quello che stai cercando.

Dai un'occhiata a questo post sul mio blog ChangeType – Changing the type of a variable in C#

In sostanza, si ottiene un singolo metodo denominato ChangeType<T> che restituisce il valore del parametro che stai cercando in un modo fortemente tipizzato o un valore predefinito se il parametro non esiste.

Ora per quanto riguarda le classi personalizzate (principalmente le classi di tipo DTO), se non ti dispiace usare il reflection, allora ho una soluzione che gestirà anche la maggior parte delle classi personalizzate. La classe DtoBinder menzionata verso la fine della volontà funzionerà bene.

In sostanza, gli ultimi 3 elenchi di codici contengono tutto il codice necessario per gestire quasi ogni esigenza in uno scenario di applicazione Web tipica. Inoltre è estendibile, quindi se hai bisogno di implementare il tuo raccoglitore puoi farlo molto semplicemente e registrare il raccoglitore con il RequestBinder da qualsiasi punto della tua app.

Quindi, se non si desidera utilizzare la riflessione per determinati oggetti DTO utilizzati di frequente, è possibile implementare un raccoglitore per il tipo e registrarlo e da quel punto in poi utilizzerà il raccoglitore personalizzato. In molti modi è simile al concetto di MVC ModelBinder.

Edited -

Qui di seguito è una cs file con un gruppo di classi che ho usato in passato per fare esattamente quello che ti serve. Il primo MsPropertyAssignerProvider è quello con cui lavorerai dalla tua pagina.

Eseguire iterate sui controlli e chiamare il metodo GetPropertyAssigner passandogli il nome del tipo del controllo. Questo metodo restituisce un'istanza di ObjectPropertyAssigner con un metodo denominato SetPropertyValue che consente di trasferire l'istanza dell'oggetto e l'istanza di controllo.

internal class MsPropertyAssignerProvider 
    { 
    private Hashtable propertyAssigners; 

    internal MsPropertyAssignerProvider() 
    { 
     propertyAssigners = new Hashtable(); 
     RegisterPropertyAssigner(typeof(TextBox).ToString(), new TextBoxValueExtractor()); 
     RegisterPropertyAssigner(typeof(DropDownList).ToString(), new DropDownListValueExtractor()); 
     RegisterPropertyAssigner(typeof(Label).ToString(), new LabelValueExtractor()); 
     RegisterPropertyAssigner(typeof(CheckBox).ToString(), new CheckBoxValueExtractor()); 
    } 

    internal void RegisterPropertyAssigner(string identifier, IMsObjectPropertyAssigner assigner) 
    { 
     if (propertyAssigners.ContainsKey(identifier)) 
     throw new DuplicatePropertyAssignerRegistrationException(identifier); 
     propertyAssigners.Add(identifier, assigner); 
    } 

    internal IMsObjectPropertyAssigner GetPropertyAssigner(string identifier) 
    { 
     return (propertyAssigners.ContainsKey(identifier)) ? (IMsObjectPropertyAssigner)propertyAssigners[identifier] : null; 
    } 
    } 

La classe di accompagnamento sono elencati di seguito

public interface IMsObjectPropertyAssigner 
    { 
    void SetPropertyValue(object obj, System.Web.UI.Control control); 
    } 

    internal abstract class BaseValueExtractor : IMsObjectPropertyAssigner 
    { 
    protected MsReflectionHelper reflectionHelper = new MsReflectionHelper(); 
    protected string FixStringForNumber(string stringValue) 
    { 
     if (stringValue.Length == 0) 
     return "0"; 
     else 
     return stringValue; 
    } 
    public abstract void SetPropertyValue(object obj, System.Web.UI.Control control); 
    } 

    internal class TextBoxValueExtractor : BaseValueExtractor 
    { 
    public override void SetPropertyValue(object obj, System.Web.UI.Control control) 
    { 
     TextBox textBox = (TextBox)control; 
     PropertyInfo propInfo = reflectionHelper.GetPropertyInfo(obj, control.ID); 
     Type propType = propInfo.PropertyType; 
     if (propType == typeof(System.String)) 
     reflectionHelper.SetPropertyValue(obj, control.ID, textBox.Text); 
     else if (propType == typeof(System.Int16)) 
     reflectionHelper.SetPropertyValue(obj, control.ID, Int16.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency)); 
     else if (propType == typeof(System.Int32)) 
     reflectionHelper.SetPropertyValue(obj, control.ID, Int32.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency)); 
     else if (propType == typeof(System.Int64)) 
     reflectionHelper.SetPropertyValue(obj, control.ID, Int64.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency)); 
     else if (propType == typeof(System.Double)) 
     reflectionHelper.SetPropertyValue(obj, control.ID, Double.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency)); 
     else if (propType == typeof(System.Single)) 
     reflectionHelper.SetPropertyValue(obj, control.ID, Single.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency)); 
     else 
     reflectionHelper.SetPropertyValue(obj, control.ID, textBox.Text); 
    } 
    } 

    internal class DropDownListValueExtractor : BaseValueExtractor 
    { 
    public override void SetPropertyValue(object obj, System.Web.UI.Control control) 
    { 
     DropDownList dropDownList = (DropDownList)control; 
     reflectionHelper.SetPropertyValue(obj, control.ID, dropDownList.SelectedValue); 
    } 
    } 

    internal class LabelValueExtractor : BaseValueExtractor 
    { 
    public override void SetPropertyValue(object obj, Control control) 
    { 
     Label label = (Label)control; 
     reflectionHelper.SetPropertyValue(obj, control.ID, label.Text); 
    } 
    } 

    internal class CheckBoxValueExtractor : BaseValueExtractor 
    { 
    public override void SetPropertyValue(object obj, Control control) 
    { 
     CheckBox checkbox = (CheckBox)control; 
     reflectionHelper.SetPropertyValue(obj, control.ID, checkbox.Checked); 
    } 
    } 

Spiacente, non importa quello che faccio l'editor scombina completamente il Codice. Ma spero che questo aiuti.

+0

Solo il primo e l'ultimo paragrafo sono in qualche modo pertinenti alla domanda sollevata. Non mi dispiace usare il riflesso. Ecco come funzionava la libreria proprietaria. – Sherlock

+0

Credo che nel tuo caso, perché stai lavorando con Controls, la soluzione è un po 'più coinvolta. La classe DtoBinder può creare un'istanza dell'oggetto Dto e assegnare tutti i valori di proprietà dati una raccolta di NameValues. Quindi, ciò che devi fare è assemblare questa raccolta dai nomi e dai valori del controllo e consegnarla a DtoBinder. –

+0

Ho appena modificato la mia risposta originale con alcune classi aggiuntive che ho usato in passato. –

1

Non sareste in grado di utilizzare AutoMapper per qualcosa di simile? Basta impostare le mappe e creerà nuovi oggetti e copierà i valori in essi.

0

Questa è una domanda piuttosto vecchia, ma l'ho trovata mentre cercavo di capire come funziona il legatore modello predefinito.

Ho un progetto su CodeProject che effettivamente fa ciò che vuoi (ed), have a look.

Cheers!

Problemi correlati