.NET CORE_Blazor Cannot find Http.SendAsJsonAsync() - c#

Please I have trying to call my web API request in .Net Core Blazor project. I cannot seem to find Http.SendAsJsonAsync what I have is Http.SendAsAsync Please what do I need to do? Does this mean that in 3.1 we cannot use SendAsJsonAsync or am I missing out a particular reference?
Please find the image screenshot and code below.
The sample code is here:
#page "/counter"
#using BlazeCRUD.Models;
#using BlazeCRUD.Services;
#using System.Net.Http;
#inject HttpClient Http
#inherits OwningComponentBase<BlazeServices>
<h3><b>New Loan Application</b></h3>
<p></p>
<div class="row">
<div class="col-md-4">
<form>
<div class="form-group">
<label for="Name" class="control-label">Name</label>
<input for="Name" class="form-control" bind="" />
</div>
<div class="form-group">
<label asp-for="Department" class="control-label">Department</label>
<input asp-for="Department" class="form-control" bind="" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-default" onclick="">Save</button>
<button class="btn" onclick="">Cancel</button>
</div>
</form>
</div>
</div>
#code {
Performanceappuser pc = new Performanceappuser();
protected async Task AddLoanApplication()
{
await Http.
}
List<Performanceappuser> pau;
protected override void OnInitialized()
{
pau = Service.appUser();
}
}

Related

Why do I receive null values in my controller when I submit a form from a view with multiple forms? With ASP.NET Core 5 MVC

