_ManageNav doesn't work after add my own Identity class - c#

I used Identity in .NET Core 2.1. MVC app and I have one problem. As long as I used build-in class IdentityUser, my _ManageNav works good: when I clicked on UserName, on the left side of my application I saw ManageNav menu. But I must implicate my own class, because I must have list for users:
public class MyAppUser : IdentityUser
{
public ICollection<Recipe> Recipes { get; set; }
}
Of course I change in Startup information about class:
services.AddIdentity<MyAppUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
Also add a mail sender, because I had error with this:
services.AddTransient<IEmailSender, MyAppMailSender>();
My _ManaveNav is practically build-in, I didn't have to change anything because first I wanted configure my own class, this is my _ManageNav:
#inject SignInManager<IdentityUser> SignInManager
#{
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<div class="menu-left">
<ul class="nav nav-pills nav-stacked">
<li class="#ManageNavPages.IndexNavClass(ViewContext)"><a asp-page="./Index">Profile</a></li>
<li class="#ManageNavPages.ChangePasswordNavClass(ViewContext)"><a id="change-password" asp-page="./ChangePassword">Password</a></li>
#if (hasExternalLogins)
{
<li class="#ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a id="external-login" asp-page="./ExternalLogins">External logins</a></li>
}
<li class="#ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)"><a asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
<li class="#ManageNavPages.PersonalDataNavClass(ViewContext)"><a asp-page="./PersonalData">Personal data</a></li>
</ul>
</div>
I tried with IdentityUser or MyAppUser in first line (#inject), but always I have default menu, which I have normal in app. My Identity layout:
#{
Layout = "/Areas/Identity/Pages/_Layout.cshtml"; }
<h2>Manage your account</h2>
<partial name="_MenuTop" />
<div class="all">
<partial name="_ManageNav" />
<div class="content">
#RenderBody()
</div>
<partial name="_MenuRight" />
<div class="clearfix"></div>
</div>
#section Scripts {
#RenderSection("Scripts", required: false)
}
Maybe one of You have this problem in Your app? I think ManageNav and Layout is OK, because on version where I use IdentityUser ManageNav works great.
Best regards,
Kamil

I assume, you should use your custom class here:
#inject SignInManager<MyAppUser> SignInManager
instead of:
#inject SignInManager<IdentityUser> SignInManager

Add _ViewStart.cshtml file in the Areas/Identity/Pages/Account/Manage folder with the following content:
#{
Layout = "_Layout";
}

Related

How do you pass additional data from a razor page to a partial view and the back-end in .net core?

I have been relying on this web tutorial: Ajax Partial Page Updates in Razor
In this tutorial I have done something to match this partial view:
#page
#model RazorPagesTests.Pages.AjaxPartialModel
<h2>Ajax</h2>
<p><button class="btn btn-primary" id="load">Load</button></p>
<div id="grid"></div>
#section scripts{
<script>
$(function () {
$('#load').on('click', function () {
$('#grid').load('/ajaxpartial?handler=CarPartial');
});
});
</script>
}
The main Razor page has this included and works fine:
#page
#model RazorPagesTests.Pages.AjaxPartialModel
<h2>Ajax</h2>
<p><button class="btn btn-primary" id="load">Load</button></p>
<div id="grid"></div>
#section scripts{
<script>
document.getElementById('load').addEventListener('click', () => {
fetch('/ajaxpartial?handler=CarPartial')
.then((response) => {
return response.text();
})
.then((result) => {
document.getElementById('grid').innerHTML = result;
});
});
</script>
}
Then in the main .cs page of the app, I do something like this:
public PartialViewResult OnGetCarPartial()
{
Cars = _carService.GetAll();
return Partial("_CarPartial", Cars);
}
However, I see that the examples above pass a model to the partial view and the Ajax Fetch API passes only a handler in the URL to the base page.
Questions
How do I pass an int and string values to the base page based on user data?
Can you add ajax/Fetch API calls in the base razor app that apply to things that have been updated in the UI of the partial view?

Why does validation in ASP.NET Core Razor Pages doesn't accept empty inputs?

I am learning how to code in ASP.NET Core Razor Pages and am working on validation right now. Both in client side and server side validation no input is allowed to be empty even though I am not using the [Required] data annotation and I am looking for a solution to that. The C# code of the page is below:
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
[BindProperty]
public int number { get; set; }
public void OnGet()
{
}
public IActionResult OnPost()
{
if(!ModelState.IsValid)
{
return Page();
}
Console.WriteLine("It works.");
return Page();
}
}
The HTML code of this page is below:
<form method="post">
<label asp-for="#Model.number">Number: </label><br />
<input asp-for="#Model.number" />
<span asp-validation-for="#Model.number" class="text-danger"></span>
<br /><br />
<button class="btn btn-primary" type="submit">Submit</button>
</form>
#section Scripts
{
}
Inside the Scripts section I use partial to load the Validation Scripts Partial. It just won't load there as code for some reason when I paste it there.
It is only a simple code that is meant to take one integer from the user as I am just trying to get it to accept an empty value. I am using .NET 6.0 and Visual Studio Community Edition 2022. Does anyone know a solution to that problem?
Because the int type does not accept null value, to solve your problem, change the code as follows To accept the amount of null as well
[BindProperty]
public int? number { get; set; }

Navigate from one Razor page to another Razor page with button click?

