flip
flip

Reputation: 391

ASP.NET MVC view models from key / value pairs

How would could I represent a key / value pair as an ASP.NET MVC model? My form data is not backed by a strongly typed model.

My first solution was to design my form using Razor and use some extension methods to get the FormElement values.

@model IEnumerable<FormElementKeyValues>

@Html.TextBox(Model.GenerateID("Email"), Model.GetFormElementValue("Email"))<br />

This works but it becomes messy when I want to process data from a POST. I have no model so I am forced to fall back to using a FormCollection which means I lose the benefit of strongly typed model and validation.

A second solution (I haven't tried this yet) would be to create my individual form models and decorate the properties with custom attributes that help me get access to the key / value pairs.

public SimpleFormModel {

    [FormElement("Fullname")]
    [Required(ErrorMessage = "Required")]
    public string Fullname { get; set; }

    [FormElement("Email")]
    [Required(ErrorMessage = "Required")]
    [DisplayName("E-mail")]
    public string Email { get; set; }
}

public ComplexFormModel {

    [FormElement("Firstname")]
    [Required(ErrorMessage = "Required")]
    public string Firstname { get; set; }

    [FormElement("Surname")]
    [Required(ErrorMessage = "Required")]
    public string Surname { get; set; }

    [FormElement("Email")]
    [Required(ErrorMessage = "Required")]
    [DisplayName("E-mail")]
    public string Email { get; set; }
}

This would allow me to use a strongly-typed model within my view along with the standard Razor Html Helpers.

<div class="editor-field">
  @(Html.TextBoxFor(model => model.Firstname))
  @(Html.ValidationMessageFor(model => model.Firstname))
  @(Html.DisplayFor(model => model.Firstname))
</div>

Upvotes: 1

Views: 3782

Answers (1)

Aydin
Aydin

Reputation: 15334

I think you're way over complicating this task...

Models are there for you to both render, and consume from your Razor views...

So for instance, say I had a website selling tickets to festivals, and I have a order form I want to make reusable across all the different events I'm selling tickets for and that I wanted to pre populate the name of the event in that form... this is how you would do it...

First of all you need a model,

public class RegistrationViewModel {
    [Display(Name = "Event")]
    public string EventName { get; set; }

    [Required]
    [Display(Name = "First name")]
    public string FirstName { get; set; }

    [Required]
    [Display(Name = "Last name")]
    public string LastName { get; set; }
}

Next let's imagine we have a Events Controller with an Action called Register

public class Events : Controller 
{
    public ActionResult Register(int id)
    {
        Event event = DbSource.FindEventById(id);

        RegistrationViewModel model = new RegistrationViewModel 
        {
            EventName = event.Name
        }

        return this.View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Register(RegistrationViewModel model)
    {
        if( ! ModelState.IsValid ) 
        {
            return this.View(model);
        }

        // ship the tickets, return thank you view, etc...
    }
}

And finally our view....

@model RegistrationViewModel

@using (Html.BeginForm("Register", "Events")
{
    <div>
        @(Html.AntiForgeryToken())

        @(Html.LabelFor(model => model.EventName))
        @(Html.ValueFor(model => model.EventName))

        @(Html.LabelFor(model => model.FirstName))
        @(Html.TextBoxFor(model => model.FirstName))
        @(Html.ValidationMessageFor(model => model.FirstName))

        @(Html.LabelFor(model => model.LastName))
        @(Html.TextBoxFor(model => model.LastName))
        @(Html.ValidationMessageFor(model => model.LastName))
    </div>
}

I've written this on the fly so I don't know if it will compile as is, but what I've shown you is basically all there is to it...

Upvotes: 1

Related Questions