MVC 3 Details View - asp.net-mvc-3

I am new to MVC frame work. And i am making one page where we can see details of department by clicking on details link button.
While User click link button it fetch the all the records of the particular department in List Collection and redirect to Details View.Data has been fetched in List but while going to Details view it Generates following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[DocPageSys.Models.Interfaces.DepartmentInfo]', but this dictionary requires a model item of type 'DocPageSys.Models.Interfaces.DepartmentInfo`'.
I understood the error but confusion to solve it.And stuck with this problem...

Since your Details view is strongly typed to DepartmentInfo:
#model DocPageSys.Models.Interfaces.DepartmentInfo
you need to pass a single instance of it from the controller action instead of a list:
public ActionResult Details(int id)
{
DepartmentInfo depInfo = db.Departments.FirstOrDefault(x => x.Id == id);
return View(depInfo);
}
So make sure that when you are calling the return View() method from your controller action you are passing a single DepartmentInfo instance that you have fetched from your data store.
To make it run fine initially you could simply hardcode some value in it:
public ActionResult Details(int id)
{
var depInfo = new DepartmentInfo
{
Id = 1,
Name = "Sales",
Manager = "John Smith"
}
return View(depInfo);
}
Oh, and you will notice that I didn't use any ViewData/ViewBag. You don't need it. Due to their weakly typed nature it makes things look really ugly. I would recommend you to always use view models.

Passing a list instead of a single item
This error tells you, that you're passing a list to your view but should be passing a single entity object instance.
If you did fetch a single item but is in a list you can easily just do:
return View(result[0]);
or a more robust code:
if (result != null && result.Count == 1)
{
return View(result[0]);
}
return RedirectToAction("Error", "Home");

This error will typically occur when there is a mismatch between the data that the controller action passes to the view and the type of data the view is expecting.
In this instance it looks as if you're passing a list of DepartmentInfo items when your view is expecting a single item.

Related

Manually loading navigation properties in MVC 6

What is the best way to manually load navigation property in MVC 6?
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(Reservation reservation, bool ignoreConflicts = false)
{
int id = reservation.ItemID; // correct item ID
Item item = reservation.Item; // null
}
In this example, when user submits a form, I get a Reservation object with all navigation properties set to null.
The best way I can think of is manually looking up the Item DbSet to find the item with matching ID and assigning it to the navigation property.
Well, first thing first... you are in an MVC action. What you will receive will be from the client. Not the database directly.
So reservation.Item might not be null but it might not be the real data either.
In this scenario, you first have to retrieve your data from the server and then do one of two things:
Update the EF7 entity directly by hand from what you received from the client
Use TryUpdateModelAsync to update your current entity automatically.
It could be as simple as:
public ActionResult Update(Reservation reservation)
{
var item = context.Items.FirstOrDefault(x => x.ID == reservation.ItemID);
await TryUpdateModelAsync(item);
// todo: save context
// return....
}
This is an Entity Framework 7 issue, not an MVC6 one.
Lazy loading isn't implemented for EF7 yet, possibly it won't be at all.
You can track the ticket here https://github.com/aspnet/EntityFramework/issues/3797
This means instead we need to do it as you suggested; something like:
Item item = context.Items.FirstOrDefault(x => x.ID == reservation.ItemID);

.NET MVC3/Holding temp model

I have a situation where i have to take input(form) from user. After continue button is pressed next view page is displayed. But after continue is pressed i don't want to store the model in the DB. I have to display some details(combining some tables) according to input given by the user earlier and again get some data from user. Only then i want to store the model in the respective tables.
How can i perform this? I tried getting Model from user and passing to the function that generates next page. Is this is way to do it? or there is other way around?
Store the model submitted by the first form in session.
[HttpPost]
public ActionResult ContinueForm1(Model1 model1)
{
if(ModelState.IsValid)
{
Session["Model1"] = model1;
return View("Form2");
}
return View();
}
[HttpPost]
public ActionResult ContinueForm2(Model2 model2)
{
if(ModelState.IsValid)
{
... model2 is already here, get the model1 from session
... and save to datatbase finally return a different view or redirect to some
... other action
}
return View();
}
You are heading down the right track.
You need to grab the model that is passed back from the first view - preferably you are using ViewModels here rather than binding directly to your db models. Have a look at http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ and Why should I use view models? as to why these are good things.
The easiest way to do this is to pass the model in as an argument to your method e.g.
Assuming that your views are using the same ViewModel ( which may or may not be true) then you can send the viewmodel straight to your new view - else you can copy the elements into a new viewModel and send that.
e.g.
[HttpPost]
public ViewResult Step1(MyViewModel viewModel)
{
//Do some validation here perhaps
MySecondViewModel secondViewModel = new MySecondViewModel{
Id = viewModel.Id,
// etc. etc.
};
return View("Step2", secondViewModel);
}
Then you can carry on as you need until you have to persist the entity to the database.
NB as you do not need to do anything special in the form to make it post the model as an argument as long as the view is strongly typed to that ViewModel.

Use the same instance of model view across views in ASP MVC 3

I have two views : the first one has a form which when submitted, it fills in a model view (QuizzModelView).
Now after submitting, I am redirected to another view which also has a form that I want to submit. The problem is that I want to use the same QuizzModelView for the two views. That means, when submitting the second form, I want also to submit the values of the previous form. I can do this by creating hidden inputs which take the values that come from the first view.
Is there a way to do it without hidden inputs.
Thanks
EDIT :
To explain more:
My model view contains : QuizzModelView.field1, QuizzModelView,.field2
1st step : View1 will fill in QuizzModelView.field1
2nd step : I am redirected to view2
3rd step : View2 will fill in QuizzModelView.field2
Now I want to be able to get QuizzModelView.field1 and QuizzModelView.field2. But I get Only QuizzModelView.field2 because QuizzModelView.field1 is lost when submitting View2
Here are my actions :
[HttpPost]
public ActionResult TAFPart2PopupEvents(QuizzModelView model)
{
return PartialView("PartialViews/_TAFPart2PopupEvents", model);
}
[HttpPost]
public ActionResult TAFPart3PopupEvents(QuizzModelView model)
{
// here I want to use
// model.field1 and model.field2
}
Technically (pedantically), you won't be able to use the same instance of the model. However, you can put it in the session and pass across the redirects. Session has the advantage of not getting tampered with as easily as hidden fields. Plus you wouldn't have to actually bind the whole model for each step - just the single field from each step:
[HttpPost]
public ActionResult TAFPart2PopupEvents(string field1)
{
QuizzModelView model = new QuizzModelView();
model.Field1 = field1
Session["Quiz"] = model;
return PartialView("PartialViews/_TAFPart2PopupEvents", model);
}
[HttpPost]
public ActionResult TAFPart3PopupEvents(string field2)
{
var model= (QuizzModelView )Session["Quiz"];
// Fill in field2 here
model.Field2 = field2;
}
Edit: To address Brian's comment with some actual detail -
This method with sessions is less susceptible to data tampering than hidden fields, if that's a concern at all. With hidden fields in the view, a malicious user could easily overwrite previous data. Depending on the size of your model, hidden fields could bloat up the view a bit too.
Sessions also have the drawback of expiring. Here's a simple way to handle expirations. If this is called via Ajax, then you'll have to pass an error message back to the client instead to handle there.
[HttpPost]
public ActionResult TAFPart3PopupEvents(string field2)
{
var model= Session["Quiz"] as QuizzModelView;
if (model == null)
{
// Add some kind of message here.
// TempData is like Session, but only persists across one request.
TempData["message"] = "Session Expired!";
return RedirectToAction("Index");
}
// Fill in field2 here
model.Field2 = field2;
....
}
If you want your TAFPart3PopupEvents action to have access to the data, you need to store it some place. There are many different options (session, querystring, db), but I think a hidden input (in general) is the easiest.

How do I pass an object from the Index view to the edit view using MVC3

I have created a simple WCF service that is to be configured by an MVC3 UI.
When I call the index page from my controller, I want to display the values held in the configuration, which has been returned by the service. The user could then chose to edit these settings and then send them back to the service.
I want to do something like this in the index view ...
<div>
#Html.ActionLink("Edit", "Edit", model)
</div>
and then consume the model in the controller like this...
[HttpPost]
public ActionResult Edit( SettingsModel Config)
{
try
{
List<string> configErrors = null;
if (ModelState.IsValid)
{
// Set up a channel factory to use the webHTTPBinding
using (WebChannelFactory<IChangeService> serviceChannel = new WebChannelFactory<IChangeService>(new Uri(baseServiceUrl)))
{
IChangeService channel = serviceChannel.CreateChannel();
configErrors = channel.SetSysConfig(Config);
}
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
but this doesn't work.
Any suggestions???
When the form gets posted, all the input type fields data is collected and sent to the server. You can see this data using FireBug. The key point here is that, is the data that is being posted in a form, that MVC's default model binder can understand and map it to the model object, which is being passed as input parameter to the action method.
In your case, the model is of type "SettingsModel". You have to ensure that, the form data that is being posted is in format, that can be mapped to the "SettingsModel" object.
Same kind of question discussed in another thread : Can't figure out why model is null on postback?
Check Out this article : NerdDinner Step 6: ViewData and ViewModel
In the above article, carefully go through the "Using a ViewModel Pattern" section. My guess is that, this is what you are looking for.
You will need to post the values to populate the SettingsModel object on the Edit action. You can do this using hidden form fields if you don't want the user to see it. Otherwise you could have no parameters on the Edit action and make another call to the web service to populate the Settings model.

MVC - Dealing with the model and events on the page

I have what is probably a basic question regarding how to structure an MVC page.
Assume this is my model:
public class MyModel
{
int ProductId
List<ParameterTable> ParameterTables
...
[other properties]
...
}
ProductId initially won't have a value, but when its value is selected from a DropDownList it will trigger an event that retrieves the List items associated with that product.
My problem is when I do this AJAX call to get the parameter tables I'm not sure how to handle the response. I've only seen examples where people then manually inserted this data into the page via the jquery. This would mean handling displaying the data in your view (for the first time loading the page) and in the jquery (whenever it changes).
I am wondering if there's a way to somehow pass back a model of sorts that binds my return value of List into my page without needing to specify what to do with each value.
Would I have to have the changing of the ProductId DropDownList trigger an ActionResult that would reload the whole page to do this instead of a JsonResult?
You could return a partial view with your ajax call.
Controller action:
public ActionResult Filter(int productId) {
var product = _repository.Find(productId);
if (Request.IsAjaxRequest())
{
return PartialView("_Product", product);
}
else
{
return View(product);
}
}

Resources