Display Active Directory Group in a MVC view - asp.net-mvc

I Am trying to display active directory group member in the view. When i run the Code I am having the error "The model item passed into the dictionary is of type 'System.String[]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[SSSFT.LogIT.Models.ActiveDirectory]'". Debbuging the code show all the group member i am looking for
Model Class
public class ActiveDirectory
{
public int id { get; set; }
//public string Username { get; set; }
//public string Email { get; set; }
public string SamAccountName { get; set; }
}
Controller
public ActionResult Index(string username)
{
username = "sssftappdev";
string[]output = null;
using (var ctx = new PrincipalContext(ContextType.Domain))
using (var user = UserPrincipal.FindByIdentity(ctx, username))
{
if (user != null)
{
output = user.GetGroups() //this returns a collection of principal objects
.Select(x => x.SamAccountName) // select the name. you may change this to choose the display name or whatever you want
.ToArray(); // convert to string array
}
}
return View(output);
}
View
#model IEnumerable<SSSFT.LogIT.Models.ActiveDirectory>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.SamAccountName)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.SamAccountName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.id }) |
#Html.ActionLink("Details", "Details", new { id=item.id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.id })
</td>
</tr>
}
</table>

You can fix this error by simply updating your #model with:
#model String[]
You are currently passing a String[] to your view while expecting an IEnumerable of SSSFT.LogIT.Models.ActiveDirectory. Either update your code to return the right type of data, or adapt your strongly typed view with the actual result you return.

Related

Pass multiple parameters to partial view

