use RemoteAttribute in modelview for Edit and Create Action - validation

i use RemoteAttribute in my modelview for Check Instantly If Username Exists .
[Remote("ValidUsername","UsersManagement",ErrorMessage ="this usernaem is duplicate")]
public string Username { get; set; }
This idea is useful when inserting a new record, but prevents the update from being edited. because the usernaem is exists. What is the solution to that proposal?

Option 1 - Use Additional fields:
You can use the AdditionalFields argument to your remote validation attribute in your model and combine that with a hidden field in your view .
In your model class :
[Remote("ValidUsername", "Home", ErrorMessage = "this usernaem is duplicate", AdditionalFields = "PageType")]
public string Username { get; set; }
In your edit/create page , add hidden field inside the same form as the field your are validating :
<label asp-for="Username">Username</label>
<input asp-for="Username" />
<span asp-validation-for="Username"></span>
<input type="hidden" name="PageType" value="Edit" />
Then on server side validation , you could get the Additional value(edit/create) and validate base on that , if it is edit ,just skip the validation :
[AcceptVerbs("Get", "Post")]
public IActionResult ValidUsername(string Username, string PageType)
{
if ("Edit".Equals(PageType))
{
return Json(true);
}
if (Username.Equals("21"))
{
return Json(false);
}
return Json(true);
}
Option 2 - Use different view model
You can also use different view model in create and edit pages.

Related

How to pass the name in View Data instead of ID

I'm working on an application on .NET Core MVC and I'd like to have the name of the navigated property "Hobbies" instead of the ID in my create view
I have this:
And I would like this, intead:
That I manage to get with that code for the create action in the controller:
public IActionResult Create()
{
ViewData["HobbiesName"] = new SelectList(_context.Set<Hobbies>(), "HobbiesName", "HobbiesName");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("PersonID,PersonName,PersonSurname,HobbiesID")] Person person)
{
if (ModelState.IsValid)
{
_context.Add(person);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["HobbieName"] = new SelectList(_context.Set<Hobbies>(), "HobbiesID", "HobbiesName", person.HobbiesID);
return View(person);
}
And in the view :
<div class="form-group">
<label asp-for="Hobbies.HobbiesName" class="control-label"></label>
<select asp-for="Hobbies.HobbiesName" class ="form-control" asp-items="ViewBag.HobbiesName"></select>
</div>
But that doesn't work because, I need the ID.
Does anybody know how I can manage that?
The following worked for me:
<select asp-for="Name" asp-items="#Model.NameList">
In my view model:
public string Name { get; set; }
public SelectList NameList { get; set; }
It is better to work with a view model and avoid ViewBag.
It is essential to have two different fields: the list of items (with their ids already there, behind the scenes), and a field representing the text (not the id) of the item selected

Controlling default values in view from model - EF CORE

I've set the default for a Boolean in the model using both
[DefaultValue(true)]
and
public bool IsActive { get; set; } = true;
and for good measure I've added
modelBuilder.Entity<modelName>().Property(p => p.IsActive).HasDefaultValue(true);
That all works nicely and my database table has the correct "Default value or binding". In my Create view I want the default property to be used but can't find out how to use the model's default properties in the view. Using
<input asp-for="IsActive" class="form-control" checked="checked"/>
works, but that's me hardcoding the checked="checked" value myself. How do I read the model's default value in the view?
Edited for requested code, the model is
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace securitytrials.Models {
public class CaseType {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TheID { get; set; }
[Display(Name = "Active")]
public bool IsActive { get; set; } = true;
}
}
the action method is the default generated by the template.
public IActionResult Create() {
return View();
}
Didn't include them as there's not much there but the defaults.
The DbContext.OnModelCreating is just
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<CaseType>().Property(p => p.IsActive).HasDefaultValue(true);
}
DefaultValue doesn't actually do anything. I can be utilized by code generators in certain situations, but largely in the context of your web application, it's completely meaningless. As the docs detail:
A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.
HasDefaultValue merely sets the DEFAULT for the column, so you may need that as well, if you want the actual table schema to reflect the default, but the only thing that really helps your code is:
public bool IsActive { get; set; } = true;
It's not entirely clear what you're asking. As there should be no issue with that alone in an input displaying that default value. In other words, the following code:
<input asp-for="IsActive" class="form-control" />
Will generate:
<input type="textbox" class="form-control" checked="checked" />
If it's not, then there's some issue with your model. Either you're confused on which class you've added the default value to, or something else in your code is changing that value before it hits your view. However, without more code to work with, like your action method, it's impossible to say.