Is there a better way to navigate from one Razor page to different Razor page when a button is clicked. I want to navigate from Index.cshtml to Inventory.cshtml when the button is clicked.
Below is the current solution that I have managed use that works, but I am not sure if this is correct way. Reference used: https://www.jetbrains.com/dotnet/guide/tutorials/basics/razor-pages/
Index.cshtml
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<!--Page redirect-->
<form method="post" asp-page="Index">
<button type="submit" class="btn btn-cta">View Inventory</button>
</form>
Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace TheInventory.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
//Page redirect on button form submit
public IActionResult OnPost()
{
return RedirectToPage("Inventory");
}
}
}
Inventory.cshtml
#page
#model TheInventory.Pages.InventoryModel
#{
ViewData["Title"] = "Inventory";
}
<h1>#ViewData["Title"]</h1>
<p>This is the Inventory Page</p>
To solve my problem I used the asp-page attribute with Razor Pages and set an anchor tag's href attribute value to the specific page.
Reference used: asp.net core anchor tag helper - Razor pages
<a asp-page="/PageExample">Page Example</a>
I wrapped the anchor tag element in the button element and was able to navigate to the specified page when the button was clicked.
Here is an snippet of my code:
<button type="button" class="btn btn-cta"><a asp-page="/Inventory">Manage Inventory</a></button>

Can't trigger Controller from anchor in .Net Core Razor

I'm trying to implement logout function but it won't trigger the controller cause i tried to debug it. I never used mvc before though so i can't really tell what is wrong in this.
this controller is inside Controllers folder
[Authorize]
public class AccountController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpGet]
public async Task<IActionResult> LogOut()
{
Request.HttpContext.Session.Remove("Nome");
await HttpContext.SignOutAsync();
return RedirectToPage("/Login");
}
}
and this razor view for trigger
#using Microsoft.AspNetCore.Http
#{
<aside class="control-sidebar control-sidebar-dark">
<!-- Control sidebar content goes here -->
<div class="p-3">
<div class="row py-2">
<div class="col-sm-12">
<img src="/Images/default-profile.png" class="img-circle elevation-2" width="50" alt="User Image" />
</div>
</div>
<div class="row py-2">
<div class="col-sm-12">
<h5>
#Context.Session.GetString("Nome")
</h5>
</div>
</div>
<div class="row py-2">
<div class="col-sm-12 custom-hiddenbar-link">
<a asp-action="LogOut" asp-controller="Controllers/Account" class="text-white">
<div class="row">
<div class="col-sm-2">
<i class="fas fa-sign-out-alt ml-2"></i>
</div>
<div class="col-sm-10">
Terminar Sessão
</div>
</div>
</a>
</div>
</div>
</div>
</aside>
}
what is wrong in this code?
Ok I found the answer. Needed to add this on startup
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});

Form in Layout: Razor Pages

I have a select in a form in the Layout of my web app that needs to be accessible from every page. The form sets a session variable that is required to load data on every page.
<form asp-page-handler="CustomerChange" method="post" class="navbar-form navbar-left">
<select name="Customer" id="Customer" class="form-control" onchange="this.form.submit()">
<option value="">Select Customer</option>
<option value="Vand">Vandalay</option>
<option value="Kram">Kramerica</option>
</select>
</form>
I know I can make a base PageModel and inherit from that on every page in order to respond to a OnPost e.g.
public abstract class BaseSecurePageModel : PageModel
{
[BindProperty]
public string Customer { get; set; }
public virtual void OnPostCustomerChange()
{
HttpContext.Session.SetString("Customer", Customer);
}
}
but this doesn't lend itself to having the model binded to the form and also requires that I remember to inherit from the base class in every page. Is there a correct way to handle forms that need to be available everywhere?
Try using a Controller instead and have your CustomerChange ActionResult specify a [Route()]. I use a Controller for most of my Layout items such as shopping carts, localization etc... in razor pages and works pretty well.
// Updated answer based on feedback from Steven B.
Below is an example of the localization I spoke about above. The form triggers a post against the SetLanguage method in the BaseController.cs
In the _Layout.cshtml file I have, in this instance, a partial view:
#Html.Partial("_SetLanguagePartial") // Used prior to .net core 2.1
<partial name="_SetLanguagePartial" /> // Used for .net core 2.1+
The html inside this _SetLanguagePartial.cshtml contains a form with the corresponding asp-controller and asp-action
<form id="selectLanguage" asp-controller="Base" asp-action="SetLanguage" asp-route-returnUrl="#returnUrl" method="post" class="form-horizontal" role="form">
<ul class="list-inline">
#foreach (var culture in cultureItems)
{
var countryIcon = "usa.png";
<li>
<button type="submit" class="btn btn-sm btn-link" name="culture" title="#culture.Text" value="#culture.Value">
#switch (culture.Text)
{
case "Japanese" :
countryIcon = "japan.png";
break;
case "Spanish" :
countryIcon = "spain.png";
break;
default:
break;
}
<img src="#Configuration["BlobStorage:StorageUrl"]/images/#countryIcon" alt="#culture.Text"/>
</button>
</li>
}
</ul>
</form>
BaseController.cs
[Route("[controller]/[action]")]
public class BaseController : Controller
{
[HttpGet]
public IActionResult GetCartViewComponent()
{
return ViewComponent("Cart");
}
[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1)}
);
return LocalRedirect(returnUrl);
}
}

Categories

Resources