Re-factoring Controller's Action in asp.net mvc3 - c#

I am writing this Action code (within same controller) more than 10 times for different Models. Is there any way i can reduce this code or how can i create a generic action.
[HttpPost]
public ActionResult SavePerson(Person p)
{
if (ModelState.IsValid)
{
//do something
return Redirect("/Main");
}
else
{
return View();
}
}
[HttpPost]
public ActionResult SaveCategory(Category c)
{
if (ModelState.IsValid)
{
//do something
return Redirect("/Main");
}
else
{
return View();
}
}

The main point is that //do something part always differs from action to action. So let's try to reduce all code other than that. You could use base controller for it
public class BaseController : Controller
{
[NonAction]
protected virtual ActionResult HandlePost<T>(T model, Action<T> processValidModel)
{
if (ModelState.IsValid)
{
processValidModel(model);
return RedirectToAction("Main");
}
else
{
return View(model);
}
}
}
And in derived controller
public class DerivedController : BaseController
{
[HttpPost]
public ActionResult Create(Person person)
{
return HandlePost(person, p => _repository.Save(p));
}
}

return ModelState.IsValid ? Redirect("/Main"):View();
as a start point would be the only line you need.

For functions which are going to be called too often, create a static class and define all such functions in that.
for example like following
public static class MyAppStaticClass
{
public static SavePerson(Person p)
{
... // your body
}
}
Then, you can refer it like MyAppStaticClass.SavePerson whenever you need it.

Related

MVC Redirect from void-POST Action

My current action looks like this:
[HttpPost]
public void AddMessage([FromBody] ShoutboxMessage input)
{
if (!string.IsNullOrWhiteSpace(input.Message) && Request.Cookies["usrid"] != null)
{
input.SbUserId = int.Parse(Request.Cookies["usrid"]);
input.Timestamp = DateTime.UtcNow;
context.ShoutboxMessages.Add(input);
context.SaveChanges();
}
}
I would like to just do this:
[HttpPost]
public void AddMessage([FromBody] ShoutboxMessage input)
{
if (Request.Cookies["usrid"] == null)
RedirectToAction("Login");
if (!string.IsNullOrWhiteSpace(input.Message))
{
//...
}
}
but that doesn't work, obviously. Is there a way to redirect from an action that's supposed to return void? Or, the other way around, can an Action that's supposed to return an ActionResult not result in any redirection or reload of the current page?
Edit: the "duplicate" has nothing to do with this. it may be that a void action returns basically the same as an EmptyResult action, but that's not the topic here, basically I want to know how to chose between an EmptyResult and an ActionResult at runtime.
Something like this? You can always return EmptyResult() from Action.
[HttpPost]
public ActionResult AddMessage([FromBody] ShoutboxMessage input)
{
if (Request.Cookies["usrid"] == null)
return this.RedirectToAction("Login");
if (!string.IsNullOrWhiteSpace(input.Message))
{
//...
return new EmptyResult();
}
}

Return Action to an other controller

I would like to return an Action to an other Controller
Example: i have 2 controlers:
[Route("myurl"]
public class HomeController : Controller
{
public ActionResult Action1()
{
if (...)
{
return Action2(); //working fine i will keep my route
}
else
{
return OtherController.Action3(); //Don't know how to do it here.
}
}
public ActionResult Action2()
{
return View();
}
}
and
public class OtherController : Controller
{
public ActionResult Action3()
{
return View();
}
}
It's working if the Action is inside the same controller but wish to return the Action1 from HomeController to Action3 from OtherController.
I want to keep the same route (not a redirection to an other route).
Any idea ?
Have you tried using this RedirectToAction?
return RedirectToAction("ACTION_NAME", "CONTROLLER_NAME", new { area = "" });
I found out:
I need to return like that :
return DependencyResolver.Current.GetService<OtherController>().Action3();
[Route("myurl"]
public class HomeController : Controller
{
public ActionResult Action1()
{
if (...)
{
return Action2(); //working fine i will keep my route
}
else
{
return DependencyResolver.Current.GetService<OtherController>().Action3();
}
}
public ActionResult Action2()
{
return View();
}
}
return RedirectToAction("ActionName", "ControllerName");
You can do this by calling the below method of controller class protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName); For your requirement the code inside the else block would look like base.RedirectToAction("ACtion3","OtherController");

MVC Action Attribute that checks parameter has value?

I have a handful of Actions in my ASP.NET MVC site that have one parameter. The first lines of code on all these actions checks that the parameter is not null, and if it is, redirect to a page that allows them to choose a value for the parameter.
For example:
public ActionResult Summary(string client)
{
if (String.IsNullOrEmpty(client))
return RedirectToAction("Select");
return View();
}
I'd like to create an attribute that does something like the above code, so I don't have to repeat it in every action. Something like:
[ClientRequired]
public ActionResult Summary(string client)
{
return View();
}
And then the ClientRequiredAttribute would check the value of the client parameter, and if it's empty/null, redirect to the select client page. Is such an attribute possible?
-shnar
Yes, it is possible.
It would be something like this:
public class ClientRequiredAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
object parameter = null;
filterContext.ActionParameters.TryGetValue("client", out parameter);
var client = parameter as string;
if (string.IsNullOrEmpty(client))
{
var urlHelper = new UrlHelper(filterContext.Controller.ControllerContext.RequestContext);
var url = urlHelper.Action("Select", "ControllerName");
filterContext.Result = new RedirectResult(url);
}
}
}
PS: Not tested, but it should work.
In ASP.NET MVC 5 you can use attribute routing.
http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
public class ReviewsController : Controller
{
// eg: /reviews
[Route("reviews")]
public ActionResult Index() { ... }
// eg: /reviews/5
[Route("reviews/{reviewId}")]
public ActionResult Show(int reviewId) { ... }
// eg: /reviews/5/edit
[Route("reviews/{reviewId}/edit")]
public ActionResult Edit(int reviewId) { ... }
}

