How to find api action path from another action - api

In My Reserve ApiController, I need to have may BankRedirect action's path in a string and Url.Route has been used but it doesn't work.
public string GoToBank(string token, string username )
{
string path Url.Route("BankRedirect", new { controller = "Reserve"} , new { userId = "" }))
return path;
}
[Route("BankRedirect")]
[HttpPost]
[BasicAuthenticationFilter]
public async Task<UpdateResult<string>> BankRedirect( [FromBody]string userId)
{
}

The corresponded path for decorating action with [Route("BankRedirect")] is /BankRedirectץ
The given Url.Route output is Reserve/BankRedirect.
/BankRedirect != Reserve/BankRedirect
You should change one of them, either:
[Route("Reserve/BankRedirect")]
Or
return "BankRedirect";

Related

How to handle unknown parameters in ASP.NET Core Actions

How to handle unknown parameters in ASP.NET Core? When I use [FromQuery] it just ignores the unknown parameters, but ideally it should return 400 if the parameter is unknown so the caller knows it needs to fix the parameters?
Example: GetRecords tries to use any StartDate or EndDate from query string, use default value if they are not specified.
But if a query like ?StartTime=2021/2/15&EndTime=2021/2/16, the code actually will return all records from DB as it treats like no parameters passed. Ideally it should throw an error to let caller know the parameter names are invalid.
class RecordQuery
{
public RecordQuery()
{
StartDate = DateTime.MinValue;
EndDateTime = DateTime.Now;
}
//...
}
class Controller
{
public async Task<ActionResult<RecordsResult>> GetRecords([FromQuery] RecordQuery query)
{
// query db where date < query.EndDateTime && date > query.StartDateTime;
}
}
When I use [FromQuery] it just ignores the unknown parameters
Actually, this is the default behavior of the querystring parameters. But you could return an Invalid Request status, so that the client knows that what it's trying to do isn't valid.
To implement it, you can use the ActionFilter, get both the action parameters and request query string queryParameters and make a judgement. Codes like below:
public class QueryActionFilter<T> : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var model = context.ActionArguments.Values.OfType<T>().Single();
var modelProperties = model.GetType().GetProperties();
var queryParameters = context.HttpContext.Request.Query;
if (!queryParameters.Select(q => q.Key).All(queryParameter => modelProperties.Any(p => p.Name == queryParameter)))
{
context.Result = new BadRequestObjectResult("Querystring does not match");
}
}
}
Then in controller
[TypeFilter(typeof(QueryActionFilter<RecordQuery>))]
public async Task<ActionResult<RecordsResult>> GetRecords([FromQuery] RecordQuery query)
{
// query db where date < query.EndDateTime && date > query.StartDateTime;
}
You can see example https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio#the-puttodoitem-method
if(StartDate == null){
return BadRequest();
}
Let's do the same thing with another input parameter(s) (query conditions)
If you want validate input parameter(s), use [Required] for model of [FromQuery], see https://stackoverflow.com/a/19279419/3728901 . In your case, it is model RecordQuery .

How to call some Controller's method and pass a parameters from a query string

in my app I've generated an url like this:
http://www.test.com/?mail=test%40gmail.ba&code=71147ff9-87ae-41fc-b53f-5ecb3dbe5a01
The way how I generated Url is posted below:
private string GenerateUrl(string longUrl, string email, string confirmCode)
{
try
{
// By the way this is not working (Home/MailConfirmed) I'm getting message
// Requested URL: /Home/MailConfirmed
// The resource cannot be found.
string url = longUrl + "/Home/MailConfirmed";
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query["mail"] = email;
query["code"] = confirmCode;
uriBuilder.Query = query.ToString();
uriBuilder.Port = -1;
url = uriBuilder.ToString();
return url;
}
catch (Exception ex)
{
return "Error happened: " + ex.Message;
}
}
In longUrl I'm passing www.test.com, in email I'm passing
test#gmail.com and so on..
There are informations about my website:
www.test.com
mail:test#gmail.com
confirmcode:71147ff9-87ae-41fc-b53f-5ecb3dbe5a01
And in my HomeController.cs there is a method which should took parameters out of query string - url and pass it to the method which should activate users account by getting user by mail (mail is unique) and comparing this guid with guid in database. So I'm wondering how can I call this method?
So my method looks like this:
public JsonResult MailConfirmed(string mail, string confirmCode)
{
try
{
// Here I will get user and update it in DB
return Json("success", JsonRequestBehavior.AllowGet);
}
catch(Exception ex)
{
return Json("fail", JsonRequestBehavior.AllowGet);
}
}
So my question is how is possiblee for user to click on following link and to get an my method invoked.. ?
Thanks a lot
Cheers
In order to navigate to your MailConfirmed(), your url would need to be
http://www.test.com/Home/MailConfirmed?mail=test%40gmail.ba&confirmcode=71147ff9-87ae-41fc-b53f-5ecb3dbe5a01
Note the segments for the controller and action names, and code=xxx should be confirmcode=xxx to match the name of the parameter in the method.
You can simplify your code (and delete your GenerateUrl() method) by making use of UrlHelper methods to generate the url).
To generate the above url, all you need in your controller method is
string url = Url.Action("MailConfirmed", "Home",
new { mail = email, confirmcode = confirmCode },
this.Request.Url.Scheme);

I want to keep 2 values for next save from preivous save. MVC 4

