How to keep track of things in asp.net.mvc? - asp.net-mvc

I'm developing a small web application and I need help tracking states.
This application ask few questions to a user in a random manner (one at a time). But, to do so, I need to know which question already been answered (so I don't repeat any questions) and if the user got it right or not.
I need to know if the user got the last question right because, if he awnsers wrong, the application will ask a random question from a different list.
To do so, I created this class "state" in the controller which is supposed to keep track of things.
public class state
{
public string via { get; set; }
public string previousQuestionList { get; set; }
public string currentQuestionList { get; set; }
public string leftButton { get; set; }
public string rightButton { get; set; }
public List<Question> previousQuestions { get; set; }
public Question currentQuestion { get; set; }
public bool lastAnswer { get; set; }
}
So, when the user enters the page for the first time, the controller send a default information to the view and it constructs the page.
public ActionResult Index()
{
state currentState = new state();
currentState.currentQuestion = new Question();
currentState.currentQuestion.description = "Qual a via do seu cartão?";
currentState.currentQuestion.aplicabilidade = true;
currentState.leftButton = "1a Via";
currentState.rightButton = "2a Via";
return View(currentState);
}
And the view looks like this:
The html code is something like this:
#{
ViewBag.Title = "Sistema de Script de Desbloqueio";
}
#model Sistema_de_Script_de_Desbloqueio.Controllers.HomeController.state
<div class="jumbotron">
<h1>#Model.currentQuestion.description</h1>
</div>
<form name="Formulário" action="~/Views/Home/Index.cshtml" method="post">
#if (Model.currentQuestion.aplicabilidade == true)
{
<div class="row">
<div class="col-md-6">
<div class="btn btn-primary btn-group-justified" role="group"><h2>#Model.leftButton</h2></div>
</div>
<div class="col-md-6">
<div class="btn btn-warning btn-group-justified" role="group"><h2>#Model.rightButton</h2></div>
</div>
</div>
}
else
{
<div class="row">
<div class="col-md-4">
<div class="btn btn-primary btn-group-justified" role="group"><h2>#Model.leftButton</h2></div>
</div>
<div class="col-md-4">
<div class="btn btn-warning btn-group-justified" role="group"><h2>#Model.rightButton</h2></div>
</div>
<div class="col-md-4">
<div class="btn btn-default btn-group-justified" role="group"><h2>N/A</h2></div>
</div>
</div>
}
</form>
My idea is that the user press one of the buttons and send the object of the class "state" (model) back along with the information of which button was pressed to the controller.
Is it possible?

I used the tip from "elolos" and used "Session" to maintain the date and worked just fine.
public ActionResult Index()
{
state currentState = new state();
//Some code here
Session["currentState"] = currentState
return View(currentState);
}
And then in the "Post" method I retrieved the information from "currentState"
[HttpPost]
public ActionResult Index(string lastButton)
{
state currentState = Session["currentState"] as state;
//Some code here
return View(currentState);
}
Thank you.

