Invalid DTO posted throws exception - aspnetboilerplate

Invalid DTO posted to MVC endpoint throws an exception, expecting it to record it in ModelState.
How according to Abp should such exception be handled gracefully?
I see ABP documentation on validating DTOs where it throws the exception for invalid models, but how to pass the error messages to a view.
Using
aspnetboilerplate sample for MVC + .NET Core
Abp package version 4.3
Net Core 2.2
What I did:
Added a DTO
public class ExamDtoBaseTmp
{
[Required(ErrorMessage ="Can't add without a name")]
[StringLength(EntityCommons.MaxExamNameLength,ErrorMessage ="Keep is short")]
public string Name { get; set; }
[Required(ErrorMessage ="Description is needed")]
public string Description { get; set; }
}
Added a POST endpoint that accepted above model
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ExamDtoBaseTmp model)
{
if (!ModelState.IsValid)
{
return View();
}
try
{
// TODO: Add insert logic here
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
Submitted empty form and got below exception:
AbpValidationException: Method arguments are not valid! See ValidationErrors for details.
Abp.Runtime.Validation.Interception.MethodInvocationValidator.ThrowValidationError() in MethodInvocationValidator.cs
Abp.Runtime.Validation.Interception.MethodInvocationValidator.Validate() in MethodInvocationValidator.cs
Abp.AspNetCore.Mvc.Validation.AbpValidationActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) in AbpValidationActionFilter.cs
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ExceptionContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Nivra.Authentication.JwtBearer.JwtTokenMiddleware+<>c__DisplayClass0_0+<<UseJwtTokenMiddleware>b__0>d.MoveNext() in JwtTokenMiddleware.cs
await next();
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) Nivra.Web.Startup.Startup+<>c+<<Configure>b__4_1>d.MoveNext() in Startup.cs
await next();
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Startup.cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Castle.Facilities.Logging;
using Abp.AspNetCore;
using Abp.Castle.Logging.Log4Net;
using Nivra.Authentication.JwtBearer;
using Nivra.Configuration;
using Nivra.Identity;
using Nivra.Web.Resources;
using Abp.AspNetCore.SignalR.Hubs;
using System.IO;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using System.Linq;
using Abp.Extensions;
using Swashbuckle.AspNetCore.Swagger;
using Microsoft.AspNetCore.Mvc.Cors.Internal;
using Nivra.OnlineExam.Models;
using Nivra.OnlineExam.Service;
using Microsoft.Extensions.Options;
namespace Nivra.Web.Startup
{
public class Startup
{
private const string _defaultCorsPolicyName = "localhost";
private readonly IConfigurationRoot _appConfiguration;
public Startup(IHostingEnvironment env)
{
_appConfiguration = env.GetAppConfiguration();
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<ExamDatabaseSettings>(
_appConfiguration.GetSection(nameof(ExamDatabaseSettings))
);
services.AddSingleton<IExamDatabaseSettings>(sp =>
sp.GetRequiredService<IOptions<ExamDatabaseSettings>>().Value);
services.AddSingleton<ExamService>();
// MVC
services.AddMvc(
options =>
options.Filters.Add(new CorsAuthorizationFilterFactory(_defaultCorsPolicyName))
//options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())
);
services.AddSpaStaticFiles(c =>
{
c.RootPath = "wwwroot/dist";
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddSignalR();
// Configure CORS for angular2 UI
services.AddCors(
options => options.AddPolicy(
_defaultCorsPolicyName,
builder => builder
.AllowAnyOrigin()
//.WithOrigins(
// // App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
// _appConfiguration["App:CorsOrigins"]
// .Split(",", StringSplitOptions.RemoveEmptyEntries)
// .Select(o => o.RemovePostFix("/"))
// .ToArray()
//)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
)
);
// Swagger - Enable this line and the related lines in Configure method to enable swagger UI
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Info { Title = "aspnetCoreNg API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
// Define the BearerAuth scheme that's in use
options.AddSecurityDefinition("bearerAuth", new ApiKeyScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = "header",
Type = "apiKey"
});
});
services.AddScoped<IWebResourceManager, WebResourceManager>();
var configurations = AppConfigurations.Get(AppDomain.CurrentDomain.BaseDirectory);
services.Configure<ExamDatabaseSettings>(configurations.GetSection(nameof(ExamDatabaseSettings)));
// Configure Abp and Dependency Injection
return services.AddAbp<NivraWebMvcModule>(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.
app.UseCors(_defaultCorsPolicyName); // Enable CORS!
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.Use(async (context, next) =>
{
await next();
if (
context.Response.StatusCode == 404
&& !Path.HasExtension(context.Request.Path.Value)
&& !context.Request.Path.Value.StartsWith("/api/services", StringComparison.InvariantCultureIgnoreCase)
)
{ context.Request.Path = "/index.html"; await next(); }
});
app.UseAuthentication();
app.UseJwtTokenMiddleware();
app.UseSignalR(routes =>
{
routes.MapHub<AbpCommonHub>("/signalr");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "defaultWithArea",
template: "{area}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
// app.Map("/spa", l =>
// l.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 = "./";
// if (env.IsDevelopment())
// {
// spa.UseAngularCliServer(npmScript: "start");
// }
// })
//);
app.UseSwagger();
//Enable middleware to serve swagger - ui assets(HTML, JS, CSS etc.)
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "AbpZeroTemplate API V1");
}); //URL: /swagger
}
}
}

