Need help designing to ASP.NET MVC action methods - asp.net

I'm just starting out learning ASP.NET MVC 3. I've been going through the Music store sample on the ASP.NET website, as well as starting to develop my own site, but I'm having some trouble understanding how I should setup my controller action methods.
On my site each user that is logged in will be able to perform standard CRUD operations on their Projects. I've set this up similar to the Music Store sample with the following action methods on a ProjectController. So far this makes sense to me.
ActionMethod View
ProjectController.Index() Lists the active users's projects
ProjectController.Details(int id) Shows details for project 123
ProjectController.Create() Shows a form to edit a new project
ProjectController.Create(FormCollection col) Adds a new project with the form contents
ProjectController.Edit() Shows a form to edit a new project
ProjectController.Edit(int id, FormCollection col) Adds a new project with the form contents
ProjectController.Deiete(int id) Shows a delete confirmation form
ProjectController.Delete(int id, FormCollection col) Deletes a project with the provided id.
In addition, users will be able to add Items to each project. Items can not exist on their own and must be associated to a project when being created. What I'm having trouble understanding is how to pass along the reference to the project an Item should be created in. For example in my item controller I have a pair of Create() action methods similar to the controller above.
ItemController.Create() Shows a form to create a new item
ItemController.Create(FormCollection col) Creates a new item with the details from the form.
Yet I don't understand how the first Create() method passes a reference to the project which the new Item should be created in since the View() helper method can only accept one object parameter. Should I just add a reference to a project to a property of the ViewBag? I'm new to dynamic types as well and the ViewBag just seems magic to me at the point. So I'm a little hesitant to use it. I've also always thought strongly typed design is better. So should I create a separate "NewItemData" model object that contains a reference to a new Item as well as the project it is being added to?
Once the form knows which project it is adding an item to how should it pass this information back when submitted? Should there be a hidden "ProjectID" field in the form? Or should the form POST back to a URL with the project id in the query string?
www.mysite.com/Item/Create?ProjectID=1234
Finally, I also want to be able to list the items that are added to each project. Should this be part of the ItemController or the ProjectController. For simplicities sake I'm sticking with the default Controller\Action[ID] URL routing. A few of my ideas are listed below. I'm leaning towards the last option, but would really like to hear what others with more experience with this stuff think.
Action Method URL
ItemController.Index(int ProjectID) \Item?ProjectID=1234
ItemController.List(int id) \Item\List\1234
ProjectController.Items(int id) \Project\Items\1234

To answer your last question, it depends. Do Items in your model exist independently of a project? If the answer is no, then I would tend to do
ProjectController.AddItem(int id)
ProjectController.Items(int id)
where id represents the projectID.
The name of the parameters you use in the action signature directly correspond to values from the routedata and request values. {controller}/{action}/{id} is a pattern that uses the braced names as keys in the route dictionary. If you wanted you could change the routes to be {controller}/{action}/{projectid} for that action and your method signature could be the (int projectid) signature.
I don't recommend you do this just to get awesome signatures. Use comments instead if you think people will get confused.
Without changing the route pattern, if you would prefer your urls to be /project/items?projectid=3 than /project/items/3 then the action would be this:
ProjectController.Items(int projectId)
I like the prettier urls, so i'd be more apt to use the id version. That being said, if Items do not exist independently of the Project object, I would be be more likely to do this. However, if you are going to have a TON of different actions that can be performed on an Item, it would make sense to separate them into ItemController and ProjectController.
It comes down, to a large extent, about what makes sense for your application and how many actions you think a controller should have on it.

In this case you'd create a hidden field with the name=projectId and then in your Create controller have an action method.
[HttpPost]
public ActionResult Create( int projectId, FormCollection postData )
Usually you'd also use a strongly typed viewmodel so instead the FormCollection parameter use:
[HttpPost]
public ActionResult Create( int projectId, Item or ItemViewModel postData )
And as long as the name attributes match the properties in Item or ItemViewModel MVC's ModelBinder will take care of hydrating those values.

Related

What is the "best" way to handle alternately Post and Get Actions?

