Assistance converting .NET 5 into .NET 6 - c#

I am trying to seed my database and add roles to my ASP.NET Core Web Application. In the tutorial I am following, it advised to add the following to the Configure() method:
app.UseAuthentication();
MyIdentityDataInitializer.SeedData(userManager, roleManager);
I had no issues with the first line, but with the second, I am getting an error saying userManager and roleManager doesn't exist which makes sense because if i were using .NET 5 my configure method would've looked like this and been fine:
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
UserManager<MyIdentityUser> userManager,
RoleManager<MyIdentityRole> roleManager)
{
...
app.UseAuthentication();
MyIdentityDataInitializer.SeedData(userManager, roleManager);
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
But in .NET 6 I'm not sure how to.
Can someone advise on this please?

In .NET 6, Microsoft has removed the Startup.cs class where your Configure() method was previously defined. Instead, configuration of both the DI service container (which was done previously in the ConfigureServices(IServiceCollection)) method) and the AspNet Core Application Builder are done directly in Program.cs
Now since there is nothing automatically calling the Configure() method for you (and injecting those values for you), you'll have to get references to those objects yourself using the ServiceProvider. Your Program.cs will probably look something like this:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// add services that were previously added in ConfigureServices()
var app = builder.Build();
var userManager = app.Services.GetRequiredService<UserManager<MyIdentityUser>>();
var roleManager = app.Services.GetRequiredService<RoleManager<MyIdentityRole>>();
MyIdentityDataInitializer.SeedData(userManager, roleManager);
app.UseAuthentication();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
*Edit: To fix your error, (and as the link #tappetyclick directed you to explains), you'll need to first create a scope in order to get references to your UserManager and RoleManager objects:
using (var scope = app.Services.CreateScope())
{
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<MyIdentityUser>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<MyIdentityRole>>();
MyIdentityDataInitializer.SeedData(userManager, roleManager);
}

Related

Calling class function from program.cs at runtimes in .net 6 [duplicate]

This question already has an answer here:
.NET 5 to .NET 6 Migration Startup and Configure methodology in Minimal Hosting
(1 answer)
Closed last year.
In previous core version, if there is need to pass dependency while calling any function i used to pass parameter in configure method and use same value to pass as parameter while calling function.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
UserManager<IdentityUser> usermanager, RoleManager<IdentityRole rolemanager)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
SeedData.Seed(userManager, roleManager);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
But in .Net 6 same flow cannot be applied due to only program.cs file. I tried to call function from program.cs file but i get : 'Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' from root provider.'
Program.cs File
using LeaveManagement;
using LeaveManagement.Data;
using LeaveManagement.Interfaces;
using LeaveManagement.Mapper;
using LeaveManagement.Repositories;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddAutoMapper(typeof(Maps));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews().AddRazorRuntimeCompilation();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
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();
var userManager = app.Services.GetRequiredService<UserManager<IdentityUser>>();
var roleManager = app.Services.GetRequiredService<RoleManager<IdentityRole>>();
SeedData.Seed(userManager, roleManager);
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();
I find the above solution working for some case but it is not working for me.
If you really want to get the object
var usermanager = services.BuildServiceProvider().GetService<UserManager<IdentityUser>>();
It can help (of cause, you only call it AFTER adding the services). But you can consider another way to achieve your work. Because by calling BuildServiceProvider, the framework can't guarantee the singleton scope.

System.InvalidOperationException when using HttpContext.Session with use.Session(); set

I am developing a .NET Core 3.0 application using Razor pages for a project in my studies. The application is going to use a login feature and I am want to use sessions to send data and verify what user is logged in.
For this I have decided to use HttpContext.Session to get and set strings during post.
When I use the line: HttpContext.Session.SetString("username", "test");
I get the error: System.InvalidOperationException: 'Session has not been configured for this application or request.'
After some extensive googling and using a Microsoft doc I cannot seem to find a solution. Everywhere I get the answer that I need to include services.AddSession and app.UseSession(); in my Startup.cs file which I do, These are all added before the 'UseMvc();' lines.
I have run out of options and my software teacher does not want to give me any help aside from "are you using the correct version" which I think I do according to the Microsoft docs.
What am I missing that causes this error? How can I get sessions to work? Am I implementing it wrong?
Below is my Startup.cs class:
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.AddDistributedMemoryCache();
services.AddRazorPages();
services.AddSession(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.IdleTimeout = TimeSpan.FromSeconds(10);
});
services.AddMvc(option => option.EnableEndpointRouting = false);
}
// 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");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseMvc();
}
}
Notable is when I use app.UseHttpContextItemsMiddleware(); between
app.UseSession(); and app.UseMvc(); I get an Intellisense error that says IApplicationBuilder does not have this method. In the Microsoft docs it is show that this string is included in Startup.cs.
Everywhere I get the answer that I need to include services.AddSession and app.UseSession(); in my Startup.cs file which I do, These are all added before the 'UseMvc();' lines.
Yes, you're right. However, either invoke UseMvc() or invoke UseRouting()+ UseEndpoints(), but don't invoke them both. As of ASP.NET 3.0, I would suggest you should use UseRouting()+ UseEndpoints() instead of the UseMvc().
In your original codes, the UseEndpoints() is triggered before UseSession() which makes the MVC/Razor Page execute before UseSession(). To fix that issue, change your code as below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseHttpsRedirection();
app.UseStaticFiles();
// put UseSession before the line where you want to get the session.
// at least, you should put it before `app.UseEndpoints(...)`
app.UseSession();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
// if you need mvc, don't forget to
// add `services.AddControllersWithViews`
// and add this line
endpoints.MapControllerRoute(
name: "default-controller",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseMvc();
}