Abp wraps only exception thrown in actions with ObjectResult return type by default. e.g. public JsonResult Create();
If your action is return a view result, it is recommended to catch the exception within the action yourself and add to ModelState manually.
see https://aspnetboilerplate.com/Pages/Documents/AspNet-Core#exception-filter
Referring above link
Exception handling and logging behaviour can be changed using the
WrapResult and DontWrapResult attributes for methods and classes.

Related

How to enforce lowercase routes in .NET 6?

I would like to enforce lowercase routes in .NET 6 API project.
Here is my Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Here is my WeatherForecastController.cs:
using Microsoft.AspNetCore.Mvc;
namespace Weather.API.Controllers
{
[ApiController]
[Route("weatherforecast")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
I expect only the lowercase route (https://localhost:7243/weatherforecast) to work, but the route w/ pascal/uppercase works as well (https://localhost:7243/Weatherforecast)
I thought I can add builder.Services.AddRouting(options => options.LowercaseUrls = true); and app.UseRouting(), but I'm still able to access the route with pascal/uppercase: https://localhost:7243/Weatherforecast.
Here is the modified Program.cs file that I tried, but doesn't work:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseRouting();
app.MapControllers();
app.Run();
To generate lowercase URLs, add the following to Program.cs.
(Note: this does not enforce lowercase URLs).
// generate lowercase URLs
builder.Services.Configure<RouteOptions>(options =>
{
options.LowercaseUrls = true;
});
var app = builder.Build();
To enforce lowercase URLs, create an IRule-based rule that will redirect any uppercase URLs to lowercase URLs.
see this stackoverflow answer and IRule-based rule documentation.
Once you created an IRule-based rule (i.e., RedirectLowerCaseRule), add the following to Program.cs:
var app = builder.Build();
// enforce lowercase URLs
// by redirecting uppercase urls to lowercase urls
var options = new RewriteOptions().Add(new RedirectLowerCaseRule());
app.UseRewriter(options);

Attempts of migrate from net core 2.2 to 3.0

Good Morning
I'm migrating from 2.2 to 3.0 and then moving to 3.1 in net core with visual studio 2019
my first attempt was the most basic:
docs of Microsoft
Although it is a reduced version, I add it to my code leaving the packages that I still have to use for my project and it does not work ... result: 404
second try:
err_connection_refused
change the ip project of both http and https in addition to comparing it with the .json
result: 404 ERR_CONNECTION_REFUSED
third try:
migrate 2.2 to 3.0 stackoverlofw
reduce it as much as possible but without success too
the fourth attempt was the most "promising"
https://github.com/StackExchangeExamples/DotNetCoreTargetDotNetFramework/tree/master/BasicCoreWebsite
since it showed a "complete" example of how a project with version 3.0 should look
the result: a page that says "hello world" instead of a 404, is not something successful but better than a 404 is not it?
The idea of ​​this post is not only to solve my situation so that I do not get kicked out (lol) but to create as much as possible a complete functional example for future people with the same problem.
Thank you very much in advance and the data you require I will upload with pleasure!
UPDATE (i add the startup.cs)
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using HistoriaClinica.IServicio;
using HistoriaClinica.IServicio.Servicio;
using System;
using System.IO.Compression;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Session;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace HistoriaClinica
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
/// <param name="services"></param>
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddHttpContextAccessor();
services.AddDistributedMemoryCache();
services.AddSession();
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
services.AddMemoryCache();
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
});
services.AddDataProtection().UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
// services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddResponseCompression(options =>
{
options.Providers.Add<GzipCompressionProvider>();
options.EnableForHttps = true;
options.MimeTypes = new[]
{
// General
"text/plain",
// Static files
"text/css",
"application/javascript",
// MVC
"text/html",
"text/xml",
"application/json",
"text/json",
"image/png",
"image/jpeg",
"image/svg+xml",
"application/octet-stream",
"application/font-woff",
"application/pdf"
};
});
services.Configure<GzipCompressionProviderOptions>(options =>
options.Level = CompressionLevel.Optimal
);
services.AddMemoryCache();
// Add application services.
services.AddSingleton<ILoggerServicio, LoggerServicio>();
services.AddScoped<IEncriptaServicio, EncriptaServicio>();
services.AddSingleton<IHttpServicio, HttpServicio>();
services.AddScoped<IPacienteServicio, PacienteServicio>();
services.AddScoped<IProfesionalServicio, ProfesionalServicio>();
services.AddScoped<IEspecialidadServicio, EspecialidadServicio>();
services.AddScoped<ILaboratorioServicio, LaboratorioServicio>();
services.AddScoped<IUsuarioServicio, UsuarioServicio>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<ISessionServicio, SessionServicio>();
services.AddScoped<IImagenServicio, ImagenServicio>();
services.AddScoped<INoticiaServicio, NoticiaServicio>();
services.AddScoped<IResponseServicio, ResponseServicio>();
services.AddScoped<IClienteServicio, ClienteServicio>();
// services.AddMvc(options => options.EnableEndpointRouting = false);
services.AddControllers(options => options.EnableEndpointRouting = false);
services.AddControllersWithViews(options => options.EnableEndpointRouting = false);
services.AddRazorPages().AddMvcOptions(options => options.EnableEndpointRouting = false);
// Cron jobs
//services.AddCronJob<RecordatorioTurno24>(c =>
//{
// c.TimeZoneInfo = TimeZoneInfo.Local;
// c.CronExpression = #"*/1 * * * *";
//});
//services.AddCronJob<RecordatorioTurno48>(c =>
//{
// c.TimeZoneInfo = TimeZoneInfo.Local;
// c.CronExpression = #"* * * * *";
//});
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSession();
app.UseSession();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Cuenta/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "Default",
template: "{controller=Cuenta}/{action=Login}/{id?}");
});
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller=Cuenta}/{action=Login}");
//});
}
}
}