I have a model structured like so:
public int JobID { get; set; }
public int SiteID { get; set; }
public List<AModel> ListAModel { get; set; }
In my main view, I am iterating through the List using a for loop with i as an index. I want to call a partial view from within this main page to avoid repeat code across the system but this partial view needs to be aware of the index number as well as the job id and site id.
I cannot just pass in in Model.ListAModel[i] as this will not be aware of job or site id, and likewise with the other way round.
Any help would be appreciated.
You can use the ExpandoObject Class that represents an object whose members can be dynamically added and removed at run time. Code below demonstrates how it can be used:
Data model:
public class AModel
{
public string Name { get; set; }
}
public class ViewModel
{
public int JobID { get; set; }
public int SiteID { get; set; }
public List<AModel> ListAModel { get; set; }
}
.cshtml:
#model Models.ViewModel
#using System.Dynamic
<div>
#for (int i=0; i < Model.ListAModel.Count; i++)
{
dynamic item = new ExpandoObject();
item.job = Model.JobID;
item.site = Model.SiteID;
item.amodel = Model.ListAModel[i];
Html.RenderPartial(#"PartialView", (object) item);
}
</div>
In the partial view:
#using System.Dynamic
#model dynamic
#{
Models.AModel am = #Model.amodel;
<div>job id = #Model.job, site id = #Model.site, amodel = #am.Name </div>
}
There are several posts about how to pass parameters to a view dynamically For example:
Dynamic Anonymous type in Razor causes RuntimeBinderException
In my main view, I am iterating through the List using a for loop with
i as an index. I want to call a partial view from within this main
page to avoid repeat code across the system but this partial view
needs to be aware of the index number as well as the job id and site
id.
I cannot just pass in in Model.ListAModel[i] as this will not be aware
of job or site id, and likewise with the other way round.
From your description, I assume you want to filter data based on the Job id and site id, then display the AModel via the partial view.
To pass parameters from main page to the partial view, you can use the view-data attribute. Please refer the following sample:
Model:
public class JobViewModel
{
public int JobID { get; set; }
public int SiteID { get; set; }
public List<AModel> ListAModel { get; set; }
}
public class AModel
{
public int ID { get; set; }
public string Name { get; set; }
public int JobID { get; set; }
public int SiteID { get; set; }
}
Controller:
public IActionResult Index4()
{
var initialdata = new List<JobViewModel>()
{
new JobViewModel(){
JobID = 1001,
SiteID = 102,
ListAModel = new List<AModel>()
{
new AModel(){ ID=1, Name="Joe", JobID=1001, SiteID=101},
new AModel(){ ID=2, Name="Merry", JobID=1001, SiteID=102},
new AModel(){ ID=3, Name="Henry", JobID=1001, SiteID=103},
new AModel(){ ID=4, Name="Cody", JobID=1001, SiteID=101},
new AModel(){ ID=5, Name="Simon", JobID=1001, SiteID=102},
new AModel(){ ID=6, Name="Leena", JobID=1001, SiteID=103},
new AModel(){ ID=7, Name="Ode", JobID=1001, SiteID=101},
new AModel(){ ID=8, Name="Nicky", JobID=1001, SiteID=102},
}
}
};
return View(initialdata.FirstOrDefault());
}
Main page: using ViewData and view-data attribute to pass parameters.
#model MVCWebApplication.Models.JobViewModel
#{
ViewData["JobID"] = Model.JobID.ToString();
ViewData["SiteID"] = Model.SiteID.ToString();
}
<div>
<h4>JobViewModel</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.JobID)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.JobID)
</dd>
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.SiteID)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.SiteID)
</dd>
</dl>
<div class="form-group">
<partial name="_AModelPV.cshtml" model="#Model.ListAModel" view-data="ViewData"/>
</div>
</div>
Partial View (_AModelPV.cshtml): In the partial view, you could also check whether the ViewData exists and contains the value.
#model IEnumerable<MVCWebApplication.Models.AModel>
#{
var jobid = Convert.ToInt32(ViewData["JobID"]);
var siteid = Convert.ToInt32(ViewData["SiteID"]);
}
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.ID)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.JobID)
</th>
<th>
#Html.DisplayNameFor(model => model.SiteID)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Where(c=>c.JobID == jobid && c.SiteID == siteid).ToList()) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.JobID)
</td>
<td>
#Html.DisplayFor(modelItem => item.SiteID)
</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>
}
</tbody>
</table>
The result like this:
Besides, you could also consider filtering the data before sending data to the main page. For example, in the above action method, filter the data based on the JobID and SiteID, then return the result to the main page. In this scenario, the ListAmodel contains the filtered data, there is no need to do the filter action in the partial view.
var result = initialdata.Select(c =>
new JobViewModel {
JobID = c.JobID, SiteID = c.SiteID,
ListAModel = c.ListAModel.Where(d => d.JobID == c.JobID && d.SiteID == c.SiteID).ToList() })
.FirstOrDefault();
return View(result);

Error: The call is ambiguous between the following methods or properties

I get this error:
The call is ambiguous between the following methods or properties:
DisplayNameFor<IEnumerable<Category>,string>(HtmlHelper<IEnumerable<Category>>, System.Linq.Expressions.Expression<System.Func<IEnumerable,string>>)
and
DisplayNameFor<Category,string>(HtmlHelper<IEnumerable>, System.Linq.Expressions.Expression<System.Func<Category,string>>)
My model is
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
My Context Model is
public class CategoryContext : DbContext
{
public DbSet<Category> category { get; set; }
}
My Controller is :
public ActionResult GetCategory()
{
using (CategoryContext cc = new CategoryContext())
{
var cat = cc.category.ToList();
return View();
}
}
My View is :
#model IEnumerable<CRUD_Manav_EF.Models.Category>
<h1>Get Category</h1>
<table>
<tr>
<th>#Html.DisplayNameFor(model => model.CategoryName)</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayNameFor(modelItem => item.CategoryName) // I get error here
</td>
<td>
#Html.ActionLink("Edit", "Update", new { id = item.CategoryId })
#Html.ActionLink("Details", "Details", new { id = item.CategoryId })
#Html.ActionLink("Delete", "Delete", new { id = item.CategoryId })
</td>
</tr>
}
</table>
This error is displaying because you have used
#Html.DisplayNameFor(model => model.CategoryName) in table foreach loop and call would ambiguous between those method mentioned above. Since there is no benefit of using Display name again and again while iterating. if you will see the whole description of #Html.DisplayNameFor() you will get that the first parameter accept only model(lambda expression) and not IEnumerable of model. This is also shown in your compiler error.
see in example screenshot (this is dummy project)
Use #html.DisplayFor(..) instead in your foreach loop.
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CategoryName)
</td>
<td>
#Html.ActionLink("Edit", "Update", new { id = item.CategoryId })
#Html.ActionLink("Details", "Details", new { id = item.CategoryId })
#Html.ActionLink("Delete", "Delete", new { id = item.CategoryId })
</td>
</tr>
}
This htmlhelper method will take IEnumerable of your model. And your issue will be resolved(you can check it yourself).

