I'm very new to ASP.NET, but I've added a FirstName (string), LastName (string), and AccountType (int, which can be a 0, 1, or 2) to my AspNetUsers database. I am working in MVC 5. While I've found numerous articles about changing the password, but I'd like to add the ability to let users change AccountType.
I am aware that the Roles might have been a better option in this case, but I've implemented so much already I'd rather not change that now.
The form for the Account Type Change contains a field for the user to input his/her password (to confirm that they would like the Account Type changed, and a dropdown list giving three options whose value is either 0, 1, or 2.
In short, the user will enter their password, click an option on the dropdownlist, then click the "sumbit button" and AccountType will be changed to a different int
#using SouthMeckNTHS.Models
#using SouthMeckNTHS.Extensions
#model ChangeAccountViewModel
#{
ViewBag.Title = "Change Account Type";
}
<section class="engine"></section>
<section class="mbr-section article mbr-parallax-background mbr-after-navbar" id="msg-box8-7d" style="background-image: url(../assets/images/full-unsplash-photo-1438354886727-070458b3b5cf-2000x1553-39.jpg); padding-top: 120px; padding-bottom: 80px;">
<div class="mbr-overlay" style="opacity: 0.5; background-color: rgb(34, 34, 34);">
</div>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2 text-xs-center">
<h3 class="mbr-section-title display-2">MANAGE YOUR ACCOUNT</h3>
<div class="lead"><p>Change your account settings</p></div>
</div>
</div>
</div>
#using (Html.BeginForm("AccountChange", "Manage", FormMethod.Post, new {
#class = "form-horizontal", role = "form" }))
{
Html.AntiForgeryToken();
<div class="mbr-section mbr-section__container mbr-section__container--middle">
<div class="container">
<div class="row">
<div class="col-xs-12 text-xs-center">
</div>
</div>
</div>
</div>
<div class="mbr-section mbr-section-nopadding">
<div class="container">
<div class="row">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="col-xs-12 col-lg-10 col-lg-offset-1">
<div class="row row-sm-offset">
<div class="col-xs-12 col-md-12">
<div class="form-group">
<label class="form-control-label" for="form1-z-name">Enter your current email<span class="form-asterisk">*</span></label>
#Html.TextBoxFor(m => m.CurrentPassword, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.CurrentPassword, "", new { #class = "text-danger", #style = "color:white" })
<!--<input type="text" class="form-control" name="name" required="" data-form-field="Name" id="form1-z-name">-->
</div>
</div>
<div class="col-xs-12 col-md-12">
<div class="form-group">
<label class="form-control-label" for="form1-z-name">Choose Your Account Type<span class="form-asterisk">*</span></label>
#Html.DropDownListFor(
m => m.NewAccountType,
new SelectList(
new List<Object>
{
new { value = 0 , text
= "Learner" },
new { value = 1 , text
= "Contributor" },
new { value = 2 , text
= "Competitor"}
},
"value",
"text"
), new { #style = "border: 1px solid #e8e8e8;padding: 0.5em 1.07em 0.5em;background: #f5f5f5;font-size: 0.875rem;border-radius: 5px;width: 100%;line-height: 1.43;min-height: 3.5em;" }
)
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="mbr-section mbr-section__container" id="buttons1-r" style="background-color: rgb(255, 255, 255); padding-top: 10px; padding-bottom: 5px;">
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="text-xs-center"><input type="submit" class="btn btn-primary text-xs-center" value="CHANGE ACCOUNT TYPE" /> </div>
</div>
</div>
</div>
</section>
}
And here is part of ManageViewModels.cs:
public class ChangeAccountViewModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string CurrentPassword { get; set; }
[Required]
[Display(Name = "Choose Account Type")]
public int NewAccountType { get; set; }
}
So, likely in ManageController.cs, what should I add to allow the information from the first part of the form to check against the user's password and what should I add to the same file so that (if the passwords match) it will update the AccountType database with the user's choice?
(An edited copy of the "change password" function did not work)
UPDATE
I added this to ManageController.cs:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AccountChange(ChangeAccountViewModel model)
{
if (ModelState.IsValid)
{
// Get the current application user
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
//Update the details
user.AccountType = model.NewAccountType;
// Update user address
var result = await UserManager.UpdateAsync(user);
}
return View(model);
}
But it only works once. I run a test of it, I change the user's account type, and it saves to the AspNetUsers db. However, when I run it again, I can't change it anymore in ANY user accounts. What should I do to get this to work every time the user changes the dropdownlist and clicks the submit button?
I decided to just log the user out and have them sign back in.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AccountChange(ChangeAccountViewModel model)
{
//THE THING THAT ONLY WORKED ONCE:
if (ModelState.IsValid)
{
// Get the current application user
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
//Update the details
user.AccountType = model.NewAccountType;
// Update user account type
var result = await UserManager.UpdateAsync(user);
if (result.Succeeded)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return RedirectToAction("../Account/Login");
}
}
return View(model);
}
Related
I am working on a new Asp.Net MVC project and this time to have better control over the static contents of the application, I am planning to store all content as reusable properties in readonly static variables. These values are not going to change throughout the application's lifecycle.
Example of usage:
I have created a class holding all messages in static variables so that if I want to change let's say, the default save message I can change it from here without having a need to change every occurrence in the project. This includes validation messages also. (numbers could grow rapidly, depending upon the size of the project)
Other usages: To store all application-related properties such as version, title, keys, and many more. I am also planning to store the button texts and other UI controls-related properties so that they can be easily customized, such as I don't know maybe CSS classes.
And not to mention, apart from the above I also have a number of static classes such as Data Access Helpers and Utility Functions with some static methods.
Sample Class:
public static class Messages
{
public static class Response
{
public readonly static string SUCCESS = "Process completed successfully";
public readonly static string FAILED = "Process failed";
public readonly static string ERROR = "Some error occured";
public readonly static string OPRNOTPERFORMED = "Operation aborted/failed for some unknown reason. Please contact your administrator";
//LOGIN
public readonly static string USERNOTFOUND = "Invalid username or password";
public readonly static string USERINACTIVE = "User is not active. Please contact your administrator";
public readonly static string NOROLEDEFINED = "User does not have any valid authority to access the application. Please contact your administrator";
public readonly static string FORCELOGOUT = "You have been logged out. Please login again";
//MASTERS
public readonly static string NOSTATESFOUND = "No states found in database. please contact your administrator";
public readonly static string APPCHOICENOTFOUND = "Option not found in the database. Please contact your system administrator.";
//COMPANY
public readonly static string INVALIDCOMPANY = "Please sign out from the application and login again before performing further opreations";
}
public static class Description
{
//COMPANY
public readonly static string INVALIDCOMPANY = "Company value changed between 2 consiquent requests. This happens when you left the page idle for so long. Please login again before performing further operations.";
}
public static class Instructions
{
public readonly static string MANDATORY_FIELDS = "Fields marked with <i class='text-warning-dark fw-bold fs-6'>*</i> cannot be blank.";
}
}
As of now, these are all on paper only. I am willing to take this approach so that I can easily customize the text contents according to different clients' needs. But before that, I have a few doubts to clear.
Does all static variables initialized and stored in memory as we run the web application?
Does all static variables remain in memory throughout the lifecycle of the web application, irrespective of its usage in the current View?
Does the compiler replace the occurrences of the static variable with its actual value at the time of converting the source code into bytecode? (I have seen this in java when I decompiled the class file, wherever I used the static variables, it is replaced with its actual value).
Another Example:
public class Select
{
private static readonly SelectListItem defaultChoice = new SelectListItem { Text = "Select", Value = "" };
public static readonly IEnumerable<SelectListItem> ISACTIVE = new List<SelectListItem>
{
new SelectListItem {Text = "Active", Value = "true"},
new SelectListItem {Text = "Inactive", Value = "false"}
};
private static IList<SelectListItem> STATES;
public static IEnumerable<SelectListItem> GetStates(string sessionHash)
{
if (sessionHash == null)
{
return null;
}
if (STATES == null)
{
StateService stateService = new StateService(sessionHash);
ProcessResponse response = stateService.GetStates();
IList<StateModel> statesModel = (IList<StateModel>)response.Data[0];
STATES = new List<SelectListItem>();
STATES.Add(defaultChoice);
foreach (StateModel state in statesModel)
{
STATES.Add(new SelectListItem { Text = state.Name, Value = state.StateId.ToString() });
}
}
return STATES;
}
public static IEnumerable<SelectListItem> AppChoices(IList<AppChoicesModel> choicesModel)
{
IList<SelectListItem> choices = new List<SelectListItem>();
choices.Add(defaultChoice);
if (choicesModel != null && choicesModel.Count > 0)
{
foreach(AppChoicesModel choice in choicesModel)
{
choices.Add(new SelectListItem { Text = choice.Text, Value = choice.Value });
}
}
return choices;
}
}
Usage in View
#model Cygnus.View.Models.Company.CompanyBranch
#using Cygnus.Data.Constants
#{
Layout = "~/Views/Shared/_LayoutDashboard.cshtml";
ViewBag.Title = Titles.Company.BRANCHT;
ViewBag.SubTitle = Titles.Company.BRANCHST;
var moduleName = Routes.Company.BRANCH;
var isActive = Select.ISACTIVE;
var states = Select.GetStates(Session[Codes.SessionParams.HASH].ToString());
Html.RenderPartial(Routes.Commons.PROCRESPONSE);
}
<div class="container-fluid">
<div class="row">
<!-- left column -->
<div id="#string.Format("{0}Form_Container", #moduleName)" class="col-md-7 mt-1 collapse show">
<!-- general form elements -->
<div class="card card-info">
<div class="card-header">
<h3 class="card-title">#ViewBag.SubTitle</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
#using (Html.BeginForm(moduleName, Routes.Company.CONTROLLER, FormMethod.Post, new { #name = moduleName }))
{
#Html.HiddenFor(model => model.CompanyId)
#Html.HiddenFor(model => model.CompanyBranchId)
#Html.AntiForgeryToken()
<div class="card-body">
<div class="row gx-3">
<div class="col-10">
<i class="fas fa-info-circle text-info mr-2"></i>#Html.Raw(#Messages.Instructions.MANDATORY_FIELDS)
</div>
<div class="col-2">
<button class="btn btn-block btn-info btn-flat size-width-auto float-right" value="#Codes.ButtonValue.ADD" name="#Codes.ButtonGroupName.ACTION" ><i class="fas fa-plus-square fa-1xl align-middle mr-2"></i><span class="align-middle">#Codes.ButtonValue.NEW</span></button>
</div>
</div>
<div class="row gx-3 mt-3">
<div class="input-group-sm col">
<label for="Name" class="fw-semibold">#Html.DisplayNameFor(model => model.Name)</label>
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control input-required", #placeholder = "Branch Name" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger fs-6-5" })
</div>
<div class="input-group-sm col-4">
<label for="Code" class="fw-semibold">#Html.DisplayNameFor(model => model.Code)</label>
#Html.EditorFor(model => model.Code, new { htmlAttributes = new { #class = "form-control input-required", #placeholder = "Branch Code" } })
#Html.ValidationMessageFor(model => model.Code, "", new { #class = "text-danger fs-6-5" })
</div>
</div>
<div class="row gx-3 mt-5px">
<div class="input-group-sm col">
<label for="State" class="fw-semibold">#Html.DisplayNameFor(model => model.State)</label>
#Html.DropDownListFor(model => model.State, states, new { #class = "form-control input-required" })
#Html.ValidationMessageFor(model => model.State, "", new { #class = "text-danger fs-6-5" })
</div>
<div class="input-group-sm col-2">
<label for="Pincode" class="fw-semibold">#Html.DisplayNameFor(model => model.Pincode)</label>
#Html.EditorFor(model => model.Pincode, new { htmlAttributes = new { #class = "form-control input-required", #placeholder = "Pincode" } })
#Html.ValidationMessageFor(model => model.Pincode, "", new { #class = "text-danger fs-6-5" })
</div>
<div class="input-group-sm col">
<label for="BranchType" class="fw-semibold">#Html.DisplayNameFor(model => model.BranchType)</label>
#Html.DropDownListFor(model => model.BranchType, Model.BranchTypeList, new { #class = "form-control input-required" })
#Html.ValidationMessageFor(model => model.BranchType, "", new { #class = "text-danger fs-6-5" })
</div>
</div>
<div class="row gx-3 mt-5px">
<div class="input-group-sm col">
<label for="IsActive" class="fw-semibold">#Html.DisplayNameFor(model => model.IsActive)</label>
#Html.DropDownListFor(model => model.IsActive, isActive, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.IsActive, "", new { #class = "text-danger fs-6-5" })
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" value="#Codes.ButtonValue.SAVE" name="#Codes.ButtonGroupName.ACTION" class="btn btn-success px-5">#Codes.ButtonValue.SAVE</button>
<div>#Html.ValidationSummary(true, "", new { #class = "text-danger" })</div>
</div>
}
</div>
<!-- /.card -->
</div>
<div class="col-md mt-1">
#{
Html.RenderAction(Routes.Company.BRANCHLIST, Routes.Company.CONTROLLER);
}
</div>
</div>
</div>
#section Scripts {
#Scripts.Render("~/Scripts/Cygnus/Company.js")
<script>
$(function () {
var tableId = "#listOfCompanyBranch";
initDataTableWithDefaultToolbar(tableId, '#moduleName');
attachRowDataEvenOnATag(tableId);
});
function onRowClicked(rowData, row) {
let formElement = $("##string.Format("{0}Form_Container",moduleName)");
if ($(formElement).is('.collapse:not(.show)'))
$(formElement).collapse("show");
document.getElementById("CompanyBranchId").value = $(row).attr("data-branch");
document.getElementById("CompanyId").value = $(row).attr("data-company");
FillFormControls(formArr["#moduleName"], rowData);
$("#IsActive").val((rowData[13]).toLocaleLowerCase());
}
</script>
}
Does Having Hundreds of Readonly Static Variables Cause Performance
Issues?
No. The variables in your example are a few bytes each. Let's say you have 500 variables, and they are 20 bytes each. That would be 10KB. Modern web servers generally have several gigabytes of memory, so it is unlikely that you face any performance issue because you are caching 10KB of data. See here for more info about static variables.
IMO, the main issue with having too many static types (class/variable) is that you don't know where to find them. In the examples that you have provided, it seems like you are hardcoding some constants into static variables. IMO that’s fine, provided:
You don’t define configuration variables as constants (things like connection strings, which are environment dependent)
You are using a logical approach to group these constants, so they are easy to find
I would try to limit the size of such constants (not because of performance but to keep the code clean)
Looking at your code, there might be more elegant ways to achieve this, for example you can define an interface called IResponse:
interface IResponce
{
short Code { get; }
string CssColor { get; }
string Message { get; }
}
and define different classes for response types, for example:
public class SuccessResponse : IResponse
{
public short Code => 0;
public string CssColor => "green";
public string Message => "Process completed successfully";
}
public class FailureResponse : IResponse
{
public short Code => 1;
string CssColor => "red";
public string Message => "Process failed";
}
So I have a list of clients in a database with various information about them. I need to print all of them out with a slidedown form with their current information already there, and the ability to add or change it.
I am able to print out all the clients and their info but when I try to edit the form it is disabled even though there is no disabled attribute set.
Here is the controller
public ActionResult Index()
{
var context = new U2XPlanningAutomationToolEntities();
string query = "SELECT * FROM Clients";
IEnumerable<Client> data = context.Database.SqlQuery<Client>(query);
List<Client> clients = new List<Client>(data);
ViewBag.Clients = clients;
string email = Session["email"] as string;
if (!String.IsNullOrEmpty(email))
{
return View();
}
return View("../Account/Login");
}
The View
#foreach (var client in ViewBag.Clients)
{
string plan_changes = client.plan_changes;
string critical_milestones = client.critical_milestones;
string pdd = client.pdd;
string inbound = client.inbound;
string outbound = client.outbound;
string other = client.other;
<div class="row client">
<div class="col-sm-3"><span id="#client.id" class="glyphicon glyphicon-plus dropdownBtn"></span><p>#client.name</p></div>
<div class="col-sm-3"><p>#client.oep_start</p></div>
<div class="col-sm-3"><p>#client.oep_end</p></div>
<div class="col-sm-3 text-right"><button id="#client.id" class="btn btn-primary delete-client">Delete</button></div>
<div class="col-sm-12 slider" id="slider_#client.id">
#using (Html.BeginForm("UpdateClient", "Home", FormMethod.Post))
{
<div class="col-sm-4">
<input type="hidden" name="id" value="#client.id" />
#Html.LabelFor(c => c.plan_changes, "Plan Changes")
#*<textarea name="plan_changes" class="form-control" cols="20" rows="2">#plan_changes</textarea>*#
#Html.TextArea("plan_changes", plan_changes, new { #class = "form-control" })
#Html.LabelFor(c => c.critical_milestones, "Critical Milestones")
#Html.TextArea("critical_milestones", critical_milestones, new { #class = "form-control" })
</div>
<div class="col-sm-4">
#Html.LabelFor(c => c.pdd, "Plan Document Design")
#Html.TextArea("pdd", pdd, new { #class = "form-control" })
#Html.LabelFor(c => c.inbound, "Inbound")
#Html.TextArea("inbound", inbound, new { #class = "form-control" })
</div>
<div class="col-sm-4">
#Html.LabelFor(c => c.outbound, "Outbound")
#Html.TextArea("outbound", outbound, new { #class = "form-control" })
#Html.LabelFor(c => c.other, "Other")
#Html.TextArea("other", other, new { #class = "form-control" })
</div>
<div class="col-sm-12 text-center">
<input type="submit" value="Update" name="update" class="btn btn-primary" />
</div>
}
</div>
</div>
}
If my approach seems weird to you it might be because I am brand new to MVC ASP.NET, I am coming from a PHP background.
Thanks in advance!
Please use a IEnumerable<Client> in you view instead of putting it into a viewbag. Can you try to pass the id in the Html.BeginForm. Do you have an UpdateClient method in your HomeController class?
I am trying to pass the value from my HTML select to a controller, but I am not sure why the method is not capturing the values in spite of the select id has the same name than model.
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CountryId,ProvinceId,CityId")] ads_post ads_post)
{
var currUser = currentUser.GetCurrUser();
ads_post.UserId = currUser.Id;
ads_post.PostDate = DateTime.Now;
ads_post.SponsoredType = null;
ads_post.PriorityType = null;
if (ModelState.IsValid)
{
db.ads_post.Add(ads_post);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.PriorityType = new SelectList(db.ads_priority_plan, "Id", "Name");
ViewBag.SponsoredType = new SelectList(db.ads_sponsored_plan, "Id", "Name");
ViewBag.CurrencyType = new SelectList(db.ads_currency, "Id", "Name");
return View(ads_post);
}
This is the HTML
<div class="row mb-3 mt-5">
<div class="col-md-4">
<label><strong>País donde quieres publicar:</strong> <i class="fas fa-list-ul"></i></label>
<select id="CountryId" onchange="getProvices();"></select>
</div>
<div class="col-md-4">
<label><strong>Provincia:</strong> <i class="fas fa-list-ul"></i></label>
<select id="ProvinceId" onchange="getCities();"></select>
</div>
<div class="col-md-4">
<label><strong>Ciudad:</strong> <i class="fas fa-list-ul"></i></label>
<select id="CityId"></select>
</div>
</div>
Can somebody help me out with this?
Thank in advance.
I found by myself, I had just to add a name attribute to the HTML and that's it.
I have a login page and registration page all are working fine. I have a users table i created in sql server database with the column Username, FullName, School, Course. I want to display all the user detail in a sidemenu view page in MVC. But when i login i get the error message"object-reference-not-set-to-an-instance-of-an-object". I also have a controller action. Please someone help.
This is for MVC
#model ORMOnlineExamApp.Models.Candidate
<div class="row">
<div class="col-md-3">
<div class="container-fluid">
<div class="thumbnail" style="width:200px">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Candidate's Details</h3>
</div>
</div>
<p>
<h4 style="font-weight:bold">Application No:</h4>
</p>
<p>
#Model.Username
</p>
<hr />
<p>
<h4 style="font-weight:bold">Name:</h4>
</p>
<p>
#Model.FullName
</p>
<hr />
<p>
<h4 style="font-weight:bold">School:</h4>
</p>
<p>
#Model.School
</p>
<hr />
<p>
<h4 style="font-weight:bold">Course:</h4>
</p>
<p>
#Model.Course
</p>
</div>
//Controller
public ActionResult Contact(string id)
{
using (ORMOnlineExamEntitiesApp db = new ORMOnlineExamEntitiesApp())
{
var user = db.Candidates.SingleOrDefault(u => u.Username == id);
return View(user);
}
}
Please find the login page below:
//Login POST
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(CandidateLogin login, string ReturnUrl = "")
{
string message = "";
using (ORMOnlineExamEntitiesApp dc = new ORMOnlineExamEntitiesApp())
{
var v = dc.Candidates.Where(a => a.Username == login.Username).FirstOrDefault();
if (v != null)
{
if (string.Compare(Crypto.Hash(login.Password), v.Password) == 0)
{
int timeout = login.RememberMe ? 525600 : 20; // 525600 min = 1 year
var ticket = new FormsAuthenticationTicket(login.Username, login.RememberMe, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = DateTime.Now.AddMinutes(timeout);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
if (Url.IsLocalUrl(ReturnUrl))
{
return Redirect(ReturnUrl);
}
else
{
FormsAuthentication.SetAuthCookie(login.Username, true);
Session["UserId"] = login.Username.ToString();
return RedirectToAction("Contact", "Home");
}
}
else
{
message = "Invalid credential provided";
}
}
else
{
message = "Invalid credential provided";
}
}
ViewBag.Message = message;
return View();
}
I have a form where I need to use to buttons(plus and minus) to set count, but I can't figure out how can I bind this counter to model.
I have model looks like:
public class Order
{
public string Name {get; se;}
public int Count {get; set;}
}
Also I have view with form looks like:
#model SushiJazz.Models.ViewModels.OrderViewModel
<div class="container">
#using (Html.BeginForm("CreateOrder", "Order", FormMethod.Post, new { #class = "basket-form" }))
{
<div class="basket-form__input-line">
<label for="b-name" class="basket-form__label">
Name <span class="star-req">*</span>
</label>
#Html.TextBoxFor(model=>model.Name, new { #class="basket-form__input", #id="b-name", #type="tel", #autofocus="autofocus"})
</div>
<div class="basket-counter order-counter static">
<span class="add-del-btn blue">-</span>
<span class="basket-counter-number">2</span>
<span class="add-del-btn blue">+</span>
</div>
}
</div>
So, How can I bind my basket-counter to Model.Count property?
Is it posible?
<span>#Model.Name</span>
And hide the texbox data like this:
#Html.HiddenFor(m => m.Name, new { #readonly = "readonly", #class = "form-control" })
Try this, I have used this in my project and it is working fine.