asp.net mvc newbie question - asp.net-mvc

I recently started to look into asp.net mvc. Here is my issue.
Say every page on an application needs a variable set by the user, e.g. a date. If the user starts from url I provide, it is all good as I ask for that date and save it for the session. How can I redirect the user to the first page if they save the some other url (to a different controller and action).
In other words, I guess I am looking for something like [Authorize] attribute but on an application level.
Thanks for any help.

I would probably create a base controller that all of my controllers derive from. In the base controller I'd override the OnActionExecuting method to check the session for the required variable. If the variable isn't present, I would set the ActionExecutingContext Result property to a RedirectToRouteResult to the appropriate controller/action to set the variable.
Another alternative is to create a custom FilterAttribute that you decorate the appropriate controllers/actions with that does basically the same thing. I would only do this if the filter was to apply only to certain controllers or actions and not all as you describe in your question.

Related

Sending a parameter to the controller in ASP MVC 2

I am writing an area for administering several subsites, almost all of the functionality will be the same across each site (add/edit/remove pages etc) and my repository on instantiation takes the SiteIdentity so all the data access methods are agnostic in relation to this. The problem I have at the moment is trying to make my action methods also agnostic.
The URL pattern I want to use is along the lines of:
"ExternalSite/{identity}/{controller}/{action}/{id}"
A naive approach is to have each action take the identity parameter, but this means having to pass this in to my repository on each action as well as include it in the ViewData for a couple of UI elements. I'd much rather have this something that happens once in the controller, such as in its constructor.
What is the best way to do this? Currently the best I can come up with is trying to find and cast identity from the RouteData dictionary but part of me feels like there should be a more elegant solution.
It sounds like you want to use OnActionExecuting or a Custom ModelBinder to do that logic each time you have a specific parameter name (also known as a RouteData dictionary key).
Creating a custom modelbinder in ASP.NET MVC
Creating an OnActionExecuting method in ASP.NET MVC, Doing Serverside tracking in ASP.NET MVC
You have access to your route values in Request.RequestContext.RouteData, so you can make base controller and public property SiteIdentity, in such case you can access it from all actions in all inherited controllers.

ActionFilter or RenderAction in ASP.NET MVC?

I'm working on an ASP.NET MVC controller with several action methods, all of which need the same bit of data. This data requires a lookup that can only be done with the route values (so, I can't do the lookup in the constructor). I'm sure this has been discussed at length, but I've yet to find a satisfactory recommendation.
What's the best way to get this data without repeating myself in each action method? I'm working through:
Create an Action Filter, this seems like the best bet, but where do I store the object, in the action parameters? Is it appropriate to create a ViewModel object in an action filter and pass it directly to the action methods, for them to fill out the rest of the ViewModel object?
Create a child action (Html.RenderAction) to render this data, but this requires a second set of lookups since the child action requires another full cycle of instantiating the controller.
Helper method/property called in each action method.
Thought or opinions on a best approach here?
A filter is probably your best bet and you can store the object in ViewData.
Another option (not a better one) is to create your own controller base class that overrides the ExecuteCore method and does the lookup there.
I did this for logging since I want to log each page view and I didn't want to have to add a filter to each and every controller I made. In mvc 3 there will be a way to declare global filters which can fix this as well.
Ok, so given what you've told me, I would suggest using a custom ModelBinder.
It's the best fit for the situation. I would argue that using a filter is the wrong approach because a filter's job isn't to bind data - that's a job for a ModelBinder.
HTHs,
Charles
EDIT: I've just been thinking about it and I'm a little bit torn if you should use a model binder or not.
The general rule of thumb I just came up with is that if you need the ProjectDetails inside the action itself, use a ModelBinder but if you don't need the ProjectDetails inside the action, use an ActionFilter to just add it to your model / viewdata.
Maybe someone else could throw their 2c in.
You could override the OnActionExecuting() method in your controller and get the data there.

ASP.NET MVC - Extending the Authorize Attribute