Easiest way would be to perform simple Postback or AJAX POST from view you are creating.
Add property for last button clicked to model:
public string LastClickedButton { get; set; }
Then add ActionResult to POST to:
public ActionResult IndexPost(state postedState)
{
//Do stuff.
}
And perform POST from view:
#{
ViewBag.Title = "Sistema de Script de Desbloqueio";
}
#model Sistema_de_Script_de_Desbloqueio.Controllers.HomeController.state
<div class="jumbotron">
<h1>#Model.currentQuestion.description</h1>
</div>
<form name="Formulário" action="~/Views/Home/Index.cshtml" method="post">
#if (Model.currentQuestion.aplicabilidade == true)
{
<div class="row">
#using (#Html.BeginForm("IndexPost", "Home"))
{
<div class="col-md-6">
<div class="btn btn-primary btn-group-justified" role="group"><h2>#Model.leftButton</h2></div>
</div>
#Html.Hidden("LastClickedButton", #Model.leftButton);
}
#using (#Html.BeginForm("IndexPost", "Home"))
{
<div class="col-md-6">
<button class="btn btn-warning btn-group-justified" role="group" type="submit"><h2>#Model.rightButton</h2></div>
</button>
#Html.Hidden("LastClickedButton", #Model.rightButton);
}
</div>
}
else
{
<div class="row">
<div class="col-md-4">
<button class="btn btn-primary btn-group-justified" role="group" type="submit"><h2>#Model.leftButton</h2></button>
</div>
<div class="col-md-4">
<div class="btn btn-warning btn-group-justified" role="group"><h2>#Model.rightButton</h2></div>
</div>
<div class="col-md-4">
<div class="btn btn-default btn-group-justified" role="group"><h2>N/A</h2></div>
</div>
</div>
}
</form>
Downright of this is that you need to send all the information you received, so many redundant #Html.Hidden/#Html.HiddenFor will be produced.
Another way round this is you can change Controller action to:
public ActionResult IndexPost(state postedState, string clickedButton)
{
//Do anything you need with clickedButton
}
And post clickedButton via route:
#using (#Html.BeginForm("IndexPost", "Home", new { clickedButton = #Model.rightButton }))
{
<div class="col-md-6">
<button class="btn btn-warning btn-group-justified" role="group" type="submit"><h2>#Model.rightButton</h2></div>
</button>
}

Related

Model binding null values in MVC Core

I am trying to post data from form to action method but looks like model binder is not binding to the entities and I am getting null values in the action method, your help is much appreciated
please find the code snippet below.
Action method
[HttpPost]
public async Task<IActionResult> Update(EditRoleViewModel model)
{
if (ModelState.IsValid)
{
var role = await _Roleame.FindByIdAsync(model.Id);
if (role == null)
{
return RedirectToAction("notfound");
}
role.Name = model.RoleName;
var result = await _Roleame.UpdateAsync(role);
if (result.Succeeded)
{
return RedirectToAction("getAllRoles", "Administrator");
}
}
else {
ModelState.AddModelError(string.Empty, "Error");
}
return View();
}
Model
public class EditRoleViewModel
{
public EditRoleViewModel()
{
names = new List<string>();
}
public string Id;
[Required]
public string RoleName;
public List<string> names;
}
View
#model FirstCoreApplication.Model.EditRoleViewModel
<script src="~/twitter-bootstrap/js/bootstrap.js"></script>
<link href="~/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
#{
ViewBag.Title = "Edit Role";
}
<h1>Edit Role</h1>
<form method="post" class="mt-3" asp-controller="Administrator" asp-action="Update">
<div class="form-group row">
<label asp-for="Id" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Id" disabled class="form-control">
</div>
</div>
<div class="form-group row">
<label asp-for="RoleName" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="RoleName" class="form-control">
<span asp-validation-for="RoleName" class="text-danger"></span>
</div>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Update</button>
<a asp-action="ListRoles" class="btn btn-primary">Cancel</a>
</div>
</div>
<div class="card">
<div class="card-header">
<h3>Users in this role</h3>
</div>
<div class="card-body">
#if (Model.names.Any())
{
foreach (var user in Model.names)
{
<h5 class="card-title">#user</h5>
}
}
else
{
<h5 class="card-title">None at the moment</h5>
}
</div>
<div class="card-footer">
Add Users
Remove Users
</div>
</div>
</form>
enter code here
I've spent couple of hours looking for an error in my code and the reason for the binder not working in my case was using a model with public fields rather than public properties:
public class EditRoleViewModel
{
public EditRoleViewModel()
{
names = new List<string>();
}
public string Id { get; set; }
[Required]
public string RoleName { get; set; }
public List<string> names { get; set; }
}
The form data you post does not match the property of your model.You do not post the parameter names .
public List names { get; set; }

How to make your button on a form using asp.net-mvc work?

