Razor Pages asp-page-handler OnPostcustom doesn't fired - razor-pages

I wrote asp.net razor pages web app.
On the page/form there are few controls that I want to distinct during the post.
Unfortunatly I failed to define custom handler, its always fired thruogh the default OnPost .
on the page:
<form method="post">
<button type="submit" class="btn btn-default" asp-route-data="2" asp-page-handler="custom">Start test 2</button>
</form>
in the module:
public void OnPost()
{
ViewData["confirmation"] = $"from OnPost";
}
public void OnPostcustom(string data)
{
ViewData["confirmation"] = $"from OnPostcustom";//never reach this line
}
what is my fault? according to the documentation it should be a very basic procedure.

There is a problem with the name of custom handler: handler mechanism of razor pages doesn't recognize the name if it starts with a not capital letter.
i.e OnPostcustom will never be used, while OnPostCustom will succeed

Related

Call BYOF from Blazor WASM in Azure Static Web App

I have a well functioning Azure Function App running multiple http triggered functions that provide JSON payloads.
I am trying to call a specific function from my Blazor WASM hosted on Azure Static Web App. I have linked the Function App to the Static Web App and all functions are visible in the Static Web App.
The Function App name displayed in the Static Web Apps Functions blade is my-existing-function-appand in the name list all functions are formatted: my-existing-function-app/GetMyStuff, my-existing-function-app/SetMyStuff, etc
The original uri for the function looks like this: https://my-existing-function-app.azurewebsites.net/api/GetMyStuff?code=ASDFkt5346345ywSDGSTy45734gowjgwWERT==. Calling that endpoint delivers my data as expected.
In my Blazor App I can activate the original endpoint when debugging locally by running this line: mystuff = await Http.GetFromJsonAsync<MyStuff[]>('https://my-existing-function-app.azurewebsites.net/api/GetMyStuff?code=ASDFkt5346345ywSDGSTy45734gowjgwWERT==');
My Static Web App url looks like this: https://red-sea-123.azurestaticapps.net
I have followed the documentation found here: https://learn.microsoft.com/en-us/azure/static-web-apps/functions-bring-your-own
According to the documentation it is a bit unclear, what I should write here: mystuff = await Http.GetFromJsonAsync<MyStuff[]>(HERE)
I have tried different variations like 'api/GetMyStuff', 'my-existing-function-app/GetMyStuff' and 'my-existing-function-app/api/GetMyStuff', but none of them get access to the endpoint. It is clear from the browsers developer console, that i get some error page back.
How should I construct the HERE string in my call?
Please check if the below steps for adding the await Http GetFromJsonAsync Method in the Blazor App and helps to workaround:
According to the documentation it is a bit unclear, what I should write here: mystuff = await Http.GetFromJsonAsync<MyStuff[]>(HERE)
Here is an article contains about the calling Azure Function App from the Blazor WASM.
This is the code where you have to include your await Http GetFromJsonAsync operation in the razor app:
#page "/covidfaq"
#inject HttpClient Http
<div class="d-flex justify-content-center">
<img src="../Images/COVID_banner.jpg" alt="Image" style="width:80%; height:300px" />
</div>
<br />
<div class="d-flex justify-content-center">
<h1>Frequently asked Questions on Covid-19</h1>
</div>
<hr />
#if (questionList == null)
{
<p><em>Loading...</em></p>
}
else
{
#foreach (var question in questionList)
{
<div class="card">
<h3 class="card-header">
#question.Question
</h3>
<div class="card-body">
<p class="card-text">#question.Answer</p>
</div>
</div>
<br />
}
}
#code {
private FAQ[] questionList;
protected override async Task OnInitializedAsync()
{
questionList = await Http.GetFromJsonAsync<FAQ[]>("https://faqfunctionapp20200611160123.azurewebsites.net/api/covidFAQ");
}
public class FAQ
{
public string Id { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
}
}
Inside the OnInitializedAsync method, the Azure Function app API Endpoint is hitting and the returned data stored in questionList array type variable.
Please visit the above article for more information.

