November Happy Hour will be moved to Thursday December 5th.

No parameterless constructor defined for this object. Stuck

H F
H F
Vote:
 

Hello everyone,

so, here is my problem:

I have a controller. There are 2 action methods. One for Get and the second for Post:

Get method works just fine. Instantiates the ViewModel, passes to the view.

But I do have a problem with the Post method. Here is the signature: 

public ActionResult Index(AirRegistrationViewModel model)

The view that is supposed to send the call and ViewModel alone is simplified to bare minimum:

@model AirRegistrationViewModel

@using (Html.BeginForm("Index""AirRegistrationPage"FormMethod.Post, new { enctype = "multipart/form-data" }))
              {
                  @Html.AntiForgeryToken()
                  <input type="submit" value="Login" />
              }

On Submit click I am getting 'No parameterless constructor defined for this object'.

As far as I understand the call to the post method does not send over the ViewModel, but supposed to. And MVC tries to instantiate it.
While instantiating it looks at the constructor for the ViewModel:

public AirRegistrationViewModel(AirRegistrationPage airRegistrationPage) : base(airRegistrationPage)
      {
          ShowRegistrationForm = true;
      }

can't get resolve AirRegistrationPage, and looks for parameterless constructor, can't find it, hence the error displayed... :(

If my logic is correct, then the question I have.. why? why the call from the view form does not send alone the ViewModel that has been intantiated on the previos call
to display that view?

thank you for any help.

Alex


 

#205569
Jul 16, 2019 18:04
Vote:
 

Hi H F, a bit unclear are you implementing plain ASP.NET MVC or using an Episerver page controller?

If this is about Episerver pages and you want to have an action that handles POST on that page instance, then your implementation is incorrect.

Here is a sample with Alloy demo site and using the StartPageController and adding a demo form on that page which is submitted to the page instance.

Simple input model from post

public class DemoInputModel
{
   [Required]
   public string SomeText { get; set; }
   public int SomeNumber { get; set; }
}

Action on the StartPageController to handle the post

[HttpPost]
public ActionResult Index(StartPage currentPage, DemoInputModel viewInput)
{
	if (!ModelState.IsValid)
	{
		// handle the invalid input here
	}
	
	// as this is just sample this is where you would handle the viewInput that the client posted
	// and could modify your returned view model accordingly or return a completely different view

	// code below is a copy of the Alloy demo Index action (http get)
	var model = PageViewModel.Create(currentPage);

	if (SiteDefinition.Current.StartPage.CompareToIgnoreWorkID(currentPage.ContentLink)) // Check if it is the StartPage or just a page of the StartPage type.
	{
		//Connect the view models logotype property to the start page's to make it editable
		var editHints = ViewData.GetEditHints<PageViewModel<StartPage>, StartPage>();
		editHints.AddConnection(m => m.Layout.Logotype, p => p.SiteLogotype);
		editHints.AddConnection(m => m.Layout.ProductPages, p => p.ProductPageLinks);
		editHints.AddConnection(m => m.Layout.CompanyInformationPages, p => p.CompanyInformationPageLinks);
		editHints.AddConnection(m => m.Layout.NewsPages, p => p.NewsPageLinks);
		editHints.AddConnection(m => m.Layout.CustomerZonePages, p => p.CustomerZonePageLinks);
	}

	return View(model);
}

In the controller action handling posts the first argument is your Episerver page instance (same way it should be in your get index action) and in the second argument you will have your submitted model.

In the view that renders the form, you should render it like this if you want to use the Html.BeginForm (just a demo in this case used to get the current pages url, using the Url.ContentUrl extension method, also you need to wrap the string to MvcHtmlString otherwise the action will be ?length=[number--length-of-the-string])

@using (Html.BeginForm(null, null, new MvcHtmlString(Url.ContentUrl(Model.CurrentPage.ContentLink)), FormMethod.Post))
{
    <input type="text" name="sometext" />
    <input type="text" name="somenumber" />
    <input type="submit" value="Send" />
}

In your code you are passing the BeginForm the action and controller, which will create incorrect action (url) if this really is an Episerver page, in your sample you would get something like this to the action value: /AirRegistrationPage/Index which naturally is incorrect if it really is an Episerver page which has url something like /some-path/in-your/structure/register

Hope this helps or you can clarify are you just having ASP.NET MVC Controller in an Episerver solution and you are trying to get the route to work, etc.

#205710
Jul 19, 2019 21:47
H F
Vote:
 

thank you for your comments Antti. 

I have resolved the problem by adding the paremeterless constructor:

public AirRegistrationViewModel() : base(null)
       {
 
       }

all set now.
#205711
Jul 19, 2019 22:23
Vote:
 

H F, I would not recommend to do this. Because it will violate inner state of the viewmodel in cases when you will need "something" from the page where model was used on (in your case - `AirRegistrationPage`). And this null reference exception will happen only during POST method. You will have bizzare time debugging this and discovering that you once made a workaround far far away back in time..

#205718
Jul 21, 2019 19:21
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.