I have a button, it does not seem to create new users to my database. What it does it only inherits user validaton to my Login method and need some guidance to this please and thanks. Below is the logic what i am trying to do. What i want to do my create button must be able to create new users if not exist to the database.
Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateModel objSubmit)
{
ViewBag.Msg = "Details submitted successfully";
return View(objSubmit);
}
// This is for login, and its hits this method each time.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(Login login)
{
if (ModelState.IsValid)
{
bool success = WebSecurity.Login(login.username, login.password, false);
var UserID = GetUserID_By_UserName(login.username);
var LoginType = GetRoleBy_UserID(Convert.ToString(UserID));
if (success == true)
{
if (string.IsNullOrEmpty(Convert.ToString(LoginType)))
{
ModelState.AddModelError("Error", "Rights to User are not Provide Contact to Admin");
return View(login);
}
else
{
Session["Name"] = login.username;
Session["UserID"] = UserID;
Session["LoginType"] = LoginType;
if (Roles.IsUserInRole(login.username, "Admin"))
{
return RedirectToAction("AdminDashboard", "Dashboard");
}
else
{
return RedirectToAction("UserDashboard", "Dashboard");
}
}
}
else
{
ModelState.AddModelError("Error", "Please enter valid Username and Password");
return View(login);
}
}
else
{
ModelState.AddModelError("Error", "Please enter Username and Password");
return View(login);
}
}
Model:
namespace eNtsaPortalWebsiteProject.Models
{
public class CreateModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string password { get; set; }
[Required]
public string username { get; set; }
}
}
// View for login
<div data-="mainContent">
<section class="container">
<div class="logo col-sm-12 text-center col-md-12"> <img alt="" src="~/Images/eNtsa.png" /></div>
<div class="clearfix"></div>
<div class="container">
<div class="row">
<div id="MyWizard" class="formArea LRmargin">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="divMessage" class="text-center col-md-12 col-md-offset-12 alert-success">
#Html.ValidationSummary()
</div>
<div class="col-md-12 col-md-offset-10 col-xs-12">
<div class="loginPage panel-info">
<div class="form-group"><span class=""><i class="glyphicon glyphicon-user">Username:</i></span>
#Html.TextBoxFor(model => model.username, new { #class = "form-control text-center", autocomplete = "off" })
#Html.ValidationMessageFor(model => model.username)
</div>
<div class="form-group">
<span class=""><i class="glyphicon glyphicon-lock">Password:</i></span>
#Html.PasswordFor(model => model.password, new { #class = "form-control text-center", autocomplete = "off" })
#Html.ValidationMessageFor(model => model.password)
</div>
</div>
<div class="form-group">
<input id="BtnLogin" type="submit" class="btn btn-success btn-pressure" name="BtnLogin" value="Login" />
<input type ="Submit" class="btn btn-info btn-pressure" name="BtnCreate" value="Create" />
</div>
</div>
}
<div class="clear"></div>
</div>
</div>
</div>
</section>
</div>
View for creating user:
<div class="mainContent">
<section class="container">
<div class="logo col-sm-12 text-center col-md-10">
<img alt="" src="~/Images/eNtsa.png"/>
</div>
<div class="container">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="divMessage" class="text-center col-md-12 col-md-offset-12 alert-success">
#Html.ValidationSummary()
</div>
<div class="col-md-12 col-md-offset-10 col-xs-12">
<div class="glyphicon-registration-mark">
<div class="form-group"><span class=""><i class="glyphicon glyphicon-user">Username:</i></span>
#Html.TextBoxFor(model=>model.username, new {#class ="form-control text-center", automplete="off" })
#Html.ValidationMessageFor(model=>model.username)
</div>
<div class="form-group">
<span class=""><i class="glyphicon glyphicon-lock">Password:</i></span>
#Html.PasswordFor(model=>model.password, new {#class = "form-control text-center", autocomplete="off" })
#Html.ValidationMessageFor(model=>model.password)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-success btn-pressure" name="BtnSubmit" value="Submit"/>
</div>
</div>
}
</div>
</section>
</div>
The button is working - that isn't the problem that you're having.
You can have multiple buttons to submit the form but they will return to the same place, either:
a) the controller/action specified in the "action" property of the form
b) if no action is specified then the default location - in your case there isn't one directly specified so it is posting back to the default location.
(see: How to link HTML5 form action to Controller ActionResult method in ASP.NET MVC 4)
The easiest way to accomplish what you're trying to do would be refactor your controller and branch the logic depending on what the value is of the submit button.
(see: MVC razor form with multiple different submit buttons?
and How to handle two submit buttons on MVC view)
This will require some refactoring of the code that you have written, but it is the most straightforward way of achieving what you're trying to do.
In very basic terms it would look something like this:
Model:
namespace eNtsaPortalWebsiteProject.Models
{
public class LoginCreateModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string password { get; set; }
[Required]
public string username { get; set; }
public string btnSubmit { get; set; } // both buttons will have the same name on your form, with different values ("Create" or "Login")
}
}
Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginCreateModel objSubmit)
{
if (objSubmit.btnSubmit == "Create")
{
// Handle creation logic here
}
if (objSubmit.btnSubmit == "Login")
{
// Handle login logic here
}
return View(objSubmit);
}

