Id not being passed back to controller - c#

The manageuser post back method is being called but the UserId is not being passed it comes back as 0. How do I correct this issue?
The html from view
<input type="image"
src="~/icons/bootstrap-icons-1.10.2/bootstrap-icons.css"
alt=""
class="bi bi-check-circle-fill fs-6"
name="btnDelete"
aria-label="Delete user"
onclick="location.href='#Url.Action("ManageUser", "ManageUsers", new {#executeAction = "Delete", #userId = #item.UserID})'" />
The controller code
[HttpGet]
public IActionResult ManageUser(string Status, string? StatusMessage)
{
TempData["Message"] = "";
if(statusMessage != null)
{
TempData["Message"] = statusMessage;
}
//load model
return View(model)
}
[HttpPost]
public IActionResult ManageUser(string executeAction, int userId)
{
string status = action;
string statusMessage = string.Empty;
if(executeAction == "Delete")
{
//delete the user
}
return RedirectToAction("ManageUser", "ManageUsers", status, statusMessage);
}

The manageuser post back method is being called but the UserId is not
being passed it comes back as 0. How do I correct this issue?
Well, as you may know Tag Helpers class generate link on page. Thus, we have either need to send request using query string or define get method on your controller action.
If you could seen in tag helper class service reference it doesn't allow httpverb by default because it takes request as URL that's query string.
Solution:
To resolve the issue either we have to define controller action as GET, just as following:
Controller:
public IActionResult ManageUser(string executeAction, int userId)
{
string status = "";
string statusMessage = string.Empty;
if (executeAction == "Delete")
{
//delete the user
}
return RedirectToAction("ManageUser", "ManageUsers", status, statusMessage);
}
View:
<input type="button"
src="~/icons/bootstrap-icons-1.10.2/bootstrap-icons.css"
alt=""
class="bi bi-check-circle-fill fs-6"
name="btnDelete"
value="Delete User"
aria-label="Delete user"
onclick="location.href='#Url.Action("ManageUser", "Some", new {#executeAction = "Delete", #userId = "111"})'" />
Note: Everything would remain same as yours.
Output:
Alternative Way:
We can directly pass our parameter using location.href what more is, it will send controller parameter as query string and will act accordingly.
Note: If you need more information about ASP.NET Core Tag Helpers, you can have a look on official document here.

Related

Send Query String of Current View/URL to another Action

i want to send current url query string to Action but the value is empty
inside second Action
public ActionResult Edit(string userId) // start action
{
try
{
var userID = userId.Unprotect<int>("userId");
return View(model: person);
}
catch
{
return HttpNotFound();
}
}
URL
http://localhost:25388/Home/Edit?userId=MsIJTy8Ea6ixr1E3xafN2SoUkHrXon3jcUMnlHPMaTZPW7XYma5Wqtkr9JGn4Ue8PImfNw%3D%3D
and the destination action method is:
[HttpPost]
public ActionResult EditSubmit(string userID, Person person) // second action
{
var test = Request.QueryString;
return RedirectToAction("Index", "Home");
}
is there any way to receive first action/url query strings inside second action?
(I mean receive the value of userId )
userId=MsIJTy8Ea6ixr1E3xafN2SoUkHrXon3jcUMnlHPMaTZPW7XYma5Wqtkr9JGn4Ue8PImfNw%3D%3D
i reached my goal with sending current URL QueryString part with Form submit Part
here is the code:
#using (Html.BeginForm("EditSubmit", "Home", new {userId = Request.QueryString["userId"]}, FormMethod.Post))
{
<input type="submit" value="Save" class="btn btn-success btn-sm" />
}
here is the main part
Request.QueryString["userId"] (inside view)

How do I access the variable of one method from another method within the same class C#?

