ASP.NET Core localize .cs file in Razor Pages - asp.net-core

There is a project on ASP.NET 5.0 with Identity.
Need help in how to translate messages in .cs files Razor Page.
Startup.cs looks like that
namespace localizeTest
{
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.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix).AddDataAnnotationsLocalization();
services.Configure<RequestLocalizationOptions>(
opt =>
{
var suppoortedCulteres = new List<CultureInfo>
{
new CultureInfo("ru"),
new CultureInfo("en")
};
opt.DefaultRequestCulture = new RequestCulture("ru");
opt.SupportedCultures = suppoortedCulteres;
opt.SupportedUICultures = suppoortedCulteres;
}
);
services.AddDNTCaptcha(options =>
{
options.UseCookieStorageProvider();
});
string connection = Configuration["ConnectionStrings:DefaultConnection"];
ServerVersion vesrion = ServerVersion.AutoDetect(connection);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(connection, vesrion));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// 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();
app.UseMigrationsEndPoint();
}
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.UseRequestLocalization(app.ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
In the Resources folder created two files:
/Areas/Identity/Pages/Account/Login.en.resx
/Areas/Identity/Pages/Account/Login.ru.resx
Sample page
Areas/Identity/Pages/Account/Login.cshtml
#page
#model LoginModel
#inject Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer localizer
#{
ViewData["Title"] = localizer["Login"];
}
<div class="container">
<div class="row h-100">
<div class="col-12 col-md-10 mx-auto my-auto">
<div class="card auth-card">
<div class="card-body">
<h1 class="mb-4">#ViewData["Title"]</h1>
<h4 class="pb-2">#localizer["Welcome"]</h4>
<form id="account" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email">#localizer["Email"]</label>
<input asp-for="Input.Email" class="form-control" placeholder="#localizer["YourEmail"]" required="">
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.Password">#localizer["Password"]</label>
<input asp-for="Input.Password" class="form-control" placeholder="#localizer["YourPassword"]" required="">
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input class="custom-control-input" asp-for="Input.RememberMe">
<label class="custom-control-label" asp-for="Input.RememberMe">#localizer["RememberMe"]</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">#localizer["SignIn"]</button>
</div>
<div class="form-group">
<p>
<a id="forgot-password" asp-page="./ForgotPassword">#localizer["ForgotPass"]</a>
</p>
<p>
<a asp-page="./Register" asp-route-returnUrl="#Model.ReturnUrl">#localizer["ЗарегестрироватьсяКакНовый"]</a>
</p>
<p>
<a id="resend-confirmation" asp-page="./ResendEmailConfirmation">#localizer["EmailConf"]</a>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Good, localize in Page View work it!
But, localize in Page Model not work.
File Areas/Identity/Pages/Account/Login.cshtml.cs
namespace localizeTest.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class LoginModel : PageModel
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<LoginModel> _logger;
private readonly IStringLocalizer<LoginModel> _stringLocalizer;
public LoginModel(SignInManager<IdentityUser> signInManager,
ILogger<LoginModel> logger,
UserManager<IdentityUser> userManager,
IStringLocalizer<LoginModel> stringLocalizer)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_stringLocalizer = stringLocalizer;
}
[BindProperty]
public InputModel Input { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
public string ReturnUrl { get; set; }
[TempData]
public string ErrorMessage { get; set; }
public class InputModel
{
[Display(Name = "Email")]
[Required(ErrorMessage = "{0} is required")]
[EmailAddress]
public string Email { get; set; }
[Display(Name = "Password")]
[Required(ErrorMessage = "{0} is required")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "RememberMe")]
public bool RememberMe { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
returnUrl ??= Url.Content("~/Books/List");
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/Books/List");
string WrongLoggin = _stringLocalizer["НеВерныйЛогин"].Value;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return LocalRedirect(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToPage("./Lockout");
}
else
{
ModelState.AddModelError(string.Empty, WrongLoggin);
return Page();
}
}
// If we got this far, something failed, redisplay form
return Page();
}
}
}
How to translate text in .cs files, how to make it work?
[Display(Name = "How Translate With Text?")]
[Required(ErrorMessage = "How {0} Translate with Text?")]
Img Login Ru
Img Login En
I tried examples as for pages of controllers.
Created resources with the name LoginModel+InnerModel.en.resx and LoginModel+InnerModel.ru.resx.
But it did't give results.
P.S. Sorry for Google translate, but i need help.
P.S.2. Localization made on the example of this video

