views:

152

answers:

2

Is it possible to do something like this in an ASP.NET MVC controller?

public ActionResult Index(CustomADT adt)
{
    ...
}

And you will pass in a class from another controller when you click on a link. Or is it only possible to pass around strings?

Edit:

A bit more elaboration. Let's say I have the following class hierarchy:

public class Area
{
    public string Name { get; set; }
    public ICollection<Building> Buildings { get; set; }
}

public class Building
{
    public string Name { get; set; }
}

So Area contains a list of Buildings. Now, I have two controllers, AreasController and BuildingsController. Both have an Index() method. What I'd like to do is when this URL is navigated to:

http://localhost/Areas/

It'll list all the areas. Then, when you go to this URL:

http://localhost/Areas/1/Buildings/

It'll list all the buildings for area with ID 1. In BuildingsController, I receive the ID as an int and then use it to find the correct Area, like so:

public ActionResult Index(int areaId)
{
    var area = areaRepository.GetById(areaId);
    return View(area.Buildings);
}

Now, this seems pretty clunky to me. The areaId has to be received as an int, then I have to hit up the repository again to get the actual Area object. Is there any way that I can do this instead:

public ActionResult Index(Area area)
{
    return View(area.Buildings);
}

And not hit up the repository again and re-retrieve an object that's already been instantiated? I'm leaning towards no because of how HTTP works (you can't place an object in the URL), but maybe someone has a neat trick up their sleeve.

+1  A: 

Yes, it is possible. More so, it is built right into MVC itself with what is called "ModelBinders". Model binders use reflection to match up the querystring/form key/value pairs with your CustomADT class object. What you have will work perfectly, as long as your form submits the same property names.

Your form...

<% using (Html.BeginForm()) { %>

  <%= Html.TextBox("Title", Model.Title) %>
  <%= Html.TextBox("Description", Model.Description) %>

<% } %>

Your class...

public class CustomADT
{
  public String Title {get; set;}
  public String Description {get; set;}
}

Notice how your class' properties match the form key/values? ASP.NET MVC has it built-in that it will map those together, with your sample Index(CustomADT adt) above.

If you have special requirements for binding, you can create your own custom IModelBinder class and register it within your global.asax for custom mappings between your form key/value pairs and your model (class). (bing it)

Also, I highly recommend reading up on the "ViewModel" pattern with ASP.NET MVC (bing it).

I also blogged about how to use strongly-typed action methods, which allows you to pass around classes from your view to a controller (and in the controller to, with the extensions within the Microsoft.Web.Mvc assembly I mention).

http://eduncan911.com/archive/tags/Asp.Net+Mvc/default.aspx

Finally, there is no direct conversion from a model to a querystring to call another action method on a controller. But, you can use the default Model binding to reflect your model and create them for you:

return RedirectToAction("Index", "Home", myCustomADT);

I think should work as the last parameter is a collection that will be appended as querystring. If that does not (I have doubts), you will need to pass each property as part of an anonymous collection (, new { Title = myCustomADT.Title, Description = myCustomADT.Description);).

A better question is, why would you want to? You really want to redirect and pass view models around instead.

eduncan911
He also may need to redefine his controller signature as `public ActionResult Index([Bind(Prefix="")]CustomADT adt)`.
Jason
I've revised my question with a better clarification of what I'm trying to do. I think what I want to do is a little different than what you've described.
Daniel T.
A: 

I found a possible answer here:

http://msdn.microsoft.com/en-us/library/dd394711%28VS.100%29.aspx

Under the section entitled, Passing State Between Action Methods. Basically, you store the object in the TempData dictionary and then reference it as a string. This is an ugly solution though because it's not strongly-typed.

Daniel T.
TempData is *strongly* typed. It isn't *statically* typed, though.
Craig Stuntz
I thought TempData is just a dictionary with a magic string as the key and the value is an object that you later have to cast into the correct type in the view.
Daniel T.
That is all correct, but it doesn't change what I wrote. There is a difference between strong typing and static typing. That you need to cast at all tells you that it isn't weakly typed. It is, however, dynamically, as opposed to statically, typed.
Craig Stuntz
Ah I see. I was confusing weakly typed with dynamically typed.
Daniel T.