System.NullReferenceException when trying to iterate list in view - asp.net-mvc

Im a bit new at mvc, and i dont find out what am i miss. When i launch the login, in the view at foreach (var item in Model) <- the Model gets null, and stops with a System.NullReferenceException. A dont really have a clue why, and i hope somebody can give some advice what's wrong with the following code or where to start looking for the error.
The model:
public class LoginModels
{
public string UserLogin { get; set; }
public string Address { get; set; }
public string Password { get; set; }
public List<string> emailSubject { get; set; }
}
The controller:
public ActionResult Login(string address, string password, LoginModels model)
{
using (Imap imap = new Imap())
{
try
{
imap.ConnectSSL("imap.gmail.com");
imap.Login(address, password);
imap.SelectInbox();
List<long> uids = imap.Search(Flag.All);
model.emailSubject = new List<string>();
foreach (long uid in uids)
{
var eml = imap.GetMessageByUID(uid);
IMail email = new MailBuilder().CreateFromEml(eml);
model.emailSubject.Add(email.Subject);
}
Session["user"] = new LoginModels() { UserLogin = address, Address = address };
return RedirectToAction("Index", "Home", model.emailSubject);
}
catch (Exception e)
{
ViewBag.exceptionMessage = e;
return View("LoginFailed");
}
}
The view:
#using TheOnlineArchivator.Models;
#model List<TheOnlineArchivator.Models.LoginModels>
#{
ViewBag.Title = "Home";
}
#{
var user = Session["user"] as LoginModels;
if (user != null)
{
<h2>You are logged on as #user.Address</h2>
<table>
#foreach (var item in Model)
{
foreach (var elem in item.emailSubject)
{
<tr>
<td>#elem</td>
</tr>
}
}
</table>
}
}

It looks like you forgot to pass an instance of List<TheOnlineArchivator.Models.LoginModels> to the view when you rendered this view inside your controller action. What you have shown so far is your Login controller action but you didn't show us your Home/Index action. Inside this action you should make sure that you are passing a non-null model to the view:
public class HomeController : Controller
{
public ActionResult Index()
{
List<LoginModels> model = ... go get your model from somewhere and make sure it is not null
return View(model);
}
}

Related

getting all rows from db mvc asp.net

var listdata = db.UserDetails.Select(m => new SelectListItem
{
Value = m.userid.ToString(),
Text = string.Format("{0}{1}{2}{3}",m.bankname,m.userid,m.gender,m.name)
});
Here UserDetails is the table that is present in the database and this is the way i am trying to display every entry of the table.
Controller
[HttpGet]
public ActionResult getAll()
{
var listdata = db.UserDetails.Select(m => new SelectListItem
{
Value = m.userid.ToString(),
Text = string.Format("{0}{1}{2}{3}",m.bankname,m.userid,m.gender,m.name)
});
return View("getAll", listdata);
}
View
#model UserApp.Models.UserDetails
#{
ViewBag.Title = "getAll";
}
<h2>getAll</h2>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.gender)
</td>
</tr>
}
Model
namespace UserApp.Models
{
public class UserModel : IEnumerable<UserModel>
{
public int userid {get; set;}
public string name{get; set;}
public IList<SelectListItem> bankname { get; set; }
public string gender{get; set;}
}
}
How do i get the elements and display them properly on the view?
I can't seem to get a proper solution.
Stuck on this thing for hours.
P.s: new to it, any help will be appreciated.
First, add ToList() for your listdata to make it list, currently it is still IQueryable , second your view accepts model, you are passing list of model, I guess you want that to be list not model, something like this
#model List<UserApp.Models.UserDetails>
Third, you are selecting SelectListItem but you are using UserApp.Models.UserDetails, I think you should be doing something like this
var listdata = db.UserDetails.ToList().Select(x => new UserApp.Models.UserDetails {
userid = x.userid, (repeat the same for all)
}).ToList();
because looking at your code you don't need selectListItem, you need UserApp.Models.UserDetails.
That should fix all your problems, I hope I didn't miss any.
My approach may not be the best approach but it seems to work for me.
I usually have my model for the item :
model :
namespace UserApp.Models
{
public class UserModel
{
public int userid {get; set;}
public string name{get; set;}
public IList<SelectListItem> bankname { get; set; }
public string gender{get; set;}
}
}
Then I have in my database class ( a class that calls the database and populates the queries etc: Call it CodeDB() for this example)
DB getter :
public List<UserModel> getUsers(){
{
List<UserModel> myUsers = new List<userModel>();
// however you are accessing your db do it here
string sql = "select * ...";
//access DB
//open connection
//run query command usually for me it is rdr = cmd.ExecuteReader();
while(rdr.Read()){
UserModel retrievedUser = new UserModel();
retrievedUser.userid = (int)rdr[0];
retrievedUser.name = rdr[1].ToString();
... add the other fields
myUsers.Add(retrievedUser);
}
//close db connection
return myUsers
}
In my Controller
//call my database class
CodeDB() DB = new CodeDB()
[HttpGet]
public ActionResult getAll()
{
List<UserModel> viewUsers = DB.getUsers();
ViewBag.users = viewUsers
return View();
}
in the view
#{
if(Viewbag.users != null)
{
foreach(UserApp.Models.UserModel u in ViewBag.users)
{
#Html.Raw( " userID : " + u.userid +" Gender : " + u.gender)
}
}
}
I think you could do. MVC Scaffolding of Crud with there Views Auto Generated
When you make your controller There's an option "MVC Controller with Views"
Then it will ask For your Model that you want to use for scaffolding which will be
"UserModel" Then just give your Controller a Name.
Now if you look at the Index View of your Controller it will have all the attributes you want and don't want.But of course, you can remove the unnecessary attributes
Hope this helps!

