Unable to edit IdentityRole - c#

I have the following view:
#model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
#{
ViewBag.Title = Resources.Edit;
}
<h2>#Resources.EditRole</h2>
#Html.ActionLink(Resources.ListRoles, "Index") | #Html.ActionLink(Resources.ManageUserRoles, "ManageUserRoles")
<hr />
<div class="row">
<div class="col-md-8">
<section id="editRoleForm">
#using (Html.BeginForm("Edit", "Role", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>#Resources.Role</h4>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Id)
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="#Resources.Save" class="btn btn-default" />
</div>
</div>
}
</section>
</div>
</div>
I also have the following two methods in my RoleController:
//
// GET: /Role/Edit/5
public ActionResult Edit(string Role)
{
var thisRole = context.Roles.Where(r => r.Name.Equals(Role, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
return View(thisRole);
}
//
// POST: /Role/Edit/5
[HttpPost]
public ActionResult Edit(FormCollection collection)
{
try
{
var thisRole = context.Roles.Where(r => r.Id.Equals(collection["Id"])).FirstOrDefault();
thisRole.Name = collection["Name"];
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Originally, I was trying to use this method instead of the second one:
//
// POST: /Role/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IdentityRole Name)
{
try
{
context.Entry(Name).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
But I never got it to work because the Name parameter was always null -which I still don't know why it happened, so if someone can explain it to me that'll be greatly appreciated.
I wrote then the other method since I saw the use of FormCollection in another example (to create roles) and it seems to work fine, at least it contains the information I need when I debug it. My issue is that although collection["id"] has the right Id for the Role I'm trying to edit, context.Roles is completely empty. This makes no sense to me given that when the first method is called (loading the View for the first time), this line
var thisRole = context.Roles.Where(r => r.Name.Equals(Role, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
returns the selected role (out of the several that exist and that I can see when I add to watch context.Roles). However, after the view is loaded, the textbox edited and the second method in the controller gets called, context.Roles has nothing in it. Why?

Ok you can use the already built in [Authorize(Roles="RoleType")] filter.
You then have your regular User model and Account controller so you can then authorize users. Once you have authorised them you can set them to a specific role.
E.g. user story: only admins can access action result x
[Authorize(User="Admin")]
Public ActionResult X(){
...
}
That way you simply assign user roles in the model creation.
E.g.
Public Class UserModel
{
int id {get;set;}
string name {get;set;}
string Role {get;set;}
.....
}
Now only users that have been authorised AND are of Role type "Admin" will be able to access that controller.
If you want to edit their role you can do a simple edit user action method
e.g.
[Post]
public actionresult edituser(int? id)
{
if (id == null)
{
return HttpNotFound();
}
using (var db = new UserContext())
{
UserModel editUser = db.UserModel.Find(id);
if (editUser == null)
{
return HttpNotFound();
}
db.User(editModel).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
}
RedirectToAction("Action", "Controller");
}
Now any user that is NOT of Role type "Admin" will not be able to access that screen. They will receive a 404 error.

Related

Routing is not going to the post part of the controller

I can´t get into the HttpPost part of the controller.
I´ve created another controller and the problem is the same
I was working fine before
I´ve added tags [Route("CrearSolicitud")]
[HttpPost, ActionName("CrearSolicitud")]
I´ve haven´t added anything to the routing part
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
It goes to http://localhost:55935/Solicitudes
instead of http://localhost:55935/Solicitudes/CrearSolicitud
public class SolicitudesController : Controller
{
ApplicationDbContext db = new ApplicationDbContext();
// GET: Solicitudes
public ActionResult Index()
{
return View();
}
//Get
public ActionResult Solicitud()
{
return View();
}
//Post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Solicitud(Solicitudes s)
{
s.Id = "e17cba68-0a0b-4d6e-abaf-8026cb91fcd1";
s.fk_tipo_transaccion = 3;
s.fk_estado_solicitud = 1;
db.Solicitudes.Add(s);
db.SaveChanges();
return View();
}
The view
#model HGRecursosHumanos4.Models.Solicitudes
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (#Html.BeginForm("CrearSolicitud", "Solicitudes", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="container">
<div class="form-group col-md-5">
#Html.LabelFor(model => model.VacacionesDias, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-3">
#Html.EditorFor(model => model.VacacionesDias, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.VacacionesDias, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group col-md-5">
#Html.LabelFor(model => model.FechaInicio, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-5">
<input type="date" id="fechaInicio" name="fechaInicio" class="Filtros form-control input-sm" />
</div>
</div>
<div class="form-group col-md-2">
<div class="col-md-offset-2 col-md-3">
<input type="submit" value="Solicitar" class="btn btn-success" />
</div>
</div>
</div>
</div>
}
When I use the form and hit the submit button or the application goes to Index or to the same view again
It´s like EF went broke or something
I´ve added that, an error comes out The 'CrearSolicitud' view or its master view is not found or there is no search engine that supports the search locations. We searched in the following locations:
~/Views/Solicitudes/CrearSolicitud.aspx
~/Views/Solicitudes/CrearSolicitud.ascx
~/Views/Shared/CrearSolicitud.aspx
~/Views/Shared/CrearSolicitud.ascx
~/Views/Solicitudes/CrearSolicitud.cshtml
~/Views/Solicitudes/CrearSolicitud.vbhtml
~/Views/Shared/CrearSolicitud.cshtml
~/Views/Shared/CrearSolicitud.vbhtml
#Nemanja I certainly don´t have that view, if I use the same name on the post and no the get, the application goes to the get part again
I have the solution.
The thing is, index is for showing a list of added registries, when it is changed for something else you can´t see that list and that leads you to wrong conclusions.
The routing is working fine, the program is doing what is supposed to do, the RedirectToAction("Index") is ok.
The lesson is, take a while and think about what are you changing and try to follow the VS way of doing things.
I´ve tested now and it´s working
ApplicationDbContext db = new ApplicationDbContext();
// GET: Solicitudes
public ActionResult Index()
{
return View();
}
public ActionResult Index2()
{
return View(db.Solicitudes.ToList());
}
//Get
public ActionResult Solicitud()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Solicitud(Solicitudes s)
{
try
{
if (ModelState.IsValid)
{
s.FechaFinal = DateTime.Now;
s.FechaYHoraSolicitud = DateTime.Now;
s.Id = "e17cba68-0a0b-4d6e-abaf-8026cb91fcd1";
s.fk_tipo_transaccion = 3;
s.fk_estado_solicitud = 1;
db.Solicitudes.Add(s);
db.SaveChanges();
ViewBag.Message = "Solicitud guardada";
ModelState.Clear();
return RedirectToAction("Index2");
}
return View("ModelStateError");
}
//catch
catch (Exception ex)
{
//throw ex;
Console.WriteLine(ex.Message);
return View("Error");
}
}

ASP.NET MVC - How to upload an image and save URL in the database

I would appreciate if anyone could help me with this. I have input file control in a form in a view and when someone picks a picture and clicks the submit button on the form, that file has to be saved in /Pictures folder in the application and file path needs to be saved in SQL database as string (like: /Pictures/filename).
Models class part:
[Table("Automobil")]
public partial class Automobil
{ .....
[Required]
[StringLength(30)]
public string Fotografija{ get; set; }
......
View (Create) file part:
#using (Html.BeginForm("Create", "Automobili", FormMethod.Post, new { enctype = "multipart/form-data" }))
....
<div class="form-group">
<div class="editor-field">
#Html.TextBoxFor(model => model.Fotografija, new { type = "file" })
#Html.ValidationMessageFor(model => model.Fotografija, "", new { #class = "text-danger" })
</div>
</div>
....
Controller part:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "AutomobilID,Marka,Model,Godiste,Zapremina_motora,Snaga,Gorivo,Karoserija,Fotografija,Opis,Cena,Kontakt")] Automobil automobil)
{
if (ModelState.IsValid)
{
db.Automobils.Add(automobil);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(automobil);
}
What do I need to do so the photo(Fotografija) could be saved in the application folder Pictures, and file path in SQL base (like /Pictures/filename)?
Thank you in advance for helping the beginner.
Looks like your Fotografija property is string type where you want to save the unique file name. You do not want to use that field to get the file from the browser. Let's use another input field for that.
#using (Html.BeginForm("Index", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<div class="editor-field">
#Html.TextBoxFor(model => model.Model)
#Html.ValidationMessageFor(model => model.Model)
</div>
</div>
<!-- TO DO : Add other form fields also -->
<div class="form-group">
<div class="editor-field">
<input type="file" name="productImg" />
</div>
</div>
<input type="submit" />
}
Now update your HttpPost action method to have one more parameter of type HttpPostedFileBase. The name of this parameter should be same as the input file field name we added (productImg)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "AutomobilID,Marka,Model,Godiste,
Zapremina_motora,Snaga,Gorivo,Karoserija,Opis,Cena,Kontakt")] Automobil automobil,
HttpPostedFileBase productImg)
{
if (ModelState.IsValid)
{
if(productImg!=null)
{
var fileName = Path.GetFileName(productImg.FileName);
var directoryToSave = Server.MapPath(Url.Content("~/Pictures"));
var pathToSave = Path.Combine(directoryToSave, fileName);
productImg.SaveAs(pathToSave);
automobil.Fotografija= fileName;
}
db.Automobils.Add(automobil);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(automobil);
}
You have to remove any validation data annotation decoration(Ex : [Required], [MinLength] etc) on the Fotografija field.
I also strongly suggest you to update the fileName before saving to be a unique one to avoid collision/overwriting of existing files. You can add the DateTime current value to the file name (Before the extension) to make it unique
The code that I have in controller is the basic one:
// GET: Automobili/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Automobil automobil = db.Automobils.Find(id);
if (automobil == null)
{
return HttpNotFound();
}
return View(automobil);
}
// POST: Automobili/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "AutomobilID,Marka,Model,Godiste,Zapremina_motora,Snaga,Gorivo,Karoserija,Fotografija,Opis,Cena,Kontakt")] Automobil automobil)
{
if (ModelState.IsValid)
{
db.Entry(automobil).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(automobil);
}
How to change it to be compatible with the create code above?
Thank you.

ASP.NET MVC beginform for complex property [duplicate]

TL;DR: How do I handle form data that is being submitted with nonstandard names for the data?
The stats:
MVC 5
ASP.NET 4.5.2
I am bringing in two different models:
public async Task<ActionResult> Index() {
var prospectingId = new Guid(User.GetClaimValue("CWD-Prospect"));
var cycleId = new Guid(User.GetClaimValue("CWD-Cycle"));
var viewModel = new OnboardingViewModel();
viewModel.Prospecting = await db.Prospecting.FindAsync(prospectingId);
viewModel.Cycle = await db.Cycle.FindAsync(cycleId);
return View(viewModel);
}
One called Prospecting, the other called Cycle. The Prospecting one is working just fine, as nothing else on the page needs it except one small item.
The Cycle has a mess of separate forms on the page, each needing to be separately submittable, and editing just one small part of the Cycle table. My problem is, I don't know how to submit the correct data to the backend. I am also not entirely sure how to "catch" that data.
The bright spot is that apparently the front end is properly reflective of what is in the db. As in, if I manually change the db field to a true value, the checkbox ends up being selected on refresh.
My current form is such:
#using(Html.BeginForm("UpdatePDFResourceRequest", "Onboarding", FormMethod.Post, new { enctype = "multipart/form-data" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<fieldset>
#Html.LabelFor(Model => Model.Cycle.PDFResourceLibrary, htmlAttributes: new { #class = "control-label" })
#Html.CheckBoxFor(Model => Model.Cycle.PDFResourceLibrary, new { #class = "form-control" })
#Html.ValidationMessageFor(Model => Model.Cycle.PdfResourceLibrary, "", new { #class = "text-danger" })
<label class="control-label"> </label><button type="submit" value="Save" title="Save" class="btn btn-primary glyphicon glyphicon-floppy-disk"></button>
</fieldset>
}
But the resulting HTML is such:
<input id="Cycle_PDFResourceLibrary" class="form-control" type="checkbox" value="true" name="Cycle.PDFResourceLibrary" data-val-required="'P D F Resource Library' must not be empty." data-val="true">
As you can see, the name= is Cycle.PDFResourceLibrary and I don't know how to catch this on the backend.
My model for that specific form is:
public class PDFResourceRequestViewModel {
[DisplayName("PDF Resource Library Request")]
public bool PDFResourceLibrary { get; set; }
[DisplayName("Date Requested")]
[DataType(DataType.Date)]
public DateTime PDFResourceLibraryDate { get; set; }
[DisplayName("Notes")]
public string PDFResourceLibraryNotes { get; set; }
}
(not the overall model for that table, though)
And the method used to handle the form submission is:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> UpdatePDFResourceRequest(PDFResourceRequestViewModel model) {
var id = new Guid(User.GetClaimValue("CWD-Cycle"));
Cycle cycle = await db.Cycle.FindAsync(id);
if(cycle == null) {
return HttpNotFound();
}
try {
cycle.CycleId = id;
cycle.PDFResourceLibrary = model.PDFResourceLibrary;
cycle.PDFResourceLibraryDate = DateTime.Now;
cycle.PDFResourceLibraryNotes = model.PDFResourceLibraryNotes;
db.Cycle.Add(cycle);
await db.SaveChangesAsync();
return RedirectToAction("Index");
} catch { }
return View(model);
}
Now, I know that the method is wrong, for one I am editing just three values out of dozens in that table, so I need to be using something like this method. Problem is, the form is getting submitted with the name= of Cycle.PDFResourceLibrary and it is not being matched up on the back end.
Help?
You can use the [Bind(Prefix="Cycle")] attribute to 'strip' the prefix so that name="Cycle.PDFResourceLibrary" effectively becomes name="PDFResourceLibrary" and will bind to your PDFResourceRequestViewModel
public async Task<ActionResult> UpdatePDFResourceRequest([Bind(Prefix="Cycle")]PDFResourceRequestViewModel model)

Partial views and html forms Asp Mvc

I am attempting to render a partial view that contains a simple html form. I want to render the form from a controller as I handle the postback from an overloaded controller method. I have tried #Html.Action("ContactForm")but I get an Exception because child actions cannot redirect.
My Controller:
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult ContactForm()
{
return PartialView(new ContactForm());
}
[HttpPost]
public ActionResult ContactForm(ContactForm Contact)
{
return RedirectToAction("FormResults", new { ContactForm = Contact });
}
public ActionResult FormResults(ContactForm Contact)
{
return PartialView(Contact);
}
My Form:
#using(Html.BeginForm())
{
<h2>Contact Form</h2>
<div class="input-group">
<h4>#Html.LabelFor(m => m.FirstName, "First Name")</h4>
#Html.TextBoxFor(m => m.FirstName, new { #class = "form-control", #placeholder = "First Name" })
</div>
<div class="input-group">
<h4>#Html.LabelFor(m => m.LastName, "Last Name")</h4>
#Html.TextBoxFor(m => m.LastName, new { #class = "form-control", #placeholder = "Last Name" })
</div>
<div class="input-group">
<h4>#Html.LabelFor(m => m.Email, "Email")</h4>
#Html.TextBoxFor(m => m.Email, new { #class = "form-control", #placeholder = "Email", #type = "text" })
</div>
<input type="submit" class="btn btn-info" value="Submit" />
}
Any Help on how I would accomplish this would be appreciated.
try surrounding the form with a div and a certain id and use:
#using(Ajax.BeginForm("ContactForm","YourController",new AjaxOptions()
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "yourCertainId",
HTTPMethod = "POST"
})
and your ActionMethod:
[HttpPost]
public ActionResult ContactForm(ContactForm Contact)
{
return Partial("YourPartialName", Contact });
}
make sure that you include the bundle jqueryval on the bottom of your view.
you wont need the second controller method "FormResults"
Does something like this not work for you?
I don't think you need a redirect.
[HttpPost]
public ActionResult ContactForm(ContactForm Contact)
{
return PartialView("FormResults", Contact);
}
This uses the
PartialView(string viewName, object model)
overload of the PartialView method in the Controller class.
This allows you to use a View that doesn't match the ActionResult's method name.
The same thing works for the plain "View" method as well.

Adding a variable into the HTML.BeginForm Model

I am having issues retaining the passwordToken between my GET Controller and my View. I see that the token is passed and added to the model correctly within the GET Controller but as soon as the HTML.BeginForm starts in the View the model has a new instance and the previous model with the passwordToken is lost. I need the passwordToken to be retained in order to use WebSecurity.ResetPassword. Any suggestions on how this could be done?
My GET Controller:
[AllowAnonymous]
public ActionResult PasswordReset(string passwordToken)
{
// Token Validation
var usrID = WebSecurity.GetUserIdFromPasswordResetToken(passwordToken);
var usr = _dbManager.GetUserInformation(usrID);
if (usr == null)
{
//The link you are using is not valid anymore
return RedirectToAction("Error", "Account");
}
else
{
var model = new PasswordReset();
model.PasswordResetToken = passwordToken;
return View(model);
}
}
My View:
#model Project.Models.PasswordReset
#{
ViewBag.Title = "Password Reset";
}
<h2>Password Reset</h2>
<div class="form passwordreset-form">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<div class="input-form">
<div class="inputbox-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="inputbox">
#Html.PasswordFor(m => m.Password)
</div>
<div class="inputbox-label">
#Html.LabelFor(m => m.ConfirmPassword)
</div>
<div class="inputbox">
#Html.PasswordFor(m => m.ConfirmPassword)
</div>
</div>
<div style="float:right;">
<input type="submit" value="Change Password" />
</div>
}
</div>
My POST Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult PasswordReset(PasswordReset model)
{
//Attemp to change password
var passwordChangeConfirmation = WebSecurity.ResetPassword(model.PasswordResetToken, model.Password);
//Password has been changed
if(passwordChangeConfirmation == true)
{
return RedirectToAction("Index", "Home");
}
//Password change has failed
else
{
return RedirectToAction("Error", "Account");
}
}
I ended up adjusting the POST class to make it work.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult PasswordReset(PasswordReset model, string passwordToken)
{
//Attemp to change password
model.PasswordResetToken = passwordToken;
var passwordChangeConfirmation = WebSecurity.ResetPassword(model.PasswordResetToken, model.Password);
//Password has been changed
if (passwordChangeConfirmation == true)
{
return RedirectToAction("Index", "Home");
}
//Password change has failed
else
{
return RedirectToAction("Error", "Account");
}
}
add it into your form:
#Html.HiddenFor(m => m.PasswordResetToken);
You can use a hidden input on the form for the field (from your model) that you pass it.
#Html.HiddenFor(m => m.PasswordResetToken);
in output
<input type="hidden" name="PasswordResetToken"></input>

Categories