I'm working on Asp.net project. I created a Form, which asks for connectionId and holderFirstName as Input. The name of asp-action is SendProofNameRequest.
In Controller, I wrote a Method SendProofNameRequest which take connectionId and holderFirstName as Parameters. But the problem is, the purpose I'm taking holderFirstName as Input is to use this in another Method (VerifyFirstName).
So, my question is how to take holderFirstName as input from user and use this in another method / VerifyFirstName (not SendProofNameRequest).
Details.cshtml
<form class="input-group mb-3" asp-controller="Proof" asp-action="SendProofNameRequest">
<input type="hidden" name="connectionId" value="#Model.Connection.Id" />
<input type="text" name="holderFirstName" autocomplete="off" class="form-control" placeholder="Enter First Name" aria-label="First Name" aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-outline-info" type="submit">Request a Proof of First Name</button>
</div>
</form>
ProofController.cs
[HttpPost]
public async Task<IActionResult> SendProofNameRequest(string connectionId, out string holderFirstName)
{
var agentContext = await _agentProvider.GetContextAsync();
var connectionRecord = await _walletRecordService.GetAsync<ConnectionRecord>(agentContext.Wallet, connectionId);
var proofNameRequest = await CreateProofNameMessage(connectionRecord);
await _messageService.SendAsync(agentContext.Wallet, proofNameRequest, connectionRecord);
return RedirectToAction("Index");
}
VerifyFirstName Method
I want to replace firstname (static value) with holderFirstName (dynamic value / user entered in form)
public bool VerifyFirstName(PartialProof proof)
{
var firstName = "Fyodor";
var name = proof.RequestedProof.RevealedAttributes.First();
if (name.Value.Raw.Equals(firstName))
{
return true;
}
return false;
}
UPDATE
As u said to add models, I did that... add the models in ViewModel page and call the #model in View page..
Now, to call the stored values in model in Verify methods controller.
VerifyProof(string proofRecordId) methods calls for another method VerifyFirstName(proof) which does the actual verification.
Kindly have a look at code and can u point out where to add model.HolderFirstName and SendNameRequestViewModel model in which method e.g. VerifyProof(string proofRecordId), VerifyFirstName(proof).. I was getting an errors..
[HttpGet]
public async Task<IActionResult> VerifyProof(string proofRecordId, SendNameRequestViewModel model)
{
var agentContext = await _agentProvider.GetContextAsync();
var proofRecord = await _proofService.GetAsync(agentContext, proofRecordId);
var request = JsonConvert.DeserializeObject<ProofRequest>(proofRecord.RequestJson);
var proof = JsonConvert.DeserializeObject<PartialProof>(proofRecord.ProofJson);
bool verified = false;
switch (request.Name)
{
case "ProveYourFirstName":
verified = VerifyFirstName(proof, model.HolderFirstName); break;
default:
break;
}
if (!verified)
{
proofRecord.State = ProofState.Rejected;
await _walletRecordService.UpdateAsync(agentContext.Wallet, proofRecord);
}
return RedirectToAction("Index");
}
public bool VerifyFirstName(PartialProof proof, SendNameRequestViewModel model.HolderFirstName)
{
var firstName = model.HolderFirstName;
var name = proof.RequestedProof.RevealedAttributes.First();
if (name.Value.Raw.Equals(firstName))
{
return true;
}
return false;
}
First of all, the actions/methods in the controller class are meant to handle requests coming from the client to the server. They're not just methods in a class.
Hence I think you need to take out out keyword from the parameter holderFirstName. Or better, to use a view model to pass between the view and the controller:
public class SendNameRequestViewModel
{
[Required]
public string ConnectionId { get; set; }
[Required]
public string HolderFirstName { get; set; }
}
public class ProofController : Controller
{
public async Task<IActionResult> SendNameRequest(string connectionId)
{
// Initialize the view model if needed, i.e., filling its ConnectionId either
// from query string or cache. I don't know how you get the connectionId
var agentContext = await _agentProvider.GetContextAsync();
var connectionRecord = await _walletRecordService.GetAsync<ConnectionRecord>(agentContext.Wallet, connectionId);
if (connectionRecord == null)
{
return NotFound();
}
var vm = new SendNameRequestViewModel
{
ConnectionId = connectionId
};
return View(vm);
}
}
Then on the view, you declare its model as SendNameRequestViewModel so that you don't have to hard code the input names/
Notes: I've also added validation summary and validation message for inputs.
#model SendNameRequestViewModel
...
<form class="input-group mb-3" method="post" asp-controller="Proof" asp-action="SendNameRequest">
<input type="hidden" asp-for="ConnectionId" />
<div asp-validation-summary="ModelOnly"></div>
<input asp-for="HolderFirstName" autocomplete="off" class="form-control"
placeholder="Enter First Name" aria-label="First Name" aria-describedby="basic-addon2">
<span asp-validation-for="HolderFirstName" class="text-danger"></span>
<div class="input-group-append">
<button class="btn btn-outline-info" type="submit">Request a Proof of First Name</button>
</div>
</form>
For your VerifyFirstName check, there are so many way to do it. You can directly run its logic in the controller action body, for example. I would create an extension method against PartialProof object:
public static class PartialProofExtensions
{
public static bool VerifyFirstName(this PartialProof proof, string firstName)
{
if (proof == null)
{
return false;
}
var name = proof.RequestedProof.RevealedAttributes
.FirstOrDefault();
return (name != null && name.Value.Raw.Equals(firstName));
}
}
When the form is posting back, you can just run the validation check in the action method:
[HttpPost]
[ValidateAntiforgeryToken]
public async Task<IActionResult> SendNameRequest(SendNameRequestViewModel model)
{
if (ModelState.IsValid)
{
var agentContext = await _agentProvider.GetContextAsync();
var connectionRecord = await _walletRecordService.GetAsync<ConnectionRecord>(agentContext.Wallet, model.ConnectionId);
if (connectionRecord == null)
{
ModelState.AddModalError("", "Invalid connection Id.");
return View(model);
}
var proofNameRequest = await CreateProofNameMessage(connectionRecord);
if (!proofNameRequest.VerifyFirstName(model.HolderFirstName))
{
ModelState.AddModalError(nameof(model.HolderFirstName), "Invalid first name.");
return View(model);
}
await _messageService.SendAsync(agentContext.Wallet, proofNameRequest, connectionRecord);
return RedirectToAction("Index");
}
return View(model);
}

