ASP.NET MVC controller action restricted to a specific view - asp.net-mvc

Is there a way to restrict a controller action to be accessible only from a specific view? I have a Details page for a queried entity in my database and basically by a button and a simple JS confirmation prompt I would like to change few properties of this object and save it back to the database. I've developed a controller action method which does the job but I have no idea how to restrict access to it, so users cannot (un)intentionally modify entities by passing a specific url in the browser. I would like the action to be only accessible on this specific Details page, by pressing the designated button.
I tried using [ChildActionOnly] but it's only accessible from another action method, and not a view.
Thank you for your help.

Thanks to Stephen Muecke's comment I've managed to get it working.
The button is a simple Action Link, which redirects to the restricted controller action:
public ActionResult ReturnBook(int id)
{
if (Request.UrlReferrer == null)
{
return HttpNotFound();
}
//code
}
The method checks, if there is any UrlReferrer at all. Typing action url in the browser results in the referrer being null.
If the call is made by ActionLink from a View, the UrlReferrer is not null and optionally its property Request.UrlReferrer.AbsolutePath can be checked and compared to a desired url, from which the invoke can only be made. In my case, as I am not invoking this method anywhere else in my code, I stayed with just null/notnull condition.

Related

How can I get rendered View for any Action inside different Contoller or Action?

I have some action's views that are dependant on settings from DB (for example display textbox or not). Settings are changed in admin controller.
What I'd like to achieve is to have the preview of the changed views in admin's sidebox (right side of the screen) after the changes will be saved to DB.
Is there a way to get View result of another action (casually returns View()) with button (Save and Preview) click in form of string (HTML) to display in the sidebox?
Or maybe has anyone other and better idea?
Yes. They're called child actions. Simply, you just call the action you want rendered via Html.Action:
#Html.Action("SomeAction", "SomeController")
However, there's a couple of things to keep in mind. First, your child action should return PartialView. Otherwise, you'll get the full layout rendered again where you call the action. If you want to use the same action for both a regular view and as a child action. You can branch your return:
if (ControllerContext.IsChildAction)
{
return PartialView();
}
return View();
Second, if you only return PartialView, then the action should not be available to directly route to. Otherwise, someone could enter a URL in their browser to go to this child action and only the partial view would be returned, devoid of layout. You can prevent this from occurring using the ChildActionOnly attribute:
[ChildActionOnly]
public ActionResult MyAwesomeChildAction()
{
...
}
Then, this action will only be available to be called via Html.Action.

Determining the previous page in mvc 3

How to check the previous page in mvc 3 application.
Previous Page.
On click of the above link I have to go back to previous page.
How to do this ?
This will depend on how is the navigation organized on your website. One possibility is to use the history.go(-1) javascript function which will simply simulate the browser back button:
Previous Page.
Another possibility is to have the calling page pass a ReturnUrl query string parameter to this page which could be used to construct the link:
Previous Page.
Of course this assumes that when you called the controller action that rendered this view you have passed the ReturnUrl query string parameter.
Same as Matthew's answer but using a session variable. That way you could update it selectively in the Action you want. For example, on a POST action you wouldn't want them to go back to that view with form values there. What you really want is for them to go back to the page before that.
public ActionResult MyNextPage(string prevUrl)
{
Session["prevUrl "] = prevUrl;
View();
}
Then in the View:
Previous Page
Note that if session is expired or null it will throw an exception.

How to have POST ActionHandler return the GET ActionHandler by a custom Attribute?

Our system is MVC2 authenticated by ADFS 2. So when a user clicks on a bookmark for http://www.foo.com/Car/Details/3, this hits our Car controller and calls our Details GET action handler and passes 3 in as the ID (all basic MVC stuff). So we have this ActionHandler decorated with a [Authorize] attribute and have ADFS2 hooked up, so the page then redirects to our auth server which then redirects back to our app, but with a POST (all basic ADFS stuff). The problem is that this redirect is a POST and therefore our Details POST handler is called, but clearly it doesn't have the data I need.
Now I have identified some code that detects this scenario and this code looks something like this:
[Authorize]
[MySpecialHttpGet]
public ActionResult Details(long id)
{
var model = GetModel(id);
return View(model);
}
[Authorize]
[MySpecialHttpPost]
public ActionResult Details(long id, ViewModel model)
{
/***START OF SPECIAL CODE***/
// If we were posted to by ADFS, redirect to the GET handler.
if (Request.Form["wa"] != null && Request.Form["wa"].ToLower().Contains("signin"))
{
// We were posted to here but need to respond with the GET view.
return Redirect(Request.Url.AbsoluteUri);
}
/***END OF SPECIAL CODE***/
var result = Something.SaveData(model);
return result.ActionResultToReturnWith;
}
The problem with this is that I need to do this on every single POST ActionHandler in the app and I really don't want to do that. Given that I already have custom attributes on all of these ActionHandlers, I would like to use those attributes to inject this functionality for me.
Now the MySpecialHttpGet and MySpecialHttpPost are nothing incredibly special that you really need to know about other than they extend ActionMethodSelectorAttribute. I would LIKE to add code in the MySpecialPost attribute to inject that functionality.
So my question:
How would I add code to perform this kind of check in this Attribute?
For now, we have not found the solution we wanted and are simply pasting that code (well, a function call with that code in it) at the beginning of EVERY controller.

