1

I have a view model for exams. Each exam has an arbitrary number of questions. It could be 1 question or it could be 50 questions. After this gets submitted i need to loop thru the questions and check the answers. I have a solution but i feel like it's not a best practice.

int questionNumber = 1;

        while (Request.Form["Question" + questionNumber.ToString()] != null)
        {
            int questionID = Convert.ToInt32(Request.Form["Question" + questionNumber.ToString()]);
            int answerID = Convert.ToInt32(Request.Form["Answer" + questionNumber.ToString()]);

            //TODO: Check if answer is correct
        }

Unsure of another way to do this like

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult GradeTest(int? testID, string[] questionIDs, string[] answerIDs)

What i'm doing feels a little hacky. Please help OR let me know i'm on the right track. Thanks!

2
  • 4
    Dont do this. Do it the right way, use a ViewModel. You're taking some of the core aspects of ASP.NET MVC and throwing them out the window. It may help you to walk through some tutorials Commented Jan 5, 2015 at 20:43
  • Yeah Jonesy it totally hurt me to do it this way. Commented Jan 5, 2015 at 21:13

4 Answers 4

3

I really don't get the whole context but if this is submitted from a view in a form, then the form is probably built using @Html.TextBoxFor or something like that. Just take the same model as input to the post Action. Please note that any property which is not in a form field will not be included, use HiddenFor if you must have something. I've put together an example below.

YourViewModel.cs

public class YourViewModel {
    public int ExamID { get; set; }
    public string Name { get; set; }
    public List<int> QuestionIDs { get; set; }
    public List<int> AnswerIDs { get; set; }
}

YourView.cshtml

@model YourViewModel.cs
using(Html.BeginForm("PostExam", "YourController", FormMethod.Post)        
{
    @Html.HiddenFor(m => m.ExamID)
    @Html.AntiForgeryToken()
    <strong>Please enter your name</strong>
    @Html.TextBoxFor(m => m.Name)
    @*Your question and answers goes here*@
    <input type="submit" value="Hand in" />
}

YourController.cs

public class YourController : Controller
{
    [HttpPost]
    [ValidateAntiForgeryToken()]
    public ActionResult PostExam(YourViewModel Submitted)
    {
        //Handle submitted data here
        foreach(var QuestionID in Submitted.QuestionIDs)
        {
            //Do something
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

He needs to submit a collection back to the server which is a bit advanced for a beginner if we're talking about a list of complex objects rather than primitives.
1

I'm a ding dong. I was going about this all wrong. I looked up how to pass a collection from view to controller and problem solved!

http://www.c-sharpcorner.com/UploadFile/pmfawas/Asp-Net-mvc-how-to-post-a-collection/

I updated my view / controller like so:

@foreach (var question in Model.TestQuestions)
{
    @Html.Hidden("Questions[" + questionIndex.ToString() + "].ID", question.ID)
    <h3>@question.Text</h3>
    <section>
        @foreach (var answer in question.TestAnswers)
        {
            <div>
                @Html.RadioButton("Answers[" + questionIndex.ToString() + "].ID", answer.ID) @answer.Text
            </div>
        }
    </section>
    <hr />        
    questionIndex++;    
}

and controller:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult TestDoGrade(int? testID, IEnumerable<TestQuestion> questions, IEnumerable<TestAnswer> answers)
    {

1 Comment

that's good. One improvement you could make is to create a TestViewModel that contains it's ID, questions, and answers. Then you have everything encapsulated in one object.
0

Use a viewmodel with a list. The only caveat to this is binding to a List is somewhat of an advanced technique: Model Binding to a List MVC 4

public class Response {
   public string QuestionId {get;set;}
   public string AnswerId {get;set;}
}

public class ExamViewModel {
    public int? TestId {get;set;}
    public List<Response> Responses {get;set;}
}

public ActionResult GradeTest(ExamViewModel viewModel)
{
...

Comments

0

You can accept JObject as parameter. JObject it will make covert form data into List of JProperties that you can enumerate.

JProperty has two fields, Name and Value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.