Stoping users from accessing an ActionResult but allow it to be acessed via Html.Action/RenderPartial code and AJAX calls - ajax

I have some ActionResults that I don't want an user to be able to directly access but I need to be able to call them from views using #Html.Action, #Html.RenderPartial, and AJAX. I was using the ChildActionOnly but if I use that I can't access the page via AJAX. If I remove the ChildActionOnly attribute I can call it by AJAX but I can also call it directly by URL which is what I don't want happening. Is this possible to do of do I have to leave the ActionResult opened?

You can have the public action with a parameter to indicate whether or not the method should be executed like
public ActionResult DoSomething(bool shouldBeExecuted=false)
{
if (shouldBeExecuted == false)
{
throw new UnauthorizedAccessException("The action is not available");
}
ViewBag.Title = "Test Page";
return View();
}
And when you create a link for the action, just pass the "true" as a query string value.

Related

MVC3: PRG Pattern with Search Filters on Action Method

I have a controller with an Index method that has several optional parameters for filtering results that are returned to the view.
public ActionResult Index(string searchString, string location, string status) {
...
product = repository.GetProducts(string searchString, string location, string status);
return View(product);
}
I would like to implement the PRG Pattern like below but I'm not sure how to go about it.
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
return RedirectToAction(); // Not sure how to handle the redirect
}
return View(model);
}
My understanding is that you should not use this pattern if:
You do not need to use this pattern unless you have actually stored some data (I'm not)
You would not use this pattern to avoid the "Are you sure you want to resubmit" message from IE when refreshing the page (guilty)
Should I be trying to use this pattern? If so, how would I go about this?
Thanks!
PRG Stands for Post-Redirect-Get. that means when you post some data to the server back, you should redirect to a GET Action.
Why do we need to do this ?
Imagine you have Form where you enter the customer registration information and clicking on submit where it posts to an HttpPost action method. You are reading the data from the Form and Saving it to a database and you are not doing the redirect. Instead you are staying on the same page. Now if you refresh your browser ( just press F5 button) The browser will again do a similar form posting and your HttpPost Action method will again do the same thing. ie; It will save the same form data again. This is a problem. To avoid this problem, We use PRG pattern.
In PRG, You click on submit and The HttpPost Action method will save your data (or whatever it has to do) and Then do a Redirect to a Get Request. So the browser will send a Get Request to that Action
RedirectToAction method returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action.
[HttpPost]
public ActionResult SaveCustemer(string name,string age)
{
//Save the customer here
return RedirectToAction("CustomerList");
}
The above code will save data and the redirect to the Customer List action method. So your browser url will be now http://yourdomain/yourcontroller/CustomerList. Now if you refresh the browser. IT will not save the duplicate data. it will simply load the CustomerList page.
In your search Action method, You dont need to do a Redirect to a Get Action. You have the search results in the products variable. Just Pass that to the required view to show the results. You dont need to worry about duplicate form posting . So you are good with that.
[HttpPost]
public ActionResult Index(ViewModel model) {
if (ModelState.IsValid) {
var products = repository.GetProducts(model);
return View(products)
}
return View(model);
}
A redirect is just an ActionResult that is another action. So if you had an action called SearchResults you would simply say
return RedirectToAction("SearchResults");
If the action is in another controller...
return RedirectToAction("SearchResults", "ControllerName");
With parameter...
return RedirectToAction("SearchResults", "ControllerName", new { parameterName = model.PropertyName });
Update
It occurred to me that you might also want the option to send a complex object to the next action, in which case you have limited options, TempData is the preferred method
Using your method
[HttpPost]
public ActionResult Index(ViewModel model) {
...
if (ModelState.IsValid) {
product = repository.GetProducts(model);
TempData["Product"] = product;
return RedirectToAction("NextAction");
}
return View(model);
}
public ActionResult NextAction() {
var model = new Product();
if(TempData["Product"] != null)
model = (Product)TempData["Product"];
Return View(model);
}

MVC3 Why do I get "Child actions are not allowed to perform redirect actions" error?

I got an action List
//[HttpGet] (will come back to that!)
public ViewResult List(int page = 1)
{
//blah blah blah
return View(viewModel);
}
In its view we render action:
#{
Html.RenderAction("UpdateSearch");
}
Action definitions:
[ChildActionOnly]
[HttpGet]
public PartialViewResult UpdateSearch()
{
// do something and display a form in view
return PartialView(so);
}
[HttpPost]
public RedirectToRouteResult UpdateSearch(Options searchOptions)
{
// do something and redirect to List
return RedirectToAction("List");
}
and I'm getting: Child actions are not allowed to perform redirect actions exception every time someone submits the form. I'm new to MVC3, but it looks like the redirection is also a POST, because if [HttpGet] above List method is uncommented "the resource cannot be found" happens.
How do I change Http method on redirection or am I doing something wrong? I did try to Bing it, but no success.
The redirect info is stored in response header. However, the response is already being sent when child action is run so headers can't be written.
In short, there's no way of performing a redirect from child action other than through the use of javascript on client side.

