How to prevent controller from sending identity column to database - asp.net

Controller Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New_Shelf(Shelf shelf)
{
shelf.User_Id = int.Parse(Request.Cookies["UserId"].Value);
db_shelf.Shelves.Add(shelf);
db_shelf.SaveChanges();
return RedirectToAction("Index", "Home");
}
Model:
namespace Book_shelf.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
public partial class Shelf
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int Size { get; set; }
[ForeignKey("Id")]
public int User_Id { get; set; }
}
}
View:
#model Book_shelf.Models.Shelf
#using (Html.BeginForm("New_Shelf", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<label style="font-family:sans-serif">Name</label>
<br />
#Html.TextBoxFor(a => a.Name)
<br />
<br />
<label style="font-family:sans-serif">Size</label>
<br />
#Html.TextBoxFor(a => a.Size)
<br />
<br />
<button class="btn btn-sm" type="submit"> Add</button>
}
Error:
Cannot insert explicit value for identity column in table 'Shelf' when >IDENTITY_INSERT is set to OFF.
I am new to ASP.net MVC and Entity Framework.
I am trying to Insert a new row for my table 'Shelf'.But it looks like that the view is sending Id as well when posting data to Action.I Tried to Log the value of shelf.Id in the action and it was '0'.How do i prevent the view to send any data in for Id property?

The problem was in shelf.edmx file,I checked the properties of Id column in the table designer and set the storedGeneratedPattern value to identity which was previously set to none.

Related

Dynamic Property and Child Model Not Binding

I want to build dynamic form using Blazor.
Here is my sample component.
#page "/customform"
#using System.Dynamic
#using System.Text.Json
#inject IJSRuntime JSRuntime;
<div class="card m-3">
<h4 class="card-header">Blazor WebAssembly Form Validation Example</h4>
<div class="card-body">
<EditForm EditContext="#editContext"
OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator></DataAnnotationsValidator>
#foreach (var field in Model.Fields)
{
<div class="form-group">
<label>#field.Name</label>
<input #bind-value="field.Value" class="form-control" />
<ValidationMessage For="(()=> field.Value)" />
<ValidationMessage For="(()=> field.Name)" />
<ValidationMessage For="(()=> field)" />
</div>
}
<div class="form-group">
<label>Address</label>
<input #bind-value="Model.Address" class="form-control" />
<ValidationMessage For="()=> Model.Address" />
</div>
<div class="form-group">
<label>Child</label>
<input #bind-value="Model.ChildModel.ChildName" class="form-control" />
<ValidationMessage For="()=> Model.ChildModel.ChildName" />
</div>
<div class="text-left">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</EditForm>
</div>
</div>
#code{
private SampleModel Model = new SampleModel();
private EditContext editContext;
private ValidationMessageStore _messageStore;
protected override void OnInitialized()
{
editContext = new EditContext(Model);
editContext.OnValidationRequested += ValidationRequested;
_messageStore = new ValidationMessageStore(editContext);
}
private void HandleValidSubmit(EditContext context)
{
var modelJson = JsonSerializer.Serialize(context.Model, new JsonSerializerOptions { WriteIndented = true });
JSRuntime.InvokeVoidAsync("alert", $"SUCCESS!! :-)\n\n{modelJson}");
}
async void ValidationRequested(object sender, ValidationRequestedEventArgs args)
{
_messageStore.Add(editContext.Field("FirstName"), "Test");
_messageStore.Add(editContext.Field("Address"), "Invalid Address");
_messageStore.Add(editContext.Field("ChildModel.ChildName"), "Invalid Child Name");
editContext.NotifyValidationStateChanged();
}
public class SampleModel
{
public string Address { get; set; }
public ChildModel ChildModel { get; set; }
public List<Field> Fields { get; set; }
public SampleModel()
{
this.ChildModel = new ChildModel();
this.Fields = new List<Field>();
this.Fields.Add(new Field()
{
Name = "FirstName",
Value = "",
ControlType = ControlType.Input
});
this.Fields.Add(new Field()
{
Name = "LastName",
Value = "",
ControlType = ControlType.Input
});
}
}
public class ChildModel
{
public string ChildName { get; set; }
}
public enum ControlType
{
Input
}
public class Field
{
public string Value { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public ControlType ControlType { get; set; }
}
}
Currently I am facing too many issues.
If I use For lookup instead of For each it is not working
ChildModel seems to be bind but its validation is not working
Dynamically generated based on Fields collection control does not display validation.
Only address in SimpleModel display validation.
Is there any suggestion or help around this ?
Your profile suggests you know what you're doing, so I'll keep this succinct.
Your for loop needs to look something like this. Set a local "index" variable within the loop to link the controls to. If you don't they point to the last value of i - in this case 2 which is out of range! The razor code is converted to a cs file by the razor builder. You can see the c# file generated in the obj folder structure - obj\Debug\net5.0\Razor\Pages. Note, the linkage of the Validation Message
#for(var i = 0; i < Model.Fields.Count; i++)
{
var index = i;
<div class="form-group">
<label>#Model.Fields[index].Name</label>
<input #bind-value="Model.Fields[index].Value" class="form-control" />
<ValidationMessage For="(()=> Model.Fields[index].Value)" />
</div>
}
Now the message validation store. Here's my rewritten ValidationRequested. Note I'm creating a FieldIdentifier which is the correct way to do it. "Address" works because it's a property of EditContext.Model. If a ValidationMessage doesn't display the message you anticipate, then it's either not being generated, or it's FieldIdentifier doesn't match the field the ValidationMessage is For. This should get you going in whatever project you're involved in - if not add a comment for clarification :-).
void ValidationRequested(object sender, ValidationRequestedEventArgs args)
{
_messageStore.Clear();
_messageStore.Add(new FieldIdentifier(Model.Fields[0], "Value"), "FirstName Validation Message");
_messageStore.Add(new FieldIdentifier(Model.Fields[1], "Value"), "Surname Validation Message");
_messageStore.Add(editContext.Field("FirstName"), "Test");
_messageStore.Add(editContext.Field("Address"), "Invalid Address");
_messageStore.Add(editContext.Field("ChildModel.ChildName"), "Invalid Child Name");
editContext.NotifyValidationStateChanged();
}
If you interested in Validation and want something more that the basic out-of-the-box validation, there's a couple of my articles that might give you info Validation Form State Control or there's a version of Fluent Validation by Chris Sainty out there if you search.