I am trying to build sth pretty simple, but I try to do it the correct way. But I struggle to figure out what is best.
I have a process chain where the user has to fill in some fields in different forms. Sometimes it depends from the user inputs which form the user is shown next.
[HttpGet]
public IActionResult Form1(Form1Vm f1vm)
{
return View(f1vm);
}
[HttpPost]
[ActionName("Form1")]
public IActionResult Form1Post(Form1Vm f1vm)
{
//process the data etc
//prepare the new viewmodel for the next form view (f2vm)
//Option1:
return View("Form2", f2vm);
//Option2:
return RedirectToAction("Form2", f2vm);
//for Option 2 I would need an additional HttpGet Action Method in which I
//would have to call Modelstate.Clear(); in order to not have the
//immediate validation errors on page load
//also all the properties of my viewmodel are passed as get parameters
//what looks pretty nasty for me
}
//More form views action methods should be added here...:
What is the better way? As mentioned in my comments above I have quite a big disadvantage for using the RedirectToAction option. However if I use the direct View(); call, I don't take care on https://en.wikipedia.org/wiki/Post/Redirect/Get and the user cannot simply refresh a page without getting a warning that his form is submitted once again.
Do I miss another way or don't see something obvious?
Edit: I just thought about a 3rd way, which I have seen quite often: Not transfering the whole VM to a HttpGet method but only the ID. I'd then have to load all the data stored previously directly from the db, map it again to my new VM and then call the View(); with this VM. Right now I think this is the "best" solution, however I feel like it is pretty laborious...
As per the dicussions, I would suggest using depending on your preference :
1) Save to db at the end of each form post and as you suggested use the I'd to redirect to a GET.
2) Depending on the the number of form pages and your requirements, retrieving values that a form needs on the get would be standard practice. This ensures that if a user drops off a form at any stage you can then start them off where they left off.
3) I wouldn't setup the viewmodel for the next form in the post of the previous. Generally as part of the single responsibility principle you want to ensure that your methods have only one reason to change.
4) PostRedirectGet pattern should be implemented with this to ensure data is not saved multiple times if a user refreshes after a post.

MVC4 - Relationship between a View and a Controller

