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) { ... }
}
Related
I have following code in my controller actions. I have more than 15 controllers and more than 40 actions through out the application. Example:
//Check if USER SESSION object is available
if (Session["user"] != null)
{
return View();
}
else
{
return RedirectToAction("logout", "Home", new { area = "Common", value = "SessionTimeOut" });
}
I don't want to repeat the if statement for all 40 actions. Any better way of doing this?
You'll want to look at AuthenticationFilters (see here for an MVC walkthrough).
FTA:
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext) {
//For demo purpose only. In real life your custom principal might be retrieved via different source. i.e context/request etc.
filterContext.Principal = new MyCustomPrincipal(filterContext.HttpContext.User.Identity, new []{"Admin"}, "Red");
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) {
var color = ((MyCustomPrincipal) filterContext.HttpContext.User).HairColor;
var user = filterContext.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
FTA usage:
public class HomeController : Controller
{
//***here is where it's applied. you can also do this globally in Global.asax if preferred***
[CustomAuthentication]
public ActionResult Index()
{
return View();
}
}
To supplement the answer pointing to the [CustomAuthentication] attribute, you could create a base controller class, like this:
[CustomAuthentication]
public class BaseController : Controller
{
}
Which your 15 controllers can inherit from:
public HomeController : BaseController
Now, by default, every action method on the derived controllers will execute the [Authorize] attribute, so for the action methods which do not require authorization, you can mark them with the [AllowAnonymous] attribute:
public class HomeController : BaseController
{
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
}
It seems simple like in ASP.NET MVC but I can't figure out how to map an URI with a string parameter to an action on my controller. So I have three actions in my controller as below:
//GET: api/Societe
public IEnumerable<Societe> GetSociete()
{
List<Societe> listeSociete = Librairie.Societes.getAllSociete();
return listeSociete.ToList();
}
//GET: api/Societe/id
[ResponseType(typeof(Societe))]
public IHttpActionResult GetSociete(int id)
{
Societe societeRecherchee = Librairie.Societes.getSociete(id);
if (societeRecherchee == null)
{
return NotFound();
}
else
{
return Ok(societeRecherchee);
}
}
public IHttpActionResult GetSocieteByLibelle(string name)
{
Societe societeRecherchee = new Societe();
if (!string.IsNullOrWhiteSpace(name))
{
societeRecherchee = Librairie.Societes.getSocieteByLibelle(name);
if (societeRecherchee == null)
{
return NotFound();
}
}
return Ok(societeRecherchee);
}
So I would like to map an URI with the action:
GetSocieteByLibelle(string name)
My route configuration is the default one for Wep API project. May someone explain me how to map an URI to that action ? Thanks in advance !
Looks like the two routes are resulting in the same method call being invoked. Try putting a [Route] attribute on one of them as follows:
[Route("api/Societe/libelle/{name}")]
public IHttpActionResult GetSocieteByLibelle(string name)
{
}
Note that the default /api/Societe/{id} should still hit your first Action.
There is only one control Home with a bunch of action. It also has a private method bool IsFinish (), which returns the state of the system. At a certain stage (namely when IsFinish start returning true) is necessary, what any callable method redirected to public ActionResult Result (). In principle, I do not care where this will Result - in the current controller or the other. Overview all actions forward to it.
How can this be implemented?
You could use an action filter of asp.net mvc to do it. An action filter is an attribute that you can apply to a controller action -- or an entire controller -- that modifies the way in which the action is executed, for sample:
public class RedirectFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// get the home controller in a safe cast
var homeController = filterContext.Controller as Controller;
// check if it is home controller and not Result action
if (homeController != null && filterContext.ActionDescriptor.ActionName != "Result")
{
if (homeController.IsFinish())
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "controller", "Home" },
{ "action", "Result" }
});
}
}
base.OnActionExecuting(filterContext);
}
}
And apply it on your controller:
[RedirectFilter] // apply to all actions
public class HomeController : Controller
{
public ActionResult Home()
{
/* your action's code */
}
public ActionResult Home()
{
/* your action's code */
}
public ActionResult Home()
{
/* your action's code */
}
public ActionResult Result()
{
return View();
}
}
I have MVC4 applicaton, which contains http-handler, and I want to redirect user to my first page
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
HttpHandler
public class MyPublicHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (condition)
{
var controller = new HomeController();
controller.Index(); // redirect and execute
}
// or something like that
if (condition)
{
ExecutePage("http://myWebSite/Home/Index")
}
}
}
Thanks!
I'm trying to read the a parameter that I've defined in a route from inside the controller.
The route:
routes.MapRoute(
"BusinessVoice", // Route name
"business/{controller}/{action}/{id}", // URL with parameters
new { controller = "Voice", action = "Index",
id = UrlParameter.Optional, locale = "business" } // Parameter defaults
);
From inside the controller I'd like to be able to read the route parameter locale, but have not idea where to look for it.
The controller:
namespace www.WebUI.Controllers
{
public class VoiceController : Controller
{
public VoiceController()
{
... want to read the locale param here
}
public ViewResult Index(string locale)
{
return View();
}
}
}
Any help is appreciated!
Dave,
This is from my basecontroller but you should be able to do exactly the same from a top level one too:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
var locale = requestContext.RouteData.Values["locale"].ToString() ?? System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
base.Initialize(requestContext);
}
good luck
jim
public VoiceController()
{
var locale = this.RouteData.Values["locale"];
}