0

I'm developing the ASP .Net "Student Testing" Rest API. I'm using the default System.Text.Json (de)serializer with the .net v5.0

This API is used for student testing. The student chooses a test from the list and takes it.

There are several types of questions in my API:

  • Text question - the student enters the answer into the input field
  • Single choice question - the student chooses one of the proposed options
  • Multiple choice question - the student chooses multiple options

After the student is confident in his answers, he submits them. Here is an example of the submitted answers in JSON format:

{
  "testId": "07450745-0745-0745-0745-074507450745",
  "answeredQuestions": [
    {
      "id": "abcdabcd-abcd-abcd-abcd-abcdabcdabcd",
      "type": "text",
      "givenAnswer": "Answer that student typed in the input box."
    },
    {
      "id": "88888888-4444-4444-4444-dddddddddddd",
      "type": "single-choice",
      "selectedAnswerOptionId": "00000000-0000-0000-0000-000000000008"
    },
    {
      "id": "12341234-1234-1234-1234-123412341234",
      "type": "multiple-choice",
      "selectedAnswerOptionIds": [
        "00000000-0000-0000-0000-000000000001",
        "00000000-0000-0000-0000-000000000002",
        "00000000-0000-0000-0000-000000000004"
      ]
    }
  ]
}

I have DTO questions implemented in ASP .Net Core API:

public abstract class AnsweredQuestion
{
    public Guid Id { get; set; }
    public abstract string Type { get; }
}

public class AnsweredTextQuestion : AnsweredQuestion
{
    public override string Type => "text";
    public string GivenAnswer { get; set; }
}

public class AnsweredSingleChoiceQuestion : AnsweredQuestion
{
    public override string Type => "single-choice";
    public Guid SelectedAnswerOptionId { get; set; }
}

public class AnsweredMultipleChoiceQuestion : AnsweredQuestion
{
    public override string Type => "multiple-choice";
    public ICollection<Guid> SelectedAnswerOptionIds { get; set; }
}

But I'm not really sure how to implement the presented test DTO. If I just do something like ICollection<AnsweredQuestion> for the JSON answeredQuestions field, then all data related to the specific question type is lost (e.g. givenAnswer, selectedAnswerOptionId or selectedAnswerOptionIds).

How to implement the submitted test DTO to support different types of questions?

In all my actions JSON deserialization happens automatically, but in that case it can be a problem. I think the solution is to somehow change the deserialization logic to take into account the value of the type field.

satma0745
  • 667
  • 1
  • 7
  • 26

1 Answers1

0

I would suggest you define am enum of the type of questions.

public enum QuestionType
{
    TextQuestion,
    SingleChoice, 
    MultipleChoice
}

Then you define a single table for all your question types

public class Question
{
    public int Id{get; set;} 
    public QuestionType QuestionType{get;set;} 
    public string TextQuestionAnswer{get;set;} 
    public int SingleChoiceAnswer{get;set;} 
    public ICollection<MultipleChoice> MultipleChoiceAnswers{get;set;}
}

public class MultipleChoice
{
    public int Id{get;set;} 
    public int QuestionId
    public int SelectedAnswerId{get;set;} 
    public Question Question{get;set;}
}

So, in your controllers, you will definite a logic that checks if a question is of a certain type, if it is, then only allow answers to be saved for that type, and the other types will be null.

For example, if a question is of type SingleChoice, then only the SingleChoiceAnswer property will have a value saved, other MultipleChoiceAnswers and TextQuestionAnswer properties will be null.

satma0745
  • 667
  • 1
  • 7
  • 26
Qudus
  • 1,440
  • 2
  • 13
  • 22
  • I also thought about a similar approach. This is somewhat similar to the Table-Per-Hierarchy from Entity Framework Core. I don't like this approach because I am using a language with an OOP paradigm. Somehow it seems wrong to me to create a class that represents several different entities at the same time. So I decided to abandon this approach in favor of the one suggested in [this answer](https://stackoverflow.com/a/59744873/13851956). – satma0745 Jan 30 '21 at 12:45
  • 1
    @catman0745 Yeah. I know it's not so good. I used the approach in a project, wish I had seen the suggested answer before. – Qudus Jan 30 '21 at 12:53
  • 1
    In any case, thanks for the help in solving the problem. – satma0745 Jan 30 '21 at 12:57