User enters PWS (public water system), LabID. Then clicks Save button.
I would like these values to populate the new input form that right now gets emptied out on a succesful save.
#Html.TextBoxFor(model => model.PWS, new { #autofocus = "autofocus", #style="width:50px", #maxlength="5" })
Controller ActionResult
First time through:
[HttpGet]
public ActionResult AddColiform(string sortorder)
{
int batchid;
batchid = Convert.ToInt32(Session["ThisBatch"]);
//Session["ThisBatch"] = batchid;
ViewBag.Methods = FillMethods();
ViewBag.Latest = (from m in _db.BactiBucket
where m.Batch_ID == batchid
select m).ToList();
ViewBag.ThisBatch = batchid;
return View(new BactiBucket());
}
When Save button clicked:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddColiform(BactiBucket bucket)
{
if (ModelState.IsValid)
{
//FIRST RECORD SAVED FOR USER CREATES BATCH, OTHERWISE BATCH IS ZERO
if (Session["ThisBatch"].Equals(0))
{
var newbatchid = CheckAndMakeBatchIfNone();
Session["ThisBatch"] = newbatchid;
bucket.Batch_ID = newbatchid;
}
_db.AddToBactiBucket(bucket);
_db.SaveChanges();
return RedirectToAction("AddColiform");
}
ViewBag.Methods = FillMethods();
int batchid;
batchid = Convert.ToInt32(Session["ThisBatch"]);
ViewBag.ThisBatch = batchid;
ViewBag.Latest = (from m in _db.BactiBucket
where m.Batch_ID == batchid
select m).ToList();
return View(bucket);
}
You can pass additional parameters to your GET method in the redirect, and use ths values to set the properties of your model (note its not clear why your method has a parameter string sortorder when you never use it)
[HttpGet]
public ActionResult AddColiform(string sortorder, string PWS, string LabID)
{
....
BactiBucket model = new BactiBucket() { PWS = PWS, LabID = LabID };
return View(model);
}
[HttpPost]
public ActionResult AddColiform(BactiBucket bucket)
{
if (ModelState.IsValid)
{
....
return RedirectToAction("AddColiform", new { PWS = bucket.PWS, LabID = bucket.LabID });
}
....
}
Ok, if it was a snake it would have bit me.
In the declaration of the ActionResult I pass the values of the textboxes to the controller. It comes in with the Post action. (PWS and LabID are the names of the inputs).
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddColiform(BactiBucket bucket, string PWS, string LabID)
Then right before the return RedirectToAction("AddColiform");
I set Session variables for each value:
Session["PWS"]=PWS;
Session["LabID"]=LabID;
of course I might use ViewBag.PWS and ViewBag.LabID
Then, when returning and building the new Add Record form,
I populate the #Value of each textbox respectfully:
#Html.TextBoxFor(model => model.PWS, new {#Value=Session["PWS"], #autofocus = "autofocus", #style="width:50px", #maxlength="5" })
#Html.TextBoxFor(model => model.LabID, new {#Value=Session["LabID"], #style="width:150px", #maxlength="20" })
Since I haven't run this code I know I will have to check if Session objects aren't null. Or ViewBag objects. Or set them to "" first time through.
I got this from this forum thread

How to request same parameter twice in query string?

I am trying to request the following query string url: api/item?name=storm&name=prest
I am using the following code below and I cannot get the code to work.
public class ItemController : ApiController
{
private cdwEntities db = new cdwEntities();
public HttpResponseMessage Get([FromUri] Query query)
{
var data = db.database_ICs.AsQueryable();
if (query.name != null)
{
**data = data.Where(c => c.Name.Split("&").Contains(query.name));**
}
if (query.id!= null)
{
data = data.Where(c => c.ID== query.id);
}
if (!data.Any())
{
var message = string.Format("No data was found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
return Request.CreateResponse(HttpStatusCode.OK, data);
}
}
Any help would be very much appreciated.
You can use post Api and send array of [name].
name = [item1,item2....]
public void Post([FromBody] List<string> name) {
}
You can not pass same name key in Querystring. Browser/Code did not identified which is correct value, if you want multiple value then pass as a object.

Struts2 more than one action in one class

I'm using Struts2. I have two web forms that have the same code. I would like to eliminate one form. Here is the structure of my Struts project.
\Web Pages
form.jsp
\WEB-INF
\Content
error.jsp
form.jsp
success.jsp
\Source Packages
\action
MyAction.java
MyAction.java
package action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.*;
public class MyAction extends ActionSupport {
#Action(value = "foo", results = {
#Result(name = "input", location = "form.jsp"),
#Result(name = "success", location = "success.jsp"),
#Result(name = "error", location = "error.jsp")
})
public String execute() throws Exception {
if (user.length() == 1) {
return "success";
} else {
return "error";
}
}
private String user = "";
public void validate() {
if (user.length() == 0) {
addFieldError("user", getText("user required"));
}
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
I tried to eliminate form.jsp under \Web Pages by adding a new action method to MyAction.java.
#Action(value="bar", results = {
#Result(name = "success", location = "form.jsp"),
})
public String another() {
return "success";
}
But I got the following error when I go to http : //localhost .../bar.action
HTTP Status 404 - No result defined for action action.MyAction and result input
Your MyAction has an implementation of validate(), which means it is validation aware.
What's happening is that you're calling another, but validate() is kicking in (as it's in the interceptor stack). Validation is failing, and therefore sending to INPUT result, which is not defined in another.
You should
Add #SkipValidation to the another method if you don't want validation there
Add the INPUT result to another() if you want a default input result
On a more general note, when you get that kind of error (No result defined for action X and result input) it usually means you're either having validation errors, parameter population errors (eg: an exception in preparable).