So I was following this tutorial: https://www.yogihosting.com/aspnet-core-identity-create-read-update-delete-users/ teaching how to make a CRUD for Identity users.
I've reached a point where I am getting 2 errors which I think are tied together. Firstly, I will present the code:
AdminController.cs
public ViewResult Create() => View();
[HttpPost]
public async Task<IActionResult> Create(User user)
{
if (ModelState.IsValid)
{
AppUser appUser = new AppUser
{
UserName = user.Name,
Email = user.Email
};
IdentityResult result = await userManager.CreateAsync(appUser, user.Password);
if (result.Succeeded)
return RedirectToAction("Index");
else
{
foreach (IdentityError error in result.Errors)
ModelState.AddModelError("", error.Description);
}
}
return View(user);
}
AppUser.cs
public class AppUser : IdentityUser
{
}
When accessing the `localhost/Admin/Create' link after running the application, I am getting this error:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Intersection.Models.AppUser]' while attempting to activate 'Filters.Controllers.AdminController'.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
Then, I figured that something might be wrong in the Startup.cs, therefore, after a bit of research, I added this line: services.AddIdentity<AppUser, IdentityRole>().AddEntityFrameworkStores<AppIdentityDbContext>().AddDefaultTokenProviders();
In an attempt to fix the first error, I got this second issue:
HTTP Error 500.30 - ANCM In-Process Start Failure
My Startup.cs class looks like this:
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddDbContext<AppIdentityDbContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddIdentity<AppUser, IdentityRole>().AddEntityFrameworkStores<AppIdentityDbContext>().AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
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.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
So what could be the issue? I tried following the tutorial closely but apparently I missed something out... Or things changed since it was posted. Any help is highly appreciated!
HTTP Error 500.30 - ANCM In-Process Start Failure
This was due to methods AddDbContext and AddIdentity having duplicates in the Startup.cs. After commenting out the duplicates, I got rid of it.
Secondly, in _LoginPartial.cshtml, I had this:
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
I had to replace IdentityUser with my AppUser. This fixed the first error.
Related
I'm trying to setup a chat in a .NET 5 and Angular 10 application but so far the backend part has put me to a hold. Whenever I try to access the ChatController I get
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.SignalR.IHubContext`1[iBet.Server.Hubs.ChatHub]' while attempting to activate 'iBet.Server.Controllers.ChatController'.
This is the controller itself:
[Produces("application/json")]
public class ChatController : ApiController
{
private readonly IHubContext<ChatHub> _hubContext;
public ChatController(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
[Route("send")]
[HttpPost]
public IActionResult SendRequest([FromBody] MessageRequest message)
{
_hubContext.Clients.All.SendAsync("ReceiveOne", message.User, message.MessageText);
return Ok(message.MessageText);
}
}
And this is my startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSignalR();
}
// 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.UseCors(options => options
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<ChatHub>("/chatsocket");
});
}
From what I understand once you put services.AddSignalR(); it takes care of the DI but it seems it's different in .NET 5, any suggestions would be greatly appreciated.
I just updated my version of .NET CORE. I already updated all the usings however I still have an error in the satrtup class, in the method ConfigureServices, when adding the default identity. It just gives me an error saying "'IServiceCollection' does not contain a definition for 'AddDefaultIdentity and no accessible extension method 'AddDefaultIdentity...'". Here is the method:
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
//ERROR
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
//SIGNAL R
services.AddSignalR();
}
I also have an error in the Configure method.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//ERROR
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
//MORE CODE
}
What should I do to solve this error?
Those two extension methods have moved into separate NuGet packages, which must be referenced explicitly in ASP.NET Core 3.0 and upwards:
Method
Package
AddDefaultIdentity
Microsoft.AspNetCore.Identity.UI
UseDatabaseErrorPage
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
I'm deploying my application to Azure, but the problem is that some methods, specifically POST methods give a 404 on the live site while they do work locally. I have been trying to debug it using BurpSuite, but it seems as if the requests are similar.
Controller:
[HttpPost]
public IActionResult SavePlan(string PlanDate)
{
DateTime dateFrom = DateTime.ParseExact(PlanDate, "dd/MM/yyyy", null);
// Get planCart
PlanCart planCart = GetPlanCart();
// Validate MealPlan
if (!ValidateMealPlan(planCart))
{
TempData["Error"] = "Error: MealPlan contains has too many diet restrictions per day.";
return RedirectToAction("Index");
}
// Create and set MealPlan options
MealPlan mealPlan = new MealPlan();
mealPlan.dateFrom = dateFrom;
mealPlan.dateTo = dateFrom.AddDays(7);
mealPlan.Meals = planCart.returnList().ToArray();
mealplanRepository.SaveMealPlan(mealPlan);
return RedirectToAction("Index");
}
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)
{
// Add Identity server
services.AddDbContext<AppIdentityDbContext>(options =>
options.UseSqlServer(
Configuration["Data:EasyMealIdentityServer:ConnectionString"]));
// Add OrderCustomersServer
services.AddDbContext<AppMealOrdersCustomersDbContext>(options =>
options.UseSqlServer(
Configuration["Data:EasyMealOrdersCustomersServer:ConnectionString"]));
// EasyMealMealServer
services.AddDbContext<AppMealsDbContext>(options =>
options.UseSqlServer(
Configuration["Data:EasyMealMealServer:ConnectionString"]));
services.AddTransient<IMealRepository, EFMealRepository>();
services.AddTransient<IOrderRepository, EFOrderRepository>();
services.AddTransient<IMealplanRepository, EFMealplanRepository>();
services.AddIdentity<AppUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMemoryCache();
services.AddSession();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseCookiePolicy();
}
}
Form in View (Index.cshtml):
<form id="PlanForm" asp-action="SavePlan" asp-controller="Plan" method="post">
<input id="PlanDate" name="PlanDate" value="" type="hidden" />
<button class="btn btn-success" type="submit">Save selection</button>
</form>
PlanDate, the parameter required gets set via javascript. You can see in the request in BurpSuite that it does get send. I thought maybe that was the problem.
If anybody has an idea what could be going wrong it would be greatly appreciated!
**edit 2: you need to format the date client side and use clientinfo server side to avoid mm/dd/yyyy vs dd/mm/yyyy mismatch!
edit 1:
Are you passing forward slashes in the date? that will break it.
Pass in the date with dashes instead or escape it in javascript.**
right click the project, click properties, click the web tab, scroll down to see the correct iis url with port.
for .net core use launchSettings.json and find the application url.
When you try to post to it, make sure you are doing localhost:<port>\<controller>\<action>
so controller is probably home, action is saveplan, and you need \plandate after that
So, I'm working on a project using the .net MVC framework, and we'd like to use Angular for the frontend. Our project is structured as follows:
/Areas
/ClientApp
/Controllers
/Data
/Dto
/Models
/Services
/ViewModels
/Views
It's pretty boiler-plate, and it's auto-generated from Visual Studio.
I'm attempting to add in Angular. I ran ng new and generated the ClientApp directory shown above.
However, when running the app and accessing the home page, I still end up running through Controllers/HomeController and the accompanying Views/Home/Index.cshtml.
We want to keep the controllers for future API work. We have no interest at all in keeping the Views directory.
So, how can I have my project actually use that Angular directory? What's the proper way to structure this thing?
By the way, startup.cs looks like this:
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)
{
// Add framework services.
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<Models.ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserManager<Services.ApplicationUserManager>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
// Add project services.
services.AddSingleton(_ => Configuration); // enables us to inject IConfigurationRoot into service layer class.
// other choices: services.AddScoped, services.AddTransient
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller}/{action=Index}/{id?}"
);
});
}
I've got an ASP.NET Core MVC app, hosted on Azure websites, where I've implemented Session and Identity. My problem is, after 30 minutes, I get logged out. It doesn't matter if I've been active in the last 30 minutes or not.
Doing some searching, I found that the issue is the SecurityStamp stuff, found here. I've tried implementing this by doing the following:
Here's my UserManager impelmentation with the security stamp stuff:
public class UserManager : UserManager<Login>
{
public UserManager(
IUserStore<Login> store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<Login> passwordHasher,
IEnumerable<IUserValidator<Login>> userValidators,
IEnumerable<IPasswordValidator<Login>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<Login>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
// noop
}
public override bool SupportsUserSecurityStamp => true;
public override async Task<string> GetSecurityStampAsync(Login login)
{
return await Task.FromResult("MyToken");
}
public override async Task<IdentityResult> UpdateSecurityStampAsync(Login login)
{
return await Task.FromResult(IdentityResult.Success);
}
}
Here's my ConfigureServices method on Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddSingleton(_ => Configuration);
services.AddSingleton<IUserStore<Login>, UserStore>();
services.AddSingleton<IRoleStore<Role>, RoleStore>();
services.AddIdentity<Login, Role>(o =>
{
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequiredLength = 6;
o.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(365);
o.Cookies.ApplicationCookie.SlidingExpiration = true;
o.Cookies.ApplicationCookie.AutomaticAuthenticate = true;
})
.AddUserStore<UserStore>()
.AddUserManager<UserManager>()
.AddRoleStore<RoleStore>()
.AddRoleManager<RoleManager>()
.AddDefaultTokenProviders();
services.AddScoped<SignInManager<Login>, SignInManager<Login>>();
services.AddScoped<UserManager<Login>, UserManager<Login>>();
services.Configure<AuthorizationOptions>(options =>
{
options.AddPolicy("Admin", policy => policy.Requirements.Add(new AdminRoleRequirement(new RoleRepo(Configuration))));
options.AddPolicy("SuperUser", policy => policy.Requirements.Add(new SuperUserRoleRequirement(new RoleRepo(Configuration))));
options.AddPolicy("DataIntegrity", policy => policy.Requirements.Add(new DataIntegrityRoleRequirement(new RoleRepo(Configuration))));
});
services.Configure<FormOptions>(x => x.ValueCountLimit = 4096);
services.AddScoped<IPasswordHasher<Login>, PasswordHasher>();
services.AddDistributedMemoryCache();
services.AddSession();
services.AddMvc();
// repos
InjectRepos(services);
// services
InjectServices(services);
}
And lastly, here's my Configure method on Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/home/error");
}
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseIdentity();
app.UseMiddleware(typeof (ErrorHandlingMiddleware));
app.UseMiddleware(typeof (RequestLogMiddleware));
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
What's wrong with my implementation here?
UPDATE: What a second...I noticed my UserManager is not inheriting from any interfaces for the security stamp stuff, is that what's needed?
This is simply because you need to enable and configure Data Protection. The cookie and session setup looks correct. What is happening right now for you is that whenever the app is recycled or the server load balances to another server or a new deployment happens, etc, it creates a new Data protection key in memory, so your users' session keys are invalid. So all you need to do is add the following to Startup.cs:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"D:\writable\temp\directory\"))
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
Use the documentation to learn how to properly set this up and the different options of where to save the Data Protection key (file system, redis, registry, etc). You could think of the data protection key as the replacement of the web.config's machine key in asp.net.
Since you mentioned you're using Azure, you could use this package Microsoft.AspNetCore.DataProtection.AzureStorage to save the key so that it persists. So you could use this example of how to use Azure Storage.
Are you hosted under IIS? If so, maybe nothing is wrong with your code, but your application pool could get recycled (check advanced settings on the application pool). When that happen, does your binary get unloaded from memory and replaced by a new one, its PID changing ?