Currently I use [Authorize(Roles = ".....")] to secure my controller actions on my ASP.NET MVC 1 app, and this works fine. However, certain search views need to have buttons that route to these actions that need to be enabled/disabled based on the record selected on the search list, and also the security privs of the user logged in.
Therefore I think I need to have a class accessing a DB table which cross-references these target controller/actions with application roles to determine the state of these buttons. This will, obviously, make things messy as privs will need to be maintained in 2 places - in that class/DB table and also on the controller actions (plus, if I want to change the access to the action I will have to change the code and compile rather than just change a DB table entry).
Ideally I would like to extend the [Authorize] functionality so that instead of having to specify the roles in the [Authorize] code, it will query the security class based on the user, controller and action and that will then return a boolean allowing or denying access. Are there any good articles on this - I can't imagine it's an unusual thing to want to do, but I seem to be struggling to find anything on how to do it (could be Monday-morning brain). I've started some code doing this, looking at article http://schotime.net/blog/index.php/2009/02/17/custom-authorization-with-aspnet-mvc/ , and it seems to be starting off ok but I can't find the "correct" way to get the calling controller and action values from the httpContext - I could possibly fudge a bit of code to extract them from the request url, but that doesn't seem right to me and I'd rather do it properly.
Cheers
MH
I found this on another forum and so will post it here in case anyone finds it useful. Note that how you do this changes depending on whether you are using MVC 1 or 2
the class you create needs to implement
public void OnAuthorization(AuthorizationContext filterContext)
and then you can use
string controllerName = filterContext.RouteData.Values["controller"].ToString();
and the same, substituting "action" for "controller" (make sure you check for nulls in these values first). In MVC 2 this can be changed to filterContext.ActionDescriptor.ActionName and .ActionDescriptor.ControllerDescriptor.ControllerName and you won't have to check for nulls

in ASP.Net MVC, what is the most elegant way to access objects stored in the session?

In my asp.net mvc project I store two objects in the session when the user logs in. One is a User object (representing the logged in user) and the other is the Organisation object (representing the user's organisation).
I need one or both of these objects to be available in every action method. What's the most elegant way of dealing with this? At the moment each action takes parameters for each of these objects, with a custom model binder retrieving the objects from session. This at least encapsulates the session access but it's annoying to have the params in every method signature. Is there a better way?
Here's what most of the action methods look like.
public ActionResult Pending(IUser CurrentUser)
{
var users = CurrentUser.GetMyOrgPendingUsers();
return View(users);
}
Since you need to access IUser in almost every action you can have a base controller from where every other controller is derived.
In the base controller put IUser as a member variable and override the
OnActionExecuting() method in the base controller, in which you can put the code to access the session variables.
OnActionExecuting() will be called every time a action is called.
The Controller class has a User property. Have you considered using this rather than designing your own way to track the current user?
I'd rethink using IPrincipal here--it is very handy and allows you to work your way into the rest of the .NET authentication bits very seamlessly.
As for the problem at hand, perhaps the easiest clean course of action would be to wire them into a base controller class as protected properties. Slightly more elegant would be to create a user context class, that takes a reference to Session (or better yet, whatever base interfaces you are using in the session) and expose that class from the controller. The main advantage there is it makes it easier to change the backing store if need be and lets one encapsulate more behavior in general.

Is it possible to override an attribute which has been applied at controller level on a specific method?

If I've applied an authorisation attribute at controller level, is it possible to override this on one of the methods on that controller?
Thanks
James
That depends upon what kind of "override" you want. You cannot remove the attribute which is on the class, but you can add the attribute to the method again in order to make things more restrictive.
Update in response to comments. First, making your own AuthorizeAttribute is somewhat dangerous. AuthorizeAttribute contains code which interacts with the caching attributes in order to ensure that the cache cannot serve protected content to a non-authorized user. At a minimum, you should subtype the existing AuthorizeAttribute rather than creating something wholly new. Generally, however, it's a better idea to use the existing AuthorizeAttribute and specialize your authorization by creating a new/finding an existing ASP.NET membership provider.
I don't think it would be good design to have a filter on an action which "overrides" a filter on a controller. However, you could change the design of the filter on the controller to not require authorization on an action of a certain name. You could, for example, override the AuthorizeAttribute.AuthorizeCore method to test for an action name in the same way the existing method tests for the user name and the roles. Take very careful note of the comments in this method regarding thread safety.
I'm not sure if this is exactly the same question, but it may help...
How to make ActionFilter on action method take precedence over same ActionFilter on controller

Resources