Html.BeginForm posted Model is null - c#

Hello I have following problem:
I tried to post a Model through a Form to an other controller-action.
But the received Model is only filled with null elements.
ToolController.cs
public class ToolController : Controller
{
public ActionResult Index()
{
var Model = new EditToolModel{ /* Some data */ };
return View(Model);
}
[HttpPost]
public ActionResult EditToolOverview(EditToolModel myModel)
{
return RedirectToAction("Index", "Tool", new { show = "overview" });
}
}
EditToolModel.cs
public class EditToolModel
{
public Tools tool;
public IEnumerable<Tools> tools { get; set; }
public ToolsExtention tool_extention;
public string latest_version { get; set; }
public string latest_version_type { get; set; }
public string latest_devStep { get; set; }
public IEnumerable<ToolVersionsView> versions { get; set; }
public IEnumerable<DevelopmentStep> developmentSteps { get; set; }
}
Index.cshtml
#model EditToolModel
#{
ViewBag.Title = "Index";
Layout = "~/Layout/_Layout.cshtml";
}
#Html.Partial("ToolOverview", this.Model)
ToolOverview.cshtml
#model EditToolModel
#using (Html.BeginForm("EditToolOverview", "Tool", FormMethod.Post))
{
<div class="contend">
#Html.TextBoxFor(Model => Model.tool_extention.a)
#Html.TextBoxFor(Model => Model.tool_extention.b)
<input type="submit" name="tool_submit" value="Submit"/>
</div>
}

You need to have a getter/setter on the tool_extention property in order for the DefaultModelBinder to work
public ToolsExtention tool_extention { get; set; }
Ditto for the tool property (but your only rendering controls for the tool_extention property in your view)

ToolsExtention Try changing the EditToolOverview property from EditToolModel to ToolsExtention in the form post method.
[HttpPost]
public ActionResult EditToolOverview(ToolsExtention myModel)
{
//_devProv.changeToolExtention(myModel);
return RedirectToAction("Index", "Tool", new { show = "overview" });
}

Related

I'm using a html.beginform to when i click in a button i go to a diferente Action, but i need to pass the values that i have inside my model aspnet c#

I'm developng a school project using a html.beginform to when i click in a button i go to a diferent Action, but i need to pass the values that i have inside my #model in the view to the action.How can I do that?
#using (Html.BeginForm("ExportToexcel_Click", "L_AccessPoint", FormMethod.Post))
{
<button type="submit" id="cmdAction" runat="server">
Export To Excel
</button>
}
Inside that action i will create a file, and to do that i need to pass the model that i have in the view to the action ExportToexcel_Click
[HttpPost]
public ActionResult ExportToexcel_Click(dadosPassar dp)
{
var ds = new dadosPassar();
ds = dp;
return RedirectToAction("Index",ds);
}
And thats my model,
public class dadosPassar
{
public List<Stored1>? dados2 { get; set; }
public List<L_AccessPoint>? Aps { get; set; } = new List<L_AccessPoint>();
public List<L_Zone>? Zones { get; set; } = new List<L_Zone>();
public List<int>? ap { get; set; }
public DateTime Inicial { get; set; }
public DateTime Final { get; set; }
public string? AcessoVisita { get; set; }
public string? tempo { get; set; }
public string ApZona { get; set; }
}
Edit:
I need to pass my model.dados2 to my view to i can work with that, how can i do that?
Thats my dados2 structure
public class Stored1
{
public short ap_id { get; set; }
public string ap_name { get; set; }
public int numeroAcessos { get; set; }
//public int month { get; set; }
public int year { get; set; }
public int MES { get; set; }
public int DIA { get; set; }
}
"I'm using a html.beginform to when I click in a button I go to a diferente Action?"
Yes this is very obvious it should redirect to your controller as
per your code. Because <button type="submit" runat="server"> Export To Excel </button> is not correct way to do that. You should try
below way.
Correct Way:
<input type="submit" id="cmdAction" value="Export To Excel"/>
Output:
"But I need to pass the values that I have inside my model aspnet c#"
It seems that you are sending nothing inside your BeginForm submit
action as shown below.
#using (Html.BeginForm("ExportToexcel_Click", "L_AccessPoint", FormMethod.Post))
{
<input type="submit" d="cmdAction" value="Export To Excel"/>
}
Note: Above code will submit null value to your ExportToexcel_Click controller as you are not sending anything
inside the form post action.
Demo:
Tough Its not clear what your plan is. But if you would like to load this
page with some predefined data in that case, you should initialize the
model in your controller Index action then load the value in
hidden mode like below:
Controller Action For Intial View:
public IActionResult Index()
{
var ds = new dadosPassar();
ds.AcessoVisita = "Initial AcessoVisita";
ds.tempo = "Initial Tempo";
ds.ApZona = "Initial Ap Zona";
ds.Final = DateTime.Now;
return View(ds);
}
View:
#model DotNet6MVCWebApp.Models.dadosPassar
#using (Html.BeginForm("ExportToexcel_Click", "L_AccessPoint", FormMethod.Post))
{
<input asp-for="AcessoVisita" hidden class="form-control" />
<input asp-for="tempo" hidden class="form-control" />
<input asp-for="ApZona" hidden class="form-control" />
<input type="submit" d="cmdAction" value="Export To Excel"/>
}
Controller When Submit Button Cliked:
[HttpPost]
public ActionResult ExportToexcel_Click(dadosPassar dp)
{
var ds = new dadosPassar();
ds = dp;
return RedirectToAction("Index", ds);
}
Output:
Hope that would resolve your current issue and guide you to pass values to your controller POST method.