Laravel Request does not return the modified request on validation fail

I have recently updated my controllers to use Requests to validate data before saving, originally I used $request->validate() within the controller route, but I am now at a stage where I really need to seperate it out in to a request.
Issue
Before validation takes place, I need to alter some of the parameters in the request, I found out this can be done using the prepareForValidation() method, and this works great, during validation the values in the request have been altered. My issue comes if the validation fails. I need to be able to return the request I've altered back to the view, at the moment, after redirection it appears to be using the request as it was before I ran prepareForValidation(). (i.e. returns title as 'ABCDEFG' instead of 'Changed The Title').
After some reading on other SO posts and Laravel forum posts, it looks as though I need to overwrite the FormRequest::failedValidation() method (which I've done, see code below), however I'm still struggling to find a way to pass my altered request back. I've tried to edit the failedValidation() method, I've provided details further down.
Expectation vs Reality
Expectation
User enters 'ABCDEFG' as the title and presses save.
The title is altered in the request (using prepareForValidation()) to be 'Changed The Title'.
Validation fails and the user is redirected back to the create page.
The contents of the title field is now `Changed The Title'.
Reality
User enters 'ABCDEFG' as the title and presses save.
The title is altered in the request (using prepareForValidation()) to be 'Changed The Title'.
Validation fails and the user is redirected back to the create page.
The contents of the title field shows `ABCDEFG'.
What I've tried
Passing the request over to the ValidationException class.
After digging through the code, it looks as though ValidationException allows a response to be passed over as a parameter.
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator, $this))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
However this results in the error Call to undefined method Symfony\Component\HttpFoundation\HeaderBag::setCookie() in Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::addCookieToResponse.
Flashing the request to the session
My next attempt was to just flash my request to the session, this doesn't seem to work, instead of my modified request being in the session, it looks to be the request before I ran prepareForValidation().
protected function failedValidation(Validator $validator)
{
$this->flash();
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
Returning a response instead of an exception
My final attempt to get this to work was to return a response using withInput() instead of the exception.
protected function failedValidation(Validator $validator)
{
return redirect($this->getRedirectUrl())
->withErrors($validator)
->withInput();
}
However it looks as though the code continues in to the BlogPostController::store() method instead of redirecting back to the view.
At this point I'm out of ideas, I just can't seem to get the altered request back to the view if validation fails!
Other Notes
I am pretty much a Laravel newbie, I have experience with a custom framework loosely based on Laravel, but this is my first CMS project.
I fully understand I may well be going down the wrong route, perhaps there's a better way of altering a request and passing it back when validation fails?
What am I trying to achieve by doing this? The main thing is the active checkbox. By default it is checked (See the blade below), if the user unchecks it and presses save, active is not passed over in the HTTP request, therefore active does not exist in the Laravel request object and when the user is returned back, the active checkbox has been checked again when it shouldn't be.
Then why have you used title in your example? I am using title in my post because I think it's easier to see what I am trying to achieve.
Any help is apreciated as I've currently burnt quite a few hours trying to solve this. 😣
Related Code
BlogPostController.php
<?php
namespace App\Http\Controllers;
use App\BlogPost;
use Illuminate\Http\Request;
use App\Http\Requests\StoreBlogPost;
class BlogPostController extends Controller
{
/**
* Run the auth middleware to make sure the user is authorised.
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('admin.blog-posts.create');
}
/**
* Store a newly created resource in storage.
*
* #param StoreBlogPost $request
* #return \Illuminate\Http\Response
*/
public function store(StoreBlogPost $request)
{
$blogPost = BlogPost::create($request->all());
// Deal with the listing image upload if we have one.
foreach ($request->input('listing_image', []) as $file) {
$blogPost->addMedia(storage_path(getenv('DROPZONE_TEMP_DIRECTORY') . $file))->toMediaCollection('listing_image');
}
// Deal with the main image upload if we have one.
foreach ($request->input('main_image', []) as $file) {
$blogPost->addMedia(storage_path(getenv('DROPZONE_TEMP_DIRECTORY') . $file))->toMediaCollection('main_image');
}
return redirect()->route('blog-posts.edit', $blogPost->id)
->with('success', 'The blog post was successfully created.');
}
}
// Removed unrelated controller methods.
StoreBlogPost.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;
class StoreBlogPost extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'title' => 'required',
'url' => 'required',
'description' => 'required',
'content' => 'required',
];
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'title.required' => 'The Title is required',
'url.required' => 'The URL is required',
'description.required' => 'The Description is required',
'content.required' => 'The Content is required',
];
}
/**
* Prepare the data for validation.
*
* #return void
*/
protected function prepareForValidation()
{
$this->merge([
'active' => $this->active ?? 0,
'title' => 'Changed The Title',
]);
}
/**
* #see FormRequest
*/
protected function failedValidation(Validator $validator)
{
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
}
create.blade.php
#extends('admin.layouts.app')
#section('content')
<div class="edit">
<form action="{{ route('blog-posts.store') }}" method="POST" enctype="multipart/form-data">
#method('POST')
#csrf
<div class="container-fluid">
<div class="row menu-bar">
<div class="col">
<h1>Create a new Blog Post</h1>
</div>
<div class="col text-right">
<div class="btn-group" role="group" aria-label="Basic example">
<a href="{{ route('blog-posts.index') }}" class="btn btn-return">
<i class="fas fa-fw fa-chevron-left"></i>
Back
</a>
<button type="submit" class="btn btn-save">
<i class="fas fa-fw fa-save"></i>
Save
</button>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="form-group row">
<label for="content" class="col-12 col-xl-2 text-xl-right col-form-label">Active</label>
<div class="col-12 col-xl-10">
<div class="custom-control custom-switch active-switch">
<input type="checkbox" name="active" value="1" id="active" class="custom-control-input" {{ old('active', '1') ? 'checked' : '' }}>
<label class="custom-control-label" for="active"></label>
</div>
</div>
</div>
<div class="form-group row">
<label for="title" class="col-12 col-xl-2 text-xl-right col-form-label required">Title</label>
<div class="col-12 col-xl-10">
<input type="text" name="title" id="title" class="form-control" value="{{ old('title', '') }}">
</div>
</div>
</div>
</form>
</div>
#endsection
I had the same issue and here is the solution I found after digging through laravel code.
It seems that Laravel creates a different object for the FormRequest, so you can do something like this.
protected function failedValidation(Validator $validator)
{
// Merge the modified inputs to the global request.
request()->merge($this->input());
parent::failedValidation($validator);
}

