Do I need to fill ViewData (MVC 2) more than once? - asp.net-mvc

I am following a simple ADO.NET Entity/MVC 2 tutorial wherein my Views are created by right-clicking the action and selecting 'Add View'. The views get created based on my model and all is good. I can view the initial list of items from the DB but when I click Edit or Delete or Details I get 'Object reference not set to an instance of an object'. It acts like my data is not there at all so I'm thinking I may need to fill ViewData again?
Here is how I am getting the data:
CheckingEntities chk = new CheckingEntities();
//
// GET: /CheckingMVC/
[Authorize]
public ActionResult Index()
{
ViewData.Model = chk.tblCheckings.ToList();
return View();
}
And here is an example where I am getting the details:
// GET: /CheckingMVC/Details/5
[Authorize]
public ActionResult Details(int id)
{
return View();
}
I suspect I have filled the ViewData incorrectly or need to do it again but don't know where or how to do that. Still quite new to MVC.

The values passed to your Views must be populated on every request. Furthermore, values set inside your controller during a request cannot and will not be persisted between requests as every new requests creates a brand new set of controller instances from the controller factory.
In your Details() action you are accepting an id and then returning your View without any data being placed in the Model. Instead try something along these lines:
[Authorize]
public ActionResult Details(int id)
{
var item = Entities.SomeEntitySet.SingleOrDefault(e => e.Id == id);
return View("Details", item);
}

Related

return RedirectToAction("Edit", Model)

Afternoon Folks,
I have a question in reference to how to redirect to another model within my mvc project.
I have a controller with CRUD operations, and i have a [HttpPost] action on Create. The system saves the data to the database as required but instead of me sending the user back to the "Index" page i want to sent them to another model.
I know how to use the redirect option...
// POST: CarerDetailsNew/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CarerViewModel carerViewModel)
{
if (ModelState.IsValid)
{
db.CarerDetails.Add(carerViewModel.carer);
db.SaveChanges();
return RedirectToAction("Edit", carerViewModel.carer);
//return RedirectToRoute("ClientRecordsController");
}
return View(carerViewModel);
}
However i have read that i may be able to use the "RedirectToRoute" option to get back to another model.
The model that i am in is my "Carer" model but i want to get back to my "Client" model and specifically the "Edit".
I have tried to replace my RedirectToAction to one of the following but this fails to see the "Client" model.
return RedirectToRoute("Edit", clientViewRecord.client);
Or
return RedirectToRoute(ClientRecordsController, "Edit", clientViewRecord.client);
Any suggestions are more than welcome as i am struggling to get this to work.
Regards
Betty

My mvc action can't update the model

I am trying to update my model using MVC so i write this code to do that :
SemesterRepositor obj = new SemesterRepositor();
public ActionResult Edit(int id)
{
return View(obj.FindSemesterById(id));
}
[HttpPost]
public ActionResult Edit(int id,FormCollection collection)
{
var review = obj.FindSemesterById(id);
if (TryUpdateModel(review))
{
RedirectToAction("Index");
}
return View(review);
}
One of this method get the model and another one that is for post back updates the model .but it doesn't work .Why?
Best regards
there are many ways to send data from a view back to the controller. The easiest way is to tie your model items on the view to for helpers (except display) and then do a post back. your input on the post method would need to include the model
[HttpPost]
public ActionResult Edit(SemesterRepositor sr){
//save the data in sr to your database
RedirectToAction("Index");
}
you have form collection as an input to your post method which will have fields from your view but to save the values you would have to pass the individual fields to your database. In your code you have find semester by id but you don't ever set the form collection values to that object so it will always be empty
Update:
if your view has #model SemesterRepositor at the top and you use for helpers on your view your fields will be tied to the model
#model SemesterRepositor
#Html.TextBoxFor(x => x.Name)
something like this. Then on post back the field Name will have the value of the text box tied to it

Resource Cannot Be Found Error on Using "HttpPost" in Controller

Hello Am Working on a ASP.Net MVC 3 project and am getting a error called "Resource cannot be found" My situation is i have
1: am Using my own views and returning them in actions for instance i created a view manually first called "Create.cshtml" and manually added it to a action like this
[HttpPost]
Public ActionResult CreateStudent(StudentIfo studentinfo)
{
db.StudentInfo.add(studentinfo);
db.SaveChanges();
Return View("~/Views/Student/Create.cshtml");
}
[HttpGet] Before this Action works good but why Not HttpPost???
My Route Map says:
routes.MapRoute(" ",
"{controller}/{action}/{id}",
new { controller = "Student", action = "CreateStudent", id = UrlParameter.Optional }
);
2: Whenever i write [HttpPost] i get this Error and if I remove it then everything works good if such thing continues then how to save the data??
3: My Create.cshtml has a #Html.BeginForm("CreateStudent","Student",FormMethod.Post) am not getting what the issue is?? i have searched a lot but not getting a good answer.
4: What is best way for CURD operation when we are using our own views rather using Visual studios Scaffolding templates i.e am I going in right way?? i want my own views and then write my controllers according to them not as that of Visual Studio way first write controller then right click "Add-View"
Please recommend some good ways or any site or tutorials regarding it.
In short you will need both, you need a [HttpGet] action to return the initial form that the user can enter values into and then a [HttpPost] version to do the persistence. From this [HttpPost] method you should then RedirectToAction (return RedirectToAction(...)) to ensure that reloading of the page does not re-run the post operation.
So:
[HttpGet]
public ActionResult CreateStudent()
{
var viewModel = new CreateStudentViewModel { /* Set properties here or load data for it */ };
return View(viewModel);
}
[HttpPost]
public ActionResult CreateStudent(PostedValues values)
{
if (ModelState.IsValid)
{
// Create Student Here
return RedirectToAction(/* Jump to a logical place with a Get */)
}
/* Initialize correct error viewModel again and show the create student screen with validation errors */
return View(viewModel)
}
Personally I name these methods GetCreateStudent and PostCreateStudent and add two routes with a route constraint that limits the Http Method (see here)