How to drop Angular into an existing .net MVC project

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?}"
);
});
}

Auto Login on debug ASP.Net Core 2.1

I am trying to auto login for debugging purposes on an ASP.net core 2.1 application I've built.
Getting the Error :
HttpContext must not be null.
The code below sits in the Startup.cs file
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider ServiceProvider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseCookiePolicy();
CreateRoles(ServiceProvider).Wait();
if (env.IsDevelopment())
{
DeveloperLogin(ServiceProvider).Wait();
}
}
private async Task DeveloperLogin(IServiceProvider serviceProvider){
var UserManager = serviceProvider.GetRequiredService<UserManager<User>>();
var signInManager = serviceProvider.GetRequiredService<SignInManager<User>>();
var _user = await UserManager.FindByNameAsync("test#gmail.com");
await signInManager.SignInAsync(_user, isPersistent: false);
}
This is an extension of sorts on another question I asked a while back about Windows Authentication on a Mac. Because of the nature of the application I had added Core Identity for role management even though the application still only uses Windows Auth.
Since I migrated to a Macbook for development I'm trying to autologin on build for debugging using the already existing Identity since there is no Windows Auth which is where the DeveloperLogin function fits in but I get the error mentioned above.
StackTrace:
System.AggregateException: "One or more errors occurred. (HttpContext must not be null.)"
---> System.Exception {System.InvalidOperationException}: "HttpContext must not be null."
at Microsoft.AspNetCore.Identity.SignInManager`1.get_Context()
at Microsoft.AspNetCore.Identity.SignInManager`1.SignInAsync(TUser user, AuthenticationProperties authenticationProperties, String authenticationMethod)
at myApp.Startup.DeveloperLogin(IServiceProvider serviceProvider) in /Users/user/Documents/Repositories/myApp/myApp/Startup.cs:135
For HttpContext, it only exists during http request pipeline. There is no HttpContext in Configure method, you need to refer the code during middleware.
For using Identity, you need to use app.UseAuthentication();.
Follow steps below with sigin with Identity.
Configure request pipeline.
app.UseAuthentication();
if (env.IsDevelopment())
{
app.Use(async (context, next) =>
{
var user = context.User.Identity.Name;
DeveloperLogin(context).Wait();
await next.Invoke();
});
}
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Note: you need to call app.UseAuthentication();, the order is import.
DeveloperLogin
private async Task DeveloperLogin(HttpContext httpContext)
{
var UserManager = httpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>();
var signInManager = httpContext.RequestServices.GetRequiredService<SignInManager<IdentityUser>>();
var _user = await UserManager.FindByNameAsync("Tom");
await signInManager.SignInAsync(_user, isPersistent: false);
}

.NET Core 2.0 accessing user secrets

I'm trying to setup a .net core 2.0 web application to send an email when user registers and also to recover password. I have followed this tutorial: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?tabs=visual-studio.
However, upon reading the comments sections, it seems that the tutorial is not updated for Core 2.0. My question is, when I get to part "Add the user secrets configuration source to the Startup method", I cannot figure out how the startup file should look like since my startup file is different from the one showed there. Can anyone help me by showing me how the startup file should look like? Thanks.
This is my current startup file:
public class Startup
{
string _testSecret = null;
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)
{
_testSecret = Configuration["MySecret"];
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add application services.
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc();
services.Configure<AuthMessageSenderOptions>(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var builder = new ConfigurationBuilder();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseDatabaseErrorPage();
builder.AddUserSecrets<Startup>();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
In your code I didn't find invoking of build() function of ConfigurationBuilder class. Here is the sample code.
var builder = new ConfigurationBuilder();
builder.AddUserSecrets<Startup>();
var config builder.Build(); //This line is missing from your code
string mySecret = config ['EmailAccount'];
Refernce: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=windows#access-a-secret

Categories

Resources