Calling post method from another controller's view - c#

Problem: Hi there, so in a view where a product is displayed I have a button to call post method to add this product in the cart but the button does not do it at all.
<div class="mb-3">
<input class="btn btn-primary" type="submit" value="Add to cart" asp-controller="Cart" asp-action="Add" asp-route-id="#Model.Id"/>
</div>
And this is the method in the cart's controller
[HttpPost]
public async Task<IActionResult> Add(int productId)
{
//Console.WriteLine("HelloCartAdd!");
//Some logic.
return RedirectToAction("Detail", "Product", productId);
}

When the route parameter is defined as asp-route-id="#Model.Id" the action method should use 'id' parameter name:
[HttpPost]
public async Task<IActionResult> Add(int id)
{
...
}
If the [HttpPost] attribute is applied to the action method add the formmethod="post" attribute to the <input> tag. I suppose the button is already located inside the form.
<form>
<input class="btn btn-primary" type="submit" formmethod="post" value="Add to cart" asp-controller="Cart" asp-action="Add" asp-route-id="#Model.Id" />
</form>

Related

.NET how to disable FluentValidation with formHelper on certain submit button

I'm using FluentValidation with FormHelper in order to validate my form using ajax.
My form has 2 submit buttons:
Default one that should run validation (Save method in controller has [FormValidator] annotation)
Second one (calls another controlers' method) should have validation disabled (Save method in controller has no validation annotation)
At this moment both buttons do POST call to Save method so validation run in both cases. If I remove FormHelper validation tags, client calls correct methods but there is no validation off course.
What should I do in order to enable validation only for one button?
View:
<form id="myFrom" asp-controller="MyController" asp-action="Save" method="post" asp-formhelper="true">
<label asp-for="MyField" class="form-label">My field: </label>
<input asp-for="MyField" class="form-control"/>
<span asp-validation-for="MyField" class="text-danger"></span>
<input type="submit" value="POST with validation">
<input type="submit" asp-controller="MyController" asp-action="AnotherAction" value="Post without validation">
</form>
Controller:
public class MyController
{
[HttpPost, FormValidator]
public async Task<IActionResult> Save(MyViewModel vm)
{
//do sth
}
[HttpPost]
public async Task<IActionResult> AnotherAction(MyViewModel vm)
{
//do another actions
}
}

Creating a Login Page in ASP.NET Core MVC

I am trying to create a login page. But it's saying no page found.
I have included this in Startup.cs:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{Controller=LoginController}/{action=Login}");
});
The Login.cshtml page is in views as Views/Login/Login.cshtml
and the controller lies under the Controllers folder with the name LoginController.cs
The code for LoginController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace AdminControl.Controllers
{
public class LoginController : Controller
{
// POST: LoginController
[HttpPost]
public IActionResult Login()
{
return View();
}
}
}
Login.cshtml:
<form asp-action="Users/Index" class="form-group" id="login-form" method="post" runat="server" style="text-align: center;">
<input class="form-control" placeholder="ID" runat="server" style="text-align: center;"/>
<input class="form-control" placeholder="Password" runat="server" style="text-align: center;" type="password"/>
</form>
<button class="btn btn-info" form="login-form" value="Submit" type="submit">Submit</button>
What has gone wrong?
Fix the error in a pattern: "{Controller=LoginController}/{action=Login}");
pattern: "{Controller=Login}/{action=Login}");
But it's better to use a standard default pattern
pattern: "{controller=Home}/{action=Index}/{id?}");
and redirect from Index action to login controller after checking if user hasn't logined yet
And as #IsmailDiari noticed, you should have two actions - one to get login form, another to post login form. But you also need a Model:
public class LoginViewModel
{
public string Login {get; set;}
public string Password {get; set;}
}
After this change controller and views like this:
[HttpGet]
public IActionResult Login()
{
var viewModel=new LoginViewModel;
return View(viewModel);
}
// POST: When submitting the login credentials
[HttpPost]
public IActionResult Login(LoginViewModel viewModel)
{
}
LoginForm:
#model LoginViewModel
#using (Html.BeginForm())
{
<input class="form-control" asp-for = "Login" name="login" placeholder="Login" runat="server" style
="text-align: center;"/>
<input class="form-control" asp-for="Password" name="password" placeholder="Password" runat="server" style="text-align: center;" type="password"/>
<input type="submit" value="Login" class="btn btn-primary" />
}
Please see this link to know how to set a default route, you are doing that wrong.
Also you need to provide Get action to return the view.
your controller should be like the following
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace AdminControl.Controllers
{
public class LoginController : Controller
{
// Get: Return Login View
[HttpGet]
public IActionResult Login()
{
return View();
}
// POST: When submitting the login credentials
[HttpPost]
public IActionResult Login(FormCollection collection)
{
//1. validation Goes here
//2. redirection after validation,
//return View();
}
}
}
and your cshtml body should be something like this
<body>
#using (Html.BeginForm())
{
<input class="form-control" name="id" placeholder="ID" runat="server" style
="text-align: center;"/>
<input class="form-control" name="password" placeholder="Password" runat="server" style="text-align: center;" type="password"/>
<input type="submit" value="Login" class="btn btn-primary" />
}
</body>
you should set name attribute to your input so you can find them later in your FormCollection

