I am creating a Web site that will have a lot of articles. I created a ArticleController for the Web site. As an example, the first article to be implemented is Machine Language. So I created a view called machine_language.cshtml.
public class ArticleController : Controller
{
// GET: Article
public ActionResult Index()
{
return View();
}
public ActionResult Machine_Language()
{
return View();
}
}
So far in the controller I have to code above.
So my question is, I have 500 articles that need to be converted to start with. Normally, I created an ASPX page for each article, but now I am creating a view, since I am using MVC.
So does that mean I will need to have 500+ ActionResults in the ArticleController? One for each view/article.
Before I get started I want to make sure I'm doing this correctly, because it seems rather strange. If I have to create an action result with each article's name. I will end up having a huge ArticleController. Once there are a couple thousand articles, things will get seriously out of control.
Edit: P.S. I like to use pages for the articles. Since they are static content. I am trying to stay away from having huge articles with images, videos, etc... in a database.
How are you retrieving "article data/text"? In this particular situation, I'd have a View Model that has ArticleText as a property, and then you might need other article-specific items (tags? Author(s)? etc.).
Then pass this View Model from your controller's action to the view. The view would then be in charge of rendering this particular article to the user.
With this particular design, you'd have a single action in a single controller passing data (a single view model) to a single view.
In my opinion, that is the most scalable and the best approach.
Step away from the web forms thought where a single "viewing experience" equals on a "single entity" in the backend. That's the beauty and power (and scalability) of MVC.
I would recommend you that to render your existing aspx page to the view that you have using iframe. Since you have already static pages with you. And you can simply pass the page name as parameter for each article and you can achieve what you want. It's an alternative approach. Even if you want you can add images to those aspx pages and display the same here
There seem to be several ways to integrate jQuery dialogs with ASP.NET MVC. Has a specific approach emerged as the commonly-accepted best-practice way to do so?
As an example: I have a list page where clicking "edit" for any of the listed items opens a form in a jQuery dialog, populated with the item's details. User edits details and clicks "save". If the save succeeds on the server-side, the dialog is closed and the list is re-built with fresh data. If the save fails on the server-side, the dialog remains open and displays the error message(s) to the user.
No-JSON approach: each "edit" link is an HREF to an "edit" controller action. That controller action builds a view that is identical to the "list" view, plus it includes a partial action to build the edit form, populate it, and define the javascript to pop it open as a jquery dialog. The "save" is a form-post; if it succeeds, it returns a redirect action back to the list page. If it fails, it rebuilds the entire page (including the form that pops up in a dialog) displaying the error messages as well.
All-JSON approach: the list page renders an empty edit form (hidden), ready to be popped open into a dialog. The "edit" link calls local javascript which does an ajax request to get the full object (I define a controller which returns the full object as a JsonResult). On success, it fills the edit form with the object's data and opens the dialog. The "save" link calls local javascript which bundles the form data into a json object, and calls a post operation with that json object as payload (I define a controller which expects that object, attempts the save, and returns a JsonResult indicating success/failure+errorMessages). Success callback from the ajax request evaluates the returned object, and either shows the error messages in the still-open jquery dialog, or closes the dialog and reloads the "list" page to get fresh data in the list.
[Edit] Ajax-HTML approach: just saw this SO discussion which describes another approach. The "edit" calls local javascript which does an ajax post to get the FULL HTML of the dialog (I would write a controller which returns a partial view: the fully-populated form). It renders the returned HTML into a jquery dialog, and also "re-wires" the form submission to do an ajax-post of the form's contents (I would write an httpPost controller, same as in #2 above). The success callback evaluates the response and populates error messages or closes the dialog.
Some other cool approach I haven't thought of?
Option 1 seems to be more in keeping with "pure" ASP.NET MVC. However, it seems to feature big HTTP payloads (since we're shipping the full page back to the browser on every request), and slower server-side performance (since we're re-building the list on every request).
Option 2 seems to be more consistent with more modern Ajax-based web applications (smaller HTTP payloads, more granular operations). However, it seems like many of the controllers will be JSON controllers, and I'll be writing a lot of client-side code to marshal data from JSON objects to/from form fields, display error messages, etc. It also seems like I'd be missing out on a lot of cool MVC features like EditorFor() and ValidationMessageFor(). It just "feels" like I'm working around the MVC system instead of with it.
[Edit: added option 3] Option 3 seems to be a bit of a hybrid between 1 and 2. I use the "pure" MVC approach to build and populate the form, and return a fully-formed HTML FORM tag. Returning HTML to an ajax request feels weird since it's so verbose, but I can get over it. The post operation is nice, compact JSON which "feels" better over ajax. However, it's unfortunate that the payload object is a FormCollection rather than a real viewmodel object. It seems like I can make use of some of the MVC conveniences (EditorFor()) but not others (ValidationMessageFor()).
I'm looking for the "right" way to do this, not just the fastest way to hack it together. Yeah, yeah, I know there's no universally "right" way. But I'm sure there's some notably wrong ways to do it, and I want to avoid them.
I'm pretty experienced in ASP.NET/C#, but I'm pretty new to MVC. Thanks in advance for your help!
[Edit] - outstanding responses - I wish I could award multiple answers/bounties, as I found several responses extremely useful. But since I can't, I'm marking the top-voted response as the answer. Thanks again to all respondents!
My team and I have a lot of experience writing AJAX enabled MVC apps, and we have used all 3 approaches.
However, my favorite is definitely the AJAX-HTML approach -- Use a PartialView to render the contents of the dialog, which could include server-side validation messages and any other logic.
The biggest benefit of this approach is the separation of concerns - your Views are always responsible for rendering your HTML, and your JavaScript doesn't have to contain any text, markup, or "templates" needed to render the JSON.
Another big advantage is that all the great MVC features are available for rendering the HTML: strongly-typed views, HtmlHelper, DisplayFor and EditorFor templates, DataAnnotations, etc. This makes it easier to be consistent and lends well to refactoring.
Just remember, there's no requirement to stick to a single approach. When your AJAX call only needs something simple, such as a status update like "Success", it's fine to just use a string or JSON to convey those messages. Use PartialViews when HTML is needed, and use simpler methods when communication is needed.
Your 2nd method, the All-JSON approach, seems to be increasingly prevalent with MVC and MVVM client side libraries like Knockout
In this you could actually have all of the data in JSON (including the list) and edit list items (similar to their list item editor demo, just with a dialog rendering isntead of inline, and bind the data to readonly spans in your cells) and then serialize the entirety of the set back to the server on save. Or you could do it with piece-meal saves after each popup edit.
JSFiddle: http://jsfiddle.net/paultyng/weLtH/17/
The JS could be cleaned up a bit, I didn't include a save button, but you should get the idea. The edit dialog could be a single template bound to one edit as well, instead of doing per row, this was just the simplest way to do it with Knockout.
I think the best way would be to render the list normally. Hook up the edit links to go to a separate page (follow me here) like you would normally do.
With JS handle clicking of the link, and do a get to it's href. In the edit action do a check for Request.IsAjaxRequest() and if it is, return a partial view if it isn't, return the full view. Or render the normal edit view without the master page (pass in null to the master page parameter in the View() call or call return Partial()). Take the contents of the result and put it into a dialog.
Also use JS to handle submitting the form and getting the result from the request. If it wasn't successful insert the contents of the view into the dialog to show that there were errors. Otherwise close it and move on.
The benefit to this approach is it's very unobtrusive and still allows functionality for those who don't have JS.
Ok, so your options are pretty much torching the concept of progressive enhancement here. 2 & 3 aren't going to work if your client doesn't support java script. Obviously thats ok if you don't care, but I think I'd try to engineer things so that they degrade gracefully and you are asking for best practise here.
So the way I would construct it, starts with your option 1. You have edit buttons that trigger another action which loads an edit page, and this page is designed with all the validators etc as per normal mvc. That's your base functionality so works with no js.
So then the next question is how do we progressively enhance this to have a nice popup instead of a new page?
Well first step is to create a handler to open your dialog attached to the edit links on click (make sure to e.PreventDefault). Now to save too much coding effort I would be looking to reuse the edit page. This is going to require a bit of refactoring though as you don't want to include the layout for the ajax requests. You can do this a few ways, but I think the cleanest is to have the edit area of the edit view as a partial view which the main edit view uses to render its model.
Then, in your edit action, you can check if you have an ajax request, if so then return a PartialView(mypartialeditview) or a View(editview) if not.
In terms of then submitting the results back to the server if you want an easy life just treat it like a form. You can use the micorsoft unobstrive ajax here and it will be very simple. You use Ajax.BeginForm in your partial view. n.b.This will degrade to a normal form if ajax not available. Have the AjaxOptions for this beginform set to update the div in the dialogue so if it responds with its html you don't have to do anything more, it implies a validation error.
[small aside as you asked above about this: In terms of the HttpPost handler, the default model model binder is amazingly smart, it can bind form fields to properties on a complex class object parameter. This also work with json so you don't have to end up with lots of action methods to support different scenarios.]
So if your update is unsucessful the post handler will return the partial view again, bound to the model so you'll get all your validators. If however the update is successful I would suggest that rather than return anything, the action does a redirect back to your main page which you want to reload anyway as you've changed the underlying.
If you don't like doing a full reload of the main page, then it gets more complex as with the approach above you are returning html. You will either have to jquery over that to find a hidden field or class to indicate success/failure or migrate to a pure json approach which returns a jsonresult. This is getting heavier on the maintenance/coding front though. I'd probably do the jquery check and have it wired to the completion handler of the ajax.Beginform.
If you really want to get your head around this stuff, I have found the Steve Sanderson Pro Asp.net MVC book invaluable. The one I initially read was for MVC2, but just in process of reading the MVC3 update. I have mixed feelings on the update, as its been simplified in a few places - easier to follow now but I feel like a few things are missing, also it was rushed as some errors etc as it gets near the end. I guess maybe they panicked now that MVC4 is being talked about and book wasn't out! Still a good book though and it covers all this stuff beautifully.
Hope this helps. Appreciate it covers some of the same ground as an answer above but hope I've drilled in more for you.
Using jQuery.tmpl() plugin1
I use a similar scenario but do it in a different way.
I have a master list where each item is wrapped in a container (be it table TR or DIV). Some general information about the item is displayed in the master list when there's too much data to contain in a simple list. Hence a master list and not details (of course).
Each item container is usually written this way:
<div class="item" data='<%= item.ToJson() %>'> <!-- single quotes! -->
item visible list data
</div>
The main part here is my custom extension method ToJson() that serializes my item data which can easily be used on the client.
Then I have a jQuery template at the end of a list contained inside a script tag. This template is the actual content of the edit dialog with all item variables set as needed.
Whenever user clicks edit on the item, I simply parse item JSON by:
// in edit link click handler
var itemData = $.parseJSON($(this).closest("[data]").attr("data"));
// display dialog
displayDialog($("#editDialog").tmpl(itemData));
My dialog than takes care of the rest via Ajax calls and closing the dialog when calls are successful or user cancels editing.
This keeps my HTML code to minimum (having only one template) and JSON also contains only those properties that are actually needed.
What to do when your model class has other entity references?
This is quite common that entities are related between each other. Suppose you have a Post and Comment entities:
public class Post
{
public int Id { get; set; }
public string Body { get; set; }
public IList<Comment> Comments { get; set; }
}
Of course you're not interested in related entities when converting your items to JSON on the server. That's why you can put an attribute to related properties so they don't get included in the JSON:
public class Post
{
public int Id { get; set; }
public string Body { get; set; }
[ScriptIgnore]
public IList<Comment> Comments { get; set; }
}
This will make JSON serializer ignore the related property we won't edit in our details editor.
ToJson() extension code
The last thing to put here is extension method code so here it goes:
public static class ObjectExtensions
{
/// <summary>
/// Serializes this object instance to JSON string.
/// </summary>
/// <param name="instance">Object instance being extended.</param>
/// <returns>Returns a JSON string that represents current object instance.</returns>
public static string ToJson(this object instance)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// register custom class converters
serializer.RegisterConverters(...);
return serializer.Serialize(instance);
}
/// <summary>
/// Serializes this object instance to JSON string.
/// </summary>
/// <param name="instance">Object instance being extended.</param>
/// <param name="recursionDepth">Serialization recursion limit depth.</param>
/// <returns>Returns a JSON string that represents current object instance.</returns>
public static string ToJson(this object instance, int recursionDepth)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// register custom class converters
serializer.RegisterConverters(...);
serializer.RecursionLimit = recursionDepth;
return serializer.Serialize(instance);
}
}
What to do when entities are too complex?
Upper approach is useful when your entities aren't too complex. In cases when:
your entities are complex or have long data (long in terms of serialized string)
determining JSON objects for all items would be too time consuming
unknown JSON object at time of master list display
then you can always send a remote Ajax call to server for a single entity and return either
JSON object to use with dialog template
return partial view with editor
Second approach is better, since converting object instance to either HTML or JSON is practically similar task. but in the second case there's no need for client-side template processing.
But don't use remote requests just because you can. Use an approach that's easier and better for the problem at hand.
1: jQuery template API reference
I'm new to the MVC development so please bear with me. Is it really necessary to name my partial view like _Action.cshtml (with the _ underscore) to comply with the naming convention?
Here's my problem I have a controller (StudentController) and an action (List) that has a partial view file named "List.cshtml", and have
#{ Html.RenderAction("List", "Student"); }
to display this inside my HomeController - Index view as partial view which works. But if I name my partial view to _List.cshtml of course it will not work. Visual Studio could not even find the view for my action Student - List because it think it's still looking for the exact same name as my action (List.cshtml). What should I do?
I m so used to ASP.NET ascx with a pairing ascx.cs code. :(
It's not necessary to use an underscore, but it's a common convention for files which aren't meant to be served directly.
To solve this, you do have the option of returning a View or PartialView with the name of the view as a parameter.
return View("_List");
or
return PartialView("_List");
or inside another view
#{ Html.RenderPartial("_List"); }
If Partial view depends on ActionMethod and always render by Action method, you should same partial view name same as action method like this
public PartialViewResult List()
{
DoSomthing();
//PartialView() return a "List "Parial View
return PartialView();
}
but if your partial view not depends on the action method and directly call by view like this
#Html.RenderPartial("_List");
First, there is no shame to be new to any platform. And this was eight years ago so you are probably not new any more. You can use whatever naming conventions you want to use. I go with the original MVC naming convention which uses underscores (_) only for shared views. Partial views should be named after their actions. In your case the name of the view would be Action.cshtml unless this is a shared view of course.
My reasoning is simple. If you call View or PartialView from an action and don't provide a viewName, it assumes the name of the view is the name of the action. Also _Layout.cshtml is named with an underscore. This is because it is shared, not because it is a partial view. This mistake is all over the place in the MVC world. People are really zealously wrong about it. Don't know why. Naming convention is the shop's discretion.
The helper methods Html.RenderAction and Html.Action call actions on the controller. The helper methods Html.RenderPartial and Html.Partial allow you to pass a model directly to a Razor view without passing through an action.
One final thing, call Action instead of RenderAction. RenderAction is only called if you are already inside of a code block. This is almost never the case. I see people using RenderAction and then adding a code block around it unnecessarily just because the build breaks. These two following code snippets are exactly the same and the second one is way more readable in my opinion. I put the div to emphasize that the code is not in a code block:
<div>
#{ Html.RenderAction("List", "Student"); }
</div>
<div>
#Html.Action("List", "Student")
</div>
The bottom line is don't use underscores or curly braces unnecessarily. They are ugly characters and we should avoid them. ;)
I have a web site with a growing number of AJAX calls.
I have AJAX code that looks like this:
function setupNameAutocomplete(id) {
$(id).autocomplete({
source: function(request, response) {
$.ajax({
url: "selectName.aspx/getNameAutocomplete",
....
Originally, the above javascript code was used on a web page where a user typed in the name of a person to search for; I decided I wanted to have autocomplete on the name.
However, as I continued to develop the web site, I decided that I wanted to be able to use the same "name" autocomplete on many pages. Logically, it made sense to put my javascript code in an external .js file instead of repeating it on every page.
It also makes sense that I would want to put the .net code that handles the AJAX in its own file as well. The .net autocomplete code looks like this:
[WebMethod]
public static IEnumerable<string> getNameAutocomplete(string text)
{
IEnumerable<string> values = lookupNamesThatStartWith(text);
return values;
}
Naturally, it seemed like this codes belongs in an external .asmx or perhaps a .ashx file, but I can't get my javascript code working unless I call the above code from selectName.aspx.
How can I get my AJAX .net code in a separate code file?
If I understand your problem correctly, a viable solution would be to have a base class that your services inherit from that would implement the generic WebMethod.
That, or you could get it "pretty clean" by having the logic of the autocomplete lookup abstracted into a class and just call it from your WebMethods each time, as needed.
I am using ASP.NET MVC and jquery. I would like to implement preview functionality to a form. i.e. I have a form with number of fields for example name, address etc.. Before the user submits the info, he/she can preview it as to how it will appear on the site. Could any one please point me to right direction as to how I could implement this in a cleaner way? I have tried regenearting the html on click.. but it's very messy.
Any help will be highly appreciated.
You could create a new Controller Action called Preview(YourModel model); which would display everything as needed for preview.
The Preview-View should be Strongly typed with your model containing a Submitbutton which THEN calls the [HttpPost]Save/Update(YourModel model); Action.
I'd go with the preview without posting the form, although generating the html could get a bit messy but you can use microsoft's template plugin (included in jquery 1.4.3) to alleviate that. In my book, you're on the right track already.
It should be pretty similar to your "View"<-> "Read" Action from the CRUD operations, the only difference is, you are not populating the model from the database because its not saved yet (in some cases) and you already have the model binded from the FormColecction.
public ActionResult View(int id)
{
//get the data from the DB
//populate the model
//return the view
}
public ActionResult PreView(YourModel model)
{
//populate the model or some pre-formatting
//return the view
}
Using Ajax on the Preview Action get the job done and you don't need to use too much js (that is always a little messy)