.net core 2.1 validation state: invalid

The following simple .NET Core 2.1 MVC code reports "Validation State: Invalid" when I submit to create. Everything works fine without the Owner property; and it works if Owner property is not required.
The Owner is the current user which is in the context of the server side, and it shouldn't be submitted from a client side, so the Create.cshtml doesn't have a Owner input in the form.
The error:
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method AnnouncementApp.Controllers.AnnouncementsController.Create (AnnouncementApp) with arguments (AnnouncementApp.Models.Announcement) - Validation state: Invalid
The model:
using System;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using AnnouncementApp.Models.Attributes;
using Microsoft.AspNetCore.Identity;
//using System.Security.Claims;
namespace AnnouncementApp.Models
{
public class Announcement
{
public int ID { get; set; }
[Required]
public string Content { get; set; }
[Display(Name = "Start Date and Time")]
public DateTime StartDate { get; set; }
[StartEndDate("End Date and Time must be after Start Date and Time")]
[Display(Name = "End Date and Time")]
public DateTime EndDate { get; set; }
[Required]
[BindNever]
public IdentityUser Owner { get; set; }
}
}
The controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Content,StartDate,EndDate")] Announcement announcement)
{
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(this.User);
announcement.Owner = user;
_context.Add(announcement);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(announcement);
}
The Create.cshtml
#model AnnouncementApp.Models.Announcement
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Announcement</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Content" class="control-label"></label>
<textarea asp-for="Content" class="form-control"></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="StartDate" class="control-label"></label>
<input asp-for="StartDate" class="form-control" />
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EndDate" class="control-label"></label>
<input asp-for="EndDate" class="form-control" />
<span asp-validation-for="EndDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
For Announcement, it will apply [Required] for both client validation and database table.
As the comments indicates, you could consider split Announcement to Db Model and ViewModel, you could define a new AnnouncementViewModel for client validation.
For another option, you could try configure the [Required] in the fluent api instead of attribute.
Here are the detail steps.
Change Announcement
public class Announcement
{
public int ID { get; set; }
[Required]
public string Content { get; set; }
[Display(Name = "Start Date and Time")]
public DateTime StartDate { get; set; }
public string OwnerId { get; set; }
//[Required]
[BindNever]
[ForeignKey("OwnerId")]
public IdentityUser Owner { get; set; }
}
Fluent api in ApplicationDbContext
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Announcement>()
.Property(a => a.OwnerId)
.IsRequired();
}
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Content,StartDate")] Announcement announcement)
{
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(User);
announcement.Owner = user;
_context.Add(announcement);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(announcement);
}
I am not 100 % sure, what you define as the issue, but if you want to supress the "Model Invalid" error, since you are always setting the Owner property through the HttpContext, you can use the following before validating the model:
ModelState["Owner"].ValidationState = ModelValidationState.Valid
I think your issue is that you tell the router to never bind "Owner", but you still tells it is required, and therefore the ModelState would potentially invalidate it.
As long as the "Required" annotation is used, I do not think the ModelState will validate without it being set correctly.
Example:
ModelState["Owner"].ValidationState = ModelValidationState.Valid
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(this.User);
announcement.Owner = user;
_context.Add(announcement);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(announcement);

