error to get value from controller - asp.net-mvc

i try to create new room, but roomTypeID always return 1, whats wrong with my code?
i can make a new room type, but i cant insert room facility in my database, because RoomType ID always return 1
this my code..
my controller
public ActionResult NewRoom()
{
ViewBag.hotel = _hotelService.GetByID(_HotelID).HotelName;
List<ShowEditRoomViewModel> showEditRoomViewModel = _roomTypeService.showNewRooms();
return View(showEditRoomViewModel.FirstOrDefault());
}
[HttpPost]
public ActionResult NewRoom(FormCollection typeRoom)
{
_roomTypeService.NewRoom(_HotelID, typeRoom["RoomTypeName"], typeRoom["RoomTypeDescription"]);
List<string> IDs = typeRoom["FacilityIDs"].Split(',').ToList();
List<int> FacilityIDs = new List<int>();
foreach (string ID in IDs)
{
FacilityIDs.Add(Convert.ToInt32(ID));
}
_roomTypeService.UpdateFacilityInRooms(FacilityIDs, Convert.ToInt32(typeRoom["RoomTypeID"]));
return NewRoom();
}
my service
public void UpdateFacilityInRooms(List<int> FacilityIDs, int RoomTypeID)
{
List<HotelRoomFacility> hotelRoomFacilities = _HotelRoomFacilityRopository.AsQueryable().Where(f => f.RoomTypeID == RoomTypeID).ToList();
foreach (int newRoomFacility in FacilityIDs)
{
if (hotelRoomFacilities.Where(h => h.RoomFacilityID == newRoomFacility).Count() == 0)
{
HotelRoomFacility facility = new HotelRoomFacility
{
RoomFacilityID = newRoomFacility,
RoomTypeID = RoomTypeID
};
_HotelRoomFacilityRopository.Add(facility);
}
}
_HotelRoomFacilityRopository.CommitChanges();
}
my view model
public class ShowEditRoomViewModel
{
public int RoomTypeID { get; set; }
public string RoomTypeName { get; set; }
public string RoomTypeDescription { get; set; }
public List<FaciliyInRoom> facilityinRoom { get; set; }
}
my view
#model XNet.Repository.Model.ShowEditRoomViewModel
#{
ViewBag.Title = "NewRoom";
}
<h2>New Room</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Isikan Data</legend>
<div>
#Html.Label("Hotel Name")
</div>
<div>
#ViewBag.hotel
</div>
<br />
<div>
#Html.HiddenFor(model => model.RoomTypeID)
</div>
<br />
<div>
#Html.Label("Room Type Name")
</div>
<div>
#Html.EditorFor(model => model.RoomTypeName)
#Html.ValidationMessageFor(model => model.RoomTypeName)
</div>
<br />
<div>
#Html.Label("Room Type Description")
</div>
<div>
#Html.TextAreaFor(model => model.RoomTypeDescription)
#Html.ValidationMessageFor(model => model.RoomTypeDescription)
</div>
<br />
<table>
<thead>
<tr>
<th>Facility Name</th>
<th> is available</th>
</tr>
</thead>
<tbody>
#foreach (var facility in Model.facilitiesInRoom)
{
<tr>
<td>
#(facility.RoomFacilityName)
</td>
<td style="text-align:center;">
<input type="checkbox" #(facility.RoomFacilityAvailable ? " checked=checked" : null) name="FacilityIDs" value="#facility.RoomFacilityID" />
</td>
</tr>
}
</tbody>
</table>
<br />
<p>
<input type="submit" value="Save" />
<input style="width:100px;" type="button" title="EditHotelDetail" value="Back to Detail" onclick="location.href='#Url.Action("Room", "Hotel") '" />
</p>
</fieldset>
}
My method
public List<ShowEditRoomViewModel> showNewRooms()
{
List<RoomType> roomTypes = (from d in _RoomTypeRepository.All()
select d).ToList();
List<ShowEditRoomViewModel> showEditRoomViewModel = new List<ShowEditRoomViewModel>();
foreach (RoomType roomType in roomTypes)
{
showEditRoomViewModel.Add(new ShowEditRoomViewModel
{
RoomTypeID = roomType.RoomTypeID,
facilitiesInRoom = LoadFacilityInRoom()
});
}
return showEditRoomViewModel;
}
can someone tell me, where is my mistake??
thanks

