Razor / Blazor page - form & validation without navigation - asp.net

I have a razor page with a form, this one is attached to a model.
At 'submit' time, I try to validate some data on the server-side, if it fails then I display a 'toast'.
The problem is that the form is 'refreshing' the page, it seems to navigate to himself!
Because of this, I cannot display my error in the toast because of this 'kind of refresh'.
index.cshtml
#model TestModel
<form method="post">
<button type="submit">GO</button>
</form>
TestModel.cs
public virtual async Task<IActionResult> OnPostAsync()
{
_toaster.ShowError("Hellow world", "I got an issue");
return Page();
}
Any idea to solve this ?

You should remove the Blazor tag. Your issue is with Razor Pages, not Blazor.
Do you see the code in the other answer. You should do something similar to what the EditForm does in Blazor. Generally speaking, you should use the JavaScript Fetch API to communicate with the server, without submitting your form the traditional way, the result of which is full refresh of the page. I've recommended
to use the Fetch API also because Blazor employs it to communicate with API end points on the server. But you may use jQuery instead... however, I do not recommend it. I do hope that by now you've realized that you should use AJAX, right ?
Incidentally, you may create Blazor components that implement such functionality,
and include them in your Razor Pages.
I think chris sainty has built a toast library in Blazor. It may help you.
I also think I saw a push notification sample by Daniel Wroth, demonstrated when creating a PWA in Blazor.
Hope this helps...

If you moved validation client-side, you could use an EditForm and use the DataAnnotationsValidator, for example;
<EditForm Model="#CurrentObject" OnValidSubmit="#HandleValidSubmit">
<DataAnnotationsValidator />
<div class="form-group">
<label for="Name">Name</label>
<InputText id="Name" class="form-control" #bind-Value="#CurrentObject.Name" />
<ValidationMessage For="#(() => CurrentObject.Name)" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</EditForm>
Where HandleValidSubmit would be your actual submission (create/update etc), #CurrentObject would be an instance of your model class, which in turn would be enriched with attributes from the System.ComponentModel.DataAnnotations namespace, eg;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace [YourNamespace].Data.Model
{
public class ExampleModel
{
// holds the front-end name for the record
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; } = "";
}
}
If you wanted to keep validation serverside, you can still use EditForms, and use the "HandleSubmit" method instead as detailed here; https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-3.1

Related

How to post to a Razor PageModel from partial view?

I'm building a website which has modal login and registrations forms.
The issue is when I'm trying to submit the form filled by the user, the OnPost of the corresponding razor models are not being called. I also tried using the Identity models as the models for the views and those are not being called as well.
Is there a way to do this correctly?
In your Partial view you need to point the form to the page which has the OnPost handle.
<form asp-page="/YourPage" method="post">
...inputs...
<button type="submit">Submit</button>
</form>
Make sure your OnPost accepts a a parameter of the view model like so:
OnPost(MyViewModel vm)
Realised you came after this question
Assuming you have the LoginViewModel as a property inside your razor page.
Instead of using
<partial name="_LoginPartial"
model='new LoginViewModel { InputModel = new InputModel() }' />
you want to use
<partial name="_LoginPartial" for='LoginViewModel' />

How secure the EntityId in hidden field for Editing Form in Asp.Net Core MVC?