I am developing a web application using ASP.NET Core 5 MVC, in which I seek to make multiple submissions of POST type forms to my controller from a view that receives an IEnumerable (from a model called Result) with which I am filling in dynamically the values of the inputs of each form.
However, when I send one of those forms from the view through the controller, in the controller I only receive an object from the model with all the null or empty values, which tells me that it seems that this data was never sent through the form to my controller.
Is there a better way to accomplish this or how do I pass these values from multiple forms to my controller? In advance an apology if what I am doing is already totally wrong, I have been learning ASP.NET Core MVC for a few days.
CONSIDERATIONS
What I seek to achieve is that the user can enter multiple values that belong to the same model in the same view, since each form although it is the same seeks to update a different record or column in the same model or table, so when the submit of the form is sent to the Controller the view does not change, and only the records in the database are updated with each submit in the view. If there is a better way or correct way to do this, I am willing to change the logic, because as I mentioned, I have been using the Framework for little.
Explained the problem and my goal, I will explain in greater detail the flow and code mentioned:
From the Mechanical method of my controller, I return a list of Objects to their corresponding View, which are brought by a DataBaseContext:
// CONTROLLER() that passes an enumerable list of Objects to View Mechanical.cshtml
public IActionResult Mechanical()
{
IEnumerable<Result> objList = _db.Results;
return View(objList);
}
In the Mechanical() view, I get this list of objects and iterate over it through a forEach() loop, where for each object I create a form that directs to the same controller method called Update(), in which I get the values of the object in null and empty (that being my problem):
// VIEW
#model IEnumerable<FatForm.Models.Result>
#if (Model.Count() > 0)
{
#foreach(var result in Model)
{
<form method="post" asp-action="Update">
<input asp-for="#result.Id" hidden />
<input asp-for="#result.Type" hidden />
<input asp-for="#result.FatId" hidden />
<div class="border p-3">
<div class="form-group row">
<h2 class="text-black-50 pl-3">Edit Result</h2>
</div>
<div class="row">
<div class="col-12">
<div class="form-group row">
<div class="col-3">
<label asp-for="#result.Section"></label>
</div>
<div class="col-3">
<label asp-for="#result.Procedure"></label>
</div>
<div class="col-3">
<label asp-for="#result.ResultDescription"></label>
</div>
<div class="col-3">
<label asp-for="#result.Passed"></label>
</div>
</div>
<div class="form-group row">
<div class="col-3">
<input asp-for="#result.Section" class="form-control" />
</div>
<div class="col-3">
<input asp-for="#result.Procedure" class="form-control" />
</div>
<div class="col-3">
<input asp-for="#result.ResultDescription" class="form-control" />
<span asp-validation-for="#result.ResultDescription" class="text-danger"></span>
</div>
<div class="col-3">
<input asp-for="#result.Passed" class="form-control" />
<span asp-validation-for="#result.Passed" class="text-danger"></span>
</div>
</div>
<div class="form-group row">
<div class="col-8 offset-2 row">
<div class="col">
<input type="submit" class="btn btn-info w-75" value="Save" />
</div>
</div>
</div>
</div>
</div>
</div>
</form>
}
}
else
{
<p>No results created yet</p>
}
#section Scripts{
#{
<partial name="_ValidationScriptsPartial" />
}
}
I'm supposed to be looking to send the form values to the following Update() controller method, in which I get all the object values to null:
// POST Update
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update(Result obj)
{
if (ModelState.IsValid)
{
_db.Results.Update(obj);
_db.SaveChanges();
//return RedirectToAction("Index");
}
return View(obj);
}
As I explained at the beginning, I hope can help me by indicating what I am doing wrong or in what way I should do it. Thanks in advance for your help.
Model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.In your code,the asp-for tag helper will generate the name like:result.propertyName.It could not match with backend model. You need use [Bind(Prefix ="result")] to specify the prefix:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update([Bind(Prefix ="result")]Result obj)
{
//do your stuff...
}
As for receive IEnumerable parameter in action, firstly you need change your razor view to move the form outside the foreach loop, then you need change the asp-for tag helper tattribute to #Model.ToList()[index].PropertyName:
#model IEnumerable<Result>
#if (Model.Count() > 0)
{
<form method="post" asp-action="Update">
#for (int i = 0; i < Model.Count(); i++)
{
<input asp-for="#Model.ToList()[i].Id" hidden />
<input asp-for="#Model.ToList()[i].Type" hidden />
<input asp-for="#Model.ToList()[i].FatId" hidden />
<div class="border p-3">
<div class="form-group row">
<h2 class="text-black-50 pl-3">Edit Result</h2>
</div>
<div class="row">
<div class="col-12">
<div class="form-group row">
<div class="col-3">
<label asp-for="#Model.ToList()[i].Section"></label>
</div>
<div class="col-3">
<label asp-for="#Model.ToList()[i].Procedure"></label>
</div>
<div class="col-3">
<label asp-for="#Model.ToList()[i].ResultDescription"></label>
</div>
<div class="col-3">
<label asp-for="#Model.ToList()[i].Passed"></label>
</div>
</div>
<div class="form-group row">
<div class="col-3">
<input asp-for="#Model.ToList()[i].Section" class="form-control" />
</div>
<div class="col-3">
<input asp-for="#Model.ToList()[i].Procedure" class="form-control" />
</div>
<div class="col-3">
<input asp-for="#Model.ToList()[i].ResultDescription" class="form-control" />
<span asp-validation-for="#Model.ToList()[i].ResultDescription" class="text-danger"></span>
</div>
<div class="col-3">
<input asp-for="#Model.ToList()[i].Passed" class="form-control" />
<span asp-validation-for="#Model.ToList()[i].Passed" class="text-danger"></span>
</div>
</div>
</div>
</div>
</div>
}
<div class="form-group row">
<div class="col-8 offset-2 row">
<div class="col">
<input type="submit" class="btn btn-info w-75" value="Save" />
</div>
</div>
</div>
</form>
}
else
{
<p>No results created yet</p>
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Update(IEnumerable<Result> obj)
{
return View("Mechanical", obj);
}
Result:
Here you need to add FromBody attribute in your action method parameter.
public IActionResult Update([FromBody]Result obj)
{
.....
}

Is is any way to show errors in the corresponding form?

I have an ASP.NET Core 3.1 Razor Pages application.
It is quite simple when it is only one form on a page, but how correctly show the errors when there are few forms?
Example:
/ManageUser.cshtml
<div>
<form method="post">
<div class="validation-summary-valid text-danger" asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="OldPassword"></label>
<input asp-for="OldPassword" class="form-control" />
</div>
<div class="form-group">
<label asp-for="NewPassword1"></label>
<input asp-for="NewPassword1" class="form-control" />
</div>
<div class="form-group">
<label asp-for="NewPassword2"></label>
<input asp-for="NewPassword2" class="form-control" />
</div>
<button type="submit" class="btn btn-primary" asp-page-handler="ChangePassword">Change password</button>
</form>
</div>
<!-- let's say it is the other "tab" -->
<div>
<form method="post">
<div class="validation-summary-valid text-danger" asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="ChangeEmail"></label>
<input asp-for="ChangeEmail" class="form-control" />
</div>
<button type="submit" class="btn btn-primary" asp-page-handler="ChangeEmail">Change email</button>
</form>
</div>
And, if on the backend side any error is found:
public async Task<IActionResult> OnPostChangeEmailAsync([FromService] UserManager<User> userManager)
{
//... skipped for brevity
ModelState.AddModelError("", "User not found or deleted");
return Page();
}
then this error is shown for both forms. Any way to show it for corresponding form only?
PS: Please do not propose to make the errors field-bound: it is not the case and the fields in the example is just for the simplicity.
Taking field validation as an example, you can try the following code.
View:
<div>
<form method="post">
<span class="text-danger">#Html.ValidationMessage("PasswordError")</span>
<div class="form-group">
<label asp-for="UserModel.OldPassword"></label>
<input asp-for="UserModel.OldPassword" class="form-control" />
<span asp-validation-for="UserModel.OldPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UserModel.NewPassword1"></label>
<input asp-for="UserModel.NewPassword1" class="form-control" />
<span asp-validation-for="UserModel.NewPassword1" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="UserModel.NewPassword2"></label>
<input asp-for="UserModel.NewPassword2" class="form-control" />
<span asp-validation-for="UserModel.NewPassword2" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary" asp-page-handler="ChangePassword">Change password</button>
</form>
</div>
<div>
<form method="post">
<span class="text-danger">#Html.ValidationMessage("EmailError")</span>
<div class="form-group">
<label asp-for="UserModel.ChangeEmail"></label>
<input asp-for="UserModel.ChangeEmail" class="form-control" />
<span asp-validation-for="UserModel.ChangeEmail" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary" asp-page-handler="ChangeEmail">Change email</button>
</form>
</div>
The backend side(you can remove the attributes):
public async Task<IActionResult> OnPostChangeEmailAsync(UserModel userModel)
{
if (!ModelState.IsValid)
{
ModelState.Remove("UserModel.OldPassword");
ModelState.Remove("UserModel.NewPassword1");
ModelState.Remove("UserModel.NewPassword2");
ModelState.AddModelError("EmailError", "User not found or deleted");
}
return Page();
}
public async Task<IActionResult> OnPostChangePassword(UserModel userModel)
{
if (!ModelState.IsValid)
{
ModelState.Remove("UserModel.ChangeEmail");
ModelState.AddModelError("PasswordError", "Password is inconsistent ");
}
return Page();
}
Result:

ASP.NET Core MVC post form data not bind using identity loginmodel?

I am using ASP.NET Core MVC with identity but I want to perform my own logic on login. So, what I did is I scaffolded the login page and make my own design.
Here is my form:
#page
#model LoginModel
#{
ViewData["Title"] = "Login";
}
<div class="login-page cnt-bg-photo overview-bgi" style="background-image:
url('#Url.Content("~/assets/img/banner-1.jpg")')">
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="forgot-box contact-2 clearfix">
<div class="login-header clearfix">
<div class="pull-left">
<h4>Login</h4>
</div>
</div>
<!-- <div role="alert"
class="alert alert-danger font-12">
<strong>Oops!!</strong> Invalid Email or Password
</div>-->
<p>Please enter your user name and password to login</p>
<form action="/Account/Login" method="POST">
<div class="form-group">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group w-46-f float-left">
<div class="form-check checkbox-theme pull-left">
<div class="checkbox">
<label asp-for="Input.RememberMe">
<input asp-for="Input.RememberMe" />
#Html.DisplayNameFor(m => m.Input.RememberMe)
</label>
</div>
</div>
</div>
<div class="form-group float-right">
<label class="pull-right forgotpassword-label">Forgot Password ?</label>
</div>
<div class="clearfix"></div>
<button type="submit" class="btn btn-color btn-md pull-right">Login</button>
</form>
<div class="clearfix"></div>
<div class="text-center p-t-46 p-b-20 font-14">
<span class="txt2">
Or Login with
</span>
</div>
<div class="login100-form-social flex-c-m">
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="#Model.ReturnUrl" method="post">
#foreach (var provider in Model.ExternalLogins)
{
if (provider.DisplayName == "Google")
{
<button type="submit" class="btn login100-form-social-item flex-c-m bg3 m-r-5" style="display: inline-block" name="provider" value="#provider.Name" title="Log in using your #provider.DisplayName account"><i class="fab fa-google"></i></button>
}
else if (provider.DisplayName == "Facebook")
{
<button type="submit" class="btn login100-form-social-item flex-c-m bg1 m-r-5" style="display: inline-block" name="provider" value="#provider.Name" title="Log in using your #provider.DisplayName account"> <i class="fab fa-facebook-f"></i></button>
}
else if (provider.DisplayName == "Twitter")
{
<button type="submit" class="btn login100-form-social-item flex-c-m bg2 m-r-5" style="display: inline-block" name="provider" value="#provider.Name" title="Log in using your #provider.DisplayName account"> <i class="fab fa-twitter"></i></button>
}
}
</form>
</div>
<hr>
<div class="text-center forgotpassword-label font-14">
Not a member?
<a href="#Url.Action("Packages","Account")">
<strong>Sign up now</strong>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Now I want to post the login data to my own controller action. But it get null on my action method. Parameters are not filled with actual data of the form.
Here is my controller method:
[HttpPost]
public IActionResult Login(LoginModel.InputModel model)
{
//My logic
return View();
}
Why does it get model parameter as null?
Well, specifically, the source of it being null is the fact that in the Razor Page, all the input names begin with Input. because for the code-behind, the model being bound to is LoginModel and the data in those inputs will be bound to the InputModel property (Input) there. However, in your controller, you're binding directly to InputModel, and InputModel has no Input member. As a result, none of the posted inputs match anything and are therefore not bound.
If you're going to post from a Razor Page, you need to do it to a Razor Page. There's just too many inconsistencies between Razor Pages and MVC to line everything up correctly. If you you want to use a controller, you're going to need a view specifically geared for that, not your Razor Page.

