Run single method from Multiple Actions in MVC controller - c#

I have the following code that is identical across multiple Action Methods in my controller. Is it possible to reduce this down to a single method and route multiple Actions to it?
[HttpGet]
public ActionResult Tool2(Guid? id)
{
var model = _viewModelFactory.CreateViewModel<Guid?, ToolsViewModel>(id);
return model.ReferenceFound ? View(model) : View("~/Views/Tools/InvalidReference.cshtml", model);
}
[HttpGet]
public ActionResult Tool1(Guid? id)
{
var model = _viewModelFactory.CreateViewModel<Guid?, ToolsViewModel>(id);
return model.ReferenceFound ? View(model) : View("~/Views/Tools/InvalidReference.cshtml", model);
}
Each Action does has a unique View and this needs to be retained.

Make a common method which both actions will call. Leave both actions separate as it will be clearer to understand than to write (and read!) custom routes.
public ActionResult Tool1(Guid? guid)
{
return CommonAction(guid, "Tool1");
}
public ActionResult Tool2(Guid? guid)
{
return CommonAction(guid, "Tool2");
}
private ActionResult CommonAction(Guid? guid, string viewName)
{
var model = _viewModelFactory.CreateViewModel<Guid?, ToolsViewModel>(id);
return model.ReferenceFound ?
View(model) : View("~/Views/Tools/InvalidReference.cshtml", model);
}

Related

Entity Framework : send list between methods in the same controller not working

I want to send a list to this method (inside the same controller)
[HttpGet]
public ActionResult listaExpedientesPOrCriterio(List<Expediente> expedientes)
{
ExpedienteListPorCriterio vm = new ExpedienteListPorCriterio(expedientes);
//List<Expediente> expedientes = db.Expediente.ToList();
//SelectList Tramitees = new SelectList(expedientes, "Codigo", "FechaCreacion");
return View(vm);
}
Im using this inside the other method, to send the list
return RedirectToAction("listaExpedientesPOrCriterio", "expedientes");
but I receive only null. Any idea whats going on?
You have [HttpGet] action attribute. How you intend to send to it List<T> at all? Instead, you have to use [HttpPost] and pass data in request's body, but at this case you won't can to RedirectToAction. But you can pass your expedientes list from one action to another via TempData also preserving [HttpGet]:
[HttpGet]
public ActionResult AnotherActionName()
{
//some code...
TempData["expedientes"] = expedientes;
return RedirectToAction("listaExpedientesPOrCriterio"/*, "expedientes"*/);
}
[HttpGet]
public ActionResult listaExpedientesPOrCriterio(/*List<Expediente> expedientes*/)
{
var expedientes = (List<Expediente>)TempData["expedientes"];
var vm = new ExpedienteListPorCriterio(expedientes);
return View(vm);
}

How to have multiple aliases for a controller action

I have a Search controller with a generic Search() action that takes several parameters and has a bunch of logic. I'd like to call this from other controllers without having a lot of copy/paste code.
I'd like to call this action from these different urls/controllers.actions.
/Search/Search?text=mySearchText
/User/SearchTransactions?type=purcahse
/Transactions/UserSearch?UserId=1
I could move the method to a baseController but I'd have to call /Search on each controller and I'd like to have them all named differently.
you already have your solution man put it in base controller and decorate it with actionName attribute
like
[ActionName("Search1")]
public ActionResult SearchText(string text) {
return View();
}
[ActionName("Search2")]
public ActionResult SearchType(string Type) {
return View();
}
[ActionName("Search3")]
public ActionResult searchId(int ID) {
return View();
}
now you can do like
/search1
/search2
/search3

The controller for path ... was not found or does not implement IController

