ihttpcontextaccessor.httpcontext.user.findfirst(claimtypes.nameidentifier).value is null - httpcontext

I have a service like this:
public class CurentUserService : ICurentUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public string UserId { get; set; }
public CurentUserService(IHttpContextAccessor httpContextAccessor)
{
this._httpContextAccessor = httpContextAccessor;
this.UserId = this._httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
}
and I add to startup
services.AddScoped<ICurentUserService, CurentUserService>();
//services.AddHttpContextAccessor();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
but when à used via dependency injection is all time null when I was logged.
I use asp.net core version 3.1.0
Thanks you for your help.

Can't explain why but this code works
private readonly IHttpContextAccessor _httpContextAccessor;
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
In startup
services.AddSingleton<ICurrentUserService, CurrentUserService>();
services.AddHttpContextAccessor();
source: github.com/jasontaylordev/CleanArchitecture/issues/119

Related

AutoMapperMappingException: Missing type map configuration or unsupported mapping IN .NET 6

I have this entity:
public class Genres
{
public int Id { get; set; }
[Required(ErrorMessage ="the field {0} is required")]
[StringLength(50)]
[FirstLetterUpperCase]
public string Name { get; set; }
}
And this DTO or model:
public class GenresDTO
{
public int Id { get; set; }
public string Name { get; set; }
}
I have initiated my mapper like this:
public class AutoMapperClass : Profile
{
public AutoMapperClass()
{
generateMapper();
}
private void generateMapper()
{
CreateMap<GenresDTO, Genres>().ReverseMap();
CreateMap<GenresCreationDTO, Genres>();
}
}
I have also written this part of code in my program.cs :
builder.Services.AddAutoMapper(typeof(IStartup));
I am using .NET 6 and Visual Studio, and when I run my project, I get an error that is mentioned in the title and its related to this section :
public async Task<ActionResult<List<GenresDTO>>> Get()
{
var genres = await dbContext.Genres.ToListAsync();
return mapper.Map<List<GenresDTO>>(genres);
}
which is in my Controller file, and I initiated the mapper like this :
private readonly ILogger<GenresController> ilogger;
private readonly ApplicationDBContext dbContext;
private readonly IMapper mapper;
public GenresController(ILogger<GenresController> ilogger,
ApplicationDBContext dbContext , IMapper mapper)
{
this.ilogger = ilogger;
this.dbContext = dbContext;
this.mapper = mapper;
}
Should be probably typeof(Program) in registration (assuming that you are using .Net6 where we have only Program.cs)
builder.Services.AddAutoMapper(typeof(Program))
If you have multiple projects in solution,then value used there should be a file in the assembly in which the mapping configuration resides.

Why IConfiguration object always return null in .net core?

I have this Dblayer class.
I am trying to read the connection string from the app.setting.
Here is my class
public class DbLayer
{
[Inject]
private static IConfiguration Configuration { get; set; }
public DbLayer()
{
}
public DbLayer(IConfiguration _configuration)
{
Configuration = _configuration;
}
public const string CONNECTION_STRING_NAME = "CustomersDatabase";
private static string _connectionString = string.Empty;
public static string ConnectionString
{
get
{
if (_connectionString == string.Empty)
{
_connectionString = "Data Source=.;Initial Catalog=CustomersRegistrations;" +
"Integrated Security=SSPI; " +
"Encrypt=False;";
_connectionString = Configuration.GetConnectionString(CONNECTION_STRING_NAME);
}
return _connectionString;
}
}
}
In my startup class, I have the following:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
The problem is Configuration object is always null...
Any reason for that?

How to access other entities from ASP.NET Core Identity classes?

New to ASP.NET Core. I'm using the Identity framework for authentication, scaffolding among other the Register razor page. In the Register.cshtml.cs, I'd like to get data for populating a dropdown menu. The data is in another part of the Entity Framework tables. So the intention is to be able to select e.g. "Company" when registering a user.
I don't like too fiddle to much with the Register.cshtml.cs, i.e. modifying the constructor to take my own services and/or context objects. But how to access "my own" tables from within that page?
Can it be done? Or shouldn't it be done (why?)? And if not, any advice on making this general user admin stuff in combination with the Identity framework?
Thanks,
Palle
The ASP.NET Core Identity is used to manage users, passwords, profile data, roles, claims, tokens, email confirmation, and more. We can use the UserManager, RoleManager and SignInManager to manage the following tables:
More detail information about Identity, see Identity on ASP.NET Core.
To access other Entity Framework tables, I think you have to use the database context in the Register.cshtml.cs, like this:
public class RegisterModel : PageModel
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender;
private readonly ApplicationDbContext _context;
public RegisterModel(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger,
ApplicationDbContext context,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_context = context;
_emailSender = emailSender;
}
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { get; set; }
[BindProperty]
public List<Company> Companies { get; set; }
public IList<AuthenticationScheme> ExternalLogins { get; set; }
public class InputModel
{
...
}
public async Task OnGetAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
Companies = _context.Companies.ToList(); //get all companies from database.
}
Besides, if you still don't want to use the DB context. You could consider setting the select items with fixed options list or using an enumeration list, without getting them from the database.