Required field not present on all pages leading to problems

I have a ‘Create’ page in my MVC3 application that has 4 input fields that are all required. I also have an ‘Edit’ page in which 3 of these 4 fields can be edited. I do not want to display the 4th field and want to maintain it at its initial value (the field is the date that the entry was created ).
I mark the 4th field as [Required] in the model then this causes the model to be declared as invalid in post action method of the Edit field. If I omit the [Required] annotation then someone can create a user with a null value for this 4th field.
How can I get around this problem?
Model Code:
[Required]
[DisplayName("User Name")]
public string UserName { get; set; }
[Required]
public string Role { get; set; }
[Required]
[DataType(DataType.Date)]
[DisplayName("Insert Date")]
public DateTime? InsertDate { get; set; }
[Required]
[DisplayName("Active")]
public bool ActiveInd { get; set; }
Controller Code:
public ActionResult Edit(int id, ZUserRoleModel mod)
{
if (ModelState.IsValid)
{
// code removed
return RedirectToAction("Index");
}
return View(mod);
}
You can make that field as hidden in edit mode.
#Html.HiddenFor(x => x.EntryDate)
Not sure if you still need an answer for this, but what you need to do in order for the
#Html.HiddenFor(x => x.EntryDate )
to work, is pass an existing model into view. So let's assume that your action for getting the user data looks like this. ( You did not supply it, so I am not sure if this is right )
Public ActionResult GetUser(int UserID)
{
ZUserRoleModel model = new ZUserRoleModel(UserID);
// Maybe this could go to your database and gather user
// It would populate the correct data into a model object
return View("Edit", model);
}
With combination of the hidden field, your view will be populated with the existing user information, and the hidden field will be populated with data, and it will be passed to your edit action.
NOTE: I wrote this without any kind of testing, but it should still work, or at the very least, I hope it points you in the right direction if you still need assistance.
You can use fluentvalidation: http://fluentvalidation.codeplex.com/
Have a rule that's something like
RuleFor(user => user.field4).NotEmpty().When(ViewContext.Controller.ValueProvider.GetValue("action").RawValue <> "edit")

asp.net mvc3 updated (refresh) the viewmodel in view