ASP.NET MVC: What are Action Method? Action Result? How are they related?

I'm sorry to ask such a basic question, but it's kind of fundamental for me. To better understand filters, I need to understand this notions. Although I'm on ASP.NET MVC for few months now and now are doing nice demos, I'm more familiar with Action method concept than action result.
What are:
Action Method?
Action Result?
How are they related?
Let's say I've this
public ViewResult ShowPerson(int id)
{
var friend = db.Persons.Where(p => P.PersonID == id).First();
return View(friend);
}
How those concepts apply to the above code?
Thanks for helping.
In your example ShowPerson is the action. Each action needs to return an action result (In your case it returns a view). So when a controller action method is invoked it does some processing and decides what view would be best adapted to represent the model.
There are many different action results that you might use. They all derive from ActionResult:
ViewResult - if you want to return a View
FileResult - if you want to download a file
JsonResult - if you want to serialize some model into JSON
ContentResult - if you want to return plain text
RedirectResult - if you want to redirect to some other action
HttpUnauthorizedResult - if you want to indicate that the user is not authorized to access this action
FooBarResult - a custom action result that you wrote
Answer by #Darin-dimitrov is very much upto the point. But I see explanation given on MSDN also very much helpful.
Action methods typically have a one-to-one mapping with user
interactions. Examples of user interactions include entering a URL
into the browser, clicking a link, and submitting a form. Each of
these user interactions causes a request to be sent to the server. In
each case, the URL of the request includes information that the MVC
framework uses to invoke an action method.
When a user enters a URL into the browser, the MVC application uses
routing rules that are defined in the Global.asax file to parse the
URL and to determine the path of the controller. The controller then
determines the appropriate action method to handle the request. By
default, the URL of a request is treated as a sub-path that includes
the controller name followed by the action name. For example, if a
user enters the URL http://contoso.com/MyWebSite/Products/Categories,
the sub-path is /Products/Categories. The default routing rule treats
"Products" as the prefix name of the controller, which must end with
"Controller" (such as ProductsController). It treats "Categories" as
the name of the action. Therefore, the routing rule invokes the
Categories method of the Products controller in order to process the
request. If the URL ends with /Products/Detail/5, the default routing
rule treats "Detail" as the name of the action, and the Detail method
of the Products controller is invoked to process the request. By
default, the value "5" in the URL will be passed to the Detail method
as a parameter.

How to create different View depending on logged in user's role in ASP.NET MVC?

I am kind of new to ASP.NET MVC, so need your help getting me through a problem:
In my application the LogOn will be done using the Role of the user. I have my custom database schema (like User, Role, UserInRole etc.) and I am using my custom MembershipProvider and RoleProvider to achieve Logon.
BTW I am using the MVC default Account controller itself with some modification. What I am trying to achieve now is that depending upon the Role of logged in user I want to create a different View for the user.
Can I use the returnUrl parameter of LogOn action method in any way? (This parameter is set to null by default). If yes how can I construct and send returnUrl depending on Role?
Or is there any easier way to achieve this?
By default, in your controller methods which return an ActionResult, if you just return "View()" then the page that will be displayed is the page in your Views directory with the name of your controller method. However, you can specify the name of the View which will be returned, or pass on the call to another controller method to return the appropriate view.
As in the following contrived example:
public ActionResult Edit(string id)
{
// get the object we want to edit
IObjectDefinition definedObject = _objectManager.GetObjectById(id);
if (definedObject != null)
{
ViewData.Add("definition", definedObject );// add to view data collection so can display on page
IUser user = GetCurrentUser();// get from session/cookie/whatever
if (!user.IsAccountAdmin)
{
return View("Detail");// a readonly page as has no rights to edit
}
else
{
return View();// same object displayed in editable mode in another view
}
}
else
{
return New();// call to controller method below to allow user to create new record
}
}
public ActionResult New()
{
return View();
}
You decide what view to use (render) in the action - its not dictated directly by the URL
In the code you have access to the user object and from that can determine the roles that user is in - from that it should be straightforward enough to choose the view accordingly.
I think you can do a RedirectToAction on successful login and since you now have a valid login user, in the action method you can use IsInRole property of the of the LoggedIn User and render an appropriate partial view.

Resources