Addition of two numbers in MVC

I am trying to add two numbers in MVC.
My requirement is "I have 2 text boxes in View from which I have to retrieve data to controller"
View :
#using (Html.BeginForm("Addition", "Addition", FormMethod.Post))
{
<input id="Text1" type="text" value=#ViewBag.a name="firstNum" />
<input id="Text2" type="text" value=#ViewBag.b name="secondNum" />
<input id="Text3" type="text" value=#ViewBag.result />
<input type="submit" value="Submit" />
}
Controller Name : Addition
Action Name: Addition
[HttpPost]
public ActionResult Addition(FormCollection fc)
{
string[] keyss = fc.AllKeys;
ViewBag.a = fc.Keys[0];
ViewBag.b = fc.Keys[1];
ViewBag.total = ViewBag.a + ViewBag.b;
return View();
}
Now, from this form collection I want to retrieve values of textboxes.
Thanks.
One of the powers of MVC is the model binder - which you are completely ignoring here. Create a view model to match the expected content of your view
public class AdditionViewModel
{
public int A { get; set; }
public int B { get; set; }
public int Result { get; set; }
}
Use this as the expected parameter in your action
[HttpPost]
public ActionResult Addition(AdditionViewModel model)
{
model.Result = model.A + model.B;
return View(model);
}
Then finally in your view
#model AdditionViewModel
#using (Html.BeginForm("Addition", "Addition", FormMethod.Post))
{
#Html.EditorFor(x => x.A)
#Html.EditorFor(x => x.B)
#Html.DisplayFor(x => x.Result)
<input type="submit" value="Submit" />
}
Assuming you get the data in to ur controller , afterwards you just add Addition view and use
#ViewBag.total simple or you also can use viewdata or tempdata in case if u required .
The better way is
[HttpPost]
public ActionResult Addition(int firstNum, int secondNum )
{
ViewBag.Result=firstNum+secondNum;
return View();
}
Make sure you are doing a Numeric validation at client side

asp net mvc3 post a list of objects to action