Add database model (for listing records) to a View associated already with a model (for textboxes)

I'm quite new to MVC and still making myself familiar to how MVC works. So basically, I have a User model that has a Create view. I'm using Razor syntax to get the variables from User model:
Create.cshtml
#model CDS.Models.UserModels
#{
ViewBag.Title = "Create User";
}
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.firstname)
#Html.TextBoxFor(m => m.firstname)
<input type="submit" id="btnSave" value="Save" class="btn btn-default" />
}
UserModels.cs
namespace CDS.Models
{
public class UserModels
{
public string userid { get; set; }
[Display(Name = "First Name")]
public string firstname{ get; set; }
public IEnumerable<SelectListItem> filteroptions { get; set; }
}
}
I tried auto-generating an Index view from the controller's Index method to list the database records, but found out that the generated Index view is using the Database model (first line of code). I just want to move the code from the Index.cshtml to my Create.cshtml to have the latter View also display the database records. So how will I do that? I've heard that I need to use Javascript for that?
UserController.cs
namespace CDS.Controllers
{
public class UserController : Controller
{
CDSEntities _odb = new CDSEntities(); //My Database
// GET: User
public ActionResult Index()
{
return View(_odb.USR_MSTR.ToList());
}
// GET: User/Create
public ActionResult Create()
{
var filters = GetAllFilters();
var model = new UserModels();
model.filteroptions = GetSelectListItems(filters);
return View(model);
}
}
}
Index.cshtml
#model IEnumerable<CDS.USR_MSTR>
#{
ViewBag.Title = "Index";
}
<p>#Html.ActionLink("Create New", "Create")</p>
<table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.FIRST_NM)</th>
<th>#Html.DisplayNameFor(model => model.LAST_NM)</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.FIRST_NM)</td>
<td>#Html.DisplayFor(modelItem => item.LAST_NM)</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>
}
</table>
Please note that I removed the codes that I think unnecessary to post here. These are all just summaries of my classes and HTMLs

Avoid duplicating the results on viewpage in mvc

