0

I am trying to add a new record to a database that I've created. The database is called QUESTIONNAIRES and it has the columns: QuestionnaireUID, UserUID, QuestionnaireName, DateCreated, Link, and Image.

I want the user to specify the QuestionnaireName and provide an Image and I want to generate myself the QuestionnaireUID, UserUID, DateCreated, and Link. So far, this is my View() that represents this creation process:

@using (Html.BeginForm())
        {
            @Html.AntiForgeryToken()

                @Html.ValidationSummary(true, "", new { @class = "text-danger" })

                // Hide QuestionnaireUID, UserUID, and Link from user. These fields will be generated instead of assigned by user input.    
                @Html.HiddenFor(model => model.QuestionnaireUID)
                @Html.HiddenFor(model => model.UserUID)
                @Html.HiddenFor(model => model.Link)

                <div class="form-group"> <!-- Questionnaire name. -->
                    <h2>Name</h2>
                    <p> Please provide a name for your decision tree.<p>
                    <div class="col-md-10">
                        @Html.EditorFor(model => model.QuestionnaireName, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.QuestionnaireName, "", new { @class = "text-danger" })
                    </div>
                </div>

                <div class="form-group"> <!-- Questionnaire image. -->
                    <h2>Image</h2>
                    <p> Please provide a background image for your decision tree.</p>

                    <!-- ADD FILE IMAGES & ENCODE IN BINARY. -->

                    <div class="col-md-10">
                        @Html.EditorFor(model => model.Image, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Image, "", new { @class = "text-danger" })
                    </div>
                </div>

                <div class="form-group btn_next"> <!-- Save and continue button. -->
                    <input type="submit" value="Save and Continue" class="btn">
                </div>
        }

The Questionnaire Controller methods that are being used are displayed below as well:

      // GET: Questionnaires/Create
        public ActionResult Create()
        {
            ViewBag.UserUID = new SelectList(db.Users, "UserUID", "FirstName");
            return View();
        }

        // POST: Questionnaires/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "QuestionnaireUID, UserUID, QuestionnaireName, DateCreated, Link, Image")] QUESTIONNAIRE questionnaire)
        {
            if (ModelState.IsValid)
            {
                db.QUESTIONNAIRES.Add(questionnaire);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(questionnaire);
        }

As you can see, I've hidden away the three attributes that I want to generate in my View(). I now don't know where I generate and assign these values. Do I do this in my View() or in the Controller method? And what does this assignment look like?

Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • 2
    I think you should research view models. With proper view models, you don't have to manually assign anything, the MVC engine takes care of that for you. That is the whole point of using `@Html.InputFor` where the `For` part tells MVC what property in your view model to bind to – mituw16 Mar 24 '15 at 13:11
  • 2
    Of course in Controller Method. Generate the ids, update the model and pass to save method. – BabyDuck Mar 24 '15 at 13:21

1 Answers1

1

I'd generate those values in the Controller on HttpGet, and I'd use a ViewModel.

Echoing mituw16's comment, using a ViewModel is a good way of keeping everything logically consistent and separated. There's some pretty good in-depth discussions and explanations of ViewModels elsewhere that are worth reading.

Your ViewModel could, for instance, look something (roughly) like this:

public class QuestionnaireViewModel
{
    public Guid QuestionnaireUID { get; set; }
    public Guid UserUID { get; set; }
    public string QuestionnaireName { get; set; }
    public DateTime DateCreated { get; set; }
    public string Link { get; set; }
    public Image Image { get; set; }
}

And it could be passed to the View like this:

[HttpGet]
public ActionResult Create()
{
    var vm = new QuestionnaireViewModel();
    vm.QuestionnaireUID = Guid.NewGuid();
    vm.UserUID = Guid.NewGuid();
    return View(vm);
}

When the form is posted, MVC can automatically interpret the incoming data as a QuestionnaireViewModel:

[HttpPost]
public ActionResult Create(QuestionnaireViewModel vm)
{
    if (ModelState.IsValid)
    {
        // map the viewmodel properties onto the domain model object here
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(questionnaire);
}

A couple more points:

  • In this example, you'll see that it may not even be necessary to include the UID stuff in the ViewModel, as the ViewModel only cares about data gathered from/presented to the user. Further, unless the @Html.HiddenFors have some sort of functional purpose on the view, you might be able to leave them out and generate them on HttpPost.
  • If you're looking to "create new record with a combination of values being assigned from user input and being generated in ASP.NET MVC 4" (a.k.a. creating a form in MVC), then the more complex your model/viewmodel gets, the more I'd stay away from using ViewBag for these purposes.
Community
  • 1
  • 1
alex
  • 6,818
  • 9
  • 52
  • 103
  • 1
    Agreed ViewModels are excellent mechanisms in MVC. MVC's binding engine is superb! – JWP Mar 24 '15 at 14:06