Checkbox in ASP.NET MVC without using HTML helper method - asp.net

I've written this code in View. And the picture is the output of it in Chrome Inspect.
#Html.CheckBox("KYCComplete", new { #name = "KYC", #id = "KYC" })
<label class="form-check-label" for="KYC">
KYC Complete ?
<button id="Submit">KYC Complete ?</button>
</label>
In my controller I'm using this HttpPost to use checkbox an filter:
[HttpPost]
public ActionResult Index(bool KYCComplete)
{
if (KYCComplete)
{
List<BankAccount> b= db.BankAccounts.Where(p => p.KYCComplete == true).OrderBy(b => b.City).ToList();
return View(b);
}
return RedirectToAction("Index");
}
Everything works fine, up to this point. Only name property is not overridden.
Well, I want to change the name property of the checkbox to be "KYC" from "KYCComplete".
So, firstly I look for Is there any ways to override HTML helpers. I found in several websites it's not possible to override those.
Now I tried with writing simple HTML checkbox and I'm getting an error.
Server Error in '/' Application.
The parameters dictionary contains a null entry for parameter
'KYCComplete' of non-nullable type 'System.Boolean' for method
'System.Web.Mvc.ActionResult Index(Boolean)' in
'BankAccountsMgmt.Controllers.BankAccountsController'. An optional
parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
So how can I change the name property of this checkbox to "KYC" and bind its input, to filter the desired result.
Describing the question In a Nutshell
As, you have seen the output of the view of this checkbox has name property "KYCComplete".
I've requirement to change to "KYC", and HttpPost should work along with it, without effecting domain model.
Incase extra info. is Required
model:
namespace BankAccountsMgmt.Models
{
public class BankAccount
{
...
[Display(Name = "KYC Complete?")]
public bool KYCComplete { get; set; }
...
}
}
controller:
using BankAccountsMgmt.Data;
using BankAccountsMgmt.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BankAccountsMgmt.Controllers
{
[CustomFilters.CustomExceptionFilter]
public class BankAccountsController : Controller
{
BankAccountDBContext db = new BankAccountDBContext();
// GET
public ActionResult Index()
{
//Implement your code
List<BankAccount> bank = db.BankAccounts.OrderBy(b=>b.City).ToList();
return View(bank);
}
//Implement other action methods
[HttpPost]
public ActionResult Index(bool KYCComplete)
{
if (KYCComplete)
{
List<BankAccount> AccKYC = db.BankAccounts.Where(p => p.KYCComplete == true).OrderBy(b => b.City).ToList();
return View(AccKYC);
}
return RedirectToAction("Index");
}
public ActionResult AddBankAccount()
{
return View();
}
[HttpPost]
public ActionResult AddBankAccount(BankAccount bankAccount)
{
if (ModelState.IsValid)
{
bankAccount.CalculateInterest();
db.BankAccounts.Add(bankAccount);
db.SaveChanges();
ViewBag.Message = "Bank Account added successfully!";
return View("Details", bankAccount);
}
return View(bankAccount);
}
}
}
full view:
#model List<BankAccountsMgmt.Models.BankAccount>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Bank Accounts List</h2>
#using (Html.BeginForm("Index", "BankAccounts"))
{
<div class="form-check col-md-offset-8" align="center">
#Html.CheckBox("KYCComplete", new { #name = "KYC", #id = "KYC" })
<label class="form-check-label" for="KYC">
KYC Complete ?
<button id="Submit">KYC Complete ?</button>
</label>
</div>
<table class="table">
<tr>
<th>
Account Holder Name
</th>
<th>
PAN Number
</th>
<th>
City
</th>
<th>
Gender
</th>
<th>
Amount
</th>
<th>
Interest Upto 30 Aug
</th>
<th>
Opening Date
</th>
<th>
KYC Complete?
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AccountHolderName)
</td>
<td>
#Html.DisplayFor(modelItem => item.PAN)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
#Html.DisplayFor(modelItem => item.Amount)
</td>
<td>
#Html.DisplayFor(modelItem => item.Interest)
</td>
<td>
#Html.DisplayFor(modelItem => item.OpeningDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.KYCComplete)
</td>
</tr>
}
</table>
<span id="total" class="form-check col-md-offset-6" align="center"><b>Interest Total = </b>#Model.Sum(model => model.Interest).ToString("#.##") </span>
}