Call an Angular Route from ASP.NET WEB API

I have configured my application to send a confirmation Email to the user after registration. After the registration is completed the user will see a page that is saying you need to confirm you Email:
<div *ngIf="!emailConfirmed">
<p> Please activate your account by clicking the relevant link in your Email </p>
</div>
<div *ngIf="emailConfirmed">
<p>
Your Email is now confirmed, please click the below button to Log-In.
</p>
<a class="btn btn-md btn-success btn-color" [routerLink]="['/login']">
Sign In
</a>
</div>
And emailConfirmed is just a simple variable that I have defined in the emailConfirmed's typescript relevant file:
export class EmailConfirmed {
public emailConfirmed: boolean;
}
After the user clicks on the link in his/her Email, his/her account will be verified and then the application will be redirected to the ConfirmEmail page again using the below code:
[HttpGet]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IActionResult> ConfirmEmail(string userId = "", string code = "")
{
//....
IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
{
return Redirect("http://localhost:5000/emailconfirmed");
}
}
Now the question is: I don't know how can I set the emailConfirmed variable of EmailConfirmed component to true from WEB API and in the return Redirect line, in order the user see the second message this time? Also I doubt that I have chosen the best way to redirect the application to an Angular route using the return Redirect("http://localhost:5000/emailconfirmed"); line.
#ManojChoudhari is right. You can't route like this!
First it should be a "HttpPost". Return a response and then redirect on the clientside using router.
Here is a little example. This does not take into account the separation of concerns!
Serverside
Models
public class UserRequest {
public string UserId { get; set; }
public string Code { get; set; }
}
public class EMailConfirmationResponse {
public boolean EmailConfirmed { get; set; }
}
Controller
...
[HttpPost]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IHttpActionResult> ConfirmEmail(UserRequest user)
{
var result = await UserManager.ConfirmEmailAsync(user.UserId, user.Code)
if (result.Succeeded)
{
return Ok(new EMailConfirmationResponse { EmailConfirmed = true });
}
else
{
return BadRequest("An error occurred confirming the given email-address.");
}
}
...
Clientside
import { Component } from "#angular/core";
import { Router } from "#angular/router";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "your",
templateUrl: "./your.component.html"
})
export class YourAngularComponent {
constructor(
private _router: Router,
private _http: Http
) {
...
// put this into your method
const httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json', 'Authorization': 'my-auth-token'}) };
this.http
.post("webapiurl", { userId: "TheUserId", code: "TheUserCode" }, httpOptions)
.subscribe((response) => {
const emailConfirmationResponse = response.json();
if(emailConfirmationResponse.emailConfirmed) {
this._router.navigate(["emailconfirmed"]);
}
}, (err: HttpErrorResponse) => {
// do some error handling here:
console.log(err.error);
console.log(err.name);
console.log(err.message);
console.log(err.status);
}
);
...
One thing you need to understand is - the Angular routes are only available on client side.
You will not be able to redirect user to angular template from server side.
The option you have probably is to return some flag from web API. This flag should be unique and then angular should redirect user to other page.
Your API Code should be:
[HttpGet]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IActionResult> ConfirmEmail(string userId = "", string code = "")
{
//....
IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
if (result.Succeeded)
{
return Ok();
}
else
{
return BadRequest("An error occurred confirming the given email-address.");
}
}
In your client side typescript you can add below code:
//// result = call web api and take result
//// if result is 200 OK then
this.router.navigate(['/your-path'])
Hope this helps.
I guess directly from webapi you can't redirect. use Api response and then in angular redirect to another page or domain.

How can I pass a string from View to Controller

public ActionResult Message()
{
chartstype chartname = new chartstype();
List<chartstype> listchart = new List<chartstype>();
chartname.charttype = "Column";
listchart.Add(chartname);
TempData["name"] =listchart;
TempData.Keep();
return View();
}
And I want to change my code to be able to pass a string to chartname.charttype variable from View.
you could change (or overload) the ActionMethods signature to take a string Parameter
like...
public ActionResult Message(String someVariable)
{
//do something with the contents of someVariable
chartstype chartname = new chartstype();
List<chartstype> listchart = new List<chartstype>();
chartname.charttype = "Column";
listchart.Add(chartname);
TempData["name"] =listchart;
TempData.Keep();
return View();
}
which could be called like https://www.example.com/Message?someVariable=someString
In controller
public ActionResult Message(String chartName)
{
chartstype chartname = new chartstype();
List<chartstype> listchart = new List<chartstype>();
chartname.charttype = chartName;
listchart.Add(chartname);
TempData["name"] =listchart;
TempData.Keep();
return View();
}
URL :https://www.example.com/Message?chartName=ABCD
public ActionResult Message(string message)
and make sure to see if string is null, because anyone can call this method trough url.
if(string.IsNullOrWhiteSpace(message))
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
}
And then code in view
<form action="/controlerName/Message" method="get or post , get is by default if you don't put this atribute">
<input id="txt1" type="text" name="message" value="set value here or in JS or let user enter value"/>
If you don't want textbox to be seen use
<input type="hidden" name="message" value="somevalue"/>
Unless you want to call your method from javaScript using ajax?

ASP.NET MVC 4 - Redirect to the same page after controller ends

From a page I have the following:
#using (Html.BeginForm("AddEntry", "Configure", FormMethod.Get, new { returnUrl = this.Request.RawUrl }))
{
#Html.TextBox("IP")
#Html.Hidden("TypeId", 1)
<input type="submit" value="#Resource.ButtonTitleAddComponent" />
}
so controller is called correctly:
public ActionResult AddEntry(string ip, int TypeId, string returnUrl)
{
// Do some stuff
return Redirect(returnUrl);
}
My problem is that returnUrl gets null and it does not redirect to the same page that called the controller. Ideas?
Using: ASP.NET MVC 4
Razor
you can also do this if you need to return to something like details page and return to the same page with a query:
return Redirect(Request.UrlReferrer.PathAndQuery);
You can get the Refer URL from the Request in the controller:
public ActionResult AddEntry(string ip, int TypeId, string returnUrl)
{
// Do some stuff
string url = this.Request.UrlReferrer.AbsolutePath;
return Redirect(url);
}
This will redirect you exactly to the calling URL.
You could use a Request.QueryString method to get some values from URL, for sample:
#using (Html.BeginForm("AddEntry", "Configure", FormMethod.Get, null))
{
#Html.TextBox("ip")
#Html.Hidden("TypeId", 1)
#Html.Hidden("returnUrl", this.Request.RawUrl)
<input type="submit" value="#Resource.ButtonTitleAddComponent" />
}
And in your controller, receive it as a parameter string returnUrl.
in your controller class use Request.UrlReferrer. There's no need to pass the url from the page.
public ActionResult AddEntry(string ip, int TypeId)
{
// Do some stuff
return Redirect(Request.UrlReferrer.ToString());
}
#using (Html.BeginForm("AddEntry", "Configure", new { returnUrl = this.Request.RawUrl }))
{
#Html.TextBox("IP")
#Html.Hidden("TypeId", 1)
<input type="submit" value="#Resource.ButtonTitleAddComponent" />
}
Change your code like this
I found that using UrlReferrer works well and allows me to add on extra params if needed.
Helper method example:
protected RedirectResult RedirectToCurrentUri(String strQueryStringOverride = "")
{
String strReferrer = Request.UrlReferrer.AbsoluteUri;
if (String.IsNullOrWhiteSpace(strReferrer))
{
strReferrer = "/";
}
// Can also override referrer here for instances where page has
// refreshed and replaced referrer with current url.
if (!String.IsNullOrWhiteSpace(strQueryStringOverride))
{
String strPath = (strReferrer ?? "").Split('?', '#')[0];
return Redirect(strPath + strQueryStringOverride);
}
return Redirect(strReferrer);
}
Note that the method allows Query String override.
This can be used as a helper method in any controller as per below:
Redirect without changing query string (if any):
return RedirectToCurrentUri()
Example query string override:
return RedirectToCurrentUri("?success=true")
on Get like Edit(int? id)
ViewBag.RefUrl = Request.UrlReferrer.ToString();
on view #Html.Hidden("RefUrl");
on post Edit(int id,string RefUrl)
return Redirect(RefUrl);

Categories

Resources