I'm having difficulty grasping the concept of MVC within .NET. I'm creating a basic Blog application, mainly to gain insight and skills with MVC. I just don't quite get some of it. The part I am currently unclear about is the relationship between a Controller and View. It would clear the matter up if someone would answer me this.
I have a View called TestA which corresponds to my Controller ControllerTestA. Now I've added the following inside the ControllerTestA.
public ActionResult TestA (){ //do something }
Now I need to know if all my postbacks in whatever form from view TestA will have to go through my TestA Controller method. So essentially I could have different postback with different parameters for different reasons. Some in use with one postback and others in use for another. Is that how it is done?
Would love some assistance here.
You are missing a crucial part of the relationship here, which is routing. You are speaking in terms of WebForms using terms like Postback; don't do that because you'll end up confusing yourself.
The best way to think about MVC is in Requests and Responses.
Let's look at how a request (high level) happens in an MVC application.
Request
Request hits the server with a url ex. /hello/world
That url is used to match any entries in your route table
When a match is found, that route defines basic values like what controller and action should be called.
The controller is created, and that action is called with the route values and other request properties (querystring, session, etc...).
Response
We are now in the controller action, run the code you need to fulfill the request
Pass the data to the View
The view is determined by convention and your ViewEngine
The view is then rendered and written to the response.
The request/response is finished.
Note
This whole process is determined by the route, and the relationship between the controller and view are trivial. Where the form is posted to is determined by you in the view by using helper methods that determine what route to hit in the next request/response flow.
Some Helper Methods.
#Url.Action("index", "home");
#Html.ActionLink("index", "home")
#using (Html.BeginForm("create", "home")) { }
To sum it all up, the relationship between the controller action and view is really facilitate by your routes. Once you have a grasp of how to create them, then you will better understand how to manage the interaction of your application. Hope that helps. :)
There is no such thing as "Postback" in MVC. In contrast to WebForms, a view only renders HTML to be sent to the browser. As soon as any type of request is issued by the browser, it goes to the controller, not to the view.
As for the relationships:
If you define a TestAController (note: Not "ControllerTestA"), it serves the "/TestA/*" URL's. If you have a method TestA in there it will serve "/TestA/TestA".
If your method returns View(someModel) it will look for a view named TestA.cshtml/TestA.aspx, named like your method, within a folder Views\TestA (named like your controller, without the "Controller" suffix)
The view will render the HTML based on the someModel passed by the controller.
Within the view you may call other URL's or post data to some. This closes the circle.
As for the parameters or overloads, there are some restrictions:
You can define overloads for GET vs. POST vs. PUT vs. DELETE. You will need to annotate the methods with the according attributes though.
However you cannot define multiple overloads of the same method name for POSTs with different sets of parameters. You will need to make your POST method signature such that parameters can or cannot be sent to the server:
Example:
public ActionResult TestA(
string someOptionalParameter, int? someOtherOptionalParam)
{
if (string.IsNullOrEmpty(someOptionalParameter)) { ... }
if (someOtherOptionalParam == null) { ... }
}
The model-mapper will set your parameters to null if they are not posted to the server.
Like Khalid already mentioned - you should not mix up the concepts of MVC and WebForms. They are very different. MVC has no such thing as a "view state" which could be posted to the server. It has no WebForm-like lifecycle for the ASPX (or CSHTML) pages.
If you have a form in a view, then that form has a url to which it will post to. This URL is in the Html.BeginForm method in your view.
The form will then be posted to the appropriate controller methond in the approoriate controller
So if BeginForm starts like this:
using (Html.BeginForm("AddProduct", "Product"
Then the action method "AddProduct" in the controller Product (ProductController is the class name) will be called.

MVC + POCO + Entity Framework, Passing Object between layers

I am trying my hands on MVC 2, ADO.NET EF and POCO. I have generated my entity classes in a separate library using POCO generator.These POCO entities are used as ViewPages (Not sure if that's the right way to design or do I need separate ViewModels classes ?)
Now, if I take case of a simple scenario where I need to add an Employee object( which is related to a Department Master), what then should be the recommended way to transfer these objects between layers.
Layered structure of the application is somewhat like this :
I have thought of various alternatives:
I have a method in the Employee Controller which is named AddEmployee() which accepts the FormCollection as parameter. Within the form collection I get posted data such as Employee Name, Age , Salary etc and the ID of the Selected Department .
1.) One way is that I can create another DTO say EmployeeDepartment DTO which will be used to map values from FormCollection as is. I can then break them at manager layer and use them to create entity objects i.e Employee Object and refer department by query similar to this:
e.Department = Department.where(i => i.deptId == empDepDto.dept_id).first()
I am not a big fan of this and feel that every time there is a relation involved I have to add a DTO and then map it to my entity class.
2.) Second is probably the worst, i.e passing each object as parameter and then couple them in manager layer.
3.) Use POCO as is, Create a Employee Object and Deparment Object at controller layer and pass the POCO object
public void AddEmployee(FormCollection formCollection)
{
Department d = new Deparmtent; d.id = ""; //based on the dropdown value
d.name="" //based on the dropdown selected text;
Employee e = new Employee; e.Name. e. sal....
e.Department = d;
EmployeeManager.AddEmployee(e);
}
But at manager layer I think , I still need to recreate the reference to the Department using LINQ which again is repetitive and doesn't seems to be a clean solution.
Are there better ways of handling this ? Looking for recommendations and best practices.
Firstly, is there any reason you're not using MVC version 3? There's no major breaking changes, so may as well upgrade?
Secondly is there a reason for using FormCollection rather than the strongly typed model-binding? Just change your views to use the strongly typed HTML helpers ( like <%: Html.TextBoxFor(m => m.Property) %>), or make sure the name attributes match the property names, and have your controller receive the type, and model binding will do the rest. There's plenty of tutorials showing this, and articles explaining it. Model binding will work with a name/value collection, like that posted as a form, or against JSON data, or you can find/write custom model binders that work against whatever wacky serialisation protocol you want.
One thing to watch though when passing the actual entity types that Entity Framework will store around, is that you have to be careful when updating existing objects, or with foreign key references to existing objects - all your objects must be attached to the right Entity Framework context. To achieve that you will often see the objects received by the controller having their properties copied to a freshly retrieved entity from a context, either manually or by an object mapper of some kind.
Make a seperate project called "BusinessObjects" or "Model" which contains your POCOs. Then use strongly typed model-binding for MVC and you'll be set.
The method signature will look something like this:
// In your Controller
public void AddEmployee(Employee newObject)
{
YourDataContext dc = new YourDataContext();
dc.Employees.Add(newObject);
dc.SaveChanges();
}

