I am creating a tracking application to keep track of some server and their build info. I want the user to fill out one single form that then performs a INSERT into two separate tables. Here is my code, but it only populates the "Server" table and not the "System_Build_Information" table. I have tried also changing the Bindings and even leaving them out all together. This code by the way is from my Server controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Server_Name,Server_Role,Server_OS")] Server server, [Bind(Include = "Model")] System_Build_Information sys)
{
if (ModelState.IsValid)
{
db.Servers.Add(server);
db.System_Build_Information.Add(sys);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Server_Role = new SelectList(db.Server_Roles, "Id", "Server_Role", server.Server_Role);
ViewBag.Server_OS = new SelectList(db.Operating_System, "Id", "Operating System", server.Server_OS);
string[] environments = new string[] { "Virtual", "Physical" };
ViewBag.Environments = new SelectList(environments);
return View(server);
}
I believe that the default model binder is not able to bind to the two classes that you have passed (and the Bind() statements may also be interfering). If you need to have information from two models placed into a view and POSTed back, create a new view model class that contains the models for both of those classes.
public class ServerInfoViewModel{
public Server ServerInfo {get;set;}
public System_Build_Information SystemBuildInfo {get;set;}
}
Now, send this view model back and forth to your view.
#model namespace.ServerInfoViewModel
and to use the properties in your form
#Html.TextBoxFor(x=>x.ServerInfo.Type)
#Html.TextBoxFor(x=>x.SystemBuildInfo.SomeField)
Lastly, you would need to update your POST action method to bind the new view model
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ServerInfoViewModel model)
{
if (ModelState.IsValid)
{
db.Servers.Add(model.ServerInfo);
db.System_Build_Information.Add(model.SystemBuildInfo);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.Server_Role = new SelectList(db.Server_Roles, "Id", "Server_Role", server.Server_Role);
ViewBag.Server_OS = new SelectList(db.Operating_System, "Id", "Operating System", server.Server_OS);
string[] environments = new string[] { "Virtual", "Physical" };
ViewBag.Environments = new SelectList(environments);
return View(model);
}
Related
I am developing an ASP.NET MVC application, populating dropdownlist to view working fine in get method. I am populating to view like this in my controller
[HttpGet]
public ActionResult CreateEmployeeFamilyDetails(EmployeeSuperClass employeeSuperClass, int i = 0)
{
employeeSuperClass.FamilyDetailsFields = new FamilyList();
employeeSuperClass.FamilyDetailsFields.familyMembersList.Insert(0, new EmployeeFamilyTable());
*employeeSuperClass.FamilyDetailsFields.employee_RelationTable = dt.GetRelations();*
*employeeSuperClass.FamilyDetailsFields.employee_BloodGroupTable = dt.GetBloodGroups();*
*employeeSuperClass.FamilyDetailsFields.employee_NationalityTable = dt.GetNationalities();*
return View("CreateEmployeeFamilyDetails", employeeSuperClass);
}
Please look into starred lines
In case if there is any errors in model am getting null reference
In post action method look like this
[HttpPost]
public ActionResult CreateEmployeeFamilyDetails(EmployeeSuperClass employeeSuperClass, string Command)
{
if (ModelState.IsValid)
{
return("some view");
}
else
{
return view(employeeSuperClass);
}
}
I know again we have to create instance to populate dropdownlist this is rubbish to do same again and again
Can anyone explain how to store dropdown list collection in view separately and post them also with model?
(note: employee_relationTable is IEnumerable collection and it is a relationtable type this table contains relation id and relationname fields and am using this table in this class like below
public IEnumerable<EmployeeRelationTable> employee_RelationTable { get; set; }
For rest also am using same approach
Can we post employee_RelationTable from view and how?
Please help and your help would be greatly appreciated
Assuming dt is a member field available to all methods, what you can do is DRY up the population of the DropDowns in the View Model in a separate method, e.g.
private void PopulateDropDownsOnViewModel(EmployeeSuperClass model)
{
model.FamilyDetailsFields = new FamilyList
{
employee_RelationTable = dt.GetRelations(),
employee_BloodGroupTable = dt.GetBloodGroups(),
employee_NationalityTable = dt.GetNationalities()
}
}
Which can be used in the Get:
[HttpGet]
public ActionResult CreateEmployeeFamilyDetails(EmployeeSuperClass employeeSuperClass, int i = 0)
{
PopulateDropDownsOnViewModel(employeeSuperClass);
return View("CreateEmployeeFamilyDetails", employeeSuperClass);
}
and in the Post (and any other controller actions which need the drop downs)
[HttpPost]
public ActionResult CreateEmployeeFamilyDetails(EmployeeSuperClass employeeSuperClass, string Command)
{
if (ModelState.IsValid)
{
return("some view");
}
else
{
PopulateDropDownsOnViewModel(employeeSuperClass);
return View(employeeSuperClass);
}
}
If the drop downs are static, you can also look at caching these to prevent wasted IO to the database.
But no, don't serialize the the data in the View somehow (remember WebForms ViewState?) or fetch data from the View directly - this violates the MVC paradigm - the controller is responsible for providing data for the View to render.
I'm having some issues with my DropDownLists, because when I post the information and my Model is not valid it comes back "empty" to the page triggering an error exactly like this question.
I've used the solution proposed there and it fixed my problem. Anyway, I wanted to avoid querying the database every time my ModelState is not valid and I came with this approach. I would like to know if it is valid or if there are better ways to do it now, considering that instead of MVC2 (which was the MVC version from the question) I'm now using MVC 5, maybe they added something new to tackle this.
What I've done was to use the TempData to persist the information when my model is not valid.
public class ViewModel
{
[DisplayName("Project")]
public int ProjectID { get; set; }
public List<SelectListItem> Projects { get; set; }
//Other fields
}
Now my Create() Action (that populates Projects)
[HttpGet]
public ActionResult Create()
{
ViewModel vmodel = new ViewModel();
vmodel.Projects = db.GetProjects(User.Identity.Name).Select(x => new SelectListItem { Text = x.Description, Value = x.Id }).ToList();
TempData["Projects"] = vmodel.Projects;
return View(vmodel);
}
And my post would be like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ViewModel vmodel)
{
//Clear TempData (in theory will clear my tempdata when read, so if this controller redirects to another action my tempdata will be clear)
List<SelectListItem> projects = (TempData["Projects"] as List<SelectListItem>);
if (ModelState.IsValid)
{
//...
}
//If it got here it's going back to the screen.
//Repopulate the TempData (allowing it to exist one more trip)
TempData["Projects"] = projects;
vmodel.Projects = projects
return View(atendimento);
}
Is this approach a good one? Is there a better way to achieve that without querying the database every single time?
Thanks a lot!
You don't need to use TempData at all as you have a property in your view model to hold the dropdown items.
public ActionResult Create()
{
ViewModel vmodel = new ViewModel();
vmodel.Projects = GetProjects();
return View(vmodel);
}
private List<SelectListItem> GetProjects()
{
return db.GetProjects(User.Identity.Name)
.Select(x => new SelectListItem { Text = x.Description,
Value = x.Id }).ToList();
}
And in the view
#Html.DropDownListFor(s=>s.ProjectID,Model.Projects)
And in your HttpPost action, If ModelState is not valid, Reload the Projects collection again (because http is stateless)
if(ModelState.IsValid)
{
// to do :Save and redirect
}
model.Projects = GetProjects();
return View(model);
You may cache the Projects so that you do not need to hit the database every time, if you are too much worried about performance.
Personally, I wouldn't worry about querying the database each time for this kind of operation.
What if projects are added/deleted? This could be the reason the save failed (selected project deleted) and the user would never realise it.
I usually write a method to populate all of my view model's SelectListItems and then use this in my Get and in my Post if the validation fails.
I am new in MVC.
I have a class in Models like below.
public class UserInfo
{
public string Name{get;set;}
public string Surname{get;set;}
}
And I have a controller like this.
public class HomeController : Controller
{
//
// GET: /Home/
List<UserInfo> Users = new List<UserInfo>();
public ActionResult Index()
{
return View();
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(UserInfo userInfo)
{
if (ModelState.IsValid)
{
Users.Add(userInfo);
return RedirectToAction("Index");
}
return View();
}
}
And every time when i press Create button in browser, it redirects to Index View.
But List<UserInfo> is empty. Why it happens? How to save data into List and show from grid or table from that List?
Controllers are stateless. A new instance is created each time you call an action, this is why your list is always empty.
If you want to persist the list between controller actions, you will need some sort of persistence mechanism - database, caching, etc.
Make your list static
static List<UserInfo> Users = new List<UserInfo>();
I believe Maess pointed out the details first.
Even though your [HTTPPost] Create action adds the new user to the List object, there does not appear to be any means to save the entered data to persistent storage. Every time you instantiate the controller, the List object will be empty, as you have currently coded it.
If you want the data stored to a database, check out this tutorial from asp.net for one method:
http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/accessing-your-models-data-from-a-controller
In your view put this reference for object:
Inherits="System.Web.Mvc.ViewPage<List<UserInfo>>" %>
And in your class change this:
List<UserInfo> Users = new List<UserInfo>();
public ActionResult Index()
{
return View(Users);
}
but for you to save the list data in memory, you'd better declare the List object as static, because then he retains the information already added. For example:
public class HomeController : Controller
{
public static List<UserInfo> Users = null;
//
// GET: /Home/
public ActionResult Index()
{
return View(Users);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(UserInfo userInfo)
{
if (ModelState.IsValid)
{
Users.Add(userInfo);
return RedirectToAction("Index");
}
return View();
}
}
Everytime you create a List<T> with new keyword it's instance is created which doesn't have any kind of data, so get data from database using your DatabaseContext and bind it to your list like this:
List<UserInfo> Users = new List<UserInfo>();
Users.Add(_databasecontext.Users.ToList());
and return it to the view.
Warning: This is my first web app.
I have 4 models, views and controllers. Lets call them A, B, C, D(ex. ModelA, ControllerA, ViewA). They are all basic views with list scaffolding.
/ControllerA/Index
User starts at ViewA and Selects an the first item, which redirects the user to ViewB
/ControllerB/Function?Aid=1
ViewB shows another list based on Selection from ViewA. Then the user Selects again is is redirected to ViewC
/ControllerC/Function?Aid=1&Bid=2
ViewC shows another list based on Selections from ViewA and ViewB. Then the user Selects again is is redirected to ViewD.
/ControllerD/Function?Aid=1&Bid=2&Cid=3
ViewD shows another list based on Selections from ViewA, ViewB, and ViewC, Then the user Selects again.
At this point I would like to POST Aid, Bid, Cid, and Did and save them in my database. Ideally the user would click the link, the data would be posted and then the site would redirect the user back to the homepage. Should I create another model and controller to Handle the post? I thought about trying to do the POST from controllerD but that doesn't seem like the proper way to do this.
The msdn tutorials only show posting directly from a view with a strongly typed model. I kinda stuck and I would prefer not to make this a complete mess.
Edit for Code
Controller
public ActionResult myFunction(int Aid = 0, int Bid, int Cid)
{
//query D stuff here
if (D == null)
{
return HttpNotFound();
}
return View(D.ToList());
}
[HttpPost]
[InitializeSimpleMembership]
public ActionResult CreateQuote(int Aid, int Bid, int Cid, int Did)
{
Quote myQuote = new Quote();
myQuote.Customer_ID_FK = (int)Membership.GetUser().ProviderUserKey;
myQuote.A_ID_FK = Aid;
myQuote.B_ID_FK = Bid;
myQuote.C_ID_FK = Cid;
myQuote.D_ID_FK = Did;
if (ModelState.IsValid)
{
db.Quotes.Add(myQuote);
db.SaveChanges();
db.Quotes.Max();
int mymax = db.Quotes.Max(q => q.ID);
return RedirectToAction();
}
return View(D.ToList());
}
[HttpPost]
[InitializeSimpleMembership]
public ActionResult CreateQuote(Quote myQuote)
{
myQuote.Customer_ID_FK = (int)Membership.GetUser().ProviderUserKey;
if (ModelState.IsValid)
{
db.Quotes.Max();
int mymax = db.Quotes.Max(q => q.ID);
db.Quotes.Add(myQuote);
db.SaveChanges();
return RedirectToAction();
}
return View(D.ToList());
}
It usually makes sense to put your post handler in the controller it's related to. This isn't always the case, as sometimes it would make more sense to make a new controller to handle all posts related to a certain task. You should also understand the distinction between a method IN a controller, and a controller. A controller is just a class that inherits from System.Web.Mvc.Controller and can have methods just like any other class. A perfectly reasonable controller could look like this:
public class DController : Controller
{
//GET /d
public ActionResult Index()
{
//MyModel is a class that would contain the logic to display
//the selections from A, B, and C
var model = new MyModel();
return View(model);
}
//POST /d/saveresults
//We only want this method to accept POST
[HttpPost]
public ActionResult SaveResults(MyEntity data)
{
var model = new MyModel();
model.SaveResultsToDatabase(data);
return Redirect("/");
}
}
The important thing in a controller is to keep logical processing to a minimum. There's nothing wrong with having an if statement here and there, but the majority of your logic should be handled by your model. A controller is there primarily to pass data between your views and models.
Thanks in advance for your help. I cannot move forward creating or editing fields in asp.net mvc using two tables or more. As an example: I´ve been using MVC Music Store example to learn
//
// GET: /StoreManager/Create
public ActionResult Create()
{
var viewModel = new StoreManagerViewModel
{
Album = new Album(),
Genres = storeDB.Genres.ToList(),
Artists = storeDB.Artists.ToList()
};
return View(viewModel);
}
//
// POST: /StoreManager/Create
[HttpPost]
public ActionResult Create(Album album)
{
if (ModelState.IsValid)
{
//Save Album
storeDB.AddToAlbums(album);
storeDB.SaveChanges();
return RedirectToAction("Index");
}
// Invalid – redisplay with errors
var viewModel = new StoreManagerViewModel
{
Album = album,
Genres = storeDB.Genres.ToList(),
Artists = storeDB.Artists.ToList()
};
return View(viewModel);
}
This example takes into consideration that Album is only one table at the model. My main question resides in the way I have to code in order to include another table with FK to Album. As an example if AlbumVariant table - eg: field albumid- displays a FK to Album Table - eg: field albumid-.
I´ve been trying with
[Authorize]
public ActionResult Create(int? id)
{
var albumCreate= db.Album.Include(AlbumVariant)SingleOrDefault(a => a.AlbumId == id);
var viewModel = new AlbumViewModelCreate()
{
AlbumCreate = albumCreate,
};
}
but with no success. Any Help will be appreciated. brdgs
You have to understand that AlbumVariant table takes AlbumId as a foreign key that means AlbumId has to be generated first! You can try this:
storeDB.AddToAlbums(album);
storeDB.SaveChanges();
AlbumVariant av = new AlbumVariant {
...
AlbumId = album.Id //generates after calling the 1st save changes
}
storeDB.AddToAlbumVariant(av);
storeDB.SaveChanges();