I created a page with aspnet mvc3. It show all users info as a list. I want to do something with this list. There are some checkboxes that belong to each items. When I click some checkboxes and press submit button, I want to post the whole list as a collection and save each items of this collection to database. There are several notes on internet but there is no exact solution. I have a UserDto. and want to use this to transfer users data in all sections.
Does anyone have any full solution about this or can they give any idea?
Thanks in advance.
Kerem
I added some of my codes. You can see the lead sentences what they are about.
this is my index view detail:
#model List<DomainModel.UserApprovalDto>
#{
ViewBag.Title = "Manage Users";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Manage Users</h2>
<div>#Html.Partial("_PartialManageUsers", (List<DomainModel.UserApprovalDto>)Model) </div>
this is my partial view detail:
#model List<DomainModel.UserApprovalDto>
#using (Html.BeginForm("ConfirmUsers", "ManageUsers", FormMethod.Post))
{
<table>
<tr>
<th>
Name
</th>
<th>
Is Reported
</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].FirstName)
</td>
<td>
#Html.CheckBox("IsReported", Model[i].IsReported.HasValue ? Model[i].IsReported.Value : false)
#*#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);*# #* #if (Model[i].IsReported != null)
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}
else
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}*#
</td>
<td>
</td>
</tr>
}
</table>
<div>
<input name="submitUsers" type="submit" value="Save" />
</div>
}
this is my controller submit method
[HttpPost]
public ActionResult ConfirmUsers(List<DomainModel.UserApprovalDto> collection)
{
if (ModelState.IsValid)
{
//TO-DO
}
return RedirectToAction("Index");
}
this last one is my DTO class detail:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DomainModel
{
public class UserApprovalDto
{
public long UserId { get; set; }
public Guid CarUserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhotoPath { get; set; }
public string PhotoSmallPath { get; set; }
public string PhotoSquarePath { get; set; }
public string PhotoBigPath { get; set; }
public bool IsBlocked { get; set; }
public bool IsDeleted { get; set; }
}
}
when I submit this code my list return null collection to my controller method.
thanks for your comments.
Assuming you are creating a screen which adds/ remove users to a course. So let's create some viewmodels
public class CourseVM
{
public string Name { set;get;}
public int CourseID { set;get;}
public List<UserVM> Users { set;get;}
public CourseVM()
{
Users=new List<UserVM>();
}
}
public class UserVM
{
public string Name { set;get;}
public int UserID{ set;get;}
public bool IsSelected { set;get;}
}
Now in your GET Action, you will fill the values of the ViewModel and sent it to the view.
public ActionResult Add()
{
var vm = new CourseVM();
//The below code is hardcoded for demo. you may replace with DB data.
vm.Users.Add(new UseVM { Name = "Jon" , UserID=1});
vm.Users.Add(new UseVM { Name = "Scott", UserID=2 });
return View(vm);
}
Now Let's create an EditorTemplate. Go to Views/YourControllerName and Crete a Folder called "EditorTemplates" and Create a new View there with the same name as of the Property Name(UserVM.cshtml)
Add this code to your new editor template.
#model ChannelViewModel
<p>
<b>#Model.Name</b> :
#Html.CheckBoxFor(x => x.IsSelected) <br />
#Html.HiddenFor(x=>x.Id)
</p>
Now in your Main View, Call your Editor template using the EditorFor Html Helper method.
#model CourseVM
#using (Html.BeginForm())
{
<div>
#Html.EditorFor(m=>m.Users)
</div>
<input type="submit" value="Submit" />
}
Now when you post the form, Your Model will have the Users Collection where the Selected Checkboxes will be having a True value for the IsSelected Property.
[HttpPost]
public ActionResult Add(CourseVM model)
{
if(ModelState.IsValid)
{
//Check for model.Users collection and Each items
// IsSelected property value.
//Save and Redirect(PRG pattern)
}
return View(model);
}

ASP.NET MVC3: Interaction between Partial View and Main View

