Dies ist, wie ich das Problem zu nähern beginnen würde. Ein benutzerdefiniertes Modellbinder wäre ziemlich einfach zu erstellen basierend auf der FormKey-Eigenschaft (die je nach Index und/oder Label bestimmt werden könnte).
public class CustomFormModel
{
public string FormId { get; set; }
public string Label { get; set; }
public CustomFieldModel[] Fields { get; set; }
}
public class CustomFieldModel
{
public DataType DateType { get; set; } // System.ComponentModel.DataAnnotations
public string FormKey { get; set; }
public string Label { get; set; }
public object Value { get; set; }
}
public class CustomFieldModel<T> : CustomFieldModel
{
public new T Value { get; set; }
}
Auch bemerkte ich einen der Kommentare unten hatte ein gefiltertes Modell Binder-System. Jimmy Bogard von Automapper hat einen sehr hilfreichen Beitrag über diese Methode bei http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/03/17/a-better-model-binder.aspx, und später in, http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/11/19/a-better-model-binder-addendum.aspx überarbeitet. Es war sehr hilfreich für mich beim Erstellen von benutzerdefinierten Modellbindern.
aktualisiert
Ich erkennen, dass ich die Frage falsch verstanden, und dass er speziell Entsendung von Form wurde gefragt, wie „mit einer variablen Anzahl von Eingabefeldern, die unterschiedlichen Datentypen repräsentieren“ zu behandeln. Ich denke, der beste Weg, dies zu tun ist, eine Struktur ähnlich wie oben zu verwenden, aber die Composite Pattern nutzen. Im Grunde müssen Sie eine Schnittstelle wie IFormComponent
erstellen und sie für jeden Datentyp implementieren, der dargestellt werden würde. Ich schrieb und kommentierte ein Beispiel Schnittstelle erklären zu helfen, wie dies erreicht werden würde:
public interface IFormComponent
{
// the id on the html form field. In the case of a composite Id, that doesn't have a corresponding
// field you should still use something consistent, since it will be helpful for model binding
// (For example, a CompositeDateField appearing as the third field in the form should have an id
// something like "frmId_3_date" and its child fields would be "frmId_3_date_day", "frmId_3_date_month",
// and "frmId_3_date_year".
string FieldId { get; }
// the human readable field label
string Label { get; }
// some functionality may require knowledge of the
// Parent component. For example, a DayField with a value of "30"
// would need to ask its Parent, a CompositeDateField
// for its MonthField's value in order to validate
// that the month is not "February"
IFormComponent Parent { get; }
// Gets any child components or null if the
// component is a leaf component (has no children).
IList<IFormComponent> GetChildren();
// For leaf components, this method should accept the AttemptedValue from the value provider
// during Model Binding, and create the appropriate value.
// For composites, the input should be delimited in someway, and this method should parse the
// string to create the child components.
void BindTo(string value);
// This method should parse the Children or Underlying value to the
// default used by your business models. (e.g. a CompositeDateField would
// return a DateTime. You can get type safety by creating a FormComponent<TValue>
// which would help to avoid issues in binding.
object GetValue();
// This method would render the field to the http response stream.
// This makes it easy to render the forms simply by looping through
// the array. Implementations could extend this for using an injected
// formatting
void Render(TextWriter writer);
}
Ich gehe davon aus, dass die benutzerdefinierten Formulare über eine Art von ID zugegriffen werden können, die als Formparameter enthalten sein können. Mit dieser Annahme könnte der Modellbinder und -anbieter in etwa so aussehen.
public interface IForm : IFormComponent
{
Guid FormId { get; }
void Add(IFormComponent component);
}
public interface IFormRepository
{
IForm GetForm(Guid id);
}
public class CustomFormModelBinder : IModelBinder
{
private readonly IFormRepository _repository;
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult result;
if(bindingContext.ValueProvider.TryGetValue("_customFormId", out result))
{
var form = _repository.GetForm(new Guid(result.AttemptedValue));
var fields = form.GetChildren();
// loop through the fields and bind their values
return form;
}
throw new Exception("Form ID not found.");
}
}
Offensichtlich gesamte Code ist hier nur den Punkt herüber zu erhalten, und müssten für den tatsächlichen Einsatz abgeschlossen und gereinigt werden. Selbst wenn dies abgeschlossen wäre, würde dies nur an eine Implementierung der IForm-Schnittstelle binden, nicht an ein stark typisiertes Geschäftsobjekt.(Es wäre kein großer Schritt, es in ein Wörterbuch zu konvertieren und einen stark typisierten Proxy mit dem Castle DictionaryAdapter zu erstellen, aber da Ihre Benutzer die Formulare auf der Site dynamisch erstellen, gibt es wahrscheinlich kein stark typisiertes Modell in Ihrer Lösung und das ist irrelevant). Hoffe das hilft mehr.
Danke für die Kommentare, sehr aufschlussreich. – DanP