How Can I Get ViewData in PartialView in Razor Pages

I'm Using Razor Pages For my App, in one part of my app I've used a partial view here is my codes;
public class Permission
{
[Key]
public int PermissionId { get; set; }
public string PermissionTitle { get; set; }
public int? ParentID { get; set; }
}
public class IndexModel : PageModel
{
public PartialViewResult OnGetCreateRole()
{
var ListPermission = permissionService.AllPermission();
return new PartialViewResult()
{
ViewName = "_PCreateRole", // partial's name
ViewData = new ViewDataDictionary<List<Permission>>(ViewData,
ListPermission)
};
}
}
ViewData is a List of Permission class and i've sent ViewData to partial but i dont know how to get ViewData, also my partial use another model, below is my partial:
#model ToMVC.DataLayer.Entities.User.Role
<div class="row">
<div class="col-md-12">
<form asp-page="CreateRole" method="post">
<div class="form-group">
<label class="control-label">Title</label>
<input asp-for="RoleTitle" class="form-control"/>
<p><span class="text-danger" asp-validation-for="RoleTitle"></span></p>
</div>
<div class="form-group">
<input type="submit" value="submit" class="btn btn-primary" />
</div>
//this part needs ViewData
#foreach (var item in ViewData)
{
}
</form>
</div>
</div>
I want to use ViewData in Foreach loop.
A better solution than ViewData would be to simply make a new ViewModel class containing all the information you need for a view.
public class UserRoleAndPermissions{
public UserRoleAndPermissions(){
Permissions = new List<Permissions>();
}
public List<Permission> Permissions {get;set;}
public ToMVC.DataLayer.Entities.User.Role Role {get;set;}
}
And your view
//check your namespace here - this is just an example
#model ToMVC.DataLayer.UserRoleAndPermissions
<div class="row">
<div class="col-md-12">
<form asp-page="CreateRole" method="post">
<div class="form-group">
<label class="control-label">Title</label>
<input asp-for="RoleTitle" class="form-control"/>
<p><span class="text-danger" asp-validation-for="RoleTitle"></span></p>
</div>
<div class="form-group">
<input type="submit" value="submit" class="btn btn-primary" />
</div>
#foreach (var item in Model.Permissions)
{
}
</form>
</div>
</div>

How to get the Partial View object on form submit