First you need to add AddDataAnnotationsLocalization in your Stratup,
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddRazorPages().AddDataAnnotationsLocalization();
Then you need to name your resource file like
Areas.Identity.Pages.Account.LoginModel+InputModel.en-US.resx
For any nested model in LoginModel, you need to use + instead of .
For the details you can see the doc:
DataAnnotations localization.

Related

Validation Context is always NULL

I have implemented a custom validation attribute to check column uniqueness. I want to check if the provided value already exists in the database or not.
Here is my code:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class UniqueAttribute : ValidationAttribute
{
public UniqueAttribute()
{
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return ValidationResult.Success;
}
}
the validationContext in IsValid method always returns null. How it can be fixed?
Startup.cs : ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.AddApiVersioning(o =>
{
o.ReportApiVersions = true;
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1, 0);
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddScoped<IClaimsTransformation, ClaimsTransformation>();
RegisterRepository(services);
RegisterServices(services);
RegisterAutoMapper(services);
services.AddControllersWithViews()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// 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();
app.UseMigrationsEndPoint();
}
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();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
Model class :
public class Category
{
[Unique]
public string Name { get; set; }
public string Description { get; set; }
}
Below is an example to check if the provided value already exists in the database or not, you can refer to it.
UniqueAttribute:
public class UniqueAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
var context = (MvcMovieContext)validationContext.GetService(typeof(MvcMovieContext));//change the MvcMovieContext to your DbContext
if (!context.Movie.Any(a => a.Company == value.ToString()))
{
return ValidationResult.Success;
}
return new ValidationResult("Company exists");
}
}
Movie:
public class Movie
{
[Unique]
public string Company { get; set; }
}
Create view:
#model MvcMovie.Models.Movie
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<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="Company" class="control-label"></label>
<input asp-for="Company" class="form-control" />
<span asp-validation-for="Company" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
result:

Properties set to null when OnPost handler is called in razor page