I am writing an application using ASP.NET MVC 5 using c#. I have a need to add a global menu on the upper right hand side of the application. I was advised other SO to use action with ChildActionOnly attribute.
So here is what I have done.
I created a BaseController like this
public class BaseController : Controller
{
[ChildActionOnly]
public ActionResult ClientsMenu()
{
using (SomeContext db = new SomeContext())
{
return PartialView(db.Database.SqlQuery<Client>("SELECT * FROM clients").ToList());
}
}
}
Then I inherited all my controllers from BaseController like so
public class TasksController : BaseController
{
public ActionResult Index(int ClientId)
{
...
return View();
}
public ActionResult Show(int SurveyId)
{
...
return View();
}
}
To render the ClientsMenu in my layout I added the following code
#Html.Action("ClientsMenu", "Menus")
Now when I run my application I get the following error
The controller for path '/Tasks/Index' was not found or does not implement IController.
When I remove #Html.Action("ClientsMenu", "Menus") from the layout everything works fine but the global menu does not show of course.
What can I do to resolve this issue?
Updated
Here is what I have done after the feedback I got from the comments below
public class TasksController : Controller
{
[ChildActionOnly]
public ActionResult ClientsMenu()
{
using (SomeContext db = new SomeContext())
{
return PartialView(db.Database.SqlQuery<Client>("SELECT * FROM clients").ToList());
}
}
public ActionResult Index(int ClientId)
{
...
return View();
}
public ActionResult Show(int SurveyId)
{
...
return View();
}
}
but still the same error
Take ClientMenus Action out of the BaseController and put it into its own controller MenusController. You can then call that controller from your Views.
#Html.Action("ClientsMenu", "Menus")
In your example you don't have a MenusContoller which is what #Html.Action("ClientsMenu", "Menus") is looking for.
The Phil Haacked - Html.RenderAction and Html.Action article linked to by the other post provided a good example for you to follow.

asp.net nested views with owns controllers

I have a target to create a nested architecture of view/controller. For example:
we have few areas in webpage. All this areas managed by its own controller. In another words I need to create independend pages and then join them in one page.
Please see the image:
So is it possible and where I can read about it? Thanks.
Yes you can achieve this by simply calling
#Html.Action("ActionName", "ControllerName");
Example:
in your case you can do like this
Controller1
public ActionResult View1()
{
return View("View1");
}
Controller2
public ActionResult View2()
{
return View("View2");
}
Controller3
public ActionResult View3()
{
return View("View3");
}
Calling in main page:
#Html.Action("View1", "Controller1");
#Html.Action("View2", "Controller2");
#Html.Action("View2", "Controller2");
call these in different section of main page wherever you want.
You can use #Html.Action() to render child views from different controllers
public class FirstController : Controller
{
public ActionResult Index()
{
return View();
}
}
public class SecondController : Controller
{
[ChildActionOnly]
public ActionResult Method1()
{
return PartialView();
}
}
public class ThirdController : Controller
{
[ChildActionOnly]
public ActionResult Method2(int ID)
{
return PartialView();
}
}
Index View (FirstController)
....
#Html.Action("Method1", "Second")
#Html.Action("Method2", "Third", new { ID = someValue })
You can also use #{ Html.RenderAction(); which is more efficient is you are generating a lot of html.

MVC Controller with User Access Only by Session

I am currently building a user login system in MVC 5 for practice. What I wanna do is, making a controller only accessable if you have the session "UserId".
Surely, I could just make an if statement in every action, like this:
public ActionResult Index()
{
if (Session["UserId"] != null)
{
return View();
}
else
{
return RedirectToRoute("Home");
}
}
But is there a way I can make that happen with all the actions in the controller?
Bonus info:
I have 2 controllers
- HomeController
- AccountController
You would implement an authorize filter and apply that filter to your controller.
Something like this:
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
if (filterContext.HttpContext.Session["UserId"] == null)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
Then you could apply the [CustomAuthentication] attribute to your controller directly, or you can do it by each action in your controller. Something like this:
[CustomAuthentication]//<-- If you put it here, it applies to the whole controller
public class HomeController : Controller
{
[CustomAuthentication]//<-- Here it only applies to the Index action
public ActionResult Index()
{
return View();
}
}
I believe what you are looking for is a custom ActionFilter. Code in an ActionFilter can be executed before the ActionResult, allowing you to redirect anyone without the UserId session.
Instead of putting code in every ActionResult you would do something like this
[MyCustomActionFilter]
public ActionResult Index()
{
return View();
}
Here is a tutorial on how to create one Custom Action filters in MVC

Categories

Resources