I send a BOOKVIEWMODEL with fields and a simple IEnumerable in view I get the this list IEnumerable in the view by a method with JSON AJAX in view and I fill my table Ristourne(View) with JQUERY it works very well but I not know how I fill (BIND or refresh) the list IEnumerable of my BOOKVIEWMODEL in the VIEW to recovered it in the Controller:
[HttpPost]
public ActionResult Create(BookViewModel _bookViewModel)
{
if (ModelState.IsValid)
{
_bookViewModel.Ristourne
return RedirectToAction("Index");
}
return View(_bookViewModel);
my bookviewmodel
public class BookViewModel
{
public String book { get; set; }
public String price { get; set; }
public IEnumerable<Ristourne> Ristourne { get; set; }
}
For the model binding to work, you need to "mimic" the convention MVC uses when generating the form fields.
I don't know the contents of the Ristourne class, but let's say it had 1 field called Foo.
In that case, when you render out the elements (from the JSON AJAX callback), make them look like this:
<input type="text" name="Model.Ristourne[0].Foo" id="Model.Ristourne[0].Foo"/>
<input type="text" name="Model.Ristourne[1].Foo" id="Model.Ristourne[1].Foo"/>
<input type="text" name="Model.Ristourne[2].Foo" id="Model.Ristourne[2].Foo"/>
And so on. Easiest thing to do is in your AJAX callback, just use a basic for loop to create the elements indexer.
Altenatively, a cheat/easy way around this problem would be to make your AJAX action return a PartialViewResult:
public PartialViewResult Book()
{
var ristournes = _repo.Get();
var model = new BooksViewModel { Ristourne = ristournes };
return PartialView(model);
}
Then the partial view:
#Html.EditorFor(model => mode.Ristourne)
Then MVC will create the form fields correctly.
I always prefer this option over dynamically generated form fields. If you want to go down this path often, you should consider something like Knockout.js and/or Upshot.

Need help to explain Readonly\ScaffoldColumn(false)

Please help with such a question and do not judge strictly because I'm a newbie in MVC:
I've got a model for storing names of users by ID in my DB
public class Names
{
public int NameId { get; set; }
public string Username { get; set; }
}
,
a conrtoller
[HttpPost]
public ActionResult EditforModel(Names Name)
{
if (ModelState.IsValid)
{
db.Entry(Name).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Name);
}
adding and editing view
adding is working well, the question is about editing
I use
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend> legend </legend>
#Html.EditorForModel()
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
to edit my model.
when trying to go to this view I see an editor for both Id and Username, but if i fill Id - I've got error, because there is no Entry in DB with such Id.
Ok.Let's look for attributes to hide an editor.
[ScaffoldColumn(false)] is something like a marker whether to render an editor for Id or not.
applaying it to my model I've got "0" id posting from my View.Try another attr.
[ReadOnly(true)] makes a field a readonly-field. But at the same time I've got "0" in posting Id.
Modifying a view I placed an editors for each field in model
#Html.HiddenFor(model => model.NameId)
#Html.EditorFor(model => model.Username)
but using it is dangerous because some user can post wrong Id throgh post-request.
I can't use [ScaffoldColumn(false)] with applying Id at [Httppost] action of the controller,by searching appropriate user-entry in DB, because the name was changed..
I can't believe #Html.HiddenFor is the only way out.But can't find one :(
As you mentioned "[ScaffoldColumn(false)] is something like a marker whether to render an editor for Id or not", and [ReadOnly(true)] means that this property will be excluded by the default model binder when binding your model.
The problem is that the HTTP protocol is a stateless protocol, which means that when the user posts the edit form to the MVC Controller, this controller has no clue which object he was editing, unless you include some identifier to your object in the request received from the user, though including the real object Id isn't a good idea for the reason you mentioned (that someone could post another Id).
A possible solution might be sending a View Model with an encrypted Id to the View, and decrypting this Id in the controller.
A View Model for your object might look like this :
public class UserViewModel
{
[HiddenInput(DisplayValue = false)]
public string EncryptedId { get; set; }
public string Username { get; set; }
}
So your HttpGet action method will be
[HttpGet]
public ActionResult EditforModel()
{
// fetching the real object "user"
...
var userView = new UserViewModel
{
// passing the encrypted Id to the ViewModel object
EncryptedId = new SimpleAES().EncryptToString(user.NameId.ToString()),
Username = user.Username
};
// passing the ViewModel object to the View
return View(userView);
}
Don't forget to change the model for your View to be the ViewModel
#model UserViewModel
Now the HttpPost action method will be receiving a UserViewModel
[HttpPost]
public ActionResult EditforModel(UserViewModel Name)
{
if (ModelState.IsValid)
{
try
{
var strId = new SimpleAES().DecryptString(Name.EncryptedId);
var id = int.Parse(strId);
// select the real object using the decrypted Id
var user = ...Single(p => p.NameId == id);
// update the value from the ViewModel
user.Username = Name.Username;
db.Entry(user).State = EntityState.Modified;
}
catch (CryptographicException)
{
// handle the case where the encrypted key has been changed
return View("Error");
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(Name);
}
When the user tries to change the encrypted key, the decryption will fail throwing a CryptographicException where you can handle it in the catch block.
You can find the SimpleAES encryption class here (don't forget to fix the values of Key and Vector arrays):
Simple insecure two-way "obfuscation" for C#
PS:
This answer is based on the following answer by Henry Mori:
Asp.net MVC 3 Encrypt Hidden Values

Resources