I am working on ASP.NET MVC 4 Project of our Company. It is revenue based application and It has some Filters at every Controller and Action of the application.They are Year and Quarter like some filters. for these filter changes I used Create Base Model, (It contains these filter values) and every other Models inherit from this Base Model.Base Model is use at #layout view.
Every change of filter should update the view.
Base Model in layout view something like this
public class BaseModel
{
public string YearSelected{ get; set;}
public string QuarterSelected{ get; set;}
}
and other Models are inherit from this BaseModel
public class RevenueModel:BaseModel
{
// other stuff
}
For all these things I am sending through the parameters.Seems like now Parameters are increase requirements are changes to add more parameters
1.I want to know the method that handle is correct and If method is insufficient Suggest me best
way to handle this parameter changes.
2.In the UI(View),
When user change the view by checking radio button and click on apply filter button I am using jquery for handle this,
window.href='Url Action with new Parameters';
window.href='#Url.Action("SomeAction","Controller",new{ // those all parameters } ';
When button click window.href will automatically call and update the view I want to knowIs this method Robust? Suggest me best way to handle this scenario.
"Simply I need a answer for if i use jquery to call an action and use high numbers of parameters for the call controller action"
What you're doing is doable, but as #ps2goat points out, you can run into issues if you have too many GET parameters in the URL.
But the right answer depends on how the filters will be used. Will the user often change the filters or will he rarely change them? If the user is expected to browse through your app and only rarely change the filters, I would suggest you to use another approach than including the parameters as GET parameters in the URL because:
You could run into problems if the total length of your URL becomes too long, as #ps2goat points out.
You could run into user experience problems. If a user bookmarks a page, and then later changes his filters, and uses the bookmark to return to the earlier page, his filters would be reverted, which is probably not what he would have expected.
It wouldn't look very pretty. All your urls on your site would look like /controller/action/?YearSelected=2014&QuarterSelected=1&Parameter3=2&Parameter4=8, which could also create SEO issues you would need to take care of.
In that case, I would recommend you to consider using a cookie or saving the user's filters on the server instead. (But preferably not in a Session, as that can create scalability problems for your application). If you used a cookie, the user's filters would be available to your Controller Action on each request automatically, as the cookie would be sent along with every request. (This is of course also something to have in mind when considering which strategy to use. If you have alot of cookie data, this will slow down the perceived responsiveness of your application, as the cookie data has to be sent along with every request to your server. So keep your cookie data as small as possible)
On the other hand, if you expect the user to change the filters often and maybe even several times on the same page, you could consider using jQuery to do an asynchronous POST to your MVC controller, retrieve the neccessary data using JSON, and update the view. This is actually not as difficult as it might sound.
What you would need to do to implement it, is to create a Javascript function on your page that submits your parameters to your controller action. You can send the data as JSON to the controller action also. Something like this could work: (Untested code)
<script>
function submitFilters() {
var parameters = {
parameter1: $('#parameter1').val(),
parameter2: $('#parameter2').val(),
...
};
$.ajax('#Url.Action("SomeController", "SomeAction")', {
contentType: 'application/json',
data: JSON.stringify(parameters),
success: function(data) {
alert('Received data back from server. Ready to update the view.');
}
};
}
</script>
Then you would hook up the filters (Radio buttons, drop downs etc) to call the method submitFilters.
MVC automatically converts the JSON data it receives from the client into your C# ViewModel as long as the property names match. Then you can do whatever querying and filtering you need to on the server, and then send the data back as the result of the action. (Pseudo code)
public ActionResult SomeAction(MyViewModel vm)
{
var data = SomeRepository.GetData(vm.Parameter1, vm.Parameter2, ...);
return Json(data);
}
Then you just need to update the view when the data is received. You would preferably use a template engine for that, but it's not required of course.
This is just a crude example of how you could do it. Normally I would create a Knockout View Model to encapsulate it all. But this should get you started.
Related
I've become a little lost trying to figure out the correct way to share some data between some partials. I'll do my best to explain the setup:
Layouts
_Layout.cshtml - this is the main layout for the site: top navigation, footer etc.
_SectionLayout.cshtml - this is a sub-layout of _Layout.cshtml and makes the main content area of the site into a header and two lower columns - the left column is a menu, the right loads various page content
Partials
_SectionMenu.cshtml - this is the mark-up for the left hand column menu, it builds the menu based on an ViewModel that it expects to be passed which contains an enumerable list of menu items
_SectionHeader.cshtml - this is the mark-up for the section header, it builds the header similarly to the menu above
All of the above are located in the Shared folder.
A series of controllers use the _SectionLayout style to have a consistent style for areas of the site with related pages. The layout is specified on these controllers via a _ViewStart.cshtml within the Views folder for each controller. Each controller implements an ActionResult method for both _SectionMenu() and _SectionHeader(), returning appropriately populated ViewModels for the section.
The individual pages that the menu loads have been setup to do something along the lines of the following:
if (Request.IsAjaxRequest())
return PartialView();
else
return View();
So that they can be loaded either directly via a standard GET request (which loads the header, menu and layout), or as a partial to be inserted into the right hand column of the layout. Now this is all seems to work well, until I come to deciding how to load data that is shared between actions and partials within the same controller while trying to adhere to DRY where I can and cut down on code re-use. The problem is as follows:
Within a typical controller of this type, a single full load of the page will invoke three ActionResult methods: _SectionHeader(), _SectionMenu() and whatever the main action was. Often, all three of them need to access data from the same, or similar database queries. For example, a ProductController may have an Index action which shows an overview of the product information. The header will need to show the name of the product, the menu will show statistics such as the number of images. All of this data comes from a single query which returns all of the product information from the database, but how am I best able to share this data between the three actions? Some ideas I've had:
Make all the ViewModels inherit from a base view model for that controller and pass it through to the partials after opening it in the main action
Store the data in the ViewBag or ViewData
Just open the database multiple times and hope that my ORM is clever enough to realise it doesn't need to fetch it from the server multiple times within the same request
The first one seems to me to be rather complicated for what is a fairly simple ask. The second always feels like a cheap easy way out and I try to avoid it. The third, I'm not confident enough that what I'm using (Dapper) will know not to go to the server again for the same query.
To make things just a little more complex, some of the Actions for a controller may not need to load the main database query. To extend the example from above, the Images option in the menu of the Product controller may need to run an additional query to load the list of associated images, but if it is being requested as an ajax call, it really doesn't need to load the main query for the header and menu sections.
I'm comfortable with the logic for that, but does every one of the actions within a controller of this type need to look something like the following, or can DRY be leveraged here?
public ActionResult Images(int? id)
{
if (!CheckExists(id))
return HttpNotFound();
// if this is an action that doesn't normally need the shared data,
// only load it if it isn't an ajax request, as then the menu/header will require it
if (!Request.IsAjaxRequest())
LoadSharedData(); // part of the question is how I handle this part
// load the particular model for this page
var model = GetImagesModel();
if (Request.IsAjaxRequest())
return PartialView(model);
else
return View(model);
}
In a section with say 10 similar actions in it, seeing all that extremely similar code repeated tells me that I'm doing something wrong. Thanks in advance for any help. If I haven't explained something well, please ask and I'll do my best to clarify.
I am building a cms, on the edit screen for a section you can edit multiple types of pages, the urls need to remain nutral, like this:
foobar.com/edit/section/my-content-page-name
foobar.com/edit/section/my-gallery-page-name
foobar.com/edit/section/my-blog-page-name
In this scenario the Index action is used for both gets and posts.
At the moment I have one massive ViewModel, that encompasses all the data required across all page types.
I feel this is quite wrong and, makes an ugly solution for deciding what type of page update on the post.
How can I keep the Action the same but use it with different strongly type ViewModels?
Is this even possible?
public ActionResult Index(string page)
{
var model = _pageManager.GetSection(page, SelectedSite);
return View(model.PageType, model);
// renders appropriate View based on page type.
}
[Transaction]
[HttpPost]
[ValidateInput(false)]
public ActionResult Index(SectionIndexViewModel model)
{
// all page types post back to same action to update content etc.
// at this point SectionIndexViewModel is getting bloated with properties because it must cater for ALL page types data.
var action = Request["action"] ?? "";
// currently use this to determine what event has been triggered
switch (action.ToLower())
{
// then goes to update the appropriate page, blog or gallery
// etc.
all page types post back to same action to update content etc.
There is your problem. The same action should not handle all post backs. Create one controller per feature (content, gallery, blog). It's how MVC is intended to be used.
Single Responsibility Principle do also apply to controllers.
You can even move the controllers to class libraries to get plugin like architecture for your CMS. I've described how here: http://blog.gauffin.org/2012/05/griffin-mvccontrib-the-plugin-system/
I managed to achieve this with some MVC basics that I had forgotten about.
The routing remains as per the defaults.
For each ViewModel type I delivered an extra hidden field in the form, with the type of the page/content/ViewModel eg: Content Page, or Blog Page etc.
In the Post action, I check the type of the page from this hidden field.
Then use TryUpdateModel using the expected ViewModel type for that page type.
And the rest is straight forward.
Pretty basic stuff really.
I am doing big project in Web Forms and entered a big mess of code(can be solved with little refactoring), so I decided to take a peek at mvc, seems like everyone favores it over web forms.
I have dll file with all LINQ to SQL classes and methods for existing sql db and I started teaching myself by reacreating this project in mvc.I first recreated my homepage from webforms to razor, so far so good and I recreated one of the user controls to partial view and looped it.
Partial view is strongly typed with one of L2S class, the thing is there is some raw data in it.Like for example My model for partial view is my L2S class PostDetails: it consist od some data ready from output like: Title, Permalink, ViewsNumber etc. but it also cointains some raw data like UserId(I need to call method from dll to get username),DateTimeCreated(on which I also need to call method to get time difference), In webforms I would do this in codebehind but I'm not sure where to do it in mvc, maybe in controller and pass it in ViewData.I am also asking this for future, not just this case.
You should perform those actions in the controller. The controller is exactly what it sounds like, it controls the data flow between the model and the view.
Here is an example using your PostDetails:
PostDetailsModel
String Title {get;set;}
String Permalink {get;set;}
Int ViewNumber {get;set}
Int UserId {get;set}
DateTime DateTimeCreated {get;set;}
GetDetailsView: this will be requested by your user, and will be a visual representation of the PostDetailsModel (however you want to format that). When this View is requested, a call is made to your controller....
PostDetailsController
//This method will (by default) come from calling [BASEURL]/PostDetails/GetDetails
public ActionResult GetDetails()
{
var details = new PostDetailsModel();
details.UserId = GetUserId();
details.ViewNumber = GetViewNumber();
....
//By default this looks for a view in the PostDetails folder
//by the name of your method (GetDetails)
return View(details);
}
Notice how the controller is the router between the model and the view, basically. A note, however, it would be better to fill your model from methods contained within some sort of business layer (however you implement that). Something like var details = BL.GetDetails();
Also, when the user makes requests to save data, then you can do that with another method that takes the data (whether it be the PostDetailsModel or an int or...) and does whatever it needs to do, then it can redirect back to the display action (or wherever you need it to go)
There is a wealth of information on MVC with a simple google search. Here is Microsoft's overview, but the wikipedia article is very succinct if you just want the basics
In MVC, All your requests will be handled by an action method in a controller. and then controller returns a view. So you can get the data in your controller (or a different layer which will be called from the controller) and pass that data to your view.
Strongly typed views are a clean way of doing things. Create a ViewModel for your scenario. Mostly ViewModels looks similar to the Entities. Ex : For Displaying the details about a customer, i will create a viewModel called "CustomerViewModel"
public class CustomerViewModel
{
public string CustomerId { set;get;}
public string FirstName { set;get;}
}
Then in my CustomerController, I will have a get method for the customer
public class CustomersController : Controller
{
public ActionResult Details(int id)
{
CustomerViewModel objCustomer=new CustomerViewModel;
objCustomer.FirstName="Samuel";
//Instead of hardcoding the values here , you can get it
// from the database using the id and assign to the properties
return View(objCustomer);
}
}
And you will have a view called "Details.chtml" in your Views\Customer
folder which is strongly typed to your CustomerViewModel
#model CustomerViewModel
<div>
<h2>#Model.FirstName</h2>
<p>#Model.CustomerId</h2>
</div>
This can be accessed like http://yourdomain.com/Customer/Details/25
Personally i prefer to keep my controller actions thin. so i write the GetFromDatabase code in a seperate service layer and i just call that method from my action method
I think that you'll find this article very useful:
MVC Overview
It explains in detail, as to what each component should be used for:
Models. Model objects are the parts of the application that implement
the logic for the application s data domain. Often, model objects
retrieve and store model state in a database. For example, a Product
object might retrieve information from a database, operate on it, and
then write updated information back to a Products table in SQL Server.
Views. Views are the components that display the application s user
interface (UI). Typically, this UI is created from the model data. An
example would be an edit view of a Products table that displays text
boxes, drop-down lists, and check boxes based on the current state of
a Products object.
Controllers. Controllers are the components that handle user
interaction, work with the model, and ultimately select a view to
render that displays UI. In an MVC application, the view only displays
information; the controller handles and responds to user input and
interaction. For example, the controller handles query-string values,
and passes these values to the model, which in turn queries the
database by using the values.
What is the ultimate workaround?)
Desired scenarios are:
Multistep forms.
If a page has tabs on it, the tabs should persist their `viewstate'
Whatever navigation user has chosen, it shouldn't affect (more appropriately, bother) the conversational state management.
Those are just several aspects, but I find them much practically relevant.
I have worked once on Wizard kind of form in Asp.Net MVC and best thing to do in this case is to use Model/ModelBinding to keep track of form input.
We can create a chain of Controller Actions (for each steps) with output model of each serving as the input Model for the next Step (Action).
For example if we have three steps for creating a user. Then UserController can have actions for each steps.
public ActionResult Step1()
{
User user = new User();
return View(user);
}
[Post]
public ActionResult Step1(User user)
{
//perform business validation
RedirectToAction<UserController>(u => Step2(user));
}
After this Step2 action will take over with modified user from Step1 and can render its own view and so on.
You may also want to check out http://blog.maartenballiauw.be/post/2009/10/08/Leveraging-ASPNET-MVC-2-futures-ViewState.aspx. There's an Html.Serialize() helper in MVC Futures. The article refers to it as lightweight Viewstate, but it's effectively just a glorified wrapper around "serialize this object and store the base64 string in a hidden form field." If you need state to be associated with individual pages rather than an entire Session, this helper might be appropriate for your needs.
Not sure about a "workaround", but have you considered using AJAX and jQuery? Both would be appropriate based on the requirements you listed.
Recently I started working with MVC, before that I used "classic" ASP.NET.
After using Ruby on Rails (RoR), I wonder how to implement POST request handling in MVC similar to how RoR operates. In RoR you use the Post method, so you need only one function for a view.
In ASP.NET MVC I need to use 2 separate functions for GET and for POST, so I need to initialize the same data twice, and I don't like to repeat something in my code.
How can I check if the request is POST in one method?
Update:
Solution is found: I have to use Request.HttpMethod.
Thank you!
I came across this question wanting to know the same thing. Below is a detailed description of my situation and the solution that I used (which utilizes the other answers provided here). I originally tried to use the two separate method approach, but I ran into a problem when the method signatures of these methods became identical.
I have a page that displays report data. At the top of the page there is a form with some fields, which allow the user to specify report parameters such as start date, end date, etc.
I originally approached this by creating two separate methods to handle the Get and the Post methods. The post method would redirect the browser to the get method so that any parameters that were specified would be added to the query string and so that the browser would not prompt the user with a dialog saying that it is going to resend the data that they entered if they refresh. Note: I realized later that I could accomplish this by setting the method attribute of my form element to "Get", but I think ideally a controller shouldn't have knowledge of how a view is implemented, so in my opinion that is irrelevant.
As I developed these two methods I eventually found myself in a situation where the method signatures became identical. Furthermore, my code for these two methods became nearly identical, so I decided to merge them into a single method and to just check the request verb so that I could do something slightly different when the request is not a "Get". A distilled example of my two methods is shown below:
// this will not compile because the method signatures are the same
public ActionResult MyReport(DateRangeReportItem report)
{
// if there are no validation errors and the required report parameters are completed
if (ModelState.IsValid && report.ParametersAreComplete)
{
// retrieve report data and populate it on the report model
report.Result = GetReportData(report.CreateReportParameters());
}
return View(report);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyReport(DateRangeReportItem report)
{
if (ModelState.IsValid && report.ParametersAreComplete)
{
// redirect to the same action so that if the user refreshes the browser it will submit a get request instead of a post request
// this avoids the browser prompting the user with a dialog saying that their data will be resubmitted
return RedirectToAction("MyReport", new { StartDate = report.StartDate, EndDate = report.EndDate });
}
else
{
// there were validation errors, or the report parameters are not yet complete
return View(report);
}
}
Why am I accepting a model object as the parameter to my get method? The reason is that I wanted to take advantage of the validation logic already built into the model object. If someone navigates to my page directly with all parameters already specified in the query string, then I want to go ahead and retrieve the report data and display it on the page. However, if the parameters specified in the query string are invalid then I also want validation errors to appear on the page. By putting my model object as the parameter, the MVC framework will automatically attempt to populate it and will capture any validation errors without any additional work on my part.
I used the other answers posted for this question to create a RequestHttpVerb property on a base controller class in my project:
public HttpVerbs RequestHttpVerb
{
get { return (HttpVerbs)Enum.Parse(typeof(HttpVerbs), this.Request.HttpMethod, true); }
}
So finally my consolidated method looks like the following:
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult MyReport(DateRangeReportItem report)
{
// check if there are any validation errors in the model
// and whether all required report parameters have been completed
if (ModelState.IsValid && report.ParametersAreComplete)
{
// this is unnecessary if the form method is set to "Get"
// but within the controller I do not know for sure if that will be the case in the view
if (HttpVerbs.Get != this.RequestHttpVerb)
{
// redirect to the same action so that if the user refreshes the browser it will submit a get request instead of a post request
// this avoids the browser prompting the user with a dialog saying that their data will be resubmitted
return RedirectToAction("MyReport", new { StartDate = report.StartDate, EndDate = report.EndDate });
}
// there were no validation errors and all required report parameters are complete
// retrieve report data and populate that data on the model
report.Result = GetReportData(report.CreateReportParameters());
}
// display the view with the report object
// Any model state errors that occurred while populating the model will result in validation errors being displayed
return View(report);
}
That's my current solution to the problem. I would prefer not to have to check the Request.HttpMethod property in order to determine whether I needed to perform the redirect, but I didn't see another solution to my problem. I would have been fine with keeping two separate methods to handle Get and Post requests, but the identical method signature prevented this. I would have preferred to rename my Post action handler method to avoid the method signature conflict and to use some mechanism to indicate to the MVC framework that my renamed method should still handle the "MyReport" action, but I am not aware of any such mechanism in the MVC framework.
You only need separate methods for GET and POST if their method signatures differ, there's no reason why one action method can't handle GET and POST methods.
If you need to know whether it was a GET or POST, you could check using Request.HttpMethod in your action, but I would advise using a separate method decorated with the [AcceptVerbs(HttpVerbs.Post)] attribute as suggested by the other posters.
You don't check in ASP.NET MVC. You decorate your method with the [AcceptVerbs(HttpVerbs.Post)] attribute to indicate that the method applies to post only, and accept the model in the method used to handle the post.
I'd strongly suggest doing the walkthrough for NerdDinner to understand more about the ASP.NET MVC framework.
You may take a look at the Request.HttpMethod property.
Correct way to do is using ModelBinding during Post request.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(EmployeeViewModel model)
{
//validate data, save employee, handle validation errors...
}
This way you will not have to init your data again.