I'd like to create the form for editing some Entity (for example a post) in the database using the Entity Framework Core.
I want to protect the value PostId in the hidden field before rewriting to another value from the browser. I'm wondering about checking the user permissions before updating but I want to create some encryption/signing or something like that.
How can I encrypt or sign the PostId and in the controller decrypt or validate it?
I've created the example form for editing the post like this:
Entity - Post:
public class Post
{
[Key]
public int PostId { get; set; }
[Required]
[StringLength(40)]
public string Title { get; set; }
}
Controller - PostsController with Edit method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("PostId,Title")] Post post)
{
if (ModelState.IsValid)
{
//Update method
}
return View(post);
}
Form for editing:
#model EFGetStarted.AspNetCore.NewDb.Models.Post
#{
ViewBag.Title = "Edit Post";
}
<h2>#ViewData["Title"]</h2>
<form asp-controller="Posts" asp-action="Edit" method="post" asp-antiforgery="true" class="form-horizontal" role="form">
<div class="form-horizontal">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="PostId" type="hidden" />
<div class="form-group">
<label asp-for="Title" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Edit" class="btn btn-default" />
</div>
</div>
</div>
</form>
By encrypting it you don't get any real business value and if the intent is so prevent one user to edit/modify posts he has no access to, you should do it in the backend by following the "Never trust the client" principle and always validate input on the server.
Easiest way to do is to use only the post ID from the model posted in and validate if the user has permissions to modify it. For this the new policy based systems offers resource based permissions which are well documented and can be used to validate the permissions.
Once done, passed take over the values and save the changes.
Also you shouldn't use persistence models inside the views, they easily break your API or your forms when the you change the database layout and navigation properties may cause issues (circular references etc.); especially later on, when lazy loading is implemented (lazy loading can't happen async as its inside a property, so the db call will block the thread).
Take a look at Sergey Akopov's blog post where he proposes a mechanism to deal with this scenario within ASP.NET MVC. His solution is to write a Html Helper that can be called within your view to generate a hidden input to accompany each input that you wish to make "tamper proof". This hidden input contains an encrypted copy of the value that you want to be tamper proof. When the form is posted, the server checks that the posted value and accompanying encrypted value still match - he writes a filter attribute which is applied to the corresponding controller action to perform this check. This adds an extra layer of "never trust the client" security.
Another example here has an interesting discussion (in the comments) around the potential security flaws inherent in this approach - The main one being that a determined attacker could "farm" valid combinations of secure field and encrypted value from their editing sessions, and subsequently use these farmed values to post tampered data with future edits.

Passing so far entered data to controller

In a form I have different fields (name, age, ...) and the possibility to upload an image. This I want to realize on a different view. The problem is that the data, that is made so far, are not passed to the controller when I want to change the controller. Here a small example of my code:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
#Html.EditorFor(model => model.Name)
#Html.EditorFor(model => model.Age)
<img src="#Url.Content(Model.ImagePath)" alt="Image" class="imagePreview" />
<li>
#Html.ActionLink("Upload a pic from you!", "UploadImage", new { model = Model }, null)
#* This is the 'problematic' action *#
</li>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Here the method that is calling the upload controller:
public ActionResult UploadImage(Person model)
{
// properties in the passed model are not set
return RedirectToAction("UploadImage", "UploadImage");
}
How it is possible to get the entered information without using the submit button?
Check out this blog post by Bryan Sampica on asynchronus file uploads with MVC. We just used it for a smooth async file upload experience so we didn't have to leave the page. This solves your problem of how to persist the transient data. If your users are using a modern browser (IE 10+, Chrome, FF, etc...) the progress bars actually show file upload progress. It's fairly easy to setup, but, if you follow the instructions to the letter, does require that you add a webAPI controller to your project.

More than one form in one view. Spring web flow + displaytag + checkbox