C# - Passing view model data around

I have a post method that has my view model and all of its data
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SpecialOrderSelection(JobOrder job, ItemViewModel model)
{
return RedirectToAction("SpecialOrderSummary", "JODetails", model);
}
The 'special order selection' page is where a user is shown a list of parts and must choose if the part should be transferred, harvested, or disposed of. It returns the correct data to the controller. But after the submit happens I want to give the user a summary page of everything that they have done. To do this I tried passing the view model to a 'Order summary' page. With the get method looking like this
public ActionResult SpecialOrderSummary(ItemViewModel model)
{
return View(model);
}
Here is my Model
public class ItemViewModel
{
[Required]
public int ID { get; set; }
public string ItemId { get; set; }
public string ItemName { get; set; }
public string MFGNumber { get; set; }
public IList<ItemPartViewModel> Parts { get; set; }
public IList<ItemComponentViewModel> Components{ get; set; }
public IList<ComponentPartViewModel> ComponentParts { get; set; }
public IList<ComponentSubCompViewModel> ComponentSubComps { get; set; }
public IList<SubCompPartViewModel> SubCompParts { get; set; }
public IList<SubCompSubCompViewModel> SubCompSubComps { get; set; }
public IList<SubCompSubCompPartViewModel> SubCompSubCompParts { get; set; }
}
And then I want the view to do something like this
#model PIC_Program_1._0.Models.ItemViewModel
#using PIC_Program_1._0.Models
#{
ViewBag.Title = "SpecialOrderSummary";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#*#Html.HiddenFor(model => model.ID)*#
#Html.HiddenFor(x => x.ID)
<h2>Special Order Summary</h2>
<p style="color:red" class="noprint">Please review and verify </p>
<h2>
Transfers
</h2>
<h3>
Parts
</h3>
foreach (var part in Model.Parts) // part is null here
{
<p>#part.PartName</p>
}
}
But Model.Parts always has a count of 0. So I'm wondering how I can pass the data of a view model around.
Any help is appreciated.
As David suggested, I tried doing it through AJAX but it won't go to the view page that I want it to go to, just reloads the same page. Here is my AJAX method
$(document).ready(function () {
$("button").click(function () {
$.ajax({
url: '#IGT.baseUrl/JODetails/SpecialOrderSummary',
data: $('#form').serialize(),
type: 'GET'
});
});
});
I am assuming that the client passes job and model in the request body.
I'll show what happens with this sequence: https://swimlanes.io/#pZLBbhNBDIbv+xRWLgUpTQq9rUQPBKjgkopEQj06u25notlxGHuT5u3xzCQpSHDitDP2rP35969eA7WwGFOiqPCRHO49j6lpmkXwOXR9BytKe0otONVdO5/3PKCPs46H+ZZ7UvRB5rKjzmPg1FMSCtSp59g0kZXaRp0XSPRzJFE4+BDA2hD4CDmx4f4I6gi2vAGMfTkPVjnMYJ2PpI574Cf4o44dH5artZFWvkxamVv4Tr1PxgDKgAUFvi0/VdQFR00cAqXZqkIvM/RqHAZMR7ggE/Bmm2tMCssEjjwCJoIdivj4DI7s0jNJvFL7wsGhlkf0YnV11mR4qWyJZMdR8j0Wqly/qwo7FOisBdzevCvzo+lCaEwwCdxhxm//JXWl/q9tnUvUwX84ioBntjf3zM+BYOESDzSFLybrE79M4YFFB4xT+BqFh+gROBUFyJq/tXk78nuSMouBgCjqKGVEe3h7874oZ2k2JdJlqSdlTC4zYVe1pj47JYfPapzkyfZ4NcSVnJ1iMQwHPArcf17XNZzGsYw1vGzwN6M9Wr+zVf5mi1fXlh8+xDGEpvkF
You just don't have to redirect the client, simply return the oter action's result:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SpecialOrderSelection(JobOrder job, ItemViewModel model)
{
return SpecialOrderSummary(model);
}