How to call an asynchronous method from a view?

I have an async method in a controller that has an id parameter. In my view, I want to have a button that when clicked it passes a #document.SubmissionId variable to the function and execute it. How can I achieve that? Here is what I have so far:
Controller
private async Task<ActionResult> onPostSaveImage(string id){}
View
<input type="button" value="Send Images" class="btn btn-xs btn-outline-primary" onclick="location.href='#Url.Action("onPostSaveImage", "ICRDocumentPending")?id=' + #document.SubmissionId" />
Not enough just sign a method with async to be able work asynchronously when called from a view. It is necessary to derive your controller class from System.Web.Mvc.AsyncController, which implements IAsyncController interface. And code will become like below:
public class ICRDocumentPendingController : AsyncController
{
public async Task<ActionResult> onPostSaveImage(string id)
{
return await Task<ActionResult>.Factory.StartNew(() =>
{
/* some code */
//...
return View("ViewName", (object)id);
});
}
//...
}
View code:
<input type="button" value="Send Images"
class="btn btn-xs btn-outline-primary"
onclick="location.href='#Url.Action("onPostSaveImage", "ICRDocumentPending", new { id = document.SubmissionId }))'" />

Post back view values to controller MV3

I am new to mvc 3. i am trying to create a view and controller. my scenario is that i have controller which has two actions. while i call first action inside controller i have to load default values to view. inside view i have a buttons to post back values. so while click one of the button inside view, it has to go second action in same controller and has to return back to same view with success or failure message.
My view is like this
#using (Html.BeginForm())
{
<table>
<tr>
<td>
#Html.TextBox("txtTitle")
</td>
<td>
<input type="button" value="Go Somewhere Else" onclick="location.href='#Url.Action("Postback", "Default1")'" />
</td>
</tr>
</table>
}
My Controller,
public class Default1Controller : Controller
{
//
// GET: /Default1/
public ActionResult Index()
{
// has to default load value to text box
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Postback(FormCollection obj)
{
// has to take value from txt box
object obj1 = Request["txtTitle"];
return View("Index");
}
}
My problem if call Postback action from any other view it works. but inside same view if i click on button the error shows like "http://localhost:14953/Default1/Postback".
What is solution here? i expect to navigate to same controller as well as to other controller inside same form and return to same view.
As reference to this article.....
public class HttpParamActionAttribute : ActionNameSelectorAttribute {
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
In view form like this...
#using (Html.BeginForm("Action", "Post")) {
<!— …form fields… -->
<input type="submit" name="SaveDraft" value="Save Draft" />
<input type="submit" name="Publish" value="Publish" />
}
and actions in controller...
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
You can specify an ActionName to your Postback method like this:
[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Postback(FormCollection obj)...
So F5 repost the same values and calling the URL directly from the address bar returns the View as expected.
There is a constructor for Html.BeginForm Helper method which takes action name and controller name. Use that
public static MvcForm BeginForm(
this HtmlHelper htmlHelper,
string actionName,
string controllerName
)
http://msdn.microsoft.com/en-us/library/dd492590.aspx
So your form should look like this. You dont need the onclick function in your input element.
#using (Html.BeginForm("Postback", "Default1"))
{
//Your elements
<input type="button" value="Go Somewhere Else" />
}
That will render the HTML markup like this
<form action="/Default1/Postback" method="post">
// Your elements
<input type="button" value="Go Somewhere Else" />
</form>
If you want multiple submit button in the same form, It is answered here
I think we can specific action and controller at Html helper.
#using (Html.BeginForm("Postback", "Default1"))
{
<table>
<tr>
<td>
#Html.TextBox("txtTitle")
</td>
<td>
<input type="submit" value="Go Somewhere Else" />
<!-- the input should be submit?-->
</td>
</tr>

parameters and action

How can i pass to asp.net mvc action parameters like: line[first], line[second], line[third], people[john] etc?
For example we have html:
<form>
<input type="hidden" name="line[first]" value="hello" />`
<input type"submit" value="send" />
</form>
How we can take "line[first]" value when user clicks on send button?
[HttpPost, ValidateAntiForgeryToken]
public ActionResult ShowLogin(LoginModel model)
{
model.username;
model.password
}
instead of admin you can have
public ActionResult ShowLogin(FormCollection form)
{
var user = form["username"];
}

Categories

Resources