Send data from view to controller through href in asp.net? - html

I want to send some data when user clicks on this link
<a asp-action="ViewOthersProfile">#question.Questionaire</a>
and this is my action method
[HttpGet]
public ViewResult ViewOtherProfile()
{
return View("OtherProfile");
}
also,how we'll get it in action method. Thanks in advance

//Use asp-route-myData for your data and you can name it whatever you want.
//asp-route-myData2, asp-route-data, asp-route-dog, ... you got the point.
<a asp-action="ViewOthersProfile" asp-route-myData="test string">#question.Questionaire</a>
//Here you can get your data as a parameter.
//However, the parameter name must be the last part of asp-route-myData. I mean 'myData'
[HttpGet]
public ViewResult ViewOtherProfile(string myData)
{
//And you can use myData whatever way you need
var result = myData + "test2";
return View("OtherProfile");
}

Related

Razor Pages On Server Validation returning for without some fields

I'm having an issue with a server side validation with Razor Pages (ASP.Net Core 2.0)
I have a page that creates a record
http://localhost:56876/Entries/Create?employeeID=112345
my code behind file for the OnGet looks like:
[BindProperty]
public EntryLog EntryLog { get; set; }
public Employee Employee{ get; set; }
public string empID { get; set; }
public IActionResult OnGet(string employeeID)
{
empID = employeeID;
// for Selects for lookup tables
ViewData["ReasonId"] = new SelectList(_context.Reason, "Id", "Name");
ViewData["ReasonTypeId"] = new SelectList(_context.ReasonType, "Id", "Name");
return Page();
}
The code above works just fine and client validation works perfect but I have business logic validation that if the Entry Date is 90 between today's date and hired date that I should not let the entry to be saved.
public async Task<IActionResult> OnPostAsync()
{
//Lookup current employeeID hiredDate. if is new employee do not continue.
Employee = await _context.Employee .FirstOrDefaultAsync(p => p.Id == EntryLog.EmployeeID);
//Server side validation
var age = DateTime.Today.Day - Employee.HireDate.Day;
if (age <= 90)
{
ModelState.AddModelError("NewEmp", "Emp is New Warning");
return Page();
}
if (!ModelState.IsValid)
{
return Page();
}
_context.EntryLog.Add(EntryLog);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
My server side validation works but the problem is that when I return Page();
The form gets refreshed and the two selects elements get empty out and the EmployeeID element gets empty out as well.
My guess is that the return Page() on OnPostAsync() is not calling the OnGet() method.
How can I keep the page as it is without loosing the info?
You are right the return Page() does not call OnGet() method. I´ll try to explain what is happening:
Short Answer:
When you receive the Post request (OnPost()) and return Page() the server just returns the response (html), it does not make a new Get Request so that OnGet() get called again.
The two selects elements are being cleant because they are set up in OnGet() through ViewData (that is temporary) not in OnPost(). My suggestion is that you set the "selects" again on OnPost() (extract to a method to make it easier).
Long Answer:
When you access your Page (Entries/Create) by typing or being redirected through a link, the browser request the page to the server using HTTP METHOD GET, which will invoke OnGet method. Afterwards, when you send your form (considering method="POST") the request will be sent to the server and be caught by the OnPost method.
When you code return Page(), it is not sending back a response to browser saying "Hey, you have to make a GET request again (what would make OnGet be called again)", it is returning the end response (html) itself. That´s why OnGet() is not being called. What would make the OnGet() be called again would be return RedirectToPage("./Entities/Create"), but doing so you would lose your Model state (validation result).
The two selects elements are being cleant because they are set up in OnGet() through ViewData (that is temporary) not in OnPost(). My suggestion is that you set the "selects" again on OnPost() (extract to a method to make it easier).
Regards.
You can simply call OnGet from your OnPost method, i.e.:
if (!ModelState.IsValid) {
return OnGet();
}
This works for me in ASP.NET Core 2.2 and preserves all validation errors.

MVC is it possible to target blank + parameters

See this :
#Html.ActionLink("link", "Func", new { controller = "MyControl" }, new { target = "_blank" })
It does what it is suposed to do, but what if i need my model, because here is the header of my function :
public ActionResult Func(model_1 m)
{ }
What i'm trying to do is open a new tab, and carry my model to this new tab... how can i do?
There is an overload of Html.ActionLink helper method which allows you to pass route values.
#Html.ActionLink("link", "Func", "MyControl" ,new { EmpId=1, EmpCode="E23" ,Age =23},
new { target = "_blank" })
This will basically generate an anchor tag with href value with querystring formed from the route values you provided.
link
Assuming you have a class with these 2 properties being used as the parameter of the action method
public class EmployeeVm
{
public int EmpId { set;get;}
public string EmpCode { set;get;}
public int Age{ set;get;}
}
and this is being used as the type of your action method argument
public ActoinResult Func(EmployeeVm model)
{
// To do : Return something
}
The model binder will be able to map the querystring values to the properties of the parameter object.
But remember, querystring's has limitations in how much data it can carry. Also the above approach work for a lean-flat view model class. It won't work for a complex viewmodel class where your properties are other classses /collection of other types.
In that case, The best solution is to pass a unique id / combination of Ids and use that to rebuild your model / view model in the second action method.
#Html.ActionLink("link", "Func", "MyControl" ,new { EmpId=1}, new { target = "_blank" })
and in your action method
public ActionResult Func(int empId)
{
// to do : Using empIdvalue, Get the View model /Model data
// Ex : EmployeeVm emp = SomeService.GetEmployeeFromId(empId)
}
Assuming SomeService.GetEmployeeFromId accepts an employeeId and return an object of EmployeeVm. The method can query your db table to get the corresponding employee record for the id passed in and build the EmployeeVm object from that data.

