MVC2 - Possible to invoke action from a DIFFERENT controller? - c#

In a controller, is it possible to return the view of an action from ANOTHER controller? The other option is to return a partial view, which uses Html.Action(...) to return the view from the other controller, but I was wondering if there's anything cleaner. Thanks.

If it's just the view you want to reuse, you can pass in the path to the view. For example:
public ActionResult MyAction()
{
// do your model magic here
return View( "~/Views/OtherController/View.aspx", model );
}
Or you can move the view to Views/Shared like Kyle already suggested.

Yes, if that view is a Shared view. Place the view in the Views/Shared folder in your MVC Project, then both controllers will be able to return it.

If you want to invoke an action on another controller, you can use Controller.RedirectToAction() and pass in the action and controller name.
However, this adds an additional server round trip. If you want to avoid that, you can use the TransferResult class shown here:
How to simulate Server.Transfer in ASP.NET MVC?

I ended up using my original solution, which was having a shared view that invokes an action. It was much less code than I needed. Thanks.

Here's a strategy I use to invoke another action without having to create a special view just for that purpose:
Create a shared view which takes a model that defines an Action, Controller, and RouteValues, and whose sole responsibility is to call RenderAction with the values on that model.
Next create a helper method on your base controller class that takes an Action, Controller, and RouteValues as parameters, and returns the ViewResult for this shared view. That way, you can reuse this helper method and shared view on all your controllers any time you want to render some other action from another action's context.
Of course, if it's just the view and not the action that you want to invoke, Marnix's answer is correct.

Related

ASP.NET Core 2.0 URLs