I have a partial view for contact. Currently the index view shows this partial view for contact details. There is a save button inside the partial view to save the edited data. There is a validation for age while saving the edited data. This much is working fine.
Whenever user edit age and save it, I need to show the corresponding horoscope prediction on the main view. How do we achieve it?
public class ContactEntity
{
public int ContactID { get; set; }
public string ContactName { get; set; }
[Range(18, 50, ErrorMessage = "Must be between 18 and 50")]
public int ContactAge { get; set; }
}
public class AgeHoroscope
{
public int Age { get; set; }
public string HoroscopePrediction { get; set; }
}
//Home Controller
namespace MYContactEditPartialViewTEST.Controllers
{
public class HomeController : Controller
{
List<AgeHoroscope> horoList = new List<AgeHoroscope>()
{
new AgeHoroscope{Age=16,HoroscopePrediction="You are confused"},
new AgeHoroscope{Age=26,HoroscopePrediction="You are very brilliant"},
new AgeHoroscope{Age=27,HoroscopePrediction="You are practical"}
};
public ActionResult Index()
{
AgeHoroscope selectedHoro = horoList[1];
return View(selectedHoro);
}
}
}
//Contact Controller
namespace MYContactEditPartialViewTEST.Controllers
{
public class ContactController : Controller
{
public PartialViewResult MyContactDetailEdit()
{
Thread.Sleep(500);
return PartialView(GetContact());
}
[HttpPost]
public PartialViewResult MyContactDetailEdit(string conatcclick)
{
//Save to database
Thread.Sleep(500);
return PartialView(GetContact());
}
private ContactEntity GetContact()
{
ContactEntity contactEntity = new ContactEntity();
contactEntity.ContactID = 1;
contactEntity.ContactName = "Lijo";
contactEntity.ContactAge = 26;
return contactEntity;
}
}
}
//Index.cshtml
#model MYContactEditPartialViewTEST.AgeHoroscope
#{
ViewBag.Title = "Index";
}
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<h2>
Index</h2>
<div>
<a>Your age is <b>#Html.DisplayFor(x => x.Age) </b>and the prediction is <b>" #Html.DisplayFor(x => x.HoroscopePrediction)
" </b></a>
<br />
</div>
<div style="border: 3px solid Teal">
#Html.Action("MyContactDetailEdit", "contact")
</div>
// MyContactDetailEdit.cshtml
#model MYContactEditPartialViewTEST.ContactEntity
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<h3>MyContactDetailEdit PARTIAL</h3>
<div>
#Html.HiddenFor(x => x.ContactID)
<br />
<div style="font-weight:bold">
Name:
<br />
</div>
#Html.DisplayFor(x => x.ContactName)
<br />
<br />
<div style="font-weight:bold">
Age
<br />
</div>
#Html.EditorFor(x => x.ContactAge)
#Html.ValidationMessageFor(model => model.ContactAge)
<br />
<br />
</div>
<input type="submit" id="saveButton" value="Save" />
}
READING
ASP.Net MVC Passing multiple parameters to a view
ASP.Net MVC 3 RC2, Partial Views Form Handling
I would like just use jQuery to do ajax post and then change the parent view client side directly
you'll need to create a new ViewModel to do this. This ViewModel (IndexViewModel.cs) would look something like this (I'm guessing at this):
public class IndexViewModel
{
public int ContactID { get; set; }
public string ContactName { get; set; }
public int ContactAge { get; set; }
public string HoroscopePrediction { get; set; }
}
you'd then use it in your controller index action (and view):
#model MYContactEditPartialViewTEST.IndexViewModel
the idea being that you'd populate the HoroscopePrediction in a join between ContactEntity and AgeHoroscope (or via Linq etc) and thus show each line in the index as a complete object (showing contact and horoscope).
As data is posted to "HomeController" and "Index" action, so changes are reflected when you change age in View.
Try to modify the home controller as follows,then it will work as expected.
1) Instead of having a list of AgeHoroscope, we can have a dictionary of age and prediction.
2) Create two Index Action for HttpGet and HttpPost as follows.
public class HomeController : Controller
{
Dictionary<int, string> AgePred = new Dictionary<int, string>()
{
{16,"You are confused"},
{26,"You are very brilliant"},
{27,"You are practical"}
};
[HttpGet]
public ActionResult Index()
{
AgeHoroscope selectedHoro = new AgeHoroscope() { Age = 26 };
selectedHoro.HoroscopePrediction = AgePred[selectedHoro.Age];
return View(selectedHoro);
}
[HttpPost]
public ActionResult Index(AgeHoroscope model,ContactEntity entity)
{
model.Age = entity.ContactAge;
model.HoroscopePrediction = AgePred[entity.ContactAge];
return View(model);
}
}

Resources