Pass parameter from Htmldropdownlistfor to controller

I have a model passed from controller to view in my asp.net mvc5 website. Then I show the dropdownlist using the model and I want to pass an id back when submitting the form. Here is my model :
public class SiteDirectionModel
{
public int id { get; set; }
public string name { get; set; }
}
Then in the model, I use a List<SiteDirectionModel> to which I add new instances of each item I need. I fill up both these lists and then pass my model to the view.
#model List<SiteDirectionModel>
#using (Html.BeginForm("GetSiteRF", "Create", FormMethod.Post))
{
#Html.DropDownListFor(x => x.name,new SelectList(Model.name,"Sites"));
<input type="button" value="Selectionner" class="btn btn-primary"/>
}
Then how to retrieve the ids for each name ? And how to pass it as a parameter to my controller? Such that I would have :
public ActionResult GetSiteRF(int id)
{
int newId = id;
//Call method to searchId ...
return View("CreateADUser");
}
I have given how to bind and get value from dropdown. Please use your own BL in this.
Your model should be like this.
public class Something
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SiteDirectionModel
{
public SelectList MyDropDown { get; set; }
public int SelectedValue { get; set; }
}
You BL should be like this.
public List<Something> GetListofSomething()
{
//your logic.
}
Your Get method should be like this.
public ActionResult MyGetMethod()
{
SiteDirectionModel model = new SiteDirectionModel();
model.MyDropDown = new SelectList(GetListofSomething(), "key_field_name", "value_field_name", "default_value");
}
Then finally HTML
#Html.DropDownListFor(x => x.SelectedValue,Model.MyDropDown)

Problems with passing two models to one view

