2010-09-09 7 views
6

Für einige Jahre habe ich ASP.NET Web-Formulare Entwicklung ich durch eine proprietäre Bibliothek verdorben wurde, die mir Dinge wie zu tun erlaubt:Modell Binder in ASP.NET Webforms

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

Konzeptionell Code tat sehr etwas Ähnlich wie bei MVC Model Binder, dh wenn die angegebenen Werte des Formulars als Eingabe übergeben werden, würde es das benutzerdefinierte Objekt füllen. Grundsätzlich befreite es Entwickler von Affen tun Code wie

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

und so weiter ..

Nun, diese proprietäre Bibliothek auf das neue Projekt nicht zur Verfügung ich beteiligt bin, und es ist ein Web-Formulare Projekt . Ich frage mich, ob es eine Möglichkeit gibt, System.Web.Mvc.DefaultModelBinder im Kontext von Webformularen zu verwenden. Ziel ist es, eine einfache und einfache Population von Steuerelementen aus Domänenobjekten und zurück zu erreichen, idealerweise mit Validierungsannotationen, die in Betracht gezogen werden. Wenn dies nicht möglich ist, könnte jemand mich auf eine Open-Source-Lösung verweisen, um diese Notwendigkeit zu adressieren. Ich habe wirklich keine Lust, solchen Code neu zu schreiben.

Vielen Dank im Voraus.

Antwort

1

Sherlock, werden Sie in einige Probleme laufen versuchen, die Modelbinder von MVC zu verwenden, da sie auf einem Controller verlassen.

antwortete ich eine ähnliche Frage früher ChangeType, Convert - Converting from one type to another aber es ist wirklich das, was Sie suchen.

Schauen Sie sich diese Blog-Post auf meinem Blog ChangeType – Changing the type of a variable in C#

Im Wesentlichen erhalten Sie eine einzelne Methode ChangeType<T> genannt, die den Wert des Parameters zurückgibt, die Sie suchen in einer stark typisierten Mode oder einen Standardwert, wenn die Parameter existiert nicht.

nun in Bezug auf kundenspezifische Klassen (DTO Typklassen in erster Linie), wenn Sie nicht dann mit Reflexion machen es mir eine Lösung, die auch die meisten benutzerdefinierten Klassen behandelt. Die gegen Ende des Willens erwähnte DtoBinder-Klasse geht gut an.

Im Wesentlichen sind die letzten 3 Codebeispiele enthalten alle den Code, den Sie brauchen, um fast jeden zu behandeln müssen Sie in einer typischen Web-Anwendungsszenario haben. Außerdem ist es erweiterbar. Wenn Sie also Ihren eigenen Binder implementieren müssen, können Sie dies ganz einfach tun und Ihren Binder mit dem RequestBinder von überall in Ihrer App registrieren.

Also, wenn Sie Reflexion für bestimmte häufig gebrauchte DTO-Objekte nicht verwenden möchten, können Sie ein Bindemittel für die Art implementieren und registrieren und von diesem Zeitpunkt an wird es Ihr individuelles Bindemittel verwendet werden. In vieler Hinsicht ähnelt es dem MVC ModelBinder im Konzept.

Edited -

Im Folgenden finden Sie eine CS-Datei mit einer Reihe von Klassen, die ich in der Vergangenheit verwendet habe, genau das zu tun, was Sie brauchen. Der erste MsPropertyAssignerProvider ist derjenige, mit dem Sie von Ihrer Seite aus arbeiten würden.

Sie würden Ihre Kontrollen durchlaufen und die GetPropertyAssigner Methode nennen es den Namen Art der Steuerung übergeben. Diese Methode gibt eine Instanz eines ObjectPropertyAssigner zurück, der über eine Methode namens SetPropertyValue verfügt, an die Sie Ihre Objektinstanz und die Steuerungsinstanz übergeben können.

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

Die begleitende Klasse sind unter

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

Leider egal aufgelistet, was ich tue der Editor vollständig den Code Eintrag vermasselt. Aber ich hoffe, das hilft.

+0

Nur die ersten und letzten Absätze sind für die aufgeworfene Frage etwas relevant. Es macht mir nichts aus Reflexionen zu benutzen. So funktionierte die proprietäre Bibliothek. – Sherlock

+0

Ich denke, in Ihrem Fall, weil Sie mit Controls arbeiten, ist die Lösung ein wenig komplizierter. Die DtoBinder-Klasse kann eine Instanz Ihres Dto-Objekts erstellen und bei einer Auflistung von NameValues ​​alle Eigenschaftswerte zuweisen. Sie müssen diese Sammlung also aus den Namen und Werten des Steuerelements zusammensetzen und an den DtoBinder übergeben. –

+0

Ich habe meine ursprüngliche Antwort mit einigen zusätzlichen Klassen, die ich in der Vergangenheit verwendet habe, bearbeitet. –

1

Können Sie den AutoMapper nicht für so etwas verwenden? Richten Sie einfach Ihre Karten ein und es werden neue Objekte erstellt und die Werte in sie kopiert.

0

Dies ist eine ziemlich alte Frage, aber ich stieß darauf, während ich versuchte, herauszufinden, wie der Standardmodell-Binder tatsächlich funktioniert.

Ich habe ein Projekt auf CodeProject, das tatsächlich tut, was Sie wollen (ed), have a look.

Prost!