.NET Core making an AJAX call from a Razor Page to a Controller

I have a .NET Core 3.1 project using Razor Pages. From it I created a simple test where I am able to make a successful Ajax call with the following code:
Index.cshtml.cs
public class IndexModel : PageModel
{
public void OnGet()
{
}
public JsonResult OnGetTest()
{
return new JsonResult("Ajax Test");
}
}
Index.cshtml
#page
#model IndexModel
<div class="text-center">
<p>Click here for ajax test.</p>
</div>
<script type="text/javascript">
function ajaxTest() {
$.ajax({
type: "GET",
url: "/Index?handler=Test",
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function (xhr, status, error) {
console.log(error);
}
}).done(function (data) {
console.log(data);
});
}
</script>
However, I would like to move the Ajax method out of the Razor Page and into to a Controller so I could call it from from multiple Razor Pages. I have created a controller using the following code:
public class AjaxController : Controller
{
public JsonResult Test()
{
return new JsonResult("Ajax Test");
}
}
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.AddMvc(options =>
{
options.EnableEndpointRouting = false;
});
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();
}
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.UseMvcWithDefaultRoute();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
But whatever value I use in the url for the Ajax call, I get a 404 error. Does the Controllers folder need to be in the Pages directory? Or do I need to configure some routing to use a Controller with Razor Pages?
url: "/Ajax/Test" // <-- What goes here?
Here is the current directory structure:
In Startup.cs, add this to ConfigureServices()
services.AddMvc(options => options.EnableEndpointRouting = false);
In Startupcs, also add this to Configure()
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
DisplayController.cs
public IActionResult Test()
{
return new JsonResult("Hi World");
}
Index.cshtml
<a onclick="ClickMe();">Click Me</a>
<script>
function ClickMe() {
$.get("/Display/Test", null, function (e) {
alert(e);
});
}
</script>
You need to specify a Route attribute, like this:
[Route("api/Ajax")]
public class AjaxController : Controller
{
// ...
}
It is also best to decorate each individual endpoint with a 'Method' attribute, like this:
[HttpGet]
public JsonResult Test()
{
return new JsonResult("Ajax Test");
}
Furthermore you also need to set the correct configuration in Startup.cs as shown below, add all the parts that you do not have:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
});
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// lots of stuff...
// I have this after app.UseStaticFiles(), it may also work elsewhere
app.UseMvcWithDefaultRoute();
// lots of other stuff...
}
And then you should be able to call it using the path /api/Ajax/Test.