Using ViewData to pass string from Controller to View in ASP.NET MVC3

I am trying to pass a random string from my Controller to the View.
Here is my Controller code:
[HttpPost]
public ActionResult DisplayForm(UserView user)
{
//some data processing over here
ViewData["choice"] = "Apple";
return RedirectToAction("Next", "Account");
}
Now I want to pass that data value "Apple" to my view Next.cshtml which is created as follows:
//View: Next.cshtml
#{
ViewBag.Title = "Thanks for registering";
Layout = "~/Content/orangeflower/_layout.cshtml";
}
<p>Your favorite fruit is:</p>#ViewData["choice"]
But I am not able to see my data in the browser when the project runs.
Here is the snapshot:
1) On debug, the controller showing the value:
2) The browser view doesn't show the value "Apple"
3) On further debug to my Next.cshtml View:
Why is the value not getting passed to the View correctly. Both my controllers for Next and DisplayForm are within the same Controller AccountController.cs , still value not getting displayed.
Can someone help me solve this ?
You are not rendering a view, you are redirecting. If you wanted to pass some information tyo the view you need to return this view after adding it to ViewData:
[HttpPost]
public ActionResult DisplayForm(UserView user)
{
//some data processing over here
ViewData["choice"] = "Apple";
return View();
}
If you want to pass a message that will survive after a redirect you could use TempData instead of ViewData.
[HttpPost]
public ActionResult DisplayForm(UserView user)
{
//some data processing over here
TempData["choice"] = "Apple";
return RedirectToAction("Next", "Account");
}
then inside the Next action you could fetch the data from TempData and store it inside ViewData so that the view can read it.
You are performing a post - redirect - get. The ViewData is being set for this request, which returns a redirect, clearing the ViewData, then another request happens which does not have the data. Use TempData instead and it will be added to the ViewData automatically on the next request.

Submit button which RedirectToAction to previusly page.

I have one method which I use in some place. Now I make RedirectToActio.... and back me to the concrete page. Is possible to make, it back to previusly page?
You could use the Referer HTTP header but it's not very reliable. A better way is to pass the url you want to redirect to the controller action (it's the way the POST LogOn method on the AccountController is implemented when you create a new ASP.NET MVC 3 application using the built in wizard. Take a look at it):
public ActionResult Foo(string returnUrl)
{
...
return Redirect(returnUrl);
}
Then when you call this action you pass the url of the current page. For example you could generate the following anchor:
#Html.ActionLink(
"do some processing and redirect back here",
"foo",
new { returnurl = Request.Url.AbsoluteUri }
)

Persisting Data from one controller to another

Hey guys,
What is the best mechansims for persisting viewmodel data from one controller to another.
For instance
return RedirectToAction("SomeAction", "SomeController");
I need to have some data from the previous controller available to the new controller I am redirecting to.
If you are not passing an object or something complex, make use of parameters. Just make sure redirected action gets parameters to display what it should.
return RedirectToAction("SomeAction", "SomeController",new { id=someString} );
Get the parameter in the action:
public ActionResult SomeAction(string id)
{
//do something with it
}
#Ufuk Hacıoğulları: You can't share information between 2 controllers using ViewData. ViewData only shares information between Controller and View.
If you need to share complex information between multiple Controllers while redirection, use "TempData" instead.
Here is how you use "TempData" - http://msdn.microsoft.com/en-us/library/dd394711.aspx
A redirect is going to send an http response to the client that directs it to then make a new http request to /SomeController/SomeAction. An alternative would be for you to call a method on your other controller directly... new SomeController().SomeAction(someData) for example.
I think this will be helpfull to you to pass value from one action to another action .
public ActionResult ActionName(string ToUserId)
{
ViewBag.ToUserId = ToUserId;
return View();
}
public ActionResult ssss(string ToUserId)
{
return RedirectToAction("ActionName", "ControllerName", new { id = #ToUserId });
}

Resources