Adding and removing items dynamically in one View with Entity Framework and MVC

I've been at this same question in different forms now for a while (see e.g. Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable ), and it's still bugging me, so I thought I'd put it a little more generically:
I feel this can't be a very unusual problem:
You have an entity object (using Entity Framework), say User. The User has some simple properties such as FirstName, LastName, etc. But it also has some object property lists, take the proverbial example Emails, to make this simple. Email is often designed as a list of objects so that you can add to that object properties like Address and Type (Home, Work, etc). I'm using this as an example to keep it generic, but it could be anything, the point is, you want the user to be able to add an arbitrary number of these items. You should also be able to delete items (old address, or whatever).
Now, in a normal web page you would expect to be able to add these items in the same View. But MVC as it seems designed only makes it easy to do this if you call up an entirely new View just to add the address. (In the template for an Index View you get the "Create New" link e.g.).
I've come across a couple of examples that do something close to what I mean here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
and
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
The problem is, although the sample projects on these sites work fine, with mock model objects, and simply lists (not an object with a child list), it's a different thing if you actually want to do something with the posted information - in my case save to database through the Entity Framework model. To adapt these cases to that, all of a sudden I'm in a maze of intricate and definitely not DRY code... Juggling objects with AutoMapper and whatnot, and the Entity Framework won't let you save and so on (see above link if you're interested in the details).
What I want to get at is, is it really possible that this is such an uncommon thing to want to do? Update a child collection in the same View as the parent object (such as the email addresses in this case)? It seems to me it can't be uncommon at all, and there must be a standard way of handling this sort of scenario, and I'm just missing it (and no one here so far has been able to point me to a straighforward solution, perhaps because I made it too abstract with my own application examples).
So if there is a simple solution to what should in my view be a simple problem (since the design is so common), please tell me.
Have you tried updating the project at your link to Steven Anderson's blog to bind to a complex object? Create a class in models called Sack and give it a single property and see if you can get it to work.
public class Sack
{
public IEnumberable<Gift> Gifts { get; set; }
}
It only took me a minute to get it up and running as I think you intend. The improvement I would have made next would be to add an HtmlHelper extension that is essentially the same as Html.EditorFor(m => m.SomeProperty), only call it something more meaningful and have it interface with the prefix scope extensions provided in the project.
public static class HtmlExtensions
{
public static IHtmlString CollectionEditorFor<TModel, TValue>(this HtmlHelper html, Expression<Func<TModel, TValue>> expression)
{
if (/* type of expression value is not a collection */) throw new FailureToFollowTheRulesException("id10t");
// your implementation
}
}

Grails - Removing an item from a hasMany association List on data bind?