What is the purpose of passing a data model instance from within [HttpGet] Create to its View?

I notice there are 2 common practices to implement the Create form.
First Approach
From within [HttpGet] Create action method, we pass an instance of data model to the Create.cshtml as follows:
public ActionResult Create()
{
DataModel dm = new DataModel();
return View(dm);
}
Second Approach
From within [HttpGet] Create action method, we don't pass an instance of data model to the Create.cshtml as follows:
public ActionResult Create()
{
return View();
}
The [HttpPost] Create(DataModel dm) for both approaches is as follows:
[HttpPost]
public ActionResult Create(DataModel dm)
{
if (ModelState.IsValid)
{
db.Movies.Add(dm);
db.SaveChanges();
return RedirectToAction("Index");
}
else
return View(dm);
}
The question is: What is the purpose of passing a data model instance from within [HttpGet] Create to its View ?
Passing a data model to the view associated with the 'Create' is useful if you want the application logic to supply the initial values to be displayed on the form (whether because you don't want them hard-coded in the form defined in the view, or because they might differ depending on the context).
Default values for the bound controls, values in the viewmodel to be consumed by the view to generate dropdowns, etc... as mentioned by rsalmeidafl.
At the risk of sounding like a curmudgeon, this is really best practice. You shouldn't be calling the database to generate select lists and things from your views.
Finally, sending a default instance of the model to your view can also let you reuse edit/create views very easily, since you can bind values without fear of NullRef exceptions for your model. (if you strongly type your views)

ASP.NET MVC controller parameter optional (i.e Index(int? id))

I have the following scenario: my website displays articles (inputted by an admin. like a blog).
So to view an article, the user is referred to Home/Articles/{article ID}.
However, the user selects which article to view from within the Articles.aspx view itself, using a jsTree list.
So I what I need to do is to be able to differentiate between two cases: the user is accessing a specific article, or he is simply trying to access the "main" articles page. I tried setting the "Articles" controller parameter as optional (int? id), but then I am having problems "using" the id value inside the controller.
What is the optimal manner to handle this scenario? Perhaps I simply need a better logic for checking whether or not an id parameter was supplied in the "url"?
I am trying to avoid using two views/controllers, simply out of code-duplication reasons.
Use separate actions, like:
public ActionResult Articles() ...
public ActionResult Article(int id) ...
Alternatively move it to an Articles controller (urls using the default route will be: Articles and Articles/Detail/{id}):
public class ArticlesController : Controller
{
public ActionResult Index() ...
public ActionResult Detail(int id) ...
}
If you still must use it like you posted, try one of these:
public ActionResult Articles(int id = 0)
{
if(id == 0) {
return View(GetArticlesSummaries());
}
return View("Article", GetArticle(id));
}
public ActionResult Articles(int? id)
{
if(id == null) {
return View(GetArticlesSummaries());
}
return View("Article", GetArticle(id.Value));
}
First of all, I agree with #Steve :). But if you really want to use
int? id
you can just check in your controller method if the id is set using a simple
if(id == null)
and if so, load all articles from your DB (or something alike) and pass these to your view (either directly, or by using a view model). If the id is set you just load the article having that id from your DB and send that to the view (possibly in a list as well if you dont use view models)?
Than in your view just load all articles in the list with articles supplied to the view. Which contains either all or just one.
Complete dummy code
public ActionResult showArticles(int? id){
List<Articles> aList;
if(id == null){
aList = repository.GetAllArticles().ToList();
}else{
aList = new List<Articles>();
aList.add(repository.GetArticleByID(id));
}
return View(aList);
}
Your View has something like:
<% Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<List<Articles>>"%>
foreach(Articles a in Model)
//display article
And you call it using either of the next two options:
html.ActionLink("one article","showArticles","Articles",new {id = aID},null}
html.ActionLink("all articles","showArticles","Articles"}
Define a default value for the Id that you know indicated no value was supplied - usually 0.
public ActionResult Articles([DefaultValue(0)]int Id)
{
if (Id == 0)
// show all
else
// show selected
..
The easiest solution is to have two different actions and views but name the actions the same.
public ViewResult Articles()
{
//get main page view model
return View("MainPage", model);
}
public ViewResult Articles(int id)
{
// get article view model
return View(model);
}
this to me sounds like two separate pages and should be treated as such. You have the "Main" view page and the "articles" page.
I would split it into two actions. They should not be much dupliation at all really, both should be doing a call to get the same ModelView and the article will simply get the a extension to that!
I don't know if you tried this, but instead if you are typing the value directly into the URL, then, instead of passing it like this:
controller/action/idValue
try passing it like this:
controller/action?id=value
Make the parameter required then set a default value in the routing that is a value that isn't a valid index and indicates to your action that it should render the main page.
Well, this is the combined solution I am using:
Using same controller, with DefaultValue:
public ActionResult Articles([DefaultValue(0)]int id)
If DefaultValue was used, I refer to "MainArticles" view. If an article ID was provided - I refer to the "Articles" view with the appropriate article passed inside the ViewModel.
In both cases the ViewModel is populated with the data both views need (complete article and category lists).
Thanks everyone for your help!

Resources