Mvc3 C# - Is it possible to call an action from a different controller?

In my project I have two different controllers.
This is the main one:
public class Main : Controller
{
public ActionResult Index()
{
return View();
}
}
And this is the other one:
public class OtherOne : Controller
{
public ActionResult RandomAction()
{
return ... //more code here
}
}
What should I return in "OtherOne/RandomAction" in order to obtain the same result of "Main/Index" action?
It's as simple as this:
public class OtherOneController : Controller
{
public ActionResult RandomAction()
{
return RedirectToAction("Index", "Main");
}
}
Your Controller class names must be MainController and OtherOneController. If you want to change that, check this post:
change controller name convention in ASP.NET MVC
Here is your Main Controller:
public class MainController : Controller
{
public ActionResult Index()
{
return View();
}
}

Role based controller access

I'm to new asp.net and asp.net MVC. I'm trying to show a user a page depending on the role his in.
public class HomeController : Controller
{
[Authorize(Roles = "Reviewer")]
public ActionResult Index()
{
ViewBag.Title = "Reviwer";
return View();
}
[Authorize(Roles="User")]
public ActionResult Index()
{
return View();
}
}
My code is the one above, it makes perfect sense that it won't compile like this i can't cave two idendical methods with the same name. But can someone please point me in the right direction. How am i supposed to show the user o different page based on his role.
If they must be two separate actions, then it makes more sense to name them according to role, like so:
public class HomeController : Controller
{
[Authorize(Roles = "Reviewer")]
public ActionResult Reviewer()
{
ViewBag.Title = "Reviewer";
return View();
}
[Authorize(Roles="User")]
public ActionResult User()
{
return View();
}
}
If you can have them as one, you could do:
public class HomeController : Controller
{
[Authorize(Roles = "Reviewer", "User")]
public ActionResult Index()
{
if (User.IsInRole("Reviewer"))
{
return View("Reviewer");
}
else
{
return View("User");
}
}
}
Are there different views for each role or is it just that you want to have a different title depending on their role?
What you could do is combine the roles into a single Controller method and then inside the method have conditional logic, as a naive example:
public class HomeController : Controller
{
[Authorize(Roles = "Reviewer, User")]
public ActionResult Index()
{
if (Roles.IsUserInRole("Reviewer"))
{
ViewBag.Title = "Reviwer";
}
return View();
}
}
If all you were doing was changing the title. If you wanted to display a different view or redirect them somewhere else you could do:
[Authorize(Roles = "Reviewer, User")]
public ActionResult Index()
{
if (Roles.IsUserInRole("Reviewer"))
{
return View("ReviewerView");
}
else if (Roles.IsUserInRole("User"))
{
//Or do a RedirectToAction("SomeAction")
return View("UserView");
}
}
Do a test in the action whether the user is in a role and return a different view or redirect to a different action.
You could try something like:
public class HomeController : Controller
{
[Authorize(Roles = "Reviewer,User")]
public ActionResult Index()
{
if (User.IsInRole("Reviewer")){
ViewBag.Title = "Reviwer";
return View("IndexReviwer");
}
return View();
}
}
Need to create a View called IndexReviwer

Categories

Resources