Right now, I have an action associated with just the POST from the Index page in my MVC app. But I want a generic handler action that handles all page posts and within the POST Handler action, I want to know the view that I just came from. What I want is below: Any ideas?
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GenericPostHandler(NewAccountInfo info)
{
try
{
string currentview = //how to get View for which to handle the POST?
Persist();
return RedirectToAction(StepManager.GetNextStep(currentView));
}
catch
{
return View();
}
}
I suppose you could write routes that will forward all requests to a single action in one particular controller but this will then be active for all HTTP commands, either GET or POST or otherwise.
What you are trying to achieve is very much against the spirit of MVC. Could you tell us probably what is the idea behind this requirement?
I will try to guess. You wish to perform some kind of preprocessing on each post, right? Maybe an authorization check, activity log etc. If so, you could implement your own ActionFilter and decorate with this attribute all of your controllers. Then all calls will be intercepted by this filter and you can do there whatever you need - then pass the request through to its normal handler (action) or route it elsewhere.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult GenericPostHandler(NewAccountInfo info, string fromViewName)
{
...
}
In Views:
<% var actionUrl = Url.RouteUrl(new {
controller = "yourcontroller",
action = "genericposthandler",
fromviewname = "whereyoucamefrom"
}); %>
<form action="<%= actionUrl %>" method="post">
...
</form>
produces url like /yourcontroller/genericposthandler?fromviewname=whereyoucamefrom
Related
I am working on a ASP.NET Core 2.0 project using Razor Pages (not MVC).
I have the following flow:
User fills out form and POSTs
This page's POST handler validates the info and returns Page() if there are issues. If not, handler saves data to database.
From here, I want the handler to POST to a different page's POST handler with the validated and saved data from Step 2.
How do I POST to another page from within a page handler? Is this the appropriate way to do this kind of thing? The reason I don't want to RedirectToPage() is because I don't want the final page in the sequence to be navigable via GET. The final page should not be accessible via a direct link but should only return on a POST.
I thought about validating/saving the data and setting a boolean "IsValid" and returning the page, checking for that IsValid, and immediately POSTing to the final page via JS. However this feels dirty.
Set the "asp-page" property of the form to your other page. Then set values in the standard way.
<form method="post" asp-page="/pathto/otherpage">
Select Example:<select name="DataForOtherPage">
Then in your controller, bind the value...
[BindProperty]
public string DataForOtherPage { get; set; }
You don't need to cross post!
If possible, you should avoid the cross-post. Do it all under the original action. The action can return a different view by specifying the view name in the View call.
If the target of the cross-post contains complicated logic that you don't want to duplicate, extract it to a common library, and call it from both actions.
For example, instead of
ActionResult Action1()
{
if (canHandleItMyself)
{
return View("View1");
}
else
{
return //Something that posts to action2
}
}
ActionResult Action2()
{
DoSomethingComplicated1();
DoSomethingComplicated2();
DoSomethingComplicated3();
DoSomethingComplicated4();
return View("View2");
}
Do something like this:
class CommonLibrary
{
static public void DoSomethingComplicated()
{
DoSomethingComplicated1();
DoSomethingComplicated2();
DoSomethingComplicated3();
DoSomethingComplicated4();
}
}
ActionResult Action1()
{
if (canHandleItMyself)
{
return View("View1");
}
else
{
CommonLibrary.DoSomethingComplicated();
return View("View2");
}
}
ActionResult Action2()
{
CommonLibrary.DoSomethingComplicated();
return View("View2");
}
If you really want to cross-post
If you insist on using a cross-post, you will have to render a page that does the post, e.g.
<HTML>
<BODY>
<IMG Src="/Images/Spinner.gif"> <!-- so the user doesn't just see a blank page -->
<FORM name="MyForm" Action="Action2" Method="Post">
<INPUT type="hidden" Name="Argument1" Value="Foo">
<INPUT type="hidden" Name="Argument2" Value="Bar">
</FORM>
<SCRIPT type="text/javascript>
document.getElementById("MyForm").submit(); //Automatically submit
</SCRIPT>
</BODY>
</HTML>
I'm new to ASP.Net and am trying to make a web application using MVC2.
On one particular page I need to have multiple submit buttons - after reading up from this post I found this method which worked well in my project.
So I have a few submit buttons handled in my controller like this:
[HttpPost]
[MultiButton(Key = "action", Value = "Button1")]
public ActionResult Action1(MyViewModel myViewModel)
{ //do stuff
return View(newViewModel)
}
[HttpPost]
[MultiButton(Key = "action", Value = "Button2")]
public ActionResult Action2(MyViewModel myViewModel)
My problem is that now I want to also postback my form on various client events. I tried to do this in the view by using javascript in there somewhere.
<% using (Html.BeginForm("Index", "MyController")){ %>
document.forms["form1"].submit();
With a 'normal' action on the controller:
[HttpPost]
public ActionResult Index(MyViewModel myViewModel)
{
}
But when I add this, now the multiple submit buttons do not work properly due to an ambiguous match exception between Action1 and Index. I realise that they have the same signature but as a beginner, I'm a bit stuck at this point!
What can I do to get all the different submit options working together? Please advise and/or point out where I'm going wrong. Thanks
Let's say, there is an area "Products" and two controller "Home" and "Suite" (there are more controllers that will behave in this scenario like "Suite").
I configured the "ProductAreaRegistration.cs" so that the URLs will look like this:
\Products\
(with controller = "Home", action = "Index")
\Products\Suite
(with controller = "Suite", action = "Index")
\Products\Suite\TechnicalSpecification
(with controller = "Suite", action = "TechnicalSpecification")
The action "TechnicalSpecification" appears in every controller of that area but the "Home" controller is the one, wo actually does the main work. The other controllers like "Suite" just do some controller related stuff and then redirect to "Home", "TechnicalSpecification":
// Suite-Controller
public ActionResult TechnicalSpecification()
{
//doSomethingThatOnlyThisControllerHasToDo();
return RedirectToAction("TechnicalSpecification", "Home", new { specificationId = 45 });
}
// Home-Controller
public ActionResult TechnicalSpecification(int specificationId)
{
Object model = getModelByIdWithSomeMethod(specificationId);
//DoEvenMoreThingsHere();
return View(model);
}
My problem is, when I look at the link of "Suite", "TechnicalSpecification" it shows
\Products\Suite\TechnicalSpecification
but after clicking that link the URL in the address bar changes to
\Products\TechnicalSpecification?specificationId=45
because of the redirection. I would like the URL to stay like mentioned before.
So instead of "return RedirectToAction(...)" is there something like "return ViewResultFromOtherController(...)", so that it is not redirecting?
Hope you got the idea.
If not, please ask!
Thanks in advance!
There is probably a better way than this to do it, but you could try instantiating the other controller in your Action, calling the method, and returning its results. That would leave you with the same URL you posted to, but give you the result of the other method.
Something like:
Controller home = new HomeController();
return home.TechnicalSpecification(specificationId);
This does beg for refactoring, though.
I would like to do this because I need to post to a foreign site, and would like to avoid setting a hidden input inside the form because the user might change the value inside of it (or somebody else might do it for him)
my html:
<form action="<%=Url.Action("prepare") %>" >
<input type="submit" value="submit" />
</form>
and my Action
[HttpPost]
public ActionResult Prepare()
{
if(Request.IsAuthenticated)
{
//post to "http://example.com/do"
//and add to the request userId = User.Identity.Name
return //the result of the repost
}
else
{
return RedirectToAction("youneedtobeloggedin",);
}
}
If you want to keep everything server side, you can take a look at here. It's a simple way to perform POSTs programmatically. In this way you'll handle external POSTs all server side. Please beware that this will make your server perform the POST.
In your controller you can have this Action:
[HttpGet]
public string MyActionPostingToRemote()
{
string postResult = HttpPost (remoteUrl, remotePostQueryString);
return postResult;
}
The HttpPost is the function you can find in my link.
Cross-site calls are not allowed by modern browsers. Because of security.
I'm using the jQuery NotifyBar quite nicely in an Index view to display business rule errors when a user e.g. clicks a delete link for an item than cannot be deleted. However, if the user adds a new item, they are redirected to the Create view. If the new item is successfully created, the Create action redirects back to the Index view.
My quandary is that I need (have been told) to show a success notification in the above scenario. Previously, to request a notification while remaining on the same view, I was using return JavaScript() for an action result, but when I use return RedirectAction() for the action result, I'm left with nowhere to put the return JavaScript().
The way I see this is that I need to:
a) include information in the return RedirectAction() that tells the 'destination' view to show the notification, or
b) invoke the notification in the 'source' view, instead of the return RedirectAction(), and tell it that when it closes/is closed, to perform the redirect to the 'destination' view.
I have no idea where to begin deciding between these two opetions, nor how to even begin researching how to implement either. All advicem and pointers to advice will be most appreciated.
I like option A the best. You could easily include a querystring value with the return url and have a javascript function waiting on the return page that looks for the querystring value... if present, show notification bar.
Submit action on controller:
public ActionResult Submit(ValueModel valueModel) {
//TODO: Save model to repository
//include something in the route values to act as a querystring flag.
//here, I use "success".
return RedirectToAction("Action", "Controller", new { success = 1 });
}
View action on controller:
public ViewResult Index() {
//TODO: do stuff
return View();
}
Index.aspx:
...
<div class='notificationBar'></div>
<script type="text/javascript">
$(document).ready(function() {
if(window.location.search.substring(1).indexOf("success")) {
//set notification bar here
}
});
</script>
...