I'm creating banking application in MVC 5.
Load table by bank and Load table rows by Bank,
But I cannot figure out do this exactly like above image,
This what I'm getting , it has 10 tables, instead just 2 tables
this is cshtml code for above view
#model IEnumerable<albaraka.Models.ProductApprovals>
#{
ViewBag.Title = "Product_Approvals";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>sadfasf</h2>
<h2>Product Approvals</h2>
#using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
<div> Filter by : Date #Html.TextBox("SearchString", ViewBag.CurrentFilter as string) Filter by : Country #Html.TextBox("SearchString", ViewBag.CurrentFilter as string) <input type="submit" value="Search" /> </div>
}
#foreach (var item in Model)
{
#Html.DisplayNameFor(model => model.SubsidaryName); <p &nbsp /> #Html.DisplayFor(modelItem => item.SubsidaryName);
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ProductNameEn)
</th>
<th>
#Html.DisplayNameFor(model => model.ProdcutNameAr)
</th>
<th>
#Html.DisplayNameFor(model => model.CurrentStatus)
</th>
<th>
Actions
</th>
</tr>
#foreach (var inside in Model)
{
if (inside.Subsidary_ID == item.Subsidary_ID)
{
<tr>
<td>
#Html.DisplayFor(modelItem => inside.ProductNameEn)
</td>
<td>
#Html.DisplayFor(modelItem => inside.ProdcutNameAr)
</td>
<td>
#Html.DisplayFor(modelItem => inside.CurrentStatus)
</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>
}
}
</table>
}
This is Model class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace albaraka.Models
{
public class ProductApprovals
{
public DateTime SearchDate { get; set; }
public string Country { get; set; }
public string Product_ID { get; set; }
public string Subsidary_ID { get; set; }
public string SubsidaryName { get; set; }
public string ProductNameEn { get; set; }
public string ProdcutNameAr { get; set; }
public string CurrentStatus { get; set; }
}
}
This is Controller class
public ActionResult Product_Approvals()
{
var productApproveResult =(from p in db.AB_Product
join s in db.AB_Subsidary on p.Subsidary_ID equals s.SubsidaryID
select new ProductApprovals
{
Product_ID = p.ProductID,
Subsidary_ID = s.SubsidaryID,
SubsidaryName = s.SubsidaryNameEn,
ProductNameEn = p.ProductTitleEn,
ProdcutNameAr = p.ProductTitleAr,
CurrentStatus = p.Status
}).ToList();
return View(productApproveResult);
}
How to stop this repeating ,appricate if can show a way to this in view page
You need a view model(s) to represent what you want to display in the view. It should be something like
public class BankVM
{
public string SubsidaryName { get; set; }
public IEnumerable<ProductVM> Products { get; set; }
}
public class ProductVM
{
public string ProductNameEn { get; set; }
public string ProdcutNameAr { get; set; }
public string CurrentStatus { get; set; }
}
and pass a collection of BankVM to the view
#model IEnumerable<yourAssembly.BankVM>
#foreach(var bank in Model)
{
<h3>#Html.DisplayFor(m => bank.SubsidaryName)</h3>
<table>
foreach(var product in bank.Products)
{
<tr>
<td>#Html.DisplayFor(m => product.ProductNameEn)</td>
<td>#Html.DisplayFor(m => product.ProductNameAr)</td>
....
</tr>
}
</table>
}
In the controller, you can use a Linq .GroupBy() method to populate your collection of BankVM

Compound primary key edit view MVC

Hi I'm trying to edit a Students grade in a linker table that contains the Student Id and the Course Id. I've looked around a bit, and have seen that I need to take in two id parameters into the view rather than just the one id, and then change the action link to take two parameters. But when i click on the edit button in the index, I get a 404 saying the page can't be found. Any ideas where I'm going wrong?
Thanks in advance.
Here's my index view
#model IEnumerable<S00132671CA2.Models.StudentCourse>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Grade)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Grade)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id= item.StudentId, CourseId = item.CourseId }) |
#Html.ActionLink("Details", "Details", new { id = item.StudentId, Course = item.CourseId }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
Here's my Edit action
public ActionResult Edit(int? StudentId, int? CourseId)
{
StudentCourse courseList = db.StudentCourse.Find(StudentId, CourseId);
if (courseList == null)
{
return HttpNotFound();
}
ViewBag.StudentId = new SelectList(db.Students, "StudentId", "StudentName", courseList.StudentId);
ViewBag.CourseId = new SelectList(db.Courses, "CourseId", "CourseName", courseList.CourseId);
return View(courseList);
}
Here's my model if it's any help
public class StudentCourse
{
[Key, Column(Order = 0)]
public int StudentId { get; set; }
public virtual Student Student { get; set; }
[Key, Column(Order = 1)]
public int CourseId { get; set; }
public virtual Course Course { get; set; }
public double Grade { get; set; }
}
Try
#Html.ActionLink("Edit", "Edit", new { StudentId = item.StudentId, CourseId = item.CourseId })

Resources