I cannot retrieve connection string in DbContext class in .NET Core 2.2 Razor Pages

In Startup.cs Configure Services this works:
var connection = Configuration["ConnectionStrings:DefaultConnection"];
services.AddDbContext<MyDbContext>(
options => { options.UseSqlServer(connection); });
In my MyDbContext.cs class this doesn't work:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using OESAC.Models;
namespace OESAC.Models
{
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{ }
public DbSet<Courses> Courses { get; set; }
public DbSet<Sponsors> Sponsors{ get; set; }
public IConfiguration Configuration { get; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connection = Configuration["ConnectionStrings:DefaultConnection"];
optionsBuilder.UseSqlServer(connection);
;
}
}
}
I can hardcode the connection string but I want it to dynamically change based on my appSettings.Development.json and appSettngs.json (production). I can't believe the time I've spent trying to figure this out. It has cost me way over what I am being paid.
You need to inject IConfiguration in constructor to have an access to configuration.
public class MyDbContext : DbContext
{
private readonly IConfiguration _configuration;
public MyDbContext(IConfiguration configuration)
{
_configuration = configuration
}
public DbSet<Courses> Courses { get; set; }
public DbSet<Sponsors> Sponsors{ get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connection = _configuration["ConnectionStrings:DefaultConnection"];
optionsBuilder.UseSqlServer(connection);
}
}
Startup.cs:
services.AddDbContext<ApplicationDbContext>();

asp.net core 2 Access httpcontext from scoped DI service accessed through hangfire task