When you are inserting RoomtypeId in Database, you are using ExecuteNonQuery() method, It will always return 1 whenever you insert a new record in it,
If you are using stored procedure for inserting,you can use
select Scope_identity()
after insertion.

Related

One-To-Many relationship between ApplicationUser and an other object

I am struggling trying to implement à create action and an index for my controller.
Basically, I want each user to have multiple pizzas.
I want the connected user to create his own pizzas.
And in the index of my controller I want to show, only the pizzas created by the current connected user.
Here are my models :
1/Pizzas :
public class PizzaModel
{
[Key]
public int PizzaID { get; set; }
[Display(Name = "Nom")]
public string nom { get; set; }
[Display(Name = "Prix(€)")]
public float prix { get; set; }
[Display(Name = "Végétarienne")]
public bool vegetarienne { get; set; }
[Display(Name = "Ingrédients")]
public string ingredients { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public string ApplicationUserId { get; set; }
}
2/ ApplicationUser :
public class ApplicationUser : IdentityUser
{
public ICollection<PizzaModel> Pizzas { get; set; }
}
3/ This is my Context :
public class AuthDbContext : IdentityDbContext<ApplicationUser>
{
public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options)
{
}
public DbSet<PizzaModel> Pizzas { get; set; }
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<ApplicationUser>()
.HasMany(p => p.Pizzas)
.WithOne(u => u.ApplicationUser)
.IsRequired()
.HasForeignKey(p => p.ApplicationUserId);
base.OnModelCreating(builder);
}
I want to create a "create action" and an "index action" that shows only the pizzas created by the current connected user. Here is what I have done so far :
1/ Index action method :
public async Task<IActionResult> Index(string searchByName)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
IEnumerable<PizzaModel> pizzas = new List<PizzaModel>();
pizzas = _context.Pizzas.Where(x => x.ApplicationUserId == userId);
return View(pizzas);
}
2/ Create Action Method :
public async Task<IActionResult> Create(PizzaModel model)
{
_context.ApplicationUsers.Add(model);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index), "Pizza");
}
Could you please help me with these 2 actions (Create and Index) ?
According to your Model and DbContext, I create the actions as below: I'm using the Home Controller and Project name is "WebApplication3"
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly ApplicationDbContext _dbContext;
public HomeController(ILogger<HomeController> logger, ApplicationDbContext dbContext)
{
_logger = logger;
_dbContext = dbContext;
}
public IActionResult Index()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
IEnumerable<PizzaModel> pizzas = new List<PizzaModel>();
pizzas = _dbContext.Pizzas.Where(x => x.ApplicationUserId == userId);
return View(pizzas);
}
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create(PizzaModel model)
{
//Note: if you check the ModelState.IsValid, it will return false, because there is no ApplicationID and PizzaID,
//you can create a view model to enter the new value, then, convert it to PizzaModel
//validate the model
//if (ModelState.IsValid)
//{
//get current user id
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (userId != null)
{
//based on the userid to find current user and get its pizzas.
var currentuser = _dbContext.ApplicationUsers.Include(c => c.Pizzas).First(c => c.Id == userId);
List<PizzaModel> pizzas = new List<PizzaModel>();
pizzas = currentuser.Pizzas.ToList();
//add the new item to pizza list
pizzas.Add(new PizzaModel()
{
nom = model.nom,
prix = model.prix,
vegetarienne = model.vegetarienne,
ingredients = model.ingredients
});
//update the pizzas for current user.
currentuser.Pizzas = pizzas;
await _dbContext.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
//}
//else
//{
// return View();
//}
}
The Index view as below:
#model IEnumerable<WebApplication3.Data.PizzaModel>
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.PizzaID)
</th>
<th>
#Html.DisplayNameFor(model => model.nom)
</th>
<th>
#Html.DisplayNameFor(model => model.prix)
</th>
<th>
#Html.DisplayNameFor(model => model.vegetarienne)
</th>
<th>
#Html.DisplayNameFor(model => model.ingredients)
</th>
<th>
#Html.DisplayNameFor(model => model.ApplicationUserId)
</th>
<th></th>
</tr>
</thead>
<tbody>
#if(Model.ToList().Count > 0)
{
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.PizzaID)
</td>
<td>
#Html.DisplayFor(modelItem => item.nom)
</td>
<td>
#Html.DisplayFor(modelItem => item.prix)
</td>
<td>
#Html.DisplayFor(modelItem => item.vegetarienne)
</td>
<td>
#Html.DisplayFor(modelItem => item.ingredients)
</td>
<td>
#Html.DisplayFor(modelItem => item.ApplicationUserId)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
}
else
{
<tr><td colspan="7">Empty</td></tr>
}
</tbody>
</table>
<p>
<a asp-action="Create">Create New Pizza</a>
</p>
The Create View:
#model WebApplication3.Data.PizzaModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>PizzaModel</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="nom" class="control-label"></label>
<input asp-for="nom" class="form-control" />
<span asp-validation-for="nom" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="prix" class="control-label"></label>
<input asp-for="prix" class="form-control" />
<span asp-validation-for="prix" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="vegetarienne" /> #Html.DisplayNameFor(model => model.vegetarienne)
</label>
</div>
<div class="form-group">
<label asp-for="ingredients" class="control-label"></label>
<input asp-for="ingredients" class="form-control" />
<span asp-validation-for="ingredients" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
The result as below:
Generally, in the HttpPost method such as the Create or Update action method, we need to validte the model is valid or not, then based on the result to show validation message or go the next steps. You can refer the following tutorials:
Model validation in ASP.NET Core MVC and Razor Pages
Tutorial: Implement CRUD Functionality - ASP.NET MVC with EF Core