I have a page with 2 buttons each one with their handler methods (OnPostAsync and OnPostResend) and 2 properties (LoginType and DocumentNumber) when OnPostAsync is called, properties have their values and the method works as expected but when the second button is clicked and OnPostResend is called properties are set to null. Why is this happenning and how can I prevent it?
This is the .cshtml file:
#page
#model SATCloudWebApp.Areas.Identity.Pages.Account.EnterOtpModel
#{
ViewData["Title"] = $"Ingrese el código de confirmación";
string device = TempData["PhoneNumber"]
}
}
<h2>#ViewData["Title"]</h2>
<div class="row">
<div class="col-md-6">
<h4>Por favor digite el código enviado a su #device. </h4>
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.OtpCode"></label>
<input asp-for="Input.OtpCode" class="form-control" />
<span asp-validation-for="Input.OtpCode" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-info">Siguiente</button>
</form>
<href>
<form asp-page-handler="resend" method="post">
<button id="resendToken" type="submit" class="btn btn-dark">Reenviar código</button>
</form>
</href>
</div>
</div>
This is the page model:
namespace Name
{
[AllowAnonymous]
public class EnterOtpModel : PageModel
{
// constructor goes here ...
[BindProperty]
public string LoginType { get; set; }
[BindProperty]
public string DocumentNumber { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[Required(ErrorMessage = "Ingrese el código enviado.")]
[Display(Name = "Código de inicio de sesión")]
public string OtpCode { get; set; }
}
public IActionResult OnGet(string loginType, string documentNumber)
{
if (User.Identity.IsAuthenticated)
{
return RedirectToPage("~/LoginWithOtp");
}
else
{
LoginType = loginType;
List<SATCloudUser> _users = new List<SATCloudUser>();
_users = _userManager.Users.Where(x => x.DocumentNumber == documentNumber).ToList();
SATCloudUser _satUser = _users[0];
TempData["Username"] = _satUser.Email;
TempData["PhoneNumber"] = _satUser.PhoneNumber;
return Page();
}
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
List<SATCloudUser> _users = new List<SATCloudUser>();
_users = _userManager.Users.Where(x => x.DocumentNumber == DocumentNumber).ToList();
SATCloudUser _satUser = _users[0];
if (ModelState.IsValid)
{
var result = await _userManager.VerifyTwoFactorTokenAsync(_satUser, "Email", Input.OtpCode);
if (result)
{
returnUrl = returnUrl ?? Url.Content("~/Home/Index");
var auth = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
var authenticationMethod = auth?.Principal?.FindFirstValue(ClaimTypes.AuthenticationMethod);
await _signInManager.SignInAsync(_satUser, false, authenticationMethod);
return LocalRedirect(returnUrl);
}
else
{
TempData["Username"] = _satUser.Email;
TempData["PhoneNumber"] = _satUser.PhoneNumber;
TempData["messageEnterOtp"] = "InvalidToken";
return Page();
}
}
else
{
return Page();
}
}
public async void OnPostResendAsync()
{
List<SATCloudUser> _users = new List<SATCloudUser>();
_users = _userManager.Users.Where(x => x.DocumentNumber == DocumentNumber).ToList();
SATCloudUser _satUser = _users[0];
var token = await _userManager.GenerateTwoFactorTokenAsync(_satUser, "Email");
if(LoginType == "sms")
{
AlertsManager _alertManager = new AlertsManager();
string phoneNumber = "+57" + _satUser.PhoneNumber;
string message = $"Código de inicio de sesión en Better Together SE: {token}. Por favor no comparta este código.";
await _alertManager.SendTextMessageAsync(phoneNumber, message);
}
else if(LoginType == "email")
{
EmailManager _emailManager = new EmailManager();
await _emailManager.NewTokenEmail(_satUser.Email, token);
}
}
}
}
A new instance of the EnterOtpModel class is created for each request. So the state of its properties is not preserved between different requests. You can add hidden input elements inside the resend form so that LoginType and DocumentNumber are re-sent again to the EnterOtpModel.
<form asp-page-handler="resend" method="post">
<input type="hidden" asp-for="LoginType" />
<input type="hidden" asp-for="DocumentNumber" />
<button id="resendToken" type="submit" class="btn btn-dark">Reenviar código</button>
</form>

Cannot update user Identity Role from list in razor page

I have a razor page which shows checkbox of Roles. The Roles owned by the selected user will be checked on page load. What I'm trying to do is, I want to be able to edit the roles for the selected user. But when I click update, it doesn't update.
Here is the razor page:
<EditForm Model="#RoleDto" OnValidSubmit="#EditRole">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="card">
<div class="card-header">
<h2>Manage User Roles</h2>
Add/Remove Roles for User / #UserFullname
</div>
<div class="card-body">
#for (int i = 0; i < numOfRoles; i++)
{
<div class="form-check m-1">
<input type="hidden" value="#RoleListModel[i].Id" />
<input type="hidden" value="#RoleListModel[i].Name" />
<input type="checkbox" checked="#RoleListModel[i].Selected" /> #RoleListModel[i].Name
</div>
}
</div>
</div>
<button type="submit" class="btn btn-success btn-block">
Confirm
</button>
#code {
ApplicationRoleDto RoleDto = new ApplicationRoleDto();
private List<ApplicationRoleDto> RoleListModel;
[Parameter] public string Id { get; set; }
[Parameter] public ApplicationUserDto UserDto { get; set; }
[Parameter] public string UserFullname { get; set; }
[Parameter] public int numOfRoles { get; set; }
protected async override Task OnParametersSetAsync()
{
UserDto = await _client.GetFromJsonAsync<ApplicationUserDto>($"api/userroles/{Id}");
UserFullname = UserDto.FullName;
RoleListModel = await _client.GetFromJsonAsync<List<ApplicationRoleDto>>($"api/rolemanager/{Id}");
numOfRoles = RoleListModel.Count();
}
async Task EditRole()
{
await _client.PostAsJsonAsync($"api/rolemanager/{Id}", RoleListModel);
_navManager.NavigateTo($"/userroles/");
}
}
and here is the controller:
[HttpPost]
public async Task<IActionResult> Manage(List<ApplicationRoleDto> model, string Id)
{
var user = await _userManager.FindByIdAsync(Id);
if (user == null)
{
NotFound();
}
var roles = await _userManager.GetRolesAsync(user);
var result = await _userManager.RemoveFromRolesAsync(user, roles);
if (!result.Succeeded)
{
Console.WriteLine("Cannot remove user existing roles");
return NotFound();
}
result = await _userManager.AddToRolesAsync(user, model.Where(x => x.Selected).Select(y => y.Name));
if (!result.Succeeded)
{
Console.WriteLine("Cannot add selected roles to user");
return NotFound();
}
return NoContent();
}
Did I miss anything here?