How to get the Partial View object on form submit
Main View:
#model CreateCampaignModel
....
#using (Html.BeginForm("SubmitForm", "Campaign", FormMethod.Post))
{
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapse2">Step 2: Creative*</a>
</h4>
<a style="padding-left:90%;" id="lnkEdit">Edit</a>
</div>
#Html.EditorFor(m => Model.campaignCreativeModelList[0])
#foreach (var m in Model.campaignCreativeModelList)
{
<div id="collapse2" class="panel-collapse collapse">
#Html.Partial("~/Views/Campaign/_Creative.cshtml", m)
</div>
}
</div>
}
Creative Partial View:
<div class="panel-body">
<div class="form-group">
#Html.Partial("~/Views/Shared/_ImageVideoUploadView.cshtml", Model.socialJobMediaModel)
</div>
<div class="col-md-10">
<div class="editor-field">
<input type="submit" name="Save Group" value="Review and Submit" class="btn btn-primary" />
</div>
</div>
</div>
My Controller Action:
[HttpPost]
public ActionResult SubmitForm(CreateCampaignModel createCampaignModel)
{
return (View(BindCampaignModel()));
}
I want to return the campaignCreativeModel object to the controller with all the collections of partial views inside partial views.
My Main Model:
public class CreateCampaignModel
{
public List<CampaignCreativeModel> campaignCreativeModelList { get; set; }
public List<ClientAccountCampaignBundlesModel> clientAccountCampaignBundlesModelList { get; set; }
public List<CampaignBundleSchedulesModel> campaignBundleSchedulesModelList { get; set; }
public List<CampaignConfigurationModel> campaignConfigurationModelList { get; set; }
public CampaignConfigurationModel campaignConfigurationModel { get; set; }
}
My model have all the collections related to partial views in the main view.
Screenshot:
I haven't gone through your code completely
[HttpPost]
public ActionResult SubmitForm(list<CreateCampaignModel> createCampaignModelList)
{
return (View(BindCampaignModel()));
}
this is the idea, you can get collection,if you are building the partial view from the model, I haven't tested the code..

After submit a form in a Area not displayed none of validation message?

I have a area and at this area i have a PostController, and a action with Add name for GET method and a action with Add name for POST method,after submit form i add error to modelstate BUT after postback,not displayed none of validation message and staus code is:301 Moved Permanently !!!
my viewmodel:
public class NewPostViewModel
{
[Required(ErrorMessage = "Please enter title.")]
public string Title { get; set; }
[AllowHtml]
[Required(ErrorMessage = "Please enter article content.")]
public string Content { get; set; }
[Required(ErrorMessage = "Please enter a tag.")]
public string Tags { get; set; }
public bool PublishNow { get; set; }
public string PublishDate { get; set; }
public string PublishTime { get; set; }
}
my view:
#model Soleimanzadeh.Models.ViewModels.NewPostViewModel
#{
ViewBag.Title = "Add";
Layout = MVC.Admin.Shared.Views.BaseLayout;
}
#using (Html.BeginForm(MVC.Admin.Post.Add(), FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(false, null, new { #class = "alert" })
<div class="row-fluid">
<div class="span9">
<div class="row-fluid">
<div class="span8">
#Html.TextBoxFor(np => np.Title, new { #class = "span12", placeholder = "Title" })
#Html.ValidationMessageFor(model=>model.Title)
</div>
</div>
<div class="row-fluid">
<div class="span12">
#Html.TextAreaFor(np => np.Content)
#Html.ValidationMessageFor(model=>model.Content)
</div>
</div>
</div>
<div class="span3">
<div class="row-fluid">
<div class="post-options-container">
<div class="header">
Tags
</div>
<div class="content">
<input type="text" placeholder="tags" class="tagManager" style="width: 100px;" />
</div>
</div>
</div>
<div class="row-fluid">
<div class="post-options-container">
<div class="header">
Status
</div>
<div class="content">
<label class="checkbox">
#Html.CheckBoxFor(np => np.PublishNow)
Publish Now?
</label>
<div>
Publish Date:
#Html.TextBoxFor(np => np.PublishDate, new { #class = "calcInput" })
</div>
<div>
Publish Time:
#Html.TextBoxFor(np => np.PublishTime, new { #class = "timeInput" })
</div>
<div>
<input type="submit" value="Save"/>
</div>
</div>
</div>
</div>
</div>
</div>
}
#*some scripts here*#
my controller:
public partial class PostController : Controller
{
public virtual ActionResult Add()
{
var newPost = new NewPostViewModel();
return View(MVC.Admin.Post.Views.Add, newPost);
}
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult Add(NewPostViewModel post)
{
ModelState.AddModelError("Content","Wrong");
return this.View(MVC.Admin.Post.Views.Add, post);
}
}
Also i use redactor html editor for Content.
Solution:
i use http://lowercaseroutesmvc.codeplex.com/ for convert urls to lowercase,but i not enabled this tool in area section and page redirectd after submit form.

Resources