ASP.NET MVC Send List from View to controller

I'm trying to create a product model with ID,Name and a list of specifications like above:
My model:
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public virtual List<Spec> Specifications { get; set; }
}
public class Spec
{
public int SpecID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
My Controller:
public ActionResult Create(Product product,List<Spec> Specifications)
{
......
}
My View:
using (Html.BeginForm("Create", "Products", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-2"><h3>Specifications</h3></div>
<div class="col-md-10">
<table id="tblSkills" cellpadding="0" cellspacing="0" class="table table-responsive">
<thead>
<tr>
<th style="width:150px">Name</th>
<th style="width:150px">Description</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td><input type="text" id="Name1" /></td>
<td><input type="text" id="Description" /></td>
<td>
<input type="button" id="btnAdd" class="btn btn-success btn-sm" value="Add" />
</td>
</tr>
</tfoot>
</table>
<br />
<input type="button" id="btnSave" value="SaveAll" class="bntbtn-block btn-success" />
<br />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
so it should looks like this:
I also added some Scripts so that I can enter or remove specifications, the information will be displayed inside a tbody tag in a table.
The problem is that I don't really know how to pass my list of specifications to my controller, or should I try another way of input multiple specifications instead of using table. I'm looking for a way to input it using HTMLHelper like the one I did with Product's Name.
I apologize if my question is unclear. If you have any question to understand more, feel free to ask me. Thanks for any advise or solution.
To pass the model to a view from controller you need to:
public ActionResult Create(List<Spec> Specifications)
{
return View(Specifications);
}
and in your view add these to on top of the view:
#using PathOfYourSpecificationsModel
#model List<Spec>
using (Html.BeginForm("Create", "Products", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-2"><h3>Specifications</h3></div>
<div class="col-md-10">
<table id="tblSkills" cellpadding="0" cellspacing="0" class="table table-responsive">
<thead>
<tr>
<th style="width:150px">Name</th>
<th style="width:150px">Description</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td><input type="text" id="Name1" /></td>
<td><input type="text" id="Description" /></td>
<td>
<input type="button" id="btnAdd" class="btn btn-success btn-sm" value="Add" />
</td>
</tr>
</tfoot>
</table>
<br />
<input type="button" id="btnSave" value="SaveAll" class="bntbtn-block btn-success" />
<br />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
After user clicks add button you need another [HttpPost] method for Create. Which should look like this:
[HttpPost]
public ActionResult Create(List<Spec> Specifications)
{
// Specifications should be filled with view values.
// Do your logic here. Ex: Save the data to database
}
For adding dynamic control fields, it is advised to use helper methods.
The AddNewRow helper method will return the html elements can one can make changes like changing the html attributes.
the html attributes should be unique and it is advised to use increment value for each element.
the attributes of html elements returned from helper method are changed in addNewRow() of javascript function.
Detailed steps are provided below.
In Product Model
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public List<Spec> Specifications { get; set; }
}
public class Spec
{
public int SpecID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsRemoved { get; set; }
}
In Controller
public class ProductController : Controller
{
// GET: Product
public ActionResult AddProduct()
{
Product product = new Product();
product.Specifications = new List<Spec>()
{
new Spec()
};
return View(product);
}
[HttpPost]
public ActionResult AddProduct(Product product)
{
return View(product);
}
}
In AddProduct.cshtml
#model Product
#using WebApplication3.Models
#{
ViewBag.Title = "AddProduct";
}
#helper AddNewRow()
{
<tr id="trRow_0">
<td>
#Html.HiddenFor(x => Model.Specifications[0].IsRemoved, new { id = "hdnSpecIsRemoved_0" })
#Html.TextBoxFor(x => Model.Specifications[0].Name, new { id = "txtSpecName_0" })
</td>
<td>
#Html.TextBoxFor(x => Model.Specifications[0].Description, new { id = "txtSpecDesc_0" })
</td>
<td>
Remove Row
</td>
</tr>
}
<h2>AddProduct</h2>
#using (Html.BeginForm("AddProduct", "Product", FormMethod.Post))
{
<div>
#Html.LabelFor(x => x.Name)
#Html.TextBoxFor(x => x.Name)
</div>
<table>
<thead>
<tr>
<th>
#Html.LabelFor(x => x.Specifications[0].Name)
</th>
<th>
#Html.LabelFor(x => x.Specifications[0].Description)
</th>
<th>
Action
</th>
</tr>
</thead>
<tbody id="tBody">
#for (int i = 0; i < Model.Specifications.Count; i++)
{
string trRow = "trRow_" + i;
<tr id="#trRow">
<td>
#Html.HiddenFor(x => Model.Specifications[i].IsRemoved, new { id = "hdnSpecIsRemoved_" + i })
#Html.TextBoxFor(x => Model.Specifications[i].Name, new { id = "txtSpecName_" + i })
</td>
<td>
#Html.TextBoxFor(x => Model.Specifications[i].Description, new { id = "txtSpecDesc_" + i })
</td>
<td>
Remove Row
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="2">
<br />
<button type="button" onclick="addNewRow()">Add New Row</button>
</td>
</tr>
</tfoot>
</table>
<br />
<button type="submit">Save All</button>
}
<script type="text/javascript">
function addNewRow() {
var totalSpecCount = $('#tBody tr').length;
var newRowData = `#(AddNewRow())`;
newRowData = newRowData.replaceAll("Specifications[0]", "Specifications[" + totalSpecCount + "]")
newRowData = newRowData.replaceAll("txtSpecName_0", "txtSpecName_" + totalSpecCount);
newRowData = newRowData.replaceAll("txtSpecDesc_0", "txtSpecDesc_" + totalSpecCount);
newRowData = newRowData.replaceAll("trRow_0", "trRow_" + totalSpecCount);
newRowData = newRowData.replaceAll("removeRow(0)", "removeRow(" + totalSpecCount+")");
newRowData = newRowData.replaceAll("hdnSpecIsRemoved_0", "hdnSpecIsRemoved_" + totalSpecCount);
$('#tBody').append(newRowData);
}
function removeRow(recordId) {
var trId = "#trRow_" + recordId;
var hdnSpec = "#hdnSpecIsRemoved_" + recordId;
$(hdnSpec).val(true);
$(trId).hide();
}
</script>
Here, the method addNewRow will call the helper methods and change the html attributes of the element based on row count.
In strongly typed view, the index values should unique for the list so that it can be posted using model binding
Final Result
Note: In remove row method we have to hide the element instead of removing the element completely. This is used to achieve post the list directly. To know what the rows that are removed a flag called IsRemoved is to true.
If we remove the element, the index value will not be in sequence and one cannot post the form.

how do i pass values from foreach so as to create a new list of model?

#model IEnumerable<OnlineExam.Models.CandidateExam.CandidateExam>
#{
ViewData["Title"] = "Index";
var questionList = JsonConvert.DeserializeObject<List<OnlineExam.Models.AdminQuestionModel.QuestionAndAnswers>>(TempData["questionList"].ToString());
var data = questionList as IEnumerable<OnlineExam.Models.AdminQuestionModel.QuestionAndAnswers>;
TempData.Keep();
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
#{
int count = 0;
}
#foreach (var item2 in Model)
{
#foreach (var item in data)
{
count = count + 1;
<table class="table" style="background-color:lavender">
<tbody>
<tr class="border-light"><td>Question #count : #item.Question</td></tr>
<tr class="bg-light"><td>Options : </td></tr>
<tr class="border-light"><td><input asp-for="#item2.OptionSelected" type="radio" name="counter" value="#item.OptionTwo" /> a) #item.OptionOne</td></tr>
<tr class="bg-light"><td><input asp-for="#item2.OptionSelected" type="radio" name="counter" value="#item.OptionTwo" /> b) #item.OptionTwo</td></tr>
<tr class="border-light"><td><input asp-for="#item2.OptionSelected" type="radio" name="counter" value="#item.OptionThree" /> c) #item.OptionThree</td></tr>
<tr class="bg-light"><td><input asp-for="#item2.OptionSelected" type="radio" name="counter" value="#item.OptionFour" /> d) #item.OptionFour</td></tr>
</tbody>
</table>
<br />
}
}
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
.................................................................................................
Basically i want to load data from item to item 2 ie: I want to supply values from one foreach to model(IEnumerable). How do i do tht?
You cannot bind the foreach item with the posted back items because it messes up the naming convention MVC relies on to post the data back. You will have to use For loop for this purpose.
#for(int i=0; i< Model.Count(); i++)
{
for (int j=0; i< data.Count(); j++)
{
// here you can do like this to bind your element
#Html.RadioButtonFor(x=> data[j].propertyName)
}
}
Here is a working demo:
1.Model:
public class CandidateExam
{
public int Id { get; set; }
public string OptionSelected { get; set; }
}
public class QuestionAndAnswers
{
public int Id { get; set; }
public string Question { get; set; }
public string OptionOne { get; set; }
public string OptionTwo { get; set; }
public string OptionThree { get; set; }
public string OptionFour { get; set; }
}
2.View(Note that you set the optionOne with wrong value #item.OptionTwo):
#model IEnumerable<QuestionAndAnswers>
#{
int count = 0;
int i = 0;
}
<form method="post">
#foreach (var item in Model)
{
count = count + 1;
<table class="table" style="background-color:lavender">
<tbody>
<tr class="border-light"><td>Question #count : #item.Question</td></tr>
<tr class="bg-light"><td>Options : </td></tr>
<tr class="border-light"><td><input asp-for="#item.OptionOne" type="radio" name="counter[#i]" value="#item.OptionOne" /> a) #item.OptionOne</td></tr>
<tr class="bg-light"><td><input asp-for="#item.OptionTwo" type="radio" name="counter[#i]" value="#item.OptionTwo" /> b) #item.OptionTwo</td></tr>
<tr class="border-light"><td><input asp-for="#item.OptionThree" type="radio" name="counter[#i]" value="#item.OptionThree" /> c) #item.OptionThree</td></tr>
<tr class="bg-light"><td><input asp-for="#item.OptionFour" type="radio" name="counter[#i]" value="#item.OptionFour" /> d) #item.OptionFour</td></tr>
</tbody>
</table>
i++;
<br />
}
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
3.Controller:
public class QuestionAndAnswersController : Controller
{
private readonly YourContext _context;
public QuestionAndAnswersController(YourContext context)
{
_context = context;
}
// GET: QuestionAndAnswers
public async Task<IActionResult> Index()
{
return View(await _context.QuestionAndAnswers.ToListAsync());
}
[HttpPost]
public async Task<IActionResult> Index(string[] counter)
{
foreach(var item in counter)
{
var data = new CandidateExam()
{
OptionSelected = item
};
_context.Add(data);
await _context.SaveChangesAsync();
}
//do your stuff...
}
4.Result:
#model OnlineExam.Models.CandidateExam.CandidateItem
#{
ViewData["Title"] = "Index";
var questionList = JsonConvert.DeserializeObject<List<OnlineExam.Models.AdminQuestionModel.QuestionAndAnswers>>(TempData["questionList"].ToString());
//var data = questionList as IEnumerable<OnlineExam.Models.AdminQuestionModel.QuestionAndAnswers>;
var data2 = questionList as List<OnlineExam.Models.AdminQuestionModel.QuestionAndAnswers>; //new stackov
int examAttemptId = Convert.ToInt32(TempData["examAttemptId"].ToString());
TempData.Keep();
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<div>
<form enctype="multipart/form-data" asp-action="AnswerExam">
#{
int counter = 0;
}
#for (var i = 0; i < data2.Count(); i++)
{
counter = counter + 1;
<input type="hidden" asp-for="candidateExamsList[i].ExamId" value="#data2[i].ExamId" />
<input type="hidden" asp-for="candidateExamsList[i].QuestionId" value="#data2[i].QuestionId" />
<input type="hidden" asp-for="candidateExamsList[i].ExamAttemptId" value="#examAttemptId" />
<span>Question #counter) </span>#data2[i].Question.ToString()<br />
<span>Options : </span><br />
<span>a) </span>#Html.RadioButtonFor(x => x.candidateExamsList[i].OptionSelected, data2[i].OptionOne) #data2[i].OptionOne;<br />
<span>b) </span>#Html.RadioButtonFor(x => x.candidateExamsList[i].OptionSelected, data2[i].OptionTwo) #data2[i].OptionTwo;<br />
<span>c) </span>#Html.RadioButtonFor(x => x.candidateExamsList[i].OptionSelected, data2[i].OptionThree) #data2[i].OptionThree;<br />
<span>d) </span>#Html.RadioButtonFor(x => x.candidateExamsList[i].OptionSelected, data2[i].OptionFour) #data2[i].OptionFour;<br /><br />
}
<div class="form-group">
<button type="submit" value="Submit" class="btn btn btn-primary" />
</div>
</form>
</div>
This is how i cud fix my issue..i used a for loop instead of foreach loop to bind data from the list to the model.

