I have three actions that I have a value in the first action, I pass this value to the second action. I want to use this amount in the third action, is there a solution?
First Action:
public async Task<IActionResult> LoginUser(LoginViewModel viewModel)
{
string code = await _user.SendActiveCodeForUser(viewModel);
TempData["Mobile"] = viewModel.Mobile;
return Json(new { redirectToUrl = Url.Action("Activate") });
}
Second Action:
public IActionResult Activate()
{
ViewBag.Mobile = TempData["Mobile"].ToString();
return View();
}
Third Action:
public async Task<IActionResult> SendActiveCode()
{
string code = await _user.SendActiveCodeAgain(ViewData["Mobile"].ToString());
return Json(0);
}
I used the session according to the link address below, I think it is a good solution
How To Use Sessions In ASP.NET Core
Related
I'm working on implementing the Nexmo API into my code and have run into some issues with the controller. I'm getting the error
AmbiguousMatchException: The request matched multiple endpoints. Matches:
gardenplanning.Controllers.SMSController.Send (gardenplanning)
gardenplanning.Controllers.SMSController.Send (gardenplanning)
Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
I have a feeling that it has to do with the 2 "Send" methods however I'm out of ideas as to how to modify one of them to fix the routing. The code integrated into my project is below. I commented out the Index method because in my HomeController it already has method that maps to Index. Any help as to what's causing the issue would be appreciated, thanks.
enter code here
namespace gardenplanning.Controllers {
public class SMSController : Controller
{
/*
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
*/
//Send Action Method
[System.Web.Mvc.HttpGet]
public ActionResult Send()
{
return View();
}
//Action method containing "to" and "text" params
[System.Web.Mvc.HttpPost]
public ActionResult Send(string to, string text)
{
var results = SMS.Send(new SMS.SMSRequest
{
from = Configuration.Instance.Settings["appsettings:NEXMO_FROM_NUMBER"],
to = to,
text = text
});
return View();
}
}
}
The guide for Nexmo API is below
public ActionResult Index()
{
return View();
}
[System.Web.Mvc.HttpGet]
public ActionResult Send()
{
return View();
}
[System.Web.Mvc.HttpPost]
public ActionResult Send(string to, string text)
{
var results = SMS.Send(new SMS.SMSRequest
{
from = Configuration.Instance.Settings["appsettings:NEXMO_FROM_NUMBER"],
to = to,
text = text
});
return View("Index");
}
AmbiguousMatchException: The request matched multiple endpoints. Matches: gardenplanning.Controllers.SMSController.Send (gardenplanning) gardenplanning.Controllers.SMSController.Send (gardenplanning) Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
As exception message indicated, the request matched two or more endpoints, which cause the issue.
To resolve ambiguous actions you can try to apply different HTTP verb templates to these two "Send" action methods, which constrains matching to requests with specific HTTP method only. And in ASP.NET Core app, you can use [Microsoft.AspNetCore.Mvc.HttpGet] instead of [System.Web.Mvc.HttpGet].
[HttpGet]
public ActionResult Send()
{
return View();
}
//Action method containing "to" and "text" params
[HttpPost]
public ActionResult Send(string to, string text)
{
var results = SMS.Send(new SMS.SMSRequest
{
from = Configuration.Instance.Settings["appsettings:NEXMO_FROM_NUMBER"],
to = to,
text = text
});
return View();
}
Besides, if you'd like to conditionally enable or disable an action for a given request based on query string, you can try to implement a custom ActionMethodSelectorAttribute. For more information, please check this blog:
https://devblogs.microsoft.com/premier-developer/defining-asp-net-core-controller-action-constraint-to-match-the-correct-action/
I'm pretty new with ASP.Net Core and I'm trying to show my async Task Filter return into my View but not sure how to...
This is my Controller code:
public class OrderNumberController : Controller
{
public async Task<IActionResult> Index(string orderNumber)
{
string[] locales = HPMSConstants.System.SupportedLocales.OrderBy(l => l).ToArray();
ViewBag.Locales = locales;
return View();
}
[HttpPost]
public async Task<PaymentGatewayTransactionManagerService.PaymentGatewayRecord> Filter(string orderNumber)
{
var result = await GetOrders(orderNumber);
return result;
}
private async Task<PaymentGatewayTransactionManagerService.PaymentGatewayRecord> GetOrders(string orderNumber)
{
var httpBinding = new System.ServiceModel.BasicHttpBinding();
// var address = new System.ServiceModel.EndpointAddress("http://pgtms.local.myherbalife.com/PaymentGatewayTransactionManager/Service.svc");
//var address = new System.ServiceModel.EndpointAddress("http://zus2q1ssb000000.hrbl.net:8330/Service.svc");
var address = new System.ServiceModel.EndpointAddress("http://zuswqa4svc01:8330/Service.svc");
PaymentGatewayTransactionManagerClient clientService = new PaymentGatewayTransactionManagerClient(httpBinding, address);
var result = await clientService.GetPaymentGatewayRecordAsync(orderNumber);
return result;
}
I think I see what you are asking. In the second two methods you are returning a Task<something> where the "something" is the result that you got after awaiting the result from an async method call. The first method is showing an MVC view controller method returning a view. It turns out that method is coded wrong. It should be (ignoring the first two lines which seem unrelated to the problem)
public IActionResult Index(string orderNumber)
{
string[] locales = HPMSConstants.System.SupportedLocales.OrderBy(l => l).ToArray();
ViewBag.Locales = locales;
return View();
}
This you don't need the async Task<IActionResult> because you are not awaiting any asynchronous methods within the method shown. View() is a method on the Microsoft.AspNetCore.Mvc.Controller which is not asynchronous and returns a Microsoft.AspNetCore.Mvc.ViewResult, which extends a ActionResult.
So the short answer is, just make sure your method returns the values it says it does in the method signature and make sure not to ignore the warnings and errors in Visual Studio or Visual Code. There is a warning if you add async to a method but you do not await anything in the body. There is an error if you try to return a Task<IActionResult> but are returing something that implements IActionResult instead.
I have the following action methods:
[HttpGet]
public ActionResult DBLookupIndex(DBLookupDTO dto)
{
dto.Areas = _ph.GetProfiles();
return View(dto);
}
[HttpGet]
public ActionResult Search(DBLookupDTO dto)
{
dto.Orders = _oh.GetOrders(dto.OrderNumber, dto.ProductNumber, dto.DateRange, dto.SelectDeleted, dto.AreaId);
return RedirectToAction("DBLookupIndex", dto);
}
The user simple enters valid information into one or more of the textboxes on the webpage, and submits it to the controller by pressing submit. This then calls the Search-action.
By debugging, I have determined, that the function works. It does find what it should, but it is not passed on, when it redirects back to the DBLookupIndex-action.
My question is; What am I doing wrong? I have seen code examples similar to the one above provided as solutions for similar issues, but for some reason it does not work for me.
EDIT:
I realised after the first answer came, that I was missing some information. Whenever the page is loaded, it has to update a dropdown that is rendered in the view, in case new profiles/areas have been added. I do that with razor:
<select name="AreaId" asp-for="AreaId" class="form-control">
<option disabled selected value=""> -- Vælg et område -- </option>
#foreach (var a in Model.Areas)
{
<option value="#a.ProfileId">#a.Name</option>
}
That is why I have to used RedirectToAction, instead of having a new action render the same view. Unless there is a better way to do it? :)
Thank in advance for any help!
In addition to Peter B's answer, another option is to store it in the TempData object that exists on your base controller.
[HttpGet]
public ActionResult Search(DBLookupDTO dto)
{
var orders = new List<Order>();
TempData["orders"] = orders;
return RedirectToAction("DBLookupIndex", dto);
}
You can then retrieve the data on the following request like so:
[HttpGet]
public ActionResult DBLookupIndex(DBLookupDTO dto)
{
var yourData = (List<Order>)TempData["orders"];
...
return View(dto);
}
The TempData object exists for a single request and is then cleared up. You can read more about it here.
The object parameter in RedirectToAction is meant to set querystring values for the URL that is generated and then sent to the browser as a "Redirect to other page" result. It is supposed to be an object similar to new { id = 7, otherParam = 5 }, or a Dictionary, but certainly not a recordset or any other kind of business data.
It seems like you want to show the View that belongs to the DBLookupIndex action. That can be done in a very simple way, like this:
[HttpGet]
public ActionResult Search(DBLookupDTO dto)
{
dto.Orders = _oh.GetOrders(dto.OrderNumber, dto.ProductNumber, dto.DateRange, dto.SelectDeleted, dto.AreaId);
return View("DBLookupIndex", dto); // Render the "DBLookupIndex" view and pass it the dto object
}
Update: if you need dto.Areas to be always set, you can create a method that just does that.
Like this (1):
[HttpGet]
public ActionResult DBLookupIndex(DBLookupDTO dto)
{
SetAreas(dto);
return View(dto);
}
[HttpGet]
public ActionResult Search(DBLookupDTO dto)
{
dto.Orders = _oh.GetOrders(dto.OrderNumber, dto.ProductNumber, dto.DateRange, dto.SelectDeleted, dto.AreaId);
SetAreas(dto);
return View("DBLookupIndex", dto);
}
private void SetAreas(DBLookupDTO dto)
{
dto.Areas = _ph.GetProfiles();
}
Or like this (2):
[HttpGet]
public ActionResult DBLookupIndex(DBLookupDTO dto)
{
return SetAreasAndView(dto);
}
[HttpGet]
public ActionResult Search(DBLookupDTO dto)
{
dto.Orders = _oh.GetOrders(dto.OrderNumber, dto.ProductNumber, dto.DateRange, dto.SelectDeleted, dto.AreaId);
return SetAreasAndView(dto);
}
private ActionResult SetAreasAndView(DBLookupDTO dto)
{
dto.Areas = _ph.GetProfiles();
return View("DBLookupIndex", dto);
}
public async Task<ActionResult> Print(BasicSurveyReportViewModel paramModel)
{
ActionResult OverallSummary =
await basicSurveyReportController.OverallSummary(paramModel);
ActionResult CompanyInfo =
await basicSurveyReportController.CompanyInfo(paramModel);
ViewBag.OverallSummary = OverallSummary;
ViewBag.CompanyInfo = CompanyInfo;
return View();
}
In this code, first OverallSummary variable is set successfully.
But when running at the CompanyInfo line's method, it puts the variable into both CompanyInfo and OverallSummary.
How do I can get the results into separate variables?
It looks like you're trying to call asynchronous child actions, which are not supported in ASP.NET 4.x. I suspect that the ASP.NET controller is just accessing the current request when you return View(blah) or whatever from your child actions.
The only way to correctly do this (in the current version of ASP.NET) is to write helper methods that do the actual work and return your own types (not ActionResult):
OverallSummary GetOverallSummaryAsync(BasicSurveyReportViewModel model);
CompanyInfo GetCompanyInfoAsync(BasicSurveyReportViewModel model);
public async Task<ActionResult> Print(BasicSurveyReportViewModel paramModel)
{
OverallSummary overallSummary =
await GetOverallSummaryAsync(paramModel);
CompanyInfo companyInfo =
await GetCompanyInfoAsync(paramModel);
ViewBag.OverallSummary = overallSummary;
ViewBag.CompanyInfo = companyInfo;
return View();
}
Then your other controller actions can convert to use those methods as well, like this:
public async Task<ActionResult> OverallSummary(BasicSurveyReportViewModel paramModel)
{
return View(await GetOverallSummaryAsync(paramModel));
}
I have an Asynchronous controller implementation as follows,
public Task<ActionResult> UpdateUser(ProfileModel model)
{
return Task.Factory.StartNew(showMethod).ContinueWith(
t =>
{
return RedirectToAction("ViewUser","UserProfile");
});
}
However I am unable to redirect to the action as I am keep on getting the error,
Cannot implicitly convert type, System.Threading.Taska.Task<Sytem.Web.Mvc.RedirectToRouteResult> to System.Threading.Taska.Task<Sytem.Web.Mvc.ActionResult>
However I really want to redirect to the mentioned Action, how can I do that.
For people who come here looking for an answer, the newer versions of .NET make things simpler. Use the keyword async in the definition of the method and you can clear up the body.
public async Task<ActionResult> UpdateUser(ProfileModel model)
{
return RedirectToAction("ViewUser","UserProfile");
}
You need to change the return type of UpdateUser action from Task<ActionResult> to Task<RedirectToRouteResult>
public Task<RedirectToRouteResult> UpdateUser(ProfileModel model)
{
return Task.Factory.StartNew(showMethod).ContinueWith(
t => {
return RedirectToAction("ViewUser","UserProfile");
});
}
Or you could explicitly set the generic type argument of ContinueWith method with ActionResult, like this:
public Task<ActionResult> UpdateUser(ProfileModel model)
{
return Task.Factory.StartNew(showMethod).ContinueWith<ActionResult>(
t => {
return RedirectToAction("ViewUser","UserProfile");
});
}
Use this example:
public async Task<ActionResult> Login(LoginModel model) {
//You would do some async work here like I was doing.
return RedirectToAction("Action","Controller");//The action must be async as well
}
public async Task<ActionResult> Action() {//This must be an async task
return View();
}