How would I pass a json object from a ActionMethod as a parameter to a different Action Method in MVC?

In My project i have two ActionResult Methods in my Controller. The first ActionResult method is retrieving a Json from an Ajax call.
ActionResult Method1 is something like this:....
public ActionResult VehicleModel(int id)
{
var vehicle = myService.VehicleModel(id);
myserviceService.Close();
return Json(new { model = vehicle }, JsonRequestBehavior.AllowGet);
}
ActionResult Method2
public ActionResult Vehicles(string id, string vehicle)
{
var _cat = _catalogue.Data.FirstOrDefault(x => x.manufacturerId == id && x.Vehicle == vehicle);
ViewData["id"] = id;
return PartialView("_vehicle", _cat);
}
Now .. I would i gain access to Method 1 in method 2? What i would to do is get the json returned in method (vehicle) and pass as a parameter in Method2.. I am not so sure on how i would go about in achieving this.. Please help.
Thank you
I hope that I understand you correctly.
If you want VehicleModel to send the data to Vehicles and continue from there, you should use this:
var jsonVehicle = Json(vehicle); //or whatever way you want to serialize your object to json
return RedirectToAction("Vehicles", new { id = this.id, vehicle = jsonVehicle});
This will redirect your action to Vehicles and will also bind the routing values.
For more information on RedirectToAction, read this.

Loading View with data upon reload error

I have a view which I load with product data. When I press the 'Add to Basket' button I'd like the same page to reload again but I'm getting errors such as:
Object reference not set to an instance of an object.
View:
#model List<Ecommerce.Models.HomeModels.Product>
#foreach (Ecommerce.Models.HomeModels.Product product in Model)
{ // above error points here!!!!!!!!!!!
using (Html.BeginForm())
{
<input type="hidden" name="productId" value="#product.ID" />
<input type="submit" value="Add to Basket"/>
}
}
Controller:
public ActionResult BuyProducts()
{
List<Models.HomeModels.Product> products = new List<Models.HomeModels.Product>();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
//Method to load data into products
}
}
TempData["products"] = products;
return View(products);
}
[HttpPost]
[AllowAnonymous]
public ActionResult BuyProducts(string productID)
{
string id = productID;
return View(TempData["products"]);
}
TempData only exists for one request, so it is gone by the time you try to send it back (Which is why you get the error - TempData["products"] is null). Either way, you should use the post redirect get pattern, like this:
[HttpPost]
[AllowAnonymous]
public ActionResult BuyProducts(string productID)
{
string id = productID;
return RedirectToAction("BuyProducts");
}
The main reason is that if the user refreshes the page and you returned a view from post, the data will be posted a second time causing duplication.
TempData isn't persisted across requests. You can either use Session or ViewData to save "products"
Try one of those and see if that fixes your issue.

Sending JSON object to the server via http GET

I am looking for sending JSON object to the server via GET.
Chris's answer on Post an Array of Objects via JSON to ASP.Net MVC3 works for the http POST but not for GET.
My case also works for POST but not for GET. What can I do to make GET work
Here is my case:
in Controller I have the following method
public ActionResult Screenreport(Screentable screendata)
{
// do something here
return View();
}
I have two ModelView as follows:
public class Screenrecord
{
public string Firstname{ get; set; }
public string Lastname{ get; set; }
}
public class Screentable
{
public List<Screenrecord> Screenlist { get; set; }
}
On the client side I generate JSON object
var Screentable = { Screenlist: screendata };
screendata is an array of Screenrecord
All this work when I use POST but when I use GET I am getting null value (screendata = null) Controllers' method.
In other word when click GO, screendata is null in Screenreport(Screentable screendata) routine.
Also, if I send one JSON object it works but if I send an array (list) like I described, it does not.
Is what I am trying to do doable?
No :-)
Thats not how get works.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
(see 9.3 GET)
"The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI"
Request-URI being the important part here. There is no concept of body data in a GET request.
Try changing method to public ActionResult Screenreport(HttpRequestMessage request)
Then use below code to get JSON object.
data = request.RequestUri.Query;
data = HttpUtility.ParseQueryString(data).Get("request");
Try this example in Javascript:
var someObject = {
id:123456,
message:"my message",
}
var objStr = JSON.stringify(someObject);
var escapedObjStr = encodeURIComponent(objStr);
var getUrlStr = "http://myserver:port?json="+escapedObjStr
and now you can forward this URL to your server. I know this is not in any .NET language but you can definitely find the equivalent methods used, or just use the JS right away.