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
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();
}
}
Noob needs help!) How can I return an existing view from a new action within the same controller?
For example I have a following code:
[HttpGet]
public ActionResult Index()
{
return View(); //returns Index.cshtml
}
[HttpPost]
public ActionResult Index(string id, string condition)
{
SomeModel.ID = id;
SomeModel.Condition = condition;
return View(SomeModel); //returns Index.cshtml delegating the model
}
public ActionResult someAction()
{
return View(); //How to make this action return Index.cshtml??
}
You can specify the view name to return:
public ActionResult someAction()
{
return View("Index");
}
public ActionResult someAction()
{
return View("Index"); //How to make this action return Index.cshtml??
}
Just add
return View("YourView");
If you want send a model to it you can do this
var model = new YourViewModel
{
}
return View("YourView", model);
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();
}
}
Not sure if I am following MVC conventions but I have some variables passed from one Controller A to Controller B. My objective is to have another view named 'Publish' with an ActionLink to do some processing upon clicking on it.
The redirection from Controller A:
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Publish", new { accTok = facebookAccessTok, fullImgPath = fullpath });
return Json(new { Url = redirectUrl });
I now have the values for 'accTok' and 'fullImgPath' in my 'Publish' Index for Controller B which contains an ActionLink in its View to do the processing, but I am not sure how do I pass them to my 'Publish' ViewResult' method to do it:
namespace SF.Controllers
{
public class PublishController : Controller
{
public ViewResult Index(string accTok, string fullImgPath)
{
return View();
}
// This ViewResult requires the values 'accTok' and 'fullImgPath'
public ViewResult Publish()
{
// I need the values 'accTok' and 'fullImgPath'
SomeProcessing();
return View();
}
public SomeProcessing(string accessToken, string fullImagePath)
{
//Implementation
}
}
}
Index View:
#{
ViewBag.Title = "Index";
}
<h2>Publish</h2>
<br/><br/>
#Html.ActionLink("Save Image", "Publish")
I would suggest doing this
public ViewResult Publish(string accTok, string fullImgPath)
{
SomeProcessing(accTok,fullImgPath);
return View();
}
In your controller:
public ViewResult Index(string accTok, string fullImgPath)
{
ViewModel.Acctok = accTok;
ViewModel.FullImgPath = fullImgPath;
return View();
}
public ViewResult Publish(string accTok, string fullImgPath)
{
SomeProcessing(accTok,fullImgPath);
return View();
}
In the view:
#Html.ActionLink("Save Image", "Publish","Publish",new {accTok=ViewModel.Acctok, fullImgPath=ViewModel.FullImgPath},null )
Instead of the ActionLink you could also make it a form with hidden input fields (if this method changes thing in a database/on disk, it actually should be in a post).
But anyway use a viewmodel to pass the parameters from the index action to the view, so that in turn can send them to the publish action. This is generally the way to do it with the stateless web in MVC.
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.