I have a table, using display tag, in my application, that is using spring web flow. I would like to have a check box in each row, a button that allows me to select/uselect all and a button to execute a function. After clicking the button, the action will perform some database actions and the page should be render, so we can see these changes.
I don´t know which could be the best option, submitting the whole table
<form method="POST" (more params)>
<display:table id="row">
....
</display:table>
</form>
Or only the checkbox column. I this case I wouldn´t know how to implement it.
I have tryed two different approaches:
1. Using a simple input text, checkbox type. This is not possible, because when I submit the form, I need to set a path to another page.jsp (I am working with flows). Besides, I wouldn´t know how to send these values to java backend.
Using spring tags.
In this case, the problem comes whith the class conversationAction
I found some examples, but allways using MVC and controller cases.
How could I implement this issue??
EDIT
I have found a kind of solution, but I faced a new problem...
flow.xml
var name="model1" class="com.project.Model1"/>
var name="model2" class="com.project.Model2"/>
view-state id="overview" model="formAggregation">
...
</view-state>
page.jsp
form:form modelAttribute="formAggregation.model1" id="overviewForm">
...
/form:form>
...
form:form method="POST" modelAttribute="formAggregation.model2">
display:table id="row" name="displayTagValueList" requestURI="overview?_eventId=tableAction">
display:column title="">
form:checkbox path="conversationIds" value="${row.threadId}"/>
/display:column>
/display:table>
input type="submit" name="_eventId_oneFunction" value="Send>>"/>
/form:form>
FormAggregation.java
#Component("formAggregation")
public class FormAggregation {
private Model1 model1;
private Model2 model2;
//Getters and setters
I need this aggregator, because I need both models. I have tested it one by one and it is working as wished. Any idea about that??
Thanks!!
I couldn´t find a solution to add two model in a view-state. So I made a workaround, adding the fields I needed to the model I was using, com.project.Model1. So the result is:
page.jsp
<form:form method="POST" id="tableForm" modelAttribute="model1">
<display:table id="row">
<display:column title="">
<form:checkbox path="chosenIds" value="${row.id}"/>
</display:column>
<display:footer>
<div class="tableFooter" >
<input type="submit" name="_eventId_workIds" value="Send"/>
</div>
</display:footer>
</display:table>
</form:form>
flow.xml
<var name="model1" class="com.project.Model1"/>
...
<transition on="workIds" to="overview" validate="false">
<evaluate expression="actionBean.workIds(model1.chosenIds)" />
</transition>
java class
public void workIds(List<Long> ids) {
Hope it helps

Formatting Controls in ASP.NET

I feel as though this this is a simple question, but can't find an answer anywhere. We've got an interface we're trying to move to an ASP.NET control. It currently looks like:
<link rel=""stylesheet"" type=""text/css"" href=""/Layout/CaptchaLayout.css"" />
<script type=""text/javascript"" src=""../../Scripts/vcaptcha_control.js""></script>
<div id="captcha_background">
<div id="captcha_loading_area">
<img id="captcha" src="#" alt="" />
</div>
<div id="vcaptcha_entry_container">
<input id="captcha_answer" type="text"/>
<input id="captcha_challenge" type="hidden"/>
<input id="captcha_publickey" type="hidden"/>
<input id="captcha_host" type="hidden"/>
</div>
<div id="captcha_logo_container"></div>
</div>
However all the examples I see of ASP.NET controls that allow for basical functionality - i.e.
public class MyControl : Panel
{
public MyControl()
{
}
protected override void OnInit(EventArgs e)
{
ScriptManager.RegisterScript( ... Google script, CSS, etc. ... );
TextBox txt = new TextBox();
txt.ID = "text1";
this.Controls.Add(txt);
CustomValidator vld = new CustomValidator();
vld.ControlToValidate = "text1";
vld.ID = "validator1";
this.Controls.Add(vld);
}
}
Don't allow for the detailed layout that we need. Any suggestions on how I can combine layout and functionality and still have a single ASP control we can drop in to pages? The ultimate goal is for users of the control to just drop in:
<captcha:CaptchaControl ID="CaptchaControl1"
runat="server"
Server="http://localhost:51947/"
/>
and see the working control.
Sorry for the basic nature of this one, any help is greatly appreciated.
Although you may want to look into user controls, the following page has an example of doing this using a web control. http://msdn.microsoft.com/en-us/library/3257x3ea.aspx The Render() method does the output of the actual HTML for the control.
There are a couple of ways to do it. You can make a custom control, or a user control. I think you will find it easier to do a user control. It lets you lay out parts of your control as you would a regular page. Here is some example documentation: http://msdn.microsoft.com/en-us/library/26db8ysc(VS.85).aspx
By contrast a custom control typically does all of the rendering in code (as your example you show). It is harder to make your first control in this way.

Resources