I have an asp.net core2 application with hangfire. Configuration works fine for basic tasks, however now I need to enqueue a background job which accesses the dependency injected httpcontext and dbcontext and I am getting null reference exceptions for httpcontext - I understand why this would be, but...
Can I configure hangfire's enqueue such that the httpcontext and dbcontext from which the task is fired are included with the job? The job is always originally fired from within a controller where the contexts are available. The job is a method on ApprovalService which has _userservice injected into its constructor. _Userservice has the httpContext injected in its constructor.
As I understand it, the graph should be able to resolve this, it is just a question of how...
I dont want to refactor to pass these as arguments as the services are used elsewhere where they do have access to the contexts.
The
My startup is as follows (a lot of things removed for clarity)
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
private IHostingEnvironment _env;
public static string connection;
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc(config => {
config.Filters.Add(new AuthorizeFilter(authorizePolicy));
config.OutputFormatters.OfType<StringOutputFormatter>().Single().SupportedMediaTypes.Add("text/html");
})
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
connection = Configuration.GetConnectionString("(default)");
services.AddDbContext<CpContext>(options =>
{
options.UseSqlServer(connection);
});
services.AddHangfire(configuration => configuration
.UseSqlServerStorage(connection));
services.AddScoped<IApprovalService, ApprovalService>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<SystemControlService>();
services.AddScoped<ProjectControlService>();
services.AddIdentity<CpIdentityUser, IdentityRole>().AddUserManager<cpUserManager>();
services.AddScoped<ApprovalService>();
services.AddTransient<IEmailService, EmailService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
Log.Information("In configure");
_env = env;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseBrowserLink();
}
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseAuthentication();
app.UseMvc();
app.UseStaticFiles();
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new CustomAuthorizeFilter() }
});
app.UseHangfireServer();
}
public class CustomAuthorizeFilter : IDashboardAuthorizationFilter
{
public bool Authorize([NotNull] DashboardContext context)
{
var httpcontext = context.GetHttpContext();
return httpcontext.User.Identity.IsAuthenticated;
}
}
}
I fire the job like this (non job version commented and works - hangfire job hangs on nullreference when trying to get userID from the context);
[Produces("application/json")]
[Route("api/Approvals")]
public class ApprovalsController : Controller
{
private readonly CpContext _context;
private IUserService _userService;
private IBackgroundJobClient _backgroundJobClient;
private ApprovalService _approvalService;
public ApprovalsController(CpContext context, IUserService userService, ApprovalService approvalService, IBackgroundJobClient backgroundJobClient)
{
_context = context;
_userService = userService;
_approvalService = approvalService;
_backgroundJobClient = backgroundJobClient;
}
public class approvalWrapper
{
public int ApprovalId { get; set; }
public List<string> emailTo { get; set; }
public List<string> ccTo { get; set; }
public string ManualApprCode { get; set; }
public int RequestToId { get; set; }
public DateTime RequestDate { get; set; }
public DateTime RequiredDate { get; set; }
public DateTime ResponseDate { get; set; }
public string RequestText { get; set; }
public string ResponseText { get; set; }
public int ApprovalStatusTypeId { get; set; }
public int ApprovalItemTypeId { get; set; }
public int? NcrLinkId { get; set; }
public int? LotItpDetailLinkId { get; set; }
public int? LotQtyLinkId { get; set; }
}
// POST: api/Approvals/sendRequest
[HttpPost("sendRequest")]
public async Task<IActionResult> sendRequest([FromBody] approvalWrapper approvalInfo)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
Approval approval = new Approval()
{
RequestById = _userService.User_ID,
RequestToId = approvalInfo.RequestToId,
RequestDate = approvalInfo.RequestDate,
RequiredDate = approvalInfo.RequiredDate,
RequestText = approvalInfo.RequestText,
NcrLinkId = approvalInfo.NcrLinkId,
LotItpDetailLinkId = approvalInfo.LotItpDetailLinkId,
LotQtyLinkId = approvalInfo.LotQtyLinkId,
ApprovalItemTypeId = approvalInfo.ApprovalItemTypeId,
ApprovalStatusTypeId = 5,
};
try
{
_context.Approval.Add(approval);
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
Log.Error(ex, "Error trying to create approval.");
return StatusCode(422);
}
_backgroundJobClient.Enqueue<IApprovalService>(serv => serv.sendRequestEmailAsync(approval.ApprovalId, approvalInfo.emailTo, approvalInfo.ccTo));
//await _approvalService.sendRequestEmailAsync(approval.ApprovalId, approvalInfo.emailTo, approvalInfo.ccTo);
return Ok(1);
}
}
interface IApprovalService
{
Task<string> getApprovalRequestTextForChecklistItem(int checklistItemId);
Task<string> getApprovalRequestTextForNCR(int NCRId);
Task<bool> sendRequestEmailAsync(int apprToRequestID, List<string> emailTo = null, List<string> ccTo = null);
Task<bool> sendResponseEmailAsync(int apprToRequestID, List<string> emailTo = null, List<string> ccTo = null);
Task<bool> isApprovalCodeValidAsync(string qryString, int apprToRequestID);
}
public class ApprovalService: IApprovalService
{
CpContext _context;
IEmailService _emailService;
private ProjectControlService _projectControlService;
private SystemControlService _systemControlService;
private IUserService _userService;
public ApprovalService(CpContext context, IEmailService emailService, SystemControlService systemControlService,
ProjectControlService projectControlService, IUserService userService)
{
_context = context;
_emailService = emailService;
_userService = userService;
_systemControlService = systemControlService;
_projectControlService = projectControlService;
}
public interface IUserService
{
int Project_ID { get; }
int User_ID { get; }
Task<UserCredDto> AuthenticateAsync(string username, string password);
HashSet<string> getUserPermsForProject(int userID, int ProjectID);
IEnumerable<User> GetAll();
Task<User> GetByIdAsync(int id);
Task<User> GetUserAsync();
Task<User> CreateUserAsync(User user, string password);
Task UpdateAsync(User user, string password = null);
Task<User> DeleteAsync(int id);
bool Exists(int id);
string checkRefreshToken(string refreshToken, UserCredDto tokenOwner, int refreshLifeTime);
Task<string> getNewRefreshTokenAsync(UserCredDto tokenOwner, int refreshLifeTime = 60);
string GetUserName();
Task<UserDto> GetUser();
ClaimsPrincipal GetClaimsPrincipal();
}
public class UserService : IUserService
{
private CpContext _context;
private readonly IHttpContextAccessor _httpcontext;
public UserService(CpContext context, IHttpContextAccessor httpcontext)
{
_context = context;
_httpcontext = httpcontext;
}
}