Asp.net core Identity multiple roles to user

I am working on asp.net core 3.1 project. There are several types of users in project. For example :
Some of users type
Admin
writer
Manager
Accountants
Operator
and ...
Users type are different and may increase or decrease. We may have 20 writers or 100 operators users in this project that all writers or all operators have same roles.
Now i can set roles to user manually. But i want to set a bunch of roles to users.
For example if user type was operator all roles depends on operator set to user.
I create a simple demo which you could choose UserType when you register a user. And assign all related roles of the UserType to user.
1.Models:
public class ApplicationUser : IdentityUser
{
[ForeignKey("UserType")]
public int UserTypeId {get;set;}
public UserType UserType { get; set; }
}
public class UserType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<ApplicationUser> Users { get; set; }
public List<ApplicationRole> Roles { get; set; }
}
public class ApplicationRole : IdentityRole
{
[ForeignKey("UserType")]
public int? UserTypeId {get;set;}
public UserType UserType { get; set; }
}
2.DbContext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<UserType> UserTypes { get; set; }
public DbSet<ApplicationRole> AppRoles { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>()
.HasOne(c => c.UserType)
.WithMany(u=>u.Users)
.OnDelete(DeleteBehavior.Restrict);
}
}
3.Register.cshtml.cs
public class InputModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public int UserTypeId { get; set; }
}
public async Task OnGetAsync(string returnUrl = null)
{
ViewData["UserType"] = new SelectList(_context.UserTypes, "Id", "Name");
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email, UserTypeId = Input.UserTypeId };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
//add bunch of roles to user
var roles = _context.AppRoles.Where(r => r.UserTypeId == user.UserTypeId).Select(r => r.Name).ToList();
foreach(var role in roles)
{
await _userManager.AddToRoleAsync(user, role);
}
//...
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
4.Register.cshtml
<form asp-route-returnUrl="#Model.ReturnUrl" method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<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">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Input.UserTypeId"></label>
<select asp-for="Input.UserTypeId" asp-items="#ViewBag.UserType" class="form-control"></select>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
4.Startup.cs
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();

Simple Role Manager and authorization In ASP.NET MVC 5 without using Identity(CustomRoleProvider)