Grails offers the ability to automatically create and bind domain objects to a hasMany List, as described in the grails user guide.
So, for example, if my domain object "Author" has a List of many "Book" objects, I could create and bind these using the following markup (from the user guide):
<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />
In this case, if any of the books specified don't already exist, Grails will create them and set their titles appropriately. If there are already books in the specified indices, their titles will be updated and they will be saved. My question is: is there some easy way to tell Grails to remove one of those books from the 'books' association on data bind?
The most obvious way to do this would be to omit the form element that corresponds to the domain instance you want to delete; unfortunately, this does not work, as per the user guide:
Then Grails will automatically create
a new instance for you at the defined
position. If you "skipped" a few
elements in the middle ... Then Grails
will automatically create instances in
between.
I realize that a specific solution could be engineered as part of a command object, or as part of a particular controller- however, the need for this functionality appears repeatedly throughout my application, across multiple domain objects and for associations of many different types of objects. A general solution, therefore, would be ideal. Does anyone know if there is something like this included in Grails?
removeFrom*
Opposite of the addTo method in that it removes instances from an association.
Examples
def author = Author.findByName("Stephen King")
def book = author.books.find { it.title = 'The Stand' }
author.removeFromBooks(book)
Just ran into this issue myself. It's easy to solve. Grails uses java.util.Set to represent lists. You can just use the clear() method to wipe the data, and then add in the ones you want.
//clear all documents
bidRequest.documents.clear()
//add the selected ones back
params.documentId.each() {
def Document document = Document.get(it)
bidRequest.documents.add(document)
log.debug("in associateDocuments: added " + document)
};
//try to save the changes
if (!bidRequest.save(flush: true)) {
return error()
} else {
flash.message = "Successfully associated documents"
}
I bet you can do the same thing by using the "remove()" method in the case that you don't want to "clear()" all the data.
For a good explanation of deleting a collection of child objects with GORM have a look at the Deleting Children section of this blog post - GORM gotchas part 2
It's recommended reading, as are parts 1 and 3 of the series.
I am just starting to learn Grails myself and saw your question as an interesting research exercise for me. I do not think you can use the conventional data binding mechanism - as it fills in the blanks using some kind of Lazy map behind the scenes. So for you to achieve your goal your "save" method (or is it a function?) is unlikely to contain anything like:
def Book = new Book(params)
You need a mechanism to modify your controller's "save" method.
After some research, I understand you can modify your scaffolding template which is responsible for generating your controller code or runtime methods. You can get a copy of all the templates used by Grails by running "grails install-templates" and the template file you would need to modify is called "Controller.groovy".
So in theory, you could modify the "save" method for your whole application this way.
Great! You would think that all you need to do now is modify your save method in the template so that it iterates through the object entries (e.g. books) in the params map, saving and deleting as you go.
However, I think your required solution could still be quite problematic to achieve. My instinct tells me that there are many reasons why the mechanism you suggest is a bad idea.
For one reason, off the top of my head, imagine you had a paginated list of books. Could that mean your "save" could delete the entire database table except the currently visible page? Okay, let us say you manage to work out how many items are displayed on each page, what if the list was sorted so it was no longer in numerical order - what do you delete now?
Maybe multiple submit buttons in your form would be a better approach (e.g. save changes, add, delete). I have not tried this kind of thing in Grails but understand actionSubmit should help you achieve multiple submit buttons. I certainly used to do this kind of thing in Struts!
HTH
I'm just running into this same issue.
My application's domain is quite simple: it has Stub objects which have a hasMany relationship with Header objects. Since the Header objects have no life of their own, they're entirely managed by the Stub controller and views.
The domain class definitions:
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {headers lazy: false}
}
class Header {
String value
static belongsTo = Stub
}
I've tried the "clear and bind" method but the end result is that the "cleared" objects are left over in the database and grails will just create new instances for the ones that were not removed from the relationship. It does seem to work from an user's perspective, but it will leave lots of garbage objects in the database.
The code in the controller's update() method is:
stubInstance.headers.clear()
stubInstance.properties = params
An example: while editing the -many side of this relationship I have (for a given Stub with id=1):
<g:textField name="headers[0].value" value="zero" id=1 />
<g:textField name="headers[1].value" value="one" id=2 />
<g:textField name="headers[2].value" value="two" id=3 />
in the database there are 3 Header instances:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
after removing header "one" and saving the Stub object the database will have headers:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
id=4;value="zero"
id=5;value="two"
and the Stub object will now have an association with Headers with id=4 and id=5...
Furthermore, without the clearing of the list, if an index is not present in the submitted request.headers list, on data binding grails will keep the existing object at that location unchanged.
The solution that occurs to me is to bind the data, then check the Stub's headers for elements that are not present in the submitted list and remove them.
This looks like a pretty simple scenario, isn't there any built-in functionality to address it?
It's a bit overkill to have to write your own synchronization logic for maintaining relationships, especially when the quirks that make it non-trivial are caused by grails itself.
What about deletion, shouldn't the clear()'ed elements be gone from the database? Am I missing something in the relationship or domain object definitions?
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {
headers lazy: false
**headers cascade: "all-delete-orphan"**
}
}
class Header {
String value
static belongsTo = Stub
}
I have added the cascade property on the owning side of relationship and Now if you try to save the stub, it will take care of removing deleted items from the collection and delete them from the DataBase.

Resources