Showing posts with label Action. Show all posts
Showing posts with label Action. Show all posts

Thursday, December 20, 2012

@Html.ActionLink to call action in different controller

@Html.ActionLink has many overloads (at least 17), and so sometimes it becomes confusing if the operation is not so straight-foward. 

For example, if you want to execute an Action of different controller, you must take care to use it like following:

@Html.ActionLink("Link Text", "MyAction", "MyController", new {id = item.ID}, null)
 

Its important to pass the last parameter (which is, "hostname"),
eventhough if you pass it as "null". Doing this will take up proper overload and will call the action from different controller.


Saturday, September 8, 2012

Disable Caching for a Controller Action in ASP.NET MVC

At times, we need to disable the caching for some controller actions in our MVC application.
Say for example, there is an "Add Entry" link on your view, and it has a controller action assigned to it.
Clicking on this "Add Entry" link should call an action, and that will eventually load an Entry fill-up screen/ dialog.
Now when user clicks it for the first time it will call the controller action fine. But for next consecutive clicks, it may or may not call controller action and due to which the target dialog/ entry screen will remain prefilled with old data.
This is because of caching. Under some circumstances, browser caches controller actions, and that is why the cached operation is performed rather than the controller action.

To deal with this problem, we need to disable caching of those controller actions. (Its always recommended to disable caching of controller actions that invoke Add/ Edit of entry).

Following is the walkthrough to achieve the same:

1. Create an action filter. To do that create a new class inherited  ActionFilterAttribute class.

public
class NoCache : ActionFilterAttribute
{
   
public override void OnResultExecuting(ResultExecutingContext filterContext)
   
{
        filterContext
.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        filterContext
.HttpContext.Response.Cache.SetValidUntilExpires(false);
        filterContext
.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        filterContext
.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        filterContext
.HttpContext.Response.Cache.SetNoStore();

       
base.OnResultExecuting(filterContext);
   
}
}

2. Decorate your controller action with the action filter class.

[NoCache]
public ActionResult EditEntry(int entryId)
{
..... the controller action code.}

This is what we need to do to disable caching of controller action in ASP.NET  MVC.

Wednesday, April 25, 2012

Binding two or more types of objects (models) to single view in ASP.NET MVC

This article aims to explain how we can bind two or more different types of objects to single view in ASP.NET MVC application. (Please note, the code snippets are in razor view engine, but I know its not as such difficult for you to comprehend them in ASPX engine :))

As we know, its straight-forward bind a single type of object (or collection) to a view and we can pass it from Controller action to the View.
I mean, if your need to bind a View to an object of PersonEntity type(or its collection), you can bind, pass, and post it like below:

Binding in View: 
@model MVCTutorialApp.Models.PersonEntity

Passing it from controller action:
public ActionResult PersonEdit()
{
..................
return View("EditPerson", _person);
}

HttpPost action in your controller:

        [HttpPost]

        public ActionResult PersonEdit(PersonEntity  _person)

But sometimes we need to pass multiple different types of objects to a single view.
Say, for example, you have two different types "PersonEntity", and "ContactEntity", and you need to bind them to a single view.

There are various ways to achieve them:
But two of the most ideal approaches are Wrapper class, and System.Tuple

Approach AWrapper class
Create a class that can hold instance of both "PersonEntity" and "ContactEntity".
Like, 
public class PersonContactEntity
    {
        public PersonContactEntity()
        {
        }

        public PersonEntity Person { get; set; }
        public ContactEntity Contact { get; set; }
    }

Now in your corresponding action of controller -
Create an instance of the class "PersonContactEntity".
Assign "Person" and "Contact" properties with the their respective instances.
Pass instance of "PersonContactEntity" to the view. 
public ActionResult PersonContactEdit()
{
PersonContactEntity personContact = new PersonContactEntity();
..................
personContact.Person = person object;
PersonContact.Contact = contact object;
return View("EditPersonContact",  PersonContact );
}


Create your view as strongly typed view by adding following line at top:
@model MVCTutorialApp.Models.PersonContactEntity

Once done, when you write @Model followed by dot (.) the intellisense will show you "Person" and "Contact" both, and you can  now bind your controls, or use them in your view.
Example:

@Html.TextBoxFor(m => m.Person.FullName)
Also, @Model.Contact.Email

And, also corresponding HttpPost method (controller action) can also accept PersonContactEntity when a view post data to controller action:
        [HttpPost]
        public ActionResult PersonEdit(PersonContactEntity   _personContact)

Approach B: System.Tuple
A tuple is a data structure that has a specific number and sequence of elements (Ref: MSDN)
Please visit following MSDN link to know more about tuples

Please note that, Tuple in our scenario should only be used if you do not need to do Post data from View to controller action. As tuple does not have a default constructor, it cannot be used as a parameter in HttpPost method, or you may need to find a workaround to make it possible (instead, Wrapper class (approach A) would be an easy to implement).

Coming back to using System.Tuple in our scenario:
Your controller action launching a view should be like:
public ActionResult PersonContactEdit()
{
..................
System.Tuple<PersonEntity, ContactEntity> personContactEntity = Tuple.Create(person object, contact object);
return View("EditPersonContact",   personContactEntity );
}

Create your view as strongly typed view by adding following line at top:
@model System.Tuple<LearnMVC4.Models.PersonEntity, LearnMVC4.Models.ContactEntity>

Once done, when you write @Model followed by dot (.) the intellisense will show you "Item1" and "Item2" both. Item1 corresponds to first type in tuple which is "PersonEntity", and Item2 corresponds to second type which is "ContactEntity". And you can now bind your controls, or use them in your view.
Example:

@Html.LabelFor(m => m.Item1.FullName)
Also, @Model.Item2.Email

So this is how we can pass different types of objects to single view, and can bind them.