Custom Role Provider and authorization without using Identity in ASP.NET MVC 5
Here is the Roles Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace SN.Helios.Portal.Controllers
{
[Authorize(Roles = "Admin")]
public class RolesController : Controller
{
// GET: Roles
public ActionResult Index()
{
var context = new ApplicationDbContext();
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr =>
new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
ViewBag.Message = "";
return View();
}
// GET: /Roles/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Roles/Create
[HttpPost]
public ActionResult Create(Role role)
{
try
{
var context = new ApplicationDbContext();
context.Roles.Add(role);
context.SaveChanges();
ViewBag.Message = "Role created successfully !";
return RedirectToAction("Index");
}
catch
{
return View();
}
}
public ActionResult Delete(string RoleName)
{
var context = new ApplicationDbContext();
var thisRole = context.Roles.Where(r => r.RoleName.Equals(RoleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
context.Roles.Remove(thisRole);
context.SaveChanges();
return RedirectToAction("Index");
}
//
// GET: /Roles/Edit/5
public ActionResult Edit(string roleName)
{
var context = new ApplicationDbContext();
var thisRole = context.Roles.Where(r => r.RoleName.Equals(roleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
return View(thisRole);
}
//
// POST: /Roles/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Role role)
{
try
{
var context = new ApplicationDbContext();
context.Entry(role).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
// Adding Roles to a user
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RoleAddToUser(string UserName, string RoleName)
{
var context = new ApplicationDbContext();
if (context == null)
{
throw new ArgumentNullException("context", "Context must not be null.");
}
Employee user = context.Employees.Where(u => u.FullName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
Role role = context.Roles.Where(u => u.RoleName.Equals(RoleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
AssignUserRole assignUserRole = new AssignUserRole
{
EmployeeId = user.EmployeeID,
RoleId = role.RoleID
};
var EmpRoleToAdd = (from emprole in context.AssignUserRoles
where emprole.EmployeeId == user.EmployeeID && emprole.RoleId == role.RoleID
select emprole).FirstOrDefault();
if (EmpRoleToAdd == null)
{
context.AssignUserRoles.Add(assignUserRole);
context.SaveChanges();
ViewBag.Message = "Role created successfully !";
}
else
{
ViewBag.Message = " This Role already exists for this user !";
}
// Repopulate Dropdown Lists
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr => new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
return View("Index");
}
//Getting a List of Roles for a User
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult GetRoles(string UserName)
{
if (!string.IsNullOrWhiteSpace(UserName))
{
var context = new ApplicationDbContext();
Employee user = context.Employees.Where(u => u.FullName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var roles = user.AssignUserRoles.Select(u => u.Role).Select(u => u.RoleName).ToArray();
ViewBag.RolesForThisUser = roles;
// Repopulate Dropdown Lists
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr => new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
ViewBag.Message = "Roles retrieved successfully !";
}
return View("Index");
}
//Deleting a User from A Role
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DeleteRoleForUser(string UserName, string RoleName)
{
var context = new ApplicationDbContext();
Employee user = context.Employees.Where(u => u.FullName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
Role role = context.Roles.Where(u => u.RoleName.Equals(RoleName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var EmpRoleToDelete = (from emprole in context.AssignUserRoles
where emprole.EmployeeId == user.EmployeeID && emprole.RoleId == role.RoleID
select emprole).FirstOrDefault();
if (EmpRoleToDelete != null)
{
context.AssignUserRoles.Remove(EmpRoleToDelete);
context.SaveChanges();
ViewBag.Message = "Role removed from this user successfully !";
}
else
{
ViewBag.Message = "This user doesn't belong to selected role.";
}
// Repopulate Dropdown Lists
var rolelist = context.Roles.OrderBy(r => r.RoleName).ToList().Select(rr => new SelectListItem { Value = rr.RoleName.ToString(), Text = rr.RoleName }).ToList();
ViewBag.Roles = rolelist;
var userlist = context.Employees.OrderBy(u => u.FullName).ToList().Select(uu =>
new SelectListItem { Value = uu.FullName.ToString(), Text = uu.FullName }).ToList();
ViewBag.Users = userlist;
return View("Index");
}
}
}
Create Index View for Roles Controller
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_mainView.cshtml";
}
<div class="row col-sm-12 col-lg-12 col-md-12">
<h1 style="text-align:center">Role Manager</h1>
<br />
</div>
<div class="row col-sm-12 col-lg-12 col-md-12">
<div class="col-sm-6 col-lg-6 col-md-6">
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Role List</h4>
</div>
<div class="panel-body">
<table class="table table-striped table-hover col-sm-6 col-lg-6 col-md-6 ">
#foreach (var role in ViewBag.Roles)
{
<tr>
<td class="col-sm-1 col-lg-5 col-md-5">
<strong>#role.Text </strong>
</td>
<td class="col-sm-1 col-lg-1 col-md-1">
<span onclick="return confirm('Are you sure to delete?')">Delete</span> |
#Html.ActionLink("Edit", "Edit", new { roleName = #role.Text })
</td>
</tr>
}
</table>
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Create A New Role</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("Create", "Roles", new { #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div>
Role name: #Html.TextBox("RoleName")
<input type="submit" value="Save" class="btn-primary" />
</div>
}
</div> <!--End Panel Body-->
</div> <!--End Panel-->
</div> <!--End First Column-->
<div class="col-sm-6 col-lg-6 col-md-6">
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Add a Role to a User</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("RoleAddToUser", "Roles"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>User Name: #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")</p>
<p>Role Name: #Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")</p>
<p><input type="submit" value="Save" class="btn-primary" /></p>
}
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
<div class="panel panel-primary">
<div class="panel-heading">
<h4>List Roles for a User</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("GetRoles", "Roles"))
{
#Html.AntiForgeryToken()
<p>
User Name: #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")
<input type="submit" value="Get Roles for this User" class="btn-primary" />
</p>
}
#if (ViewBag.RolesForThisUser != null)
{
<div class="alert-info">
<strong>Roles for this user </strong>
<ol>
#foreach (string s in ViewBag.RolesForThisUser)
{
<li>#s</li>
}
</ol>
</div>
}
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
<div class="panel panel-primary">
<div class="panel-heading">
<h4>Remove Role from User</h4>
</div>
<div class="panel-body">
#using (Html.BeginForm("DeleteRoleForUser", "Roles"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<p>User Name: #Html.DropDownList("UserName", (IEnumerable<SelectListItem>)ViewBag.Users, "Select ...")</p>
<p>Role Name: #Html.DropDownList("RoleName", (IEnumerable<SelectListItem>)ViewBag.Roles, "Select ...")</p>
<p><input type="submit" value="Delete this user from Role" class="btn-primary" /></p>
}
</div> <!-- End Panel Body-->
</div> <!-- End Panel -->
</div> <!--End Second Column-->
</div> <!--Overall Page Wrapper-->
<div class="alert-info col-sm-12 col-lg-12 col-md-12">
#ViewBag.Message
</div>
---------------------------------------------------------------------
Create Edit View For Roles Controller
#model yournamespace.Role
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_mainView.cshtml";
}
<h2>Edit Role</h2>
#Html.ActionLink("Return to Role Manager", "Index")
<hr />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.RoleID)
<div>
Role name
</div>
<p>
#Html.TextBoxFor(model => model.RoleName)
</p>
<input type="submit" value="Save" />
}
Create Roles and Assign to the Users
Create Class CustomRoleProvider
Inherit CustomRoleProvider from RoleProvider class as shown below and implement abstract class.Make changes in the classes as shown below
using System;
using System.Linq;
using System.Web.Security;
namespace yournamespace.Models
{
public class CustomRoleProvider : RoleProvider
{
public override string ApplicationName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
using (var usersContext = new SNHeliosWork2017Entities())
{
return usersContext.Roles.Select(r => r.RoleName).ToArray();
}
}
public override string[] GetRolesForUser(string username)
{
using (var usersContext = new SNHeliosWork2017Entities())
{
var user = usersContext.Employees.SingleOrDefault(u => u.FullName == username);
if (user == null)
return new string[] { };
return user.AssignUserRoles == null ? new string[] { } :
user.AssignUserRoles.Select(u => u.Role).Select(u => u.RoleName).ToArray();
}
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
using (var usersContext = new SNHeliosWork2017Entities())
{
var user = usersContext.Employees.SingleOrDefault(u => u.FullName == username);
if (user == null)
return false;
return user.AssignUserRoles != null && user.AssignUserRoles.Select(
u => u.Role).Any(r => r.RoleName == roleName);
}
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
}
In web.config add the following code within system.web tag
<system.web>
<sessionState mode="InProc" timeout="20" cookieless="false"></sessionState>
<authentication mode="Forms">
<forms loginUrl="~/Home/LogIn" defaultUrl="~/" timeout="20" slidingExpiration="true"/>
</authentication>
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear/>
<add name="CustomRoleProvider" type="MyProject.Models.CustomRoleProvider" />
</providers>
</roleManager>
</system.web>
The first thing to note is that I have set the enabled attribute to true so that the framework enables the role manager. Then you have to specify the defaultProvider attribute, which is used to identify the default provider if a number of providers are specified. But in this case, I am going to have only one provider CustomRoleProvider, still the default provider has to be specified. This is contained within the providers element. The clear element is used to clear all the providers stored for this application earlier, for example the default providers. Then I have defined the custom role provider by specifying the name "CustomRoleProvider", which was used in the defaultProvider attribute. This contains a number of attributes. The most important one is the type attribute where the fully-qualified name of the custom role provider is specified (MyProject.Models.CustomRoleProvider), followed by the assembly containing this type (MyProject) and the version. Note that only the type name is required and others are optional if the type is contained within the same assembly - the web application itself. Other attributes are self-explanatory and I am not going to bore you with all these details!
Use authorize attribute to authorize controllers
As,
[Authorize(Roles = "Admin")]
public class RolesController : Controller
{
}