MVC AD search - Displaying multiple results as .cshtml

I have fully working code that searches active directory and displays it with MVC .cshtml But I have been trying to figure out away to add all the users found to a list then display them. As currently it just displays the first user found.
This is the HomeController that takes a value, Searches AD and returns the results.
public class HomeController : Controller
{
public ActionResult Index(IndexViewModel profile)
{
if (ModelState.IsValid)
{
//List<Principal> users = new List<Principal>();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.DisplayName = profile.Name + "*";
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
if(!(srch.FindAll().Count() < 0))
{
foreach(var found in srch.FindAll())
{
//users.Add(found);
IndexViewModel returnmodel = new IndexViewModel(found);
return View(returnmodel);
}
}
}
}
}
return View(profile);
}
}
The IndexViewModel
public class IndexViewModel
{
public IndexViewModel(Principal found)
{
Name = found.DisplayName;
Email = found.UserPrincipalName;
Description = found.Description;
}
[Required(ErrorMessage = "Please enter a name")]
[Display(Name = "Persons Name")]
public string Name { get; set; }
public string Email { get; set; }
public string Description { get; set; }
//public List<Principal> user { get; set; }
}
Index.cshtml
<div id="content">
#Html.ValidationSummary(true)
#using (Html.BeginForm("Index", "Home"))
{
<fieldset>
<div class="form-group col-md-12">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.EditorFor(modelItem => Model.Name, new { htmlAttributes = new { #class = "form-control", #style = "width:280px" }, })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div class="col-md-2">
<input type="submit" class="btn btn-default" value="Search">
</div>
<div class="col-md-3">
</div>
</div>
</fieldset>
}
<br>
</div>
<table id="historyTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>#Model.Name</td>
<td>#Model.Email</td>
<td>#Model.Description</td>
</tr>
</tbody>
</table>
EDIT-----------
This is one method I tried ----------------
HomeController.cs
public class HomeController : Controller
{
public ActionResult Index(IndexViewModel profile)
{
if (ModelState.IsValid)
{
List<Principal> users = new List<Principal>();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.DisplayName = profile.Name + "*";
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
if(!(srch.FindAll().Count() < 0))
{
foreach(var found in srch.FindAll())
{
users.Add(found);
IndexViewModel returnmodel = new IndexViewModel(users);
return View(returnmodel);
}
}
}
}
}
return View(profile);
}
IndexViewModel.cs
public class IndexViewModel
{
public IndexViewModel(List<Principal> found)
{
user = found;
}
[Required(ErrorMessage = "Please enter a name")]
[Display(Name = "Persons Name")]
public string Name { get; set; }
public string Email { get; set; }
public string Description { get; set; }
public List<Principal> user { get; set; }
}
index.html
<div id="content">
#Html.ValidationSummary(true)
#using (Html.BeginForm("Index", "Home"))
{
<fieldset>
<div class="form-group col-md-12">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.EditorFor(modelItem => Model.Name, new { htmlAttributes = new { #class = "form-control", #style = "width:280px" }, })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div class="col-md-2">
<input type="submit" class="btn btn-default" value="Search">
</div>
<div class="col-md-3">
</div>
</div>
</fieldset>
}
<br>
</div>
<table id="historyTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
</tr>
</thead>
<tbody>
#using System.DirectoryServices.AccountManagement
#foreach (Principal prin in Model.user)
{
<tr>
<td>#prin.DisplayName</td>
<td>#prin.UserPrincipalName</td>
<td>#prin.Description</td>
</tr>
}
</tbody>
</table>
The error I get on compile is --
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 37: <tbody>
Line 38: #using System.DirectoryServices.AccountManagement
Line 39: #foreach (Principal prin in Model.user)
Line 40: {
Line 41: <tr>
Source File: C:\Users\hga\Documents\Visual Studio 2015\Projects\Intra AD people searcher\Intra AD people searcher\Views\Home\Index.cshtml Line: 39
You can add if statement to check for null
#if(Model.user !=null)
{
#foreach (Principal prin in Model.user)
{
<!--your code here-->
}
}
In your controller, your return statement is inside your foreach loop. So the first time it goes through the loop, it will return. That means you will only have one result.
Try this:
foreach(var found in srch.FindAll())
{
users.Add(found);
}
IndexViewModel returnmodel = new IndexViewModel(users);
return View(returnmodel);

How to get data from partial in form

I have
ASP.NET MVC Form in popup with some controls and partial (data grid) with his own Model.
here is popup:
<div id="AddEditDialog" class="none">
#using (Ajax.BeginForm("Save", "Templates", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "AddEditPlaceHolder",
OnSuccess = "OnSaveSuccess",
HttpMethod = "Post"
}))
{
<div>
<div id="AddEditPlaceHolder"></div>
<div id="PopupButtons" class="btn-holder-centered">
<input type="submit" value="Save" name="SaveButton" />
<input type="button" value="Cancel" name="SaveCancelButton" id="CancelEditHandler" />
</div>
</div>
}
</div>
here is form which I render in AddEditPlaceHolder via js:
#model TemplatesViewModel
<div class="form-field-plain overflow">
<div class="forRow narRow float-left">
#Html.LabelFor(x => x.Revocable)
#Html.CheckBoxFor(x => x.Revocable)
</div>
</div>
<div class="form-field-plain overflow">
<div class="forRow narRow float-left">
#Html.LabelFor(x => x.HtmlTemplate)
#Html.TextAreaFor(x => x.HtmlTemplate)
</div>
</div>
#Html.Partial("_VariablesGridView", Model.Variables)
_VariablesGridView.cshtml:
#model List<TemplateVariableViewModel>
<table id="TemplateVariablesGrid">
<thead>
<tr>
<td>Tag/Code</td>
<td>Prompt</td>
<td>Action</td>
</tr>
</thead>
<tbody>
#foreach (var i in Model)
{
<tr>
<td>
#Html.TextBox("txtTag", #i.Tag, new {})
</td>
<td>
#Html.TextBox("txtPrompt", #i.Prompt, new { })
</td>
<td>
#Html.HiddenFor(x => x.First(s => s.Id == #i.Id).Id)
<label class="delete-variable">delete</label>
</td>
</tr>
}
</tbody>
</table>
<br />
<input type="button" name="btnAddTemplateVariable" value="add new variable"/>
<br />
My problem is :
in Controller 'save form' method public ActionResult Save(TemplateViewModel model)
my model contains all data from form but TemplateViewModel.Variables is empty
Is there any way to fill it in there?
Models:
public class TemplateViewModel
{
public int Id { get; set; }
public string HtmlTemplate { get; set; }
public List<TemplateVariableViewModel> Variables { get; set; }
}
public class TemplateVariableViewModel
{
public int Id { get; set; }
public string Tag { get; set; }
public string Prompt { get; set; }
}
I believe it is because the ASP.Net MVC binding is not putting these fields in context, have a look at your field names delivered to the browser, what is txtTag prefixed by when it gets to the browser and what is is after you do the following:
#Html.Partial("_VariablesGridView", Model)
_VariablesGridView.cshtml:
#model TemplatesViewModel
...
#for (int i = 0; i < Model.Variables.Count; i++)
#Html.TextBox("txtTag", #Model.Variables[i].Tag, new {})
Forgive me if this fails miserably (again), I'm shooting from the hip.

Resources