No service for type Identity.RoleManager - Identity.IdentityRole has been registered error

I use Microsoft Identity for the first time. I configured users and roles with IdentityUser and IdentityRole. I want to assign a role to users in Startup.cs. I wrote a method to make it which is
private async Task CreateUserRoles(IServiceProvider serviceProvider) {
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole<int>>>();
var userManager = serviceProvider.GetRequiredService<UserManager<User>>();
var roleName = "Super Admin";
var roleCheck = await roleManager.RoleExistsAsync(roleName);
if (!roleCheck) {
Role role = new Role();
role.Name = roleName;
IdentityResult result = roleManager.CreateAsync(role).Result;
//IdentityResult roleResult = await roleManager.CreateAsync(new IdentityRole<int>(roleName));
}
User user = new User();
user.UserName = "someone";
user.Password = "someone";
user.Email = "someone#gmail.com";
ApplicationDbContext context = new ApplicationDbContext();
context.Users.Add(user);
context.SaveChanges();
user = await userManager.FindByEmailAsync("someone#gmail.com");
await userManager.AddToRoleAsync(user, roleName);
}
Hovewer there is a problem :
No service for type
'Microsoft.AspNetCore.Identity.RoleManager1[Microsoft.AspNetCore.Identity.IdentityRole1[System.Int32]]' has been registered.
How can I fix it?
Here is a 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.Configure<CookiePolicyOptions>(options => {
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Add MVC services to the services container.
services.AddMvc();
services.AddDistributedMemoryCache(); // Adds a default in-memory implementation of IDistributedCache
services.AddSession(opt => { opt.Cookie.IsEssential = true; });
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddRazorPagesOptions(options => {
options.AllowAreas = true;
options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Settings");
options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql("User ID = postgres; Password = sa; Host = localhost; Port = 5432; Database = CCN; Pooling = true;"));
services.ConfigureApplicationCookie(options => {
options.LoginPath = $"/Account/Login"; //options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Account/Logout";
options.AccessDeniedPath = $"/Account/AccessDenied";
});
//Password settings
services.AddIdentity<User, Role>(o => {
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
//o.Password.RequiredLength = 3;
}).AddEntityFrameworkStores<ApplicationDbContext>().AddRoles<IdentityRole>()
.AddDefaultTokenProviders();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider services) {
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
else {
app.UseExceptionHandler("/Home/Index");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
//Enable session
app.UseSession();
app.UseAuthentication();
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}");
});
//Create user role and assign it
CreateUserRoles(services).Wait();
}
}
No service for type
'Microsoft.AspNetCore.Identity.RoleManager1[Microsoft.AspNetCore.Identity.IdentityRole1[System.Int32]]' has been registered.
When registering IdentityRole for the AspNetCore Identity, the RoleManager<> type will be registered to the ServiceCollection as RoleManager<IdentityRole>.
Whenever you want to resolve the RoleManager<>, specify the identity role model registered in your startup as the type parameter. Which would be RoleManager<IdentityRole> in your specific case.
When calling GetRequiredService<RoleManager<IdentityRole>>() on the resulting service provider, GetRequiredService<RoleManager<IdentityRole>>() will throw the above exception.
Make the below modification:
In CreateUserRoles
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
Register the role services in the DI container (choose one of the two methods)
1.Use AddIdentity()
services.AddIdentity<User, IdentityRole()
.AddDefaultUI()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
2.Use AddDefaultIdentity , include roles by using the [AddRoles][1] method
services.AddDefaultIdentity<User>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Reference : AddDefaultIdentity and AddIdentity
I tried those solutions but it didn't work. Then I recognize that I created an entity called Role which is derived from IdentityRole and its id data type is int. I changed
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole<int>>>();
this line with
var roleManager = serviceProvider.GetRequiredService<RoleManager<Role>>();
this one. Then it works.
On the other hand, thanks for your help!