I'm developing a large ASP.NET Core 2 web application but I still get confused with URLs.
When fist learning, I thought URL's took on the name of the View, but discovered they come from the Controller method.
Here is an example to convey my issue:
I have a controller method named Daysheet, which returns a view and model with the same name.
In the Daysheet view, I call various controller methods from Javascript to perform specific actions. One of them is called AssignStaff which takes two integer parameters.
In the AssignStaff method I again return the Daysheet view with model, but now my URL is "AssignStaff"!
I can't just do a redirect because the whole Daysheet model is not being passed to the AssignStaff method.
I have many situations like this where after calling an action, I end up with another URL that I don't want.
UPDATE/EDIT
Thanks for assistance and apologies if my explanation is confusing. I simply have a view called Daysheet that uses a model. I want to call various controller methods to perform various actions, but I want to stay on the "Daysheet" view/URL.
As mentioned, I can't just redirect because in the action method I no longer have the whole model from the Daysheet view. Also, if I redirect I can't pass the whole model because that causes an error saying the header is too long. I think my only choice may be to use ajax for the actions so that the URL doesn't change.
When you just do Return View("") name in a Controller Action, the URL will be the name of the Action you are using.
If you want to redirect to some specific Action, that will help to make sure the Url matches to where you are. You might want to read more about it here.
To do so, use:
RedirectToAction()
The URLs your application responds to are called "routes", and they are either created by convention or explicitly. The default is by convention, of course, which is a URL in the form of /{controller=Home}/{action=Index}. Index is the default action if that portion of the route is left off, so a request to /foo will by convention map to FooController.Index. HomeController is the default controller, so an empty path (e.g. http://sample.com) will by convention invoke HomeController.Index.
Razor Pages have their own conventions. These do somewhat follow the file system, but exclude the Pages part of the path. So a Razor Page like Pages/Foo/MyRazorPage.cshtml, will load up under /Foo/MyRazorPage.
There there is the Route attribute, which allows you to specify a totally custom route. This attribute can be applied to a controller class and individual actions in the class. For example:
[Route("foo")]
public class MyAwesomeController
{
[Route("bar")]
public IActionResult MyAwesomeAction()
{
return View();
}
}
With that, a request to /foo/bar will actually invoke MyAwesomeController.MyAwesomeAction.

Calling controller action method directly from Razor View

I looked around and couldn't find an easy solution.
I've tried #GetUserName which doesn't work.
I've tried # { GetUserName which doesn't work.
There has to be an easy way to call a method from the razor view engine.
It is within a foreach loop.
I need GetUserName(item.userID)
The below code is in my controller:
[ChildActionOnly]
public string GetUserName(int userID)
{
ProPit_User user = db.ProPit_User.Find(userID);
return user.username;
}
Trying to call a controller action method directly from your view is usually a sign of bad design.
You have a few options, depending on what you are trying to do:
Avoid calling the method, instead put the data in your model, and render the model
Use Html.RenderAction
Put the method in another class and use normal function syntax.
(1) is usually my default approach, often incorporating DisplayTemplates and EditorTemplates
For (3), e.g.
public static class Util
{
public string MyUtilMethod(int blah)
}
And the view:
#Util.MyUtilMethod(1)
Although you can obtain the controller instance from your view, doing so is plain wrong as it violates the whole MVC (and MVVM) paradigm, as the view should not be aware of its controller.
(The only possible reason I can think of where this would be useful would perhaps be for testing the controller from a mocked view, although even here, it should be possible to test the exposed controller functionality directly from unit tests):
#{
var controller = ViewContext.Controller as MyController;
var userName = controller.GetUserName(123);
}
The better way to have arrived at this result is for the controller to pre-populate, and pass all the data needed by the View, such as the userName, to a custom ViewModel (as typed by the #model directive at the top of the Razor page), or to the ViewBag dynamic.

return View() not working inside controller

I am using ASP.NET MVC C#. I have my view with the following line of code:
#using (Html.BeginForm("TastingParty", "Contact"))
I am submitting to a different controller and action than the current page is on so I had to add a custom controller and action in that line. Now it gets to my controller and at the bottom of the method I call "return View();" so it will display the same page again. But it is looking for that view in the Contact controller because that is where I sent it.
How do I return the original View that it came from? Hopefully that all makes sense.
return RedirectToAction(Action,Controler)
You are searching for this?
You can either use return RedirectToAction(...
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction(v=vs.118).aspx
Or, if you want to be able to reuse the view across different controllers, you can place it in the Views\Shared folder.
In the latter case, you then have the ability to return the posted model back out to that view.
public ActionResult YourAction(YourViewModel postedModel) {
// do something
return View(postedModel);
}
And again, if you want this to be a shared view, you could place it under Views\Shared\YourAction.cshtml.

passing a view-model with a controller around multiple Views

So I have 3 views, a controller and one model. (just an example) The first view sets the user first name and last name. Which gets posted back to the controller, and I can see the data in the view-model. The controller then calls the second view sets the email (I can call the data from view 1). The third view shows all of the data (the original stuff from view 1 is no longer there)
#Html.DisplayFor(m => m.FirstName)
#Html.DisplayFor(m => m.LastName)
#Html.DisplayFor(m => m.Email)
Do you think creating a static singleton model would work in the controller? or should I be using TempData
EDIT: sorry I forgot about my controller
Would my GET methods in my controller need a parameter?
[HttpGet]
public virtual ActionResult SignUp1(model m)
{
return View(m)
}
you can call into another view using #Html.Partial("view name", object) if you want to preform logic you can call another controller action with #Html.Action("action", "controller", object). then it's just like any other controller action. typically calling actions from a view are decorated with [ChildActionOnly]
Static is a bad idea for web pages, because it is not inherently thread-safe (see here). That means that you'll get really bizarre behavior if you have two or more people using it at once.
I'm not sure why you're even considering doing it this way - is there some specific reason you're thinking about it? The proper way to do it would be to post the model back to each controller action from each view, populating more data each time. Alternatively, you could post back to the same action, and then return the appropriate view based on which fields are missing from the model (and the display if none are).

How to handle shared data between the controller and the view in ASP.NET MVC?

We have a model (say, List<string>). The function that builds the list is non-deterministic and the output is needed to be referenced in both controller and the view during the lifetime of the request. Since it's per-request, it cannot be static or singleton.
It's a common structure and it can be referenced from any view or controller.
Since we can't access controller from the view (by principle, and we agree), we cannot keep it in the controller. We're currently keeping it in the ViewData dictionary and initialize it in the controller, or the view (if the controller didn't need it).
We think that using ViewData for this purpose may not be ideal since it's not created to be consumed by a controller in the first place. Is there a better way to share common per-request data between Controller and the View? If not we'll stick with ViewData.
There is HttpContext.Items dictionary but I'm not sure if it fits to this purpose.
the output is needed to be referenced in both controller and the view during the lifetime of the request
The way MVC works, the Action code in the Controller is executed, and the resulting data is passed to the view engine that draws the page using the info you passed either with the call to View(data) or in the ViewData dictionary.
I don't know what you are trying to do, but it sounds like it's more a problem of a bad approach than a technical one (I might be wrong, though).
Could you explain why you need the controller while the View is rendered? If you need any logic associated with the List (to process it or do anything with it) I would just create a new class that extends List<T>, add the logic to that class instead of the controller, and pass an object of that class to the View, either using View() or ViewData[].
What is exact thing you're trying to do?
Seems like you just asking about the way to pass some data from the Controller to the View which is rather trivial task. Just use ViewData, yes, or ViewBag in MVC3 case or use ViewModels.
Or there is somewhat special case? What does "referencing from Controller and from View" mean? Where the data is coming from? Usually the case is that Controller prepares data for the View and passes it as an ActionResult (or better, as a ViewModel). View should never take some data on its own bypassing the controller.
Controller action should always be called be first. If you have multiple controllers calling the same view/partial view then you should be refactoring the code to one method and call that.
ViewData is the solution to do this, if your really wanting "once access" type information then maybe TempData but ViewData is designed for this.

Categories