You could try Html Checkbox instead of using html helper method:
Example:
<input type="checkbox" id="KYC" name="KYC">
<label for="KYC"> KYC Complete</label>

The name of your form control must match the name of the parameter to your action method for model binding to work.
If you change the name of the checkbox to "KYC", but leave the action parameter as "KYCComplete", you will get the exception mentioned in your question.
Change the name in both places.
[HttpPost]
public ActionResult Index(bool KYC)
{
if (KYC)
{
List<BankAccount> b= db.BankAccounts.Where(p => p.KYCComplete == true).OrderBy(b => b.City).ToList();
return View(b);
}
return RedirectToAction(nameof(Index));
}
#Html.CheckBox("KYC", new { #id = "KYC" })

Related

#Html.DisplayNameFor() respects [Display] attribute but #Html.DisplayFor() ignores [DisplayFormat] attribute

I have this view model:
public class ConceptViewModel
{
public int Id { get; set; }
[Required(ErrorMessageResourceName = "Message_Required", ErrorMessageResourceType = typeof(Resources.Web.ValidationsViewModels))]
[Display(Name = "ConceptViewModel_Name", ResourceType = typeof(Resources.Web.Contracts))]
public string Concept { get; set; }
[Required(ErrorMessageResourceName = "Message_Required", ErrorMessageResourceType = typeof(Resources.Web.ValidationsViewModels))]
[Display(Name = "ConceptViewModel_TotalUnits", ResourceType = typeof(Resources.Web.Contracts))]
[DisplayFormat(DataFormatString = "{0:###,###}")] // Ignored by #Html.DisplayFor()
public decimal TotalUnits { get; set; }
}
That view model is inside a collection property of another view model that happens to be the one passed to the view:
public class ContratConceptsViewModel : BaseClass
{
public int ContratId { get; set; }
// This collection
public List<ConceptViewModel> Concepts { get; set; }
public ContratConceptsViewModel()
{
Concepts = new List<ConceptViewModel>();
}
}
And then, inside the view, I have this code:
#model ContratConceptsViewModel
#foreach (var concept in Model.Concepts)
{
<thead>
<tr>
<td> #Html.DisplayNameFor(model => concept.Concept) </td> #* Works as expected *#
<td> #Html.DisplayNameFor(model => concept.TotalUnits) </td> #* Works as expected *#
</tr>
</thead>
<tbody>
<tr>
<td> #Html.DisplayFor(model => concept.Concept) </td>
<td> #Html.DisplayFor(model => concept.TotalUnits) </td> #* Doesn't show the correct format *#
</tr>
</tbody>
}
When I execute this code, the [Display] attribute is taken into account, but the [DisplayFormat] attribute is totally ignored. What am I doing wrong?
NOTE: I have searched for a question like this one, and despite there are many others with a similar title, they are different from this one.
Ok, it was all my fault. One of my coworkers created a template for decimal inside the folder Views\Shared\DisplayTemplates\Decimal.cshtml. That's why #Html.DisplayFor() was ignoring the attribute, it was because it was respecting the template created by my coworker.
You should amend you expressions inside DisplayFor and DisplayNameFor.
It must be #Html.DisplayFor(model => model.TotalUnits), not #Html.DisplayFor(model => concept.TotalUnits).
UPDATE
Because you're displaying items from the list #Html.DisplayFor will not work properly: it's supposed to work with single model. I would suggest to extract your template for each item into separate file(it's called display template in MVC):
Your display template(it must be placed in DisplayTemplates folder):
#model ConceptViewModel
<thead>
<tr>
<td> #Html.DisplayNameFor(model => model.Concept) </td>
<td> #Html.DisplayNameFor(model => model.TotalUnits) </td>
</tr>
</thead>
<tbody>
<tr>
<td> #Html.DisplayFor(model => model.Concept) </td>
<td> #Html.DisplayFor(model => model.TotalUnits) </td>
</tr>
</tbody>
Your main page:
#model ContratConceptsViewModel
#foreach (var concept in Model.Concepts)
{
#Html.DisplayFor(model => concept, "name of your display template, optional if you follow conventions")
}
Here is the link about display templates.

How to export string data to pdf format in .Net Core MVC

How to export string data to pdf format in .Net Core MVC. Please anyone help me for export the data in pdf format in .net core.
You might be able to tap into the Response during OnResultExecuting and replace the Filter property with something that stores the resultant HTML in a MemoryStream. Then you could clear the Response during OnResultExecuted and replace it with the results of your PDF conversion. I'm not sure that this would be better than just getting the HTML from the URL, though.
eg =
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebApplication2.Models
{
public class Person
{
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
}
public ActionResult GetPersons()
{
List<Person> persons = new List<Person>();
persons.Add(new Person() { Age = 29, Name = "Rami1", Email = "Rami1#abc.com" });
persons.Add(new Person() { Age = 28, Name = "Rami2", Email = "Rami2#abc.com" });
return View(persons);
}
#model IEnumerable<WebApplication2.Models.Person>
#{
ViewBag.Title = "GetPersons";
}
<h2>GetPersons</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.Age)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Age)
</td>
</tr>
}
</table>