.net core 2.0 Razor pages VS 2017 Tabular data download

I am new to web development with Razor pages .net core VS 2017.
I have index page that lists my data in the form of rows & columns using EF core Model.
I am also providing data filtering options via DropDowns and search box.
I want to export this tabular filtered/unfiltered data to excel. --- For which i think i can use NPOI nuget package (http://www.talkingdotnet.com/import-export-excel-asp-net-core-2-razor-pages/).
I want to do this using asp-page-handler with button click.
Questions:
1. Will this be GET request or POST ?
How to pass data (e.g. model object with all data) to the page handler ?
Any help is Appreciated.
Thanks.
For your first question about using GET or POST, both methods can be used but I personally use the POST method for cases like this.
For your second question I would not send to server all the filtered data but I would pass the filtering information which will be used in order to generate the data and export them to an Excel file.
Update 1
I made a simple example for you. Type the following html in your cshtml file:
<form method="post">
<button type="submit" class="btn btn-info"> Export</button>
<input asp-for="Value1" type="hidden" value="1" />
<input asp-for="Value2" type="hidden" value="2" />
</form>
The two inputs will be used in order to submit to the server values which will be used in order to filter your data. The following OnPost will return a static file but you can write your own code in order to return the filtered data and return them to the browser.
[BindProperty]
public int Value1 { get; set; }
[BindProperty]
public int Value2 { get; set; }
public ActionResult OnPost()
{
// example of returning a file
return File("~/Images/accounts.png", "image/png", "FileNameForBrowser.png");
}
Thanks #pitaridis for your valuable inputs.
i ended up doing like this:
` <a asp-page="./Index" asp-page-handler="Export"
asp-route-param1 = "#Model.data1"
asp-route-param2 = "#Model.data2"
asp-route-param3 = "#Model.data3"
class="btn btn-info">
Export
</a>
`
Page handler is OnGetExportAsync(...).On handler call I am getting page refresh, Not sure Why I have to again repopulate all the controls. Any idea on this ?
or other option could be to use the OnGetAsync() method & by passing a param that identify it as file download ?

Update #Html.Partial() View only

I am not looking for a javascript/jquery answer. I can do that, but I feel like it breaks the purpose. This seems like something that should be possible without javascript.
I'm trying to get a simple listbox selection to update an #Html.Partial section, and I'm not exactly sure what to do. Everything loads initially just fine. After I submit, however, I am not quite sure how to 'attach' to my partial view to update it.
The purpose here is to only load the listbox one time, and let them view or request as many new reports as they want without reloading. If it's not possible, that's fine, I can use one page, reload the listboxes, and it will work. I just don't see why I would need to go to the database to reload the listbox items every time they view or request a report.
"master" html page:
#using TCTReports.Models
#model ReportViewModel
<h2>My Reports</h2>
<div class="row">
<div class="col-md-6">
<h3>Select Report</h3>
#using (Html.BeginForm("GetReport", "Report"))
{
#Html.DropDownListFor(m => m.SelectedMyID, Model.myLB)
<input type="submit" value="View" />
}
</div>
<div class="col-md-6">
<h3>All Reports</h3>
#using (Html.BeginForm("ReqReport", "Report"))
{
#Html.DropDownListFor(m => m.SelectedAllID, Model.allLB)
<input type="submit" value="View" />
}
</div>
</div>
#Html.Partial("_Msg")
_Msg is super simple atm. It would eventually be a report viewer, for now, it looks at #Viewbag...
<h2>#ViewBag.Message</h2>
Controller submit actions (I get my selected value just fine. currently on void but was ActionResult with Views - but I don't feel like that is correct either, as it completely overwrites the page (even with PartialView) and I lose my listboxes and _layout...):
public void GetReport(ReportViewModel model)
{
var myID = model.SelectedMyID;
ViewBag.Message = "Report: " + myID.ToString() + " Selected.";
//return PartialView("_Msg","Test");
}
public void ReqReport(ReportViewModel model)
{
var allID = model.SelectedAllID;
ViewBag.Message = "Report: " + allID.ToString() + " Requested.";
//return PartialView("_Msg", "Test");
}
Ok, so how would I go about updating _Msg and refreshing only the #Html.PartialView() section of my master html page? I played with #sections briefly but didn't make much progress.

Submit Html form with a specific model

I am using MVC, Razor, Knockout, typescript in my application. Need to prepare a excel file with a model/dataset that is set at client side. I am using the following code but the problem i understand is that the dataset is being taken as string and not exactly like the model it is supposed to take as. Here is the code
This is observable (dataset)
vmExportData = ko.observableArray<ExcelModel>([]);
Push data to the dataset
vmExportData.push(new ExcelModel (
e.sender.data()[i].Id,
e.sender.data()[i].Name,
e.sender.data()[i].Address1,
));
Html code, to prepare excel file (at the controller)
#using (Html.BeginForm("ExportToExcel", "MyController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div data-bind="css:{hidden: true}">
<input type="text" data-bind="value: vmExportData" />
</div>
<input class='excelIcon' type="submit" data-ux-access="true" value="">
}
Controller method :
public ActionResult ExportToExcel(ExportModel exportModel)
{
The problem is, the exportModel parameter value is coming as null ! Any other way out to get it to work ? Is there a way to make excel at client side and render as well ?
Try setting name="exportModel" on your tag.
Also make sure to have an [HttpPost] on top of your controller action, since your form method is post.
What does the ExportModel class look like?

Resources