Using Tag helpers; calling scripts

I'm a newbie with asp.net core & tag helpers. I'm trying to use an example from the web to auto-populate the city / state from the zip code. The example works for me if I use the web example straight up. However, when I switched to tag helpers it stopped hitting the script.
Here's my code:
$(document).ready(function() {
//when the user clicks off of the zip field:
$('#zip').keyup(function() {
alert("here");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<form asp-action="NewGroup" method="post">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label asp-for="Zip"></label>
<input id="zip" asp-for="Zip" class="form-control" />
</div>
<div class="form-group">
<label asp-for="City"></label>
<div id="city_wrap">
<input id="city" asp-for="City" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="State"></label>
<input id="state" asp-for="State" class="form-control" />
</div>
</div>
</div>
</form>
</div>

pass textbox value as parameter to controller route

I'm trying to use a textbox value in controller route and am having some trouble with the syntax. Essentially, I have my end users selecting a file and then submitting the data to the api to process and send the data off. I have working static code below, but can't get the xml path to be dynamically populated via the textbox value.
note that (as far as I can tell) the forward slash at the end of the path is required since there is a dot in the file path.
#using (Html.BeginForm("", "api/food/dummy food file.xml/"))
{
<div class="row">
<div class="col-lg-6">
<label class="control-label">Select File</label>
<div class="input-group">
<label class="input-group-btn">
<span class="btn btn-default">
Browse… <input type="file" style="display: none;" single>
</span>
</label>
<input id="food.filepath" name="food.filepath" type="text" class="form-control" readonly>
</div>
</div>
</div>
<br />
<div>
<button id = "btnSubmit" type="submit" class="btn btn-primary">Submit</button>
</div>
}
I don't what the syntax would be, but I can't get something like the below to work.
#using (Html.BeginForm("", "api/food/" + food.filepath + "/"))
{
<div class="row">
<div class="col-lg-6">
<label class="control-label">Select File</label>
<div class="input-group">
<label class="input-group-btn">
<span class="btn btn-default">
Browse… <input type="file" style="display: none;" single>
</span>
</label>
<input id="food.filepath" name="food.filepath" type="text" class="form-control" readonly>
</div>
</div>
</div>
<br />
<div>
<button id = "btnSubmit" type="submit" class="btn btn-primary">Submit</button>
</div>
}
Because the form is rendered on server and the value food.filepath is on client, you cannot mix them. Changing form action according to client values need to be done on client with javascript.
You can remove the file from action a add it on submit javascript action, for example by changing BeginForm to this:
#using (Html.BeginForm("", "api/food/", FormMethod.Get, new { onSubmit = "this.dataset.act = this.dataset.act||this.action; this.action = this.dataset.act + this['food.filepath'].value" } ))

Categories