Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to model bind a class that implements an interface?

The model binding worked fine until i implemented interfaces on top of the following classes:

public class QuestionAnswer : IQuestionAnswer
    {

        public Int32 Row_ID { get; set; }
        public Int32 Column_ID { get; set; }
        public String Value { get; set; }

    }

    public class HiddenAnswer : IHiddenAnswer
    {

        public Int32 Hidden_Field_ID { get; set; }
        public String Hidden_Field_Value { get; set; }

    }

    public class SurveyAnswer : ISurveyAnswer
    {

        public string SessionID { get; set; }

        public List<IQuestionAnswer> QuestionAnswerList { get; set; }

        public List<IHiddenAnswer> HiddenAnswerList { get; set; }

        public SurveyAnswer()
        {
            QuestionAnswerList = new List<IQuestionAnswer>();
            HiddenAnswerList = new List<IHiddenAnswer>();
        }
    }

Now that the interfaces are there, i get a 500 (Internal Server Error)

The javascript that i use to model bind is the following:

$('#submitbutton').click(function () {

            var answers = new Array();
            var hiddenfields = new Array();

            var formname = "#" + $("#formname").val();

            $(':input', formname).each(function () {

                if ($(this).is(":text") || $(this).is(":radio") || $(this).is(":checkbox")) 
                {
                    var answerObject = {
                        Column_ID: $(this).attr('data-column_id'),
                        Row_ID: $(this).attr('data-row_id'),
                        Value: $(this).attr('data-theValue')
                    };

                    answers.push(answerObject);
                }

                else if($(this).is(":hidden")) {
                    var hiddenObject = 
                    {
                        Hidden_Field_ID: $(this).attr('data-hidden_field_id'),
                        Hidden_Field_Value: $(this).attr('data-hidden_field_value')
                    }

                    hiddenfields.push(hiddenObject);
                }
            });

            $('textarea', formname).each(function () {
                var answerObject = {
                    Column_ID: $(this).attr('data-column_id'),
                    Row_ID: $(this).attr('data-row_id'),
                    Value: $(this).val(),
                };

                answers.push(answerObject);
            });

            var allAnswers = {
                SessionID: 0,
                QuestionAnswerList: answers,
                HiddenAnswerList: hiddenfields
            }

            postForm(allAnswers);
        });

The Controller Action looks like this:

 [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SubmitSurvey(SurveyAnswer answers)
        {
            // Dette tillader CORS
            Response.AppendHeader("Access-Control-Allow-Origin", "*");

            bc.SaveSurvey(answers);

            return null;
        }

what am i doing wrong?

like image 705
Kenci Avatar asked Dec 16 '22 23:12

Kenci


1 Answers

what am i doing wrong?

You cannot expect the model binder to know that when it encounters the IQuestionAnswer interface on your SurveyAnswer view model it should use the QuestionAnswer type. It's nice that you have declared this implementation of the interface but the model binder has no clue about it.

So you will have to write a custom model binder for the IQuestionAnswer interface (same for the IHiddenAnswer interface) and indicate which implementation do you want to be used:

public class QuestionAnswerModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var type = typeof(QuestionAnswer);
        var model = Activator.CreateInstance(type);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
        return model;
    }
}

which will be registered in your Application_Start:

ModelBinders.Binders.Add(typeof(IQuestionAnswer), new QuestionAnswerModelBinder());
like image 180
Darin Dimitrov Avatar answered Jan 01 '23 23:01

Darin Dimitrov