Inconsistent culture - decimal separator ignored in model binding between razor view and viewmodel

I have the following behaviour in my program:
User input for a decimal variable
A) jquery validation turned off:
1) If the user uses a comma as decimal separator, the value is stored correctly in the ViewModel
2) If the user uses a point as decimal separator, the value is multiplied by 100 (as if there was no decimal separator)
B) jquery validation turned on:
1) I get an error, that a number must be supplied
2) same Problem as A2)
However if I display a decimal value of the ViewModel in the view it is shown per default with a point as a decimal separator.
This inconsistency is confusing me and I would like to implement a consistent behaviour, but unfortunately I don't know what I am actually looking for.
The website will be localized in german and italian. The localization works without any problems, so far.
This is my
startup.cs
namespace XXX
{
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)
{
// Added - uses IOptions<T> for your settings.
services.AddOptions();
// Added - Confirms that we have a home for our DemoSettings
services.Configure<DatabaseSettings>(Configuration.GetSection("DatabaseSettings"));
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc()
.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, IHostingEnvironment env)
{
app.UseStatusCodePagesWithReExecute("/Error/Index", "?i_statusCode={0}");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
IList<CultureInfo> supportedCultures = new List<CultureInfo>
{
new CultureInfo("de"),
new CultureInfo("it"),
};
var localizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("de"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
var requestProvider = new RouteDataRequestCultureProvider();
localizationOptions.RequestCultureProviders.Insert(0, requestProvider);
app.UseRouter(routes =>
{
routes.MapMiddlewareRoute("{culture=de}/{*mvcRoute}", subApp =>
{
subApp.UseRequestLocalization(localizationOptions);
subApp.UseMvc(mvcRoutes =>
{
mvcRoutes.MapRoute(
name: "defaultLocalized",
template: "{culture=de}/{controller=Contract}/{action=Index}/{id?}");
mvcRoutes.MapRoute(
name: "error",
template: "Error/Index",
defaults: new { controller = "Error", action = "Index", culture = "de" });
mvcRoutes.MapRoute(
name: "default",
template: "{*catchall}",
defaults: new { controller = "Home", action = "Index", culture = "de" });
});
});
});
}
}
}

Resources