i want to pass two models to one view using a ViewModel
My models :
public class Candidat
{
public int Id { set; get; }
public string num_cin { set; get; }
public ICollection<Poste> postes { get; set; }
}
public class Poste
{
public int Id { set; get; }
public string poste_name {set;get}
public List<Candidat> candidats {set;get;}
}
public class PosteCandidatViewModel
{
public Candidat candidat { get; set; }
public Poste poste { get; set; }
}
the controller action :
[HttpPost]
public ActionResult Index( Poste poste,string num_cin)
{
if (ModelState.IsValid)
{
var v = (from c in _db.Candidats
where c.num_cin == num_cin
&& c.postes.Any(p => p.Id == poste.Id)
select c)
.SingleOrDefault();
if (v != null)
{
return RedirectToAction("Inscription", "Candidat");
}
else
{
return RedirectToAction("index", "BureauOrdre");
}
}
return View();
the view :
#model ProcRec.Models.PosteCandidatViewModel
<td>#Html.TextBoxFor(model => model.candidat.num_cin)</td>
<td><p>#Html.DropDownListFor(model => model.poste.Id,new
SelectList(ViewBag.Postes, "Id", "intitule_poste"),"choisir le poste")
</p></td>
my problem is that the linq query is not giving the result i want
(but if i gave to num_cin an poste.id some values it's work )
so the problem is that num_cin not have a valu from dropdownlist ...it's like having an empty value!!!!!!!!!
Change the POST method signature to accept the model, and the access the model properties
[HttpPost]
public ActionResult Index(PosteCandidatViewModel model)
{
Poste poste = model.Poste;
string num_cin = model.Candidat.num_cin;
The reason that parameter string num_cin is null is because #TextBoxFor(model => model.candidat.num_cin) generates <input type="text" name="candidat.num_cin" ... />which is trying to map to property candidat that contains property num_cin. Alternatively upi can use
[HttpPost]
public ActionResult Index( Poste poste, [Bind(Prefix="candidat")]string num_cin)
{
Note, if ModelState is invalid, you need to reassign the the value of ViewBag.Postes that you use in DropDownListFor()
if (ModelState.IsValid)
{
....
}
ViewBag.Postes = // set the value here before returning the view
return View(model);

Binding a nested collection in MVC3

I have a ViewModel which contains a list of polymorphic objects.
public class InputParameters
{
public InputParameters()
{
InputPrompts = new List<IInputPrompt>();
}
public string Name { get; set; }
public string Path { get; set; }
public IList<IInputPrompt> InputPrompts { get; set; }
}
Which in turn look this:
public interface IInputPrompt
{
string Name { get; set; }
bool IsHidden { get; set; }
bool IsRequired { get; set; }
dynamic Value { get; set; }
}
public class TextPrompt : IInputPrompt
{
public string Name { get; set; }
public bool IsHidden { get; set; }
public bool IsRequired { get; set; }
public dynamic Value { get; set; }
}
public class MultiSelectPrompt : IInputPrompt
{
public string Name { get; set; }
public bool IsHidden { get; set; }
public bool IsRequired { get; set; }
public dynamic Value { get; set; }
public MultiSelectList Values
{
get
{
return new MultiSelectList(((IDictionary<int, string>)Value).ToList(), "Key", "Value");
}
}
}
There is a Editor View Template for each of the derived types, the views look this this:
#model OptionListModelBinding.Models.InputParameters
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
<fieldset>
<legend><strong>#Model.Name</strong></legend>
<div><em>#Model.Path</em></div>
<div>#Html.EditorFor(p => p.InputPrompts)</div>
<div><input type="submit" /></div>
</fieldset>
}
// editor template
#model OptionListModelBinding.Models.InputParameters
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm())
{
<fieldset>
<legend><strong>#Model.Name</strong></legend>
<div><em>#Model.Path</em></div>
<div>#Html.EditorFor(p => p.InputPrompts)</div>
<div><input type="submit" /></div>
</fieldset>
}
// editor template
#model OptionListModelBinding.Models.MultiSelectPrompt
#{
ViewBag.Title = "MultiSelectPrompt";
}
<h2>MultiSelectPrompt</h2>
<div><strong>#Model.Name</strong></div>
<div><em>#Html.ListBox(Model.Name, Model.Values)</em></div>
This all renders nicely:
The question is this:
How do I bind this back to the model? I have a custom model binder: (excuse the hacked up nature of this code).
public class InputParameterModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException("bindingContext");
}
// iterate over the form fields
foreach (string item in controllerContext.HttpContext.Request.Form.AllKeys)
{
// this is where the problem is ... I cannot use the generic here.
var dog = FromPostedData<string>(bindingContext, item);
}
InputParameters userInput = new InputParameters();
return userInput;
}
// Dino Esposito code
private T FromPostedData<T>(ModelBindingContext context, string id)
{
if (String.IsNullOrEmpty(id)) return default(T);
var key = String.Format("{0}.{1}", context.ModelName, id);
var result = context.ValueProvider.GetValue(key);
if (result == null && context.FallbackToEmptyPrefix)
{
result = context.ValueProvider.GetValue(id);
if (result == null) return default(T);
}
context.ModelState.SetModelValue(id, result);
T valueToReturn = default(T);
try
{
valueToReturn = (T)result.ConvertTo(typeof(T));
}
catch { }
return valueToReturn;
}
}
EDIT
Did i mention that the items in the list are determined at runtime?
EDIT
This is the front end of a report generating tool. The backend service provides a list of available reports and the parameters needed to run each one. None of this is known at compile time and the report definitions can even change with the web portal needing to be recompiled.
I can have a variable number and type of input parameters.
I don't think you need the custom binder. You can simply pass back your view model to the post method:
[HttpPost]
public ActionResult ProcessForm(InputParameters viewModel)
{
...
}
The default MVC binder will match up the form values with the properties of the InputParameters argument. You may need to use a [Bind] attribute on that argument to indicate a variable name prefix that the binder must look for if your view uses any kind of special form variable names.
You cannot expect MVC to instantiate an IInputPrompt because it has not logic to figure out what class you actually want. Your options are to either create a ModelBinder for model binding to this specific interface, or changing the interface into a concrete class.

Categories

Resources