MVC Error using Lists and Model

I am very new to this and am doing a little project to get to know how it all works.
So I'm looking to create a header image area on each page by placing the code in the "_Layout.cshtml" file and attempting to control what image displays according to "ViewBag.Title".
I have broken the code up into the pages, followed by a pic. of the error. I just can't work out what the problem is.
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebSite_Project_1.Controllers
{
public partial class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
[ActionName("Funny-Bones")]
public ActionResult FunnyBones()
{
ViewBag.Message = "This is funny bones.";
return View();
}
public class Headers
{
public string HeaderName { get; set; }
public string PageName { get; set; }
public int HeaderWidth { get; set; }
public int HeaderHeight { get; set; }
public string HeaderType { get; set; }
}
public ActionResult HeaderImages()
{
var model = new List<Headers>();
model.Add(new Headers { HeaderName = "home", PageName = "Home Page", HeaderWidth = 2200, HeaderHeight = 1172, HeaderType = ".png" });
model.Add(new Headers { HeaderName = "about", PageName = "About", HeaderWidth = 2200, HeaderHeight = 1172, HeaderType = ".png" });
model.Add(new Headers { HeaderName = "contact", PageName = "Contact", HeaderWidth = 2200, HeaderHeight = 1172, HeaderType = ".png" });
model.Add(new Headers { HeaderName = "funnybones", PageName = "Funny Bones", HeaderWidth = 2200, HeaderHeight = 1172, HeaderType = ".png" });
return View(model);
}
}
}
_Layout.cshtml
#model IEnumerable<WebSite_Project_1.Controllers.HomeController.Headers>
<div class="headersImage">
#foreach (var item in Model)
{
if (#item.PageName == #ViewBag.Title)
{
<img src="~/Content/Images/#item.HeaderName+#item.HeaderType" title="#item.HeaderName" />
}
}
</div>
#RenderBody()
The problem starts when I try and publish it and then i get this error pointing to Model in the "foreach" loop.
I'm not a 100% sure the loop is right, but haven't been able to get that far yet.
Link to MVC error
You should never specify a model for a layout. The model passed in will always be the one for the view, which almost invariably, will not be the same one the layout is wanting.
For things like this, you should use child actions. Essentially, just take your existing HeaderImages action, add the [ChildActionOnly] attribute (which prevents it from being routed to directly), and change the return to:
return PartialView("_HeaderImages", model);
You can call the view whatever you want, but essentially it would just have the following:
#model IEnumerable<WebSite_Project_1.Controllers.HomeController.Headers>
<div class="headersImage">
#foreach (var item in Model)
{
if (#item.PageName == #ViewBag.Title)
{
<img src="~/Content/Images/#item.HeaderName+#item.HeaderType" title="#item.HeaderName" />
}
}
</div>
Finally, in your layout, remove the model definition line and replace the header image code currently there with:
#Html.Action("HeaderImages", "Home")
EDIT
Sorry, I missed one thing. The child action will render in a separate context from the main view/layout (that's sort of the point). However, that means it has its own ViewBag, so you can't access the ViewBag from the main action directly. Instead, you'll need to pass it in as a route value:
#Html.Action("HeaderImages", "Home", new { title = ViewBag.Title })
Then, modify your child action to accept this param, and set its ViewBag:
[ChildActionOnly]
public ActionResult HeaderImages(string title)
{
...
ViewBag.Title = title;
return PartialView("_HeaderImages", model);
}

How to clear text from a search textbox after search is complete in MVC

I have two dropdown lists and two textboxes
Search By: ByHtml.DropDownList("Search1", "Please Select...")
Html.TextBox("searchString1")
Search By: Html.DropDownList("Search2", "Please Select...")
#Html.TextBox("searchString2")
<input type="submit" value="Filter" />
When I make my selection from whichever DDL and type text into the textbox and hit filter my search returns, however after the search the text remains in the textbox, is there a way of clearing it after the search so that the textbox is empty again? I tried
ModelState.Remove("");
but it didn't work.
A sample from My controller code is
public class MainController : Controller
{
private DBEntities db = new DBEntities();
// GET: /Main/
public ActionResult Index(string searchString1, string searchString2, string Search1, string Search2)
{
//Create a Dropdown list
var SearchOptionList = new List<string>();
SearchOptionList.Add("LandLord");
SearchOptionList.Add("Postcode");
SearchOptionList.Add("Street Address");
ViewBag.Search1 = new SelectList(SearchOptionList);
ViewBag.Search2 = new SelectList(SearchOptionList);
var mylist = from m in "mydatabase" select m;
//This statement runs if the user selects a parameter from Search2 and leaves Search1 empty
if (String.IsNullOrEmpty(Search1) && !String.IsNullOrEmpty(Search2))
{
if (Search2 == "Postcode")
{
mylist = mylist.Where(s => s.Postcode.Contains(searchString2));
}
if (Search2 == "LandLord")
{
mylist = mylist.Where(s => s.Name.Contains(searchString2));
}
if (Search2 == "Street Address")
{
mylist = mylist.Where(s => s.StreetAddress.Contains(searchString2));
}
}
return View(mylist.ToList());
}
Your should have a view model containing properties searchString1 and searchString2 and the select lists
public class SearchVM
{
public string searchString1 { get; set; }
public string searchString2 { get; set; }
public SelectList SearchList1 { get; set; }
public SelectList SearchList2 { get; set; }
}
Controller
public ActionResult Search()
{
SearchVM model = new SearchVM();
model.SearchList1 = new SelctList(...);
model.SearchList2 = new SelctList(...);
return View(model);
}
View
#model SearchVM
#using(Html.BeginForm())
{
....
#Html.DropDownListFor(m => m.searchString1, Model.SearchList1, "--Please select--")
#Html.DropDownListFor(m => m.searchString2, Model.SearchList2, "--Please select--")
....
}
Post
[HttpPost]
public ActionResult Search(SearchVM model)
{
// to clear all modelstate and reset values
ModelState.Clear();
model.searchString1 = null;
model.searchString2 = null;
// or to clear just one property and reset it
ModelState.Remove("searchString1");
model.searchString1 = null;
// repopulate select lists if your returning the view
return View(model);
}
At the end of my public ActionResult Index method but before return View() I placed the following code which worked perfectly
ModelState.Remove("searchString1");
ModelState.Remove("searchString2");
ModelState.Remove("Search1");
ModelState.Remove("Search2");
I know is an old question, but I fall in the same issue. So I put my solution.
View:
#Html.TextBox("Search", null, new { #autofocus = "autofocus" })
Controller:
ViewBag.Search= null;
ModelState.Remove("Search");
return View(list.ToList());
Hope to help someone

Form not passing values on POST

Here's my view code:
#model pedidosOnlineMVC.Models.ViewModel.AdmView
#using pedidosOnlineMVC.Models
#{
Layout = "~/Views/Administrador/_LayoutAdm.cshtml";
List<Usuario> lu = pedidosOnlineMVC.Controllers.UsuarioController.favoreds(Model.adm.estabelecimento.Estabelecimento_Id);
}
#using (var f = Html.Bootstrap().Begin(new Form()))
{
using (var p = Html.Bootstrap().Begin(new Panel()))
{
using (var t = Html.Bootstrap().Begin(new Table()))
{
using (var h = t.BeginHeader())
{
using(var hr = h.BeginHeaderRow())
{
#hr.Cell("Usuário")
#hr.Cell("Status")
}
}
using(var b = t.BeginBody())
{
for(int i=0;i<lu.Count;i++)
{
using(var c = b.BeginRow())
{
#f.FormGroup().CustomControls(Html.HiddenFor(model => model.Usuario_Id[i], lu[i].Usuario_Id))
#c.Cell(lu[i].nome)
#c.Cell(f.FormGroup().CustomControls(Html.Bootstrap().CheckBoxFor(model=>model.checkAuts[i])))
}
}
}
}
using (var pf = p.BeginFooter())
{
#f.FormGroup().CustomControls(#Html.HiddenFor(model => model.adm.Administrador_Id, Model.adm.Administrador_Id))
#f.FormGroup().CustomControls(Html.Bootstrap().SubmitButton().Text("Autorizar"))
}
}
}
And I had a similar problem here: cshtml page not passing date value on post, but what I did then doesn't work here.
I tried looking in the network window in the developer tools and I can see the ID values (Administrador_ID and Usuario_ID) being sent on post, but they never reach my controller.
Here's the code for the controller:
[HttpPost]
public ActionResult autCli(AdmView adm)
{
return null;
}
It has no code in it because I still didn't get it to work, but the parameters should still work when debugging, but I get NULL in every attribute instead.
If anyone can help, I'd appreciate it.
AdmView model, as requested:
public class AdmView
{
public Administrador adm { get; set; }
public Produto prod { get; set; }
public virtual List<bool> checkAuts { get; set; }
public virtual List<int> Usuario_Id { get; set; }
}
Try to use the FormCollection to pass data from view to controller.
Just like this:
[HttpPost]
public ActionResult autCli(FormCollection collection)
{
strint Usuario_Id = collection["Usuario_Id"]; //You can get data with this way...
return View();
}
Check this question for more info.
Add [HttpPost] before your ActionResult method.

Finding Roles MVC 4 Simple Membership

My Action
[Authorize(Roles = "Admin")]
public ActionResult Index()
{
using (var ctx = new _dbContext())
{
return View(ctx.UserProfiles.OrderBy(x => x.UserId).ToList());
}
}
I want to display roles with UserId and UserName how can i do that??
Update:
View Model
public class AccountIndexViewModel
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Roles { get; set; }
}
View
#using GoldCalculator.Models
#model IEnumerable<AccountIndexViewModel>
#foreach (var user in Model)
{
<tr>
<td>#user.UserId</td>
<td>#user.UserName</td>
<td>#user.Roles</td>
<td> #Html.ActionLink("X", "Delete", new { id = #user.UserName }, new { #class = "deletebtn"})</td>
</tr>
}
The output is System.String[]
Assuming you have enabled roles in your application and that you have already created some roles:
using WebMatrix.WebData;
///blah blah blah...
///inside some action:
var roles = (SimpleRoleProvider)Roles.Provider;
var allRoles = roles.GetAllRoles();
Getting role for specific user:
var userRoles = roles.GetRolesForUser("admin#user.com");
Answering you new question, try this:
var model = ctx.UserProfiles.OrderBy(x => x.UserId);
var newModel = from ab in model
select new
{
UserName = ab.UserName,
UserId = ab.UserId,
Role = roles.GetRolesForUser(ab.UserName)
};
You are assigning value to variable that already has been declared and apparently data types don't match.

Resources