just started with Blazor created my first app its a CRUD app with api. But i get this huge error and i can't figure out what is wrong and what it actual means? think something with the api links? I've tried the Unhandled exception rendering component: '<' is an invalid start of a value for Blazor WASM solutions but none of these seems to work for me. I'm using the blazor webassembly in visualstudio 17.2.0 with entityframework.
When i start my project i get this message at the bottom of my page :
An unhandled error has occurred. Reload
blazor.webassembly.js:1 crit:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
System.Text.Json.JsonException: '<' is an invalid start of a value.
Path: $ | LineNumber: 0 | BytePositionInLine: 0. --->
System.Text.Json.JsonReaderException: '<' is an invalid start of a
value. LineNumber: 0 | BytePositionInLine: 0. at
System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader&
json, ExceptionResource resource, Byte nextByte, ReadOnlySpan1 bytes) at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker) at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first) at System.Text.Json.Utf8JsonReader.ReadSingleSegment() at System.Text.Json.Utf8JsonReader.Read() at System.Text.Json.Serialization.JsonConverter1[[System.Collections.Generic.List1[[TreviData.Shared.Models.Ewons, TreviData.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) --- End of inner exception stack trace --- at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, JsonReaderException ex) at System.Text.Json.Serialization.JsonConverter1[[System.Collections.Generic.List1[[TreviData.Shared.Models.Ewons, TreviData.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.JsonSerializer.ReadCore[List1](JsonConverter
jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options,
ReadStack& state) at
System.Text.Json.JsonSerializer.ReadCore[List1](JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan1 buffer,
JsonSerializerOptions options, ReadStack& state, JsonConverter
converterBase) at
System.Text.Json.JsonSerializer.ContinueDeserialize[List1](ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, JsonConverter converter, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.<ReadAllAsync>d__651[[System.Collections.Generic.List1[[TreviData.Shared.Models.Ewons, TreviData.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext() at System.Net.Http.Json.HttpContentJsonExtensions.<ReadFromJsonAsyncCore>d__41[[System.Collections.Generic.List1[[TreviData.Shared.Models.Ewons, TreviData.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext() at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__131[[System.Collections.Generic.List`1[[TreviData.Shared.Models.Ewons,
TreviData.Shared, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]], System.Private.CoreLib, Version=6.0.0.0,
Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext() at
TreviData.Client.Pages.EwonDetails.GetUser() in
C:\Users\toonw\source\repos\TreviData\TreviData\Client\Pages\EwonDetails.razor:line
73 at TreviData.Client.Pages.EwonDetails.OnInitializedAsync() in
C:\Users\toonw\source\repos\TreviData\TreviData\Client\Pages\EwonDetails.razor:line
69 at
Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at
Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task
taskToHandle, ComponentState owningComponentState)
window.Module.s.printErr # blazor.webassembly.js:1
Fe._internal.dotNetCriticalError # blazor.webassembly.js:1 St #
blazor.webassembly.js:1
_mono_wasm_invoke_js_blazor # dotnet.6.0.5.wc6fu8n2ms.js:1 $func219 # 00971e46:0x1a490 $func167 # 00971e46:0xce5e $func166 # 00971e46:0xbd71
$func2812 # 00971e46:0xabf01 $func1616 # 00971e46:0x6fcc2 $func1620 #
00971e46:0x7032f $mono_wasm_invoke_method # 00971e46:0x969d
Module._mono_wasm_invoke_method # dotnet.6.0.5.wc6fu8n2ms.js:1
managed_BINDINGS_SetTaskSourceResult #
managed_BINDINGS_SetTaskSourceResult:17 (anonymous) #
dotnet.6.0.5.wc6fu8n2ms.js:1 Promise.then (async)
_wrap_js_thenable_as_task # dotnet.6.0.5.wc6fu8n2ms.js:1
_js_to_mono_obj # dotnet.6.0.5.wc6fu8n2ms.js:1
_mono_wasm_invoke_js_with_args # dotnet.6.0.5.wc6fu8n2ms.js:1 $func219 # 00971e46:0x1a449 $func167 # 00971e46:0xce5e $func166 #
00971e46:0xbd71 $func2812 # 00971e46:0xabf01 $func1616 #
00971e46:0x6fcc2 $func1620 # 00971e46:0x7032f $mono_wasm_invoke_method
# 00971e46:0x969d Module._mono_wasm_invoke_method #
dotnet.6.0.5.wc6fu8n2ms.js:1 managed_BINDINGS_SetTaskSourceResult #
managed_BINDINGS_SetTaskSourceResult:17 (anonymous) #
dotnet.6.0.5.wc6fu8n2ms.js:1 Promise.then (async)
_wrap_js_thenable_as_task # dotnet.6.0.5.wc6fu8n2ms.js:1
_js_to_mono_obj # dotnet.6.0.5.wc6fu8n2ms.js:1
_mono_wasm_invoke_js_with_args # dotnet.6.0.5.wc6fu8n2ms.js:1 $func219 # 00971e46:0x1a449 $func167 # 00971e46:0xce5e $func166 #
00971e46:0xbd71 $func2812 # 00971e46:0xabf01 $func1616 #
00971e46:0x6fcc2 $func1614 # 00971e46:0x6fc34 $func967 #
00971e46:0x50685 $func219 # 00971e46:0x1a449 $func167 #
00971e46:0xce5e $func166 # 00971e46:0xbd71 $func2812 #
00971e46:0xabf01 $func1616 # 00971e46:0x6fcc2 $func1620 #
00971e46:0x7032f $mono_wasm_invoke_method # 00971e46:0x969d
Module._mono_wasm_invoke_method # dotnet.6.0.5.wc6fu8n2ms.js:1
managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet
#
managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet:19 beginInvokeDotNetFromJS # blazor.webassembly.js:1 b #
blazor.webassembly.js:1 e.invokeMethodAsync # blazor.webassembly.js:1
(anonymous) # blazor.webassembly.js:1 ve # blazor.webassembly.js:1 we
# blazor.webassembly.js:1 (anonymous) # blazor.webassembly.js:1
(anonymous) # blazor.webassembly.js:1 onGlobalEvent #
blazor.webassembly.js:1
Here is my code.
AddEwon.Razor
#page "/ewon/add/"
#page "/ewon/edit/{Id:int}"
#using TreviData.Shared.Models
#inject HttpClient Http
#inject NavigationManager NavigationManager
<h1>#Title Ewon</h1>
<hr />
<EditForm Model="#ewon" OnValidSubmit="SaveEwon">
<DataAnnotationsValidator />
<div class="mb-3">
<label for="Name" class="form-label">EwonName</label>
<div class="col-md-4">
<InputText class="form-control" #bind-Value="ewon.EwonName" />
</div>
<ValidationMessage For="#(() => ewon.EwonName)" />
</div>
<div class="mb-3">
<label for="Address" class="form-label">ApiKey</label>
<div class="col-md-4">
<InputText class="form-control" #bind-Value="ewon.ApiKey" />
</div>
<ValidationMessage For="#(() => ewon.ApiKey)" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Save</button>
<button class="btn btn-light" #onclick="Cancel">Cancel</button>
</div>
</EditForm>
#code {
[Parameter]
public int Id { get; set; }
protected string Title = "Add";
protected Ewons ewon = new();
protected override async Task OnParametersSetAsync()
{
if (Id != 0)
{
Title = "Edit";
ewon = await Http.GetFromJsonAsync<Ewons>("api/ewon/" + Id);
}
}
protected async Task SaveEwon()
{
if (ewon.Id != 0)
{
await Http.PutAsJsonAsync("api/ewon", ewon);
}
else
{
await Http.PostAsJsonAsync("api/ewon", ewon);
}
Cancel();
}
public void Cancel()
{
NavigationManager.NavigateTo("/fetchewondetails");
}
}
FetchData.Razor
#page "/ewondetails"
#using TreviData.Shared.Models
#inject HttpClient Http
<h1>Ewon Data</h1>
<p>Ewons api-keys.</p>
<div class="row">
<div class="col-md-6">
<a href='/ewon/add' class="btn btn-primary" role="button">
<i class="fas fa-ewon-plus"></i>
Add Ewon
</a>
</div>
<div class="input-group col">
<input type="text" class="form-control" placeholder="Search Ewon by name"
#bind="SearchString" #bind:event="oninput" #onkeyup="FilterUser" />
#if (SearchString.Length > 0)
{
<div class="input-group-append">
<button class="btn btn-danger" #onclick="ResetSearch">
<i class="fas fa-times"></i>
</button>
</div>
}
</div>
</div>
<br />
#if (ewonList == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table table-striped align-middle table-bordered">
<thead class="table-success">
<tr>
<th>Id</th>
<th>Ewon Name</th>
<th>Api key</th>
</tr>
</thead>
<tbody>
#foreach (var e in ewonList)
{
<tr>
<td>#e.Id</td>
<td>#e.EwonName</td>
<td>#e.ApiKey</td>
<td>
<a href='/ewon/edit/#e.Id' class="btn btn-outline-dark" role="button">
Edit
</a>
<a href='/ewon/delete/#e.Id' class="btn btn-outline-danger" role="button">
Delete
</a>
</td>
</tr>
}
</tbody>
</table>
}
#code {
protected List<Ewons> ewonList = new();
protected List<Ewons> searchEwonData = new();
protected Ewons ewon = new();
protected string SearchString { get; set; } = string.Empty;
protected override async Task OnInitializedAsync()
{
await GetUser();
}
protected async Task GetUser()
{
ewonList = await Http.GetFromJsonAsync<List<Ewons>>("api/ewon");
searchEwonData = ewonList;
}
protected void FilterUser()
{
if (!string.IsNullOrEmpty(SearchString))
{
ewonList = searchEwonData
.Where(x => x.EwonName.IndexOf(SearchString, StringComparison.OrdinalIgnoreCase) != -1)
.ToList();
}
else
{
ewonList = searchEwonData;
}
}
protected void DeleteConfirm(int Id)
{
ewon = ewonList.FirstOrDefault(x => x.Id == Id);
}
public void ResetSearch()
{
SearchString = string.Empty;
ewonList = searchEwonData;
}
}
EwonController
using TreviData.Server.InterFaces;
using TreviData.Shared.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace TreviData.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
private readonly IEwons _IEwons;
public UserController(IEwons iEwons)
{
_IEwons = iEwons;
}
[HttpGet]
public async Task<List<Ewons>> Get()
{
return await Task.FromResult(_IEwons.GetEwonDetails());
}
[HttpGet("{Id}")]
public IActionResult Get(int id)
{
Ewons ewon = _IEwons.GetEwonData(id);
if (ewon != null)
{
return Ok(ewon);
}
return NotFound();
}
[HttpPost]
public void Post(Ewons ewon)
{
_IEwons.AddEwon(ewon);
}
[HttpPut]
public void Put(Ewons ewons)
{
_IEwons.UpdateEwonDetails(ewons);
}
[HttpDelete("{Id}")]
public IActionResult Delete(int id)
{
_IEwons.DeleteEwon(id);
return Ok();
}
}
}
I'm pretty sure the error is in the GetFromJsonAsync call returning nothing - there's a lot of code to plough through!
You are calling api/ewon/, but your controller is defined as:
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
/....
which has the url "api/user".
So sort out your controller name or your calls.
You should always test your APIs with Postman!
I got this error but mine I had my controller name correct and I fixed it after I found out that "GetFromJsonAsync" of the HttpClient is case sensitive.
So if your controller is not routed explicitly, you might want to make it be exactly like the Controller name so the case will match what you pass as a string.
So this line will be
ewonList = await Http.GetFromJsonAsync<List>("api/Ewon");
Some other way might be configuring the Json options so serialization/Deserialization can be case insensitive.
builder.Services.Configure<JsonOptions>(options =>
{
options.SerializerOptions.PropertyNameCaseInsensitive = true;
});
Related
I have a method that I only use in one property where I upload photos so I only use the Photo property
I don't want to put the object as a parameter but a string that will be a replacement for the object and overwrite the Photo or in another way when using a Dto that fails to do gets null.
It's a function that works for me but I use the whole object as a parameter when I only use the PHOTO URL:
public async Task<string> UploadPhotos(IFormFile file, Product product)
{
string wwwPath = _environment.WebRootPath;
var path = Path.Combine(wwwPath, "images", file.FileName);
if (file.Length > 0)
{
using var stream = new FileStream(path, FileMode.Create);
await file.CopyToAsync(stream);
}
return product.PhotoUrl = file.FileName;
}
What I tried to do:
public async Task<string> UploadPhotos(IFormFile file, string photoUrl)
{
Product product = new()
{
PhotoUrl = photoUrl
};
string wwwPath = _environment.WebRootPath;
var path = Path.Combine(wwwPath, "images", file.FileName);
if (file.Length > 0)
{
using var stream = new FileStream(path, FileMode.Create);
await file.CopyToAsync(stream);
}
return product.PhotoUrl = file.FileName;
}
It doesn't work for me when I try to upload it doesn't show me the picture
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddProduct([FromForm] ProductViewModel model)
{
ModelState.Clear();
await _photoService.UploadPhotos(model.Photo,model.PhotoUrl);
if (ModelState.IsValid)
{
await _productRepository.AddProduct(model.Product!);
return RedirectToAction(nameof(Index));
}
return View();
}
ViewModel:
public class ProductViewModel
{
public Product Product { get; set; } = null!;
public string PhotoUrl { get; set; } = string.Empty;
public IFormFile Photo { get; set; } = null!;
}
View:
#model Solid_Project.Models.ProductViewModel
#{
ViewBag.Title = "AddProduct";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<article>
<section>
<form asp-action="AddProduct" enctype="multipart/form-data" method="post">
<div asp-validation-summary="ModelOnly"></div>
<div class="form-group">
<label asp-for="#Model.Product!.Name"></label>
<input asp-for="#Model.Product!.Name" class="form-control" placeholder="Enter Name" style="width:30%">
<span asp-validation-for="#Model.Product!.Name" class="validation"></span>
</div>
<br />
<div class="form-group">
<label asp-for="#Model.Product!.Description"></label>
<input asp-for="#Model.Product!.Description" class="form-control" placeholder="Enter Description" style="width:30%">
<span asp-validation-for="#Model.Product!.Description" class="validation"></span>
</div>
<br />
<div class="form-group">
<label asp-for="#Model.Product!.CategoryId"></label>
<div>
<select asp-for="#Model.Product!.CategoryId" asp-items="ViewBag.Category" style="width:30%" class="dropdown-toggle dropdown-toggle-design"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></select>
</div>
<span asp-validation-for="#Model.Product!.CategoryId" class="validation"></span>
</div>
<br />
<div class="form-group">
<label asp-for="#Model.Photo"></label>
<input type="file" asp-for="#Model.Photo" accept="image/*" class="form-control" style="width:30%" />
<span asp-validation-for="#Model.Photo" class="validation"></span>
</div>
<br />
<input type="submit" value="Create" class="btn btn-primary" />
</form>
</section>
</article>
#section Scripts {
#{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
I have to implement localization in an application in ASP.NET Core MVC 3.1. I am able to localize model validations and Views. However, I am unable to localize the Identity pages of model validation. To implement localization I have made changes in the startup.cs file as below:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; });
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-GB"),
new CultureInfo("da-DK")
};
options.DefaultRequestCulture = new RequestCulture("en-GB");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Clear();
options.RequestCultureProviders.Add(new LocalizationDemoCultureProvider());
});
services.AddDbContext<LocalizationDemoDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("LocalizationDemoDbContextConnection")));
services.AddDefaultIdentity<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
}).AddRoles<IdentityRole>()
.AddEntityFrameworkStores<LocalizationDemoDbContext>();
services.AddControllersWithViews()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
services.AddRazorPages().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseRequestLocalization(app.ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
My LocalizationDemoCultureProvider.cs class is as below:
public class LocalizationDemoCultureProvider : RequestCultureProvider
{
public override async Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
await Task.Yield();
CultureInfo cultureInfoToSet = null;
cultureInfoToSet = GetRequestCultureById(1); // The Id values come from database in the real application
if (cultureInfoToSet != null)
{
return new ProviderCultureResult(cultureInfoToSet.Name);
}
return null;
}
private CultureInfo GetRequestCultureById(int Id)
{
CultureInfo cultureInfo = null;
if (Id == 1)
{
cultureInfo = new CultureInfo("da-DK");
}
else if (Id == 2)
{
cultureInfo = new CultureInfo("en-GB");
}
return cultureInfo;
}
}
After this, I can get resource keys in Views with the help of IViewLocalizer. For instance in one of the views is Create.cshtml as below:
#inject Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer localizer
#model LocalizationDemo.Models.EmployeeViewModel
#{
ViewData["Title"] = "Create";
}
<h1>#localizer["EmployeeCreate"]</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Salary" class="control-label"></label>
<input asp-for="Salary" class="form-control" />
<span asp-validation-for="Salary" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DOB" class="control-label"></label>
<input asp-for="DOB" class="form-control" />
<span asp-validation-for="DOB" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">#localizer["BackToList"]</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
My EmployeeViewModel.cs is as below which add DataAnnotations:
public class EmployeeViewModel
{
[Required(ErrorMessage ="FirstNameErrorMessage")]
[Display(Name ="FirstName")]
public string FirstName { get; set; }
[Required(ErrorMessage = "LastNameErrorMessage")]
[Display(Name = "LastName")]
public string LastName { get; set; }
[Required(ErrorMessage = "SalaryErrorMessage")]
[Display(Name = "Salary"), DisplayFormat(DataFormatString = "{0:n}")]
public decimal Salary { get; set; }
[Required(ErrorMessage = "DOBErrorMessage")]
[Display(Name = "DOB"), DisplayFormat(DataFormatString = "{0:MMMM dd, yyyy}")]
public DateTime DOB { get; set; }
}
This works fine but when I add resource files for Identity pages according to the folder structure for Login page, the DataAnnotations doesn't work. I need some help because I am stucked here. Please help.
Sample EmployeeViewModel.resx file which is working fine.
Sample Login.resx which is not working.
Below is the folder structure with corresponding Resource files.
To make the Identity pages workable, there is a different pattern for the inner model.
For example, for the Login.cshtml, LoginModel has an inner model named as InputModel. So the resources file should be LoginModel+InputModel.resx. Resource files structure is now as below:
EDIT: So After many failed attempts to figure out why this is not working I decided to create a project and choose to have user login implemented from there so it will configure everything for me.
after that I just scraped the automated login/register code and replaced it with my own. everything works amazingly well. I am pretty sure in my original version I missed some needed parameter
I am trying to make a simple login function. but I cant seem to get it to work and it drives me crazy ..
so I do my shared folder under _layout.cshtml I have added this
#inject SignInManager<IdentityUser> signInManager;
and then just a little later inside my navbar I added this elements
<ul class="navbar-nav ml-auto">
#if (signInManager.IsSignedIn(User)) {
<li class="nav-item">
<form method="post" asp-controller="User" asp-action="Logout">
<button type="submit" class="nav-link btn btn-link py-0" style="width:auto">
Logout #User.Identity.Name
</button>
</form>
</li>
}
else {
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="User" asp-action="Register">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="User" asp-action="Login">Login</a>
</li>
}
</ul>
and in my controller I added this I called this controller UserController.cs
If I enter wrong login info . like wrong password or username it will tell me I that. so the connection with the database is no issue. but when I am send in my "Home" Index I am not logged it. as if it does not create a session I am not sure
[HttpGet]
public IActionResult Login()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Login(Login model)
{
if (ModelState.IsValid)
{
var result = await signInManager.PasswordSignInAsync(model.UserName,model.Password,
model.RememberMe,false);
if (result.Succeeded)
{
//creates a temponary sign in session cookie. that cookie is going to be lost after the browser is closed
return RedirectToAction("index", "home");
}
//if succeeded = false then ew llop through the error list
ModelState.AddModelError(string.Empty,"Invalid Login");
}
return View(model);
}
Here is the whole working demo like below:
View(Login.cshtml):
#using Microsoft.AspNetCore.Identity
#model LoginViewModel
#inject SignInManager<IdentityUser> SignInManager
#{
ViewData["Title"] = "Log in";
}
<h1>#ViewData["Title"].</h1>
<div class="row">
<div class="col-md-8">
<section>
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
<h4>Use a local account to log in.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<label asp-for="RememberMe">
<input asp-for="RememberMe" />
#Html.DisplayNameFor(m => m.RememberMe)
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Log in</button>
</div>
</div>
<p>
<a asp-action="Register" asp-route-returnurl="#ViewData["ReturnUrl"]">Register as a new user?</a>
</p>
<p>
<a asp-action="ForgotPassword">Forgot your password?</a>
</p>
</form>
</section>
</div>
<div class="col-md-4">
<section>
<h4>Use another service to log in.</h4>
<hr />
#{
var schemes = await SignInManager.GetExternalAuthenticationSchemesAsync();
var loginProviders = schemes.ToList();
if (loginProviders.Count == 0)
{
<div>
<p>
There are no external authentication services configured. See this article
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
<div>
<p>
#foreach (var provider in loginProviders)
{
<button type="submit" class="btn btn-default" name="provider" value="#provider.Name" title="Log in using your #provider.Name account">#provider.Name</button>
}
</p>
</div>
</form>
}
}
</section>
</div>
</div>
#section Scripts {
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
Controller:
[Authorize]
public class AccountController : Controller
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
public AccountController(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
// GET: /Account/Login
[HttpGet]
[AllowAnonymous]
public IActionResult Login()
{
return View();
}
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
return View(model);
}
}
DbContext:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options) { }
}
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentityCore<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();
services.AddAuthentication(o =>
{
o.DefaultScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies(o => { });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Result:
I have this simple login form (Razor Page)
File: Index.chstml
<form method="post">
<label asp-for="Username"></label><br />
<input asp-for="Username" /><br />
<label asp-for="Password"></label><br />
<input asp-for="Password" /><br />
<input type="submit" />
</form>
File: Index.cshtml.cs
public class IndexModel : PageModel
{
public Login Login { get; set; }
public ActionResult OnPost()
{
if(Login.Username.Equals("user") && Login.Password.Equals("123"))
{
RedirectToPage("./Secure/Home.cshtml");
}
else
{
return Page();
}
return Page();
}
}
When I put a breakpoint in OnPost, it doesn't reach there.
I want to send the form via AJAX and do its validation via fluentValidation in mvc core. Please guide me about this
Here is a working demo , you could refer to :
Add a reference to the FluentValidation.AspNetCore assembly by installing the appropriate NuGet package:
Install-Package FluentValidation.AspNetCore
Configure FluentValidation in your app’s Startup class by calling the AddFluentValidation extension method inside the ConfigureServices method , and use the AddFromAssemblyContaining method to automatically register all validators within a particular assembly
services.AddMvc()
.AddFluentValidation(fv => {
fv.RegisterValidatorsFromAssemblyContaining<PersonValidator>();
//If you want to disable this behaviour so that FluentValidation is the only validation library that executes,
//you can set the RunDefaultMvcValidationAfterFluentValidationExecutes to false in your application startup routine
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Assume that the PersonValidator is defined to validate a class called Person
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Id).NotNull();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}
Controller
[HttpPost]
public async Task<IActionResult> CreatPerson(Person person)
{
if (!ModelState.IsValid)
{ // re-render the view when validation failed.
return BadRequest();
}
//Save the person to the database, or some other logic
_context.Add(person);
await _context.SaveChangesAsync();
var message = "Person successfully created";
return Ok(message);
}
View and related jQuery
#model TestExample.Models.Person
<hr />
<div class="row">
<div class="col-md-4">
<form id="formdata">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Age" class="control-label"></label>
<input asp-for="Age" class="form-control" />
<span asp-validation-for="Age" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$("#formdata").submit(function (e) {
e.preventDefault();
var form = $(this);
$.ajax(
{
type: "post",
url: "/people/CreatPerson",
data: form.serialize(),
success: function (data) { alert(data); },
error: function (data) { alert(data); }
});
});
</script>
}
For more details on FluentValidation , you could refer to https://fluentvalidation.net/aspnet