Posted model is empty

I have a ViewModel as following
public class MetalStockAddVM
{
public MetalStock MetalStock { get; set; }
public MetalStockAddVM()
{
this.MetalStock=new MetalStock();
}
}
Here is My controller
public class MetalStockController : Controller
{
private readonly IMetalStockRepository iMetalStockRepository;
public MetalStockController(IMetalStockRepository iMetalStockRepository)
{
this.iMetalStockRepository = iMetalStockRepository;
}
// GET: MetalStock
[HttpGet]
public ActionResult AddMetalStock()
{
MetalStockAddVM addVm=new MetalStockAddVM();
return View(addVm);
}
[HttpPost]
public ActionResult AddMetalStock([Bind(Include = "MetalStock")]MetalStockAddVM metalStock)
{
MetalStockDto metalStockDto = new MetalStockDto();
metalStockDto = Mapper.Map<MetalStock, MetalStockDto>(metalStock.MetalStock);
iMetalStockRepository.Insert(metalStockDto);
return RedirectToAction("Index","Home") ;
}
}
Here is my view
#model LearningSpike.Models.ViewModels.MetalStockAddVM
#using (Html.BeginForm("AddMetalStock","MetalStock",FormMethod.Post))
{
<table>
<tr>
<th>
#Html.LabelFor(m => m.MetalStock.MetalId)
</th>
<td>
#Html.EditorFor(m => m.MetalStock.MetalId)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(m => m.MetalStock.GlobalMaterialId)
</th>
<td>
#Html.EditorFor(m => m.MetalStock.GlobalMaterialId)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(m => m.MetalStock.Length)
</th>
<td>
#Html.EditorFor(m => m.MetalStock.Length)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(m => m.MetalStock.ColourCode)
</th>
<td>
#Html.EditorFor(m => m.MetalStock.ColourCode)
</td>
</tr>
<tr>
<th>
#Html.LabelFor(m => m.MetalStock.QuantityInStock)
</th>
<td>
#Html.EditorFor(m => m.MetalStock.QuantityInStock)
</td>
</tr>
</table>
<input type="submit" value="Create"/>
}
When I post the model that is passed to the controller action method is empty .
Please tell me what I'm doing wrong? I am creating an architectural spike for the first time so I can learn a lot.Thus its my first time implementing all heavy stuff (DI , DTO's , REpositories etc.) . I am still struggling with putting things in right places.
Thanks!
Cheers!
First remove [Bind(Include = "MetalStock")] and second rename metalStock to some something like metalStockVm and see does it works or not.
[HttpPost]
public ActionResult AddMetalStock(MetalStockAddVM metalStockVm)
Please try the below one
change your model code like below
public class MetalStockAddVM
{
public MetalStock MetalStock { get; set; }
}
And then change you Action method code for HTTPPOST in AddMetalStock as below
[HttpPost]
public ActionResult AddMetalStock(MetalStockAddVM metalStock)
{
MetalStockDto metalStockDto = new MetalStockDto();
metalStockDto = Mapper.Map<MetalStock, MetalStockDto>(metalStock.MetalStock);
iMetalStockRepository.Insert(metalStockDto);
return RedirectToAction("Index","Home") ;
}

ASP.Net MVC Posted form values not mapping back onto viewmodel in controller

My ViewModel is:
public class ObjectiveVM
{
public string DateSelected { get; set; }
public List<string> DatePeriod { get; set; }
public IList<ObList> obList { get; set; }
public class ObList
{
public int ObjectiveId { get; set; }
public int AnalystId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string AnalystName { get; set; }
public bool Include { get; set; }
}
}
This is passed to the view, populated as expected - and displays correctly in the view.
My problem is when it is posted back to the controller. My controller code to accept it back is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Analyst(ObjectiveVM ovm)
ovm.obList is always showing as null:
My View html is:
#model Objectives.ViewModels.ObjectiveVM
#{
ViewBag.Title = "Analyst";
}
<h2>Copy Objectives for Analyst</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Objective</legend>
#Html.DropDownListFor(model => model.DateSelected, new SelectList(Model.DatePeriod))
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.obList[0].Include)
</th>
<th>
#Html.DisplayNameFor(model => model.obList[0].AnalystName)
</th>
<th>
#Html.DisplayNameFor(model => model.obList[0].Title)
</th>
<th>
#Html.DisplayNameFor(model => model.obList[0].Description)
</th>
</tr>
#foreach (var obList in Model.obList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => obList.ObjectiveId)
#Html.HiddenFor(modelItem => obList.AnalystId)
#Html.HiddenFor(modelItem => obList.Title)
#Html.HiddenFor(modelItem => obList.Description)
#Html.CheckBoxFor(modelItem => obList.Include)
</td>
<td>
#Html.DisplayFor(modelItem => obList.AnalystName)
</td>
<td>
#Html.DisplayFor(modelItem => obList.Title)
</td>
<td>
#Html.DisplayFor(modelItem => obList.Description)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Copy Selected Objectives" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Looking in Developer Tools at the Posted form values, they appear to be ok:
Can anyone see any reason the posted form values, are not mapping back onto my viewmodel in the Controller HTTP post?
Thank you, Mark
You need to use a for...loop here, not a foreach....loop.
#for (int idx = 0;idx < Model.obList.Count;idx++){
#Html.HiddenFor(_ => Model.obList[idx].ObjectiveId)
// ... etc....
}
Without the indexer (idx), the model binder will not know how to bind the values back to the right collection item.
When working with collections in my views, I typically write out my markup without the use of helpers:
#for (int i = 0;i < Model.obList.Count();i++){
<input type="hidden" name="ObList[#i].ObjectiveId" id="ObList[#i].ObjectiveId" value="#ObList[i].ObjectiveId" />
<input type="hidden" name="ObList[#i].AnalystId" id="ObList[#i].AnalystId" value="#ObList[i].AnalystId" />
...
}
This will conform to the wire format the model binder expects, and will slot your values into your ViewModel: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Returning all the Users from the current Active Directory

I want to create a new Action method that when called it will return all the Active directory usernames . The asp.net mvc application and active directory are within the same domain (and currently inside the same development machine).
So I have defined the following action method:-
public ViewResult Details()
{
var c = repository.GetUserDetails3();
return View("Details2",c); }
and the following repository method:-
public DirectoryEntry GetUserDetails3()
{ DirectoryEntry de = new DirectoryEntry();
using (var context = new PrincipalContext(ContextType.Domain, "WIN-SPDEV.com")){using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{foreach (var result in searcher.FindAll())
{de = result.GetUnderlyingObject() as DirectoryEntry; }}}
return de; }
and the following model class:-
public class DirectoryUser
{public Nullable<Guid> Guid { get; set; }
public string Name { get; set; }
public string Username { get; set; }
}}
and on the view I have:-
#model IEnumerable<TMS.Models.DirectoryUser>
#{
ViewBag.Title = "Details2";
}
<h2>Details2</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Guid)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Username)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Guid)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
but when I call the action method I got the following error:-
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type
The model item passed into the dictionary is of type
'System.DirectoryServices.DirectoryEntry', but this dictionary
requires a model item of type
'System.Collections.Generic.IEnumerable`1[TMS.Models.DirectoryUser]'.
You must have link for this action like follow:
/CurrentController/Details?id=1
So, for example you can write ActionLink as follow:
<a href="#Url.Action("Details", "ControllerName", new { id = 1})" role="button" data- toggle="modal">

Resources