I have problem in my .Net project with my Controller/service.
My program works but if I want to register user in Postman program throw error 500 as at the bottom.
I really have no idea whats the problem, it works few changes ago.
Can someone explain me why it stop working?
.net 6
DbContext:
public class TrainingAppContext : DbContext
{
public DbSet<User>? User { get; set; }
public DbSet<Calendar>? Calendar { get; set; }
public DbSet<Exercises>? Exercises { get; set; }
public TrainingAppContext(DbContextOptions<TrainingAppContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(r => r.Name);
}
public static implicit operator string(TrainingAppContext v)
{
throw new NotImplementedException();
}
}
Controller:
[
Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
public AuthController(LoginService loginService)
{
_loginService = loginService;
}
private LoginService _loginService;
[HttpPost("login")]
public IActionResult Login([FromBody] User user)
{
bool checkUserLogIn = _loginService.CheckUserLogIn(user.Name, user.Password);
if (checkUserLogIn)
{
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey#345"));
var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var claims = new[] {
new Claim(ClaimTypes.Name, user.Name),
};
var tokenOptions = new JwtSecurityToken
(
issuer: "https://localhost:5001",
audience: "https://localhost:5001",
claims: claims,
expires: DateTime.Now.AddMinutes(15),
signingCredentials: signingCredentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokenOptions);
return Ok(new { Token = tokenString });
}
else
{
return Unauthorized();
}
}
[HttpPost("Register")]
public IActionResult Register([FromBody] User user)
{
bool CheckName = _loginService.CheckUserExist(user.Name);
if (!CheckName)
{
if (_loginService.AddUser(user.Name, user.Password, user.Trainer))
{
return Ok();
}
else return BadRequest();
}
else
{
return Unauthorized();
}
}
service:
public class LoginService
{
private TrainingAppContext _context;
public LoginService(TrainingAppContext context)
{
_context = context;
}
public bool CheckUserLogIn(string name, string password)
{
if(_context.User.Where(x => x.Name == name && x.Password == password).Any())
return true;
else return false;
}
public bool CheckUserExist(string name)
{
if (_context.User.Any(x => x.Name == name))
return true;
else return false;
}
public bool AddUser(string name, string password, bool trainer)
{
using (var db = _context)
{
var user = new User { Name = name, Password = password, Trainer = trainer };
db.User.Add(user);
db.SaveChanges();
return true;
}
}
}
program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(opt => {
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "https://localhost:5001",
ValidAudience = "https://localhost:5001",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey#345"))
};
});
builder.Services.AddCors(options =>
{
options.AddPolicy("EnableCORS", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
builder.Services.AddDbContext<TrainingAppContext>(
options => options.UseSqlServer("Server=(Localdb)\\mssqllocaldb;Database=TrainingAppData"));
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseCors("EnableCORS");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
error in console:
fail:
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Unable to resolve service for type 'TrainingApp.Server.Services.LoginService' while attempting to
activate 'TrainingApp.Server.Controllers.AuthController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider
sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method3(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass7_0.b__0(ControllerContext
controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass6_0.g__CreateController|0(ControllerContext
controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State&
next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker
invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker
invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint
endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext
context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext
context)
C:\Engineering
Thesis\TrainingApp.Server\TrainingApp.Server\bin\Debug\net6.0\TrainingApp.Server.exe
(process 25696) exited with code -1.
In order to use the loginService as an Injected Dependency, you need to register it in your dependency Container.
The exception states that it was unable to resolve the Login service when attempting to activate the TrainingApp.Server.Controllers.AuthController
You will need to update your Program.cs file and add this line:
builder.Services.AddControllers();
builder.Services.AddDbContext<TrainingAppContext>(
options => options.UseSqlServer("Server=(Localdb)\\mssqllocaldb;Database=TrainingAppData"));
// Add this line to add the login service as a singleton in your DI
// Be sure to add this line before calling the build() function
// If you want it to be a Singleton
// One instance will be created for the lifetime of the application
builder.Services.AddSingleton<LoginService>();
// If you want it to be a Transient
// A new instance will be created each time you inject it
builder.Services.AddTransient<LoginService>();
// If you want it to be a Scoped
// One instance will be created for each HTTP Request
builder.Services.AddScoped<LoginService>();
var app = builder.Build();
This needs to be done for every service you want to use by Dependency Injection
Check this documentation: Dependency injection in ASP.NET Core
Difference between Scoped, Transient and Singleton
Related
I am trying to add a handler to my services in Startup.cs. Doing this will give me the following error:
Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.AspNetCore.Authorization.IAuthorizationService Lifetime: Transient ImplementationType: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService': Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' while attempting to activate 'ApiPortal.Classes.PolicyAuthorizationHandler')
Here is my Startup.cs ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.Configure<OpenIdConnectOptions>("azure", options =>
{
var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await existingOnTokenValidatedHandler(context);
await context.HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme, context.Principal);
};
var existingOnUserInformationReceived = options.Events.OnUserInformationReceived;
options.Events.OnUserInformationReceived = async context =>
{
await existingOnUserInformationReceived(context);
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("AzureAccount", policy_builder => policy_builder.AddRequirements(new PolicyRequirement()));
});
services.AddScoped<IAuthorizationHandler, PolicyAuthorizationHandler>();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
Here is my PolicyAuthorizationHandler.cs:
public class PolicyAuthorizationHandler : AuthorizationHandler<PolicyRequirement>
{
readonly IHttpContextAccessor _contextAccessor;
public PolicyAuthorizationHandler(IHttpContextAccessor ca)
{
_contextAccessor = ca;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext filterContext)
{
var area = "";
var controller = (filterContext.RouteData.Values["controller"] as string)?.ToLower();
var action = (filterContext.RouteData.Values["action"] as string)?.ToLower();
var id = "";
if (await requirement.Pass(context, _contextAccessor, area, controller, action, id))
{
context.Succeed(requirement);
}
}
if (context.Resource is DefaultHttpContext httpContext)
{
var area = "";
var controller = httpContext.Request.RouteValues["controller"].ToString();
var action = httpContext.Request.RouteValues["action"].ToString();
var id = "";
if (await requirement.Pass(context, _contextAccessor, area, controller, action, id))
{
context.Succeed(requirement);
}
}
}
}
Here is my PolicyRequirement.cs class:
public class PolicyRequirement : IAuthorizationRequirement
{
IHttpContextAccessor _contextAccessor;
AuthorizationHandlerContext _context;
public async Task<bool> Pass(AuthorizationHandlerContext context, IHttpContextAccessor contextAccessor, string area, string controller, string action, string id)
{
_context = context;
_contextAccessor = contextAccessor;
bool authorized = false;
//authorization logic goes here
string email = contextAccessor.HttpContext.User.Identity.Name;
if (email == "myemail#email.com") authorized = true;
return await Task.FromResult(authorized);
}
}
I have already tried changing services.AddScoped<IAuthorizationHandler, PolicyAuthorizationHandler>() to services.AddTransient<IAuthorizationHandler, PolicyAuthorizationHandler>() and services.AddSingleton<IAuthorizationHandler, PolicyAuthorizationHandler>(). These don't seem to work.
I have also taken a look at this and this thread, but I can't seem to find a solution for my problem here as well.
What am I doing wrong and what can I do to fix this error? Thanks in advance.
This error means that PolicyAuthorizationHandler class depends on a service of type IHttpContextAccessor, but that service is not registered in the service container.
you need to register IHttpContextAccessor in ConfigureServices by adding line services.AddHttpContextAccessor();
and after this, you can pass IHttpContextAccessor to the constructor of PolicyAuthorizationHandler
`
In ASP.NET Core-6 Web API, I have this code:
BaseController:
[Produces("application/json")]
[ApiController]
[ApiVersion("1.0")]
public class BaseApiController : ControllerBase
{
}
Controller:
[Consumes("application/json")]
public class AuthController : BaseApiController
{
private readonly ILogger<AuthController> _logger;
private IAuthService _authService;
public AuthController(ILogger<AuthController> logger, IAuthService authService)
{
_logger = logger;
_authService = authService;
}
[HttpPost]
[Route(ApiRoutes.Auth.SignIn)]
public async Task<ActionResult<Response<LoginResponseDto>>> Login([FromBody] LoginRequestDto model)
{
var result = await _authService.Login(model);
return StatusCode(result.StatusCode, result);
}
}
ApiRoutes:
public static class ApiRoutes
{
public const string Domain = "api";
public const string Version = "v{version:apiVersion}";
public const string Base = Domain + "/" + Version;
public static class Auth
{
public const string SignIn = Base + "/login";
}
}
IAuthService:
public interface IAuthService
{
Task<Response<LoginResponseDto>> Login(LoginRequestDto loginDto);
}
AuthService:
using Serilog;
public class AuthService : IAuthService
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly IMapper _mapper;
private readonly ITokenGeneratorService _tokenGenerator;
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;
private readonly ITokenRepository _tokenRepository;
public AuthService(UserManager<ApplicationUser> userManager, IUnitOfWork unitOfWork, ILogger logger,
IMapper mapper, ITokenGeneratorService tokenGenerator, ITokenRepository tokenRepository)
{
_userManager = userManager;
_mapper = mapper;
_tokenGenerator = tokenGenerator;
_unitOfWork = unitOfWork;
_logger = logger;
_tokenRepository = tokenRepository;
}
public async Task<Response<LoginResponseDto>> Login(LoginRequestDto model)
{
var response = new Response<LoginResponseDto>();
_logger.Information("Login Attempt");
var validityResult = await ValidateUser(model);
if (!validityResult.Successful)
{
_logger.Error("Login operation failed");
response.Message = validityResult.Message;
response.StatusCode = validityResult.StatusCode;
response.Successful = false;
return response;
}
//var user = await _userManager.FindByEmailAsync(model.Email);
var user = await _userManager.FindByEmailAsync(model.UserName);
var roles = await _userManager.GetRolesAsync(user);
var refreshToken = _tokenGenerator.GenerateRefreshToken();
user.RefreshToken = refreshToken;
user.RefreshTokenExpiryTime = DateTime.Now.AddDays(7); //sets refresh token for 7 days
var result = new LoginResponseDto()
{
Token = await _tokenGenerator.GenerateToken(user),
RefreshToken = refreshToken,
User = _mapper.Map<UserDto>(user),
Roles = roles,
//expires = token.ValidTo
};
await _userManager.UpdateAsync(user);
_logger.Information("User successfully logged in");
response.StatusCode = (int)HttpStatusCode.OK;
response.Message = "Login Successfully";
response.Data = result;
response.Successful = true;
return response;
}
}
ApplicationDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<ApplicationRole> ApplicationRoles { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
base.OnModelCreating(builder);
}
}
Sorry if my code is too much. I just want to show full detail.
Finally in my code I have the program.cs that binds the services.
Program.cs:
var builder = WebApplication.CreateBuilder(args);
ConfigurationManager configuration = builder.Configuration;
var environment = builder.Environment;
var swaggerDocOptions = new SwaggerDocOptions();
// Add services to the container.
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>(
options =>
{
options.SignIn.RequireConfirmedAccount = false;
options.User.RequireUniqueEmail = true;
options.Password.RequireUppercase = false;
}).AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddMvc();
builder.Services.AddControllers().AddNewtonsoftJson(op => op.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore); ;
// AutoMapper
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
// Authentication
builder.Services.AddAuthentication(configuration);
// Db Injection
builder.Services.AddDbContextAndConfigurations(environment, configuration);
// Swagger
builder.Services.AddSwaggerGen();
builder.Services.AddOptions<SwaggerGenOptions>()
.Configure<IApiVersionDescriptionProvider>((swagger, service) =>
{
foreach (ApiVersionDescription description in service.ApiVersionDescriptions)
{
swagger.SwaggerDoc(description.GroupName, new OpenApiInfo
{
Title = swaggerDocOptions.Title,
Version = description.ApiVersion.ToString(),
Description = swaggerDocOptions.Description,
TermsOfService = new Uri("https://ddddd.com/LICENSE.md"),
Contact = new OpenApiContact
{
Name = swaggerDocOptions.Organization,
Email = swaggerDocOptions.Email
},
License = new OpenApiLicense
{
Name = "MIT",
Url = new Uri("https://ddddd.com")
}
});
}
var security = new Dictionary<string, IEnumerable<string>>
{
{"Bearer", new string[0]}
};
swagger.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT"
});
swagger.OperationFilter<AuthorizeCheckOperationFilter>();
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
swagger.IncludeXmlComments(xmlPath);
});
// Register and Configure API versioning
builder.Services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ReportApiVersions = true;
});
// Register and configure API versioning explorer
builder.Services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});
// DI
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
builder.Services.AddScoped<ITokenRepository, TokenRepository>();
builder.Services.AddScoped<ITokenGeneratorService, TokenGeneratorService>();
builder.Services.AddScoped<UserManager<ApplicationUser>>();
builder.Services.AddScoped<RoleManager<ApplicationRole>>();
builder.Logging.AddJsonConsole();
var app = builder.Build();
// Logging
ILogger logger = app.Logger;
// Seed At Start
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<ApplicationRole>>();
try
{
await ApplicationSeeder.SeedData(context, userManager, roleManager);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occured while attempting to create DB");
}
}
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseHsts();
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.MapControllers();
string? port = Environment.GetEnvironmentVariable("PORT");
if (!string.IsNullOrWhiteSpace(port))
{
app.Urls.Add("http://*:" + port);
}
app.Run();
I used AutoMapper and Serilog.
When I tried to Run the Application, I got this error:
System.AggregateException
HResult=0x80131500
Message=Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: IAuthService Lifetime: Scoped ImplementationType: AuthService': Unable to resolve service for type 'Serilog.ILogger' while attempting to activate 'AuthService'.)
Source=Microsoft.Extensions.DependencyInjection
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(ICollection`1 serviceDescriptors, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at Microsoft.AspNetCore.Builder.WebApplicationBuilder.Build()
at Program.<<Main>$>d__0.MoveNext() in C:\Trustedpath\Zenith_Projects\ManagedAccount\ZMA-App\ZMA.WebApi\Program.cs:line 136
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: IAuthService Lifetime: Scoped ImplementationType: AuthService': Unable to resolve service for type 'Serilog.ILogger' while attempting to activate 'AuthService'.
Inner Exception 2:
InvalidOperationException: Unable to resolve service for type 'Serilog.ILogger' while attempting to activate 'AuthService'.
I added this to Program.cs:
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.CreateLogger();
builder.Logging.ClearProviders();
builder.Logging.AddSerilog(logger);
var app = builder.Build();
and this to appsettings:
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Filter": [
{
"Name": "ByExcluding",
"Args": { "expression": "#mt = 'An unhandled exception has occurred while executing the request.'" }
}
],
"WriteTo": [
{
"Name": "File",
"Args": {
//"path": "./logs/log-.txt",
"path": "../logs/webapi-.log",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Username}{Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "Seq",
"Args": { "serverUrl": "http://localhost:5341" }
}
]
},
But the error is still there.
How do I resolve it?
Thanks
Unable to resolve service for type 'Serilog.ILogger' while attempting to activate 'AuthService' means exactly what it means. You need to register ILogger in your IOC Container, please follow the detailled steps on https://github.com/serilog/serilog-aspnetcore
Upgraded my app from .NET Core 2.2 to .NET Core 3.1. On one of my api endpoints that creates/updates a record, via HTTP POST or PUT, I am getting following error:
System.ObjectDisposedException: Cannot access a closed Stream.
at System.IO.MemoryStream.get_Position()
at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.get_Position()
at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I'm testing my api via postman. I put a breakpoint in my controller in the beginning of the endpoint method. The breakpoint isn't even getting hit so this error is happening before I can even get inside the method. Judging from the stacktrace it looks like a config issue in Startup.cs so I'll post that code.
namespace SomeTypeOf.Api
{
public class Startup
{
private bool clientSecurity = true;
// Startup constructor to set configuration
public Startup(IWebHostEnvironment env)
{
// Initial startup
// Use Environment-Instance based config files
var builder = new ConfigurationBuilder()
.SetBasePath(System.AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
//Set the local Configuration object with values from appsettings.json
Configuration = builder.Build();
clientSecurity = Boolean.Parse(Configuration["securitySettings:clientSecurity"]);
}
// Startup constructor to set configuration
public Startup(IConfiguration configuration)
{
//Set the local Configuration object with values from appsettings.json
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)
{
// Initial Setup
services.AddMvc()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver());
services.AddApplicationInsightsTelemetry(Configuration);
services.AddScoped<SomeApiResourceFilter>();
services.AddSingleton<IConfiguration>(Configuration);
// Call this in case you need aspnet-user-authtype/aspnet-user-identity
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(Configuration["appSettings:appVersion"], new OpenApiInfo { Title = Configuration["appSettings:appName"], Version = Configuration["appSettings:appVersion"] });
});
services.AddDataProtection();
// if (clientSecurity) {
//Authentication Setup
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Jwt";
options.DefaultChallengeScheme = "Jwt";
}).AddJwtBearer("Jwt", options =>
{
//TODO: Improve token validation security
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
//ValidAudience = "the audience you want to validate",
ValidateIssuer = false,
//ValidIssuer = "the isser you want to validate",
ValidateIssuerSigningKey = true, // Validate the key
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("WOOOO")),
ValidateLifetime = true, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
};
options.SaveToken = true;
//TODO: Remove this event - its not required
options.Events = new JwtBearerEvents()
{
OnTokenValidated = context =>
{
// Add the access_token as a claim, as we may actually need it
var accessToken = context.SecurityToken as JwtSecurityToken;
if (accessToken != null)
{
ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
if (identity != null)
{
identity.AddClaim(new Claim("access_token", accessToken.RawData));
}
}
return Task.CompletedTask;
}
};
});
services.AddAuthorization();
//}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
//Initial Setup
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/" + Configuration["appSettings:appVersion"] + "/swagger.json", Configuration["appSettings:appName"]);
});
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("swagger", "swagger/");
});
//Set the default landing page to Swagger
app.UseWelcomePage("/swagger");
//add NLog to ASP.NET Core
loggerFactory.AddNLog();
//Set the connection string for the loggin database
LogManager.Configuration.Variables["connectionString"] = Configuration.GetConnectionString("LoggingDatabase");
//Set the instance name for logging (used in the nlog config)
LogManager.Configuration.Variables["appInstance"] = Configuration["appSettings:appInstance"];
XmlLoggingConfiguration xmlconfig = (XmlLoggingConfiguration)LogManager.Configuration;
//Allow AutoReload of NLog config
xmlconfig.AutoReload = Boolean.Parse(Configuration["Logging:AutoReload"]);
//Run NLog internal logging
bool isInternalLogging = Boolean.Parse(Configuration["Logging:InternalLogging"]);
if (isInternalLogging)
{
InternalLogger.LogFile = Configuration["Logging:LogFiles:Internal"];
InternalLogger.LogLevel = LogLevel.FromString(Configuration["Logging:LogLevel:Internal"]);
}
//Set the Path to locally generated log files for the API
LogManager.Configuration.Variables["apiFileLogPath"] = Configuration["Logging:LogFiles:ApiFileLogPath"];
var target = (FileTarget)LogManager.Configuration.FindTargetByName("apiFile-log");
target.FileName = Configuration["Logging:LogFiles:ApiFileLog"];
}
}
}
Not sure if it matters but here is the beginning snippet of my api endpoint just in case
[HttpPost("SomeApi/SomeRecords")]
[HttpPut("SomeApi/SomeRecords")]
[ServiceFilter(typeof(SomeApiResourceFilter))]
public SomeApiResponse PutSomeRecordBody([FromBody] SomeRecord indexRecord)
{
SomeApiResponse response = new SomeApiResponse();
SomeApiError sae;
var userClaims = HttpContext.User.Claims;
var clientSystem = userClaims.First(c => c.Type == ClaimTypes.Name).Value;
...
}
Here's the filter code
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using NLog;
using System.Text;
using System.IO;
using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
namespace SomeApi.Filters
{
public class SomeApiResourceFilter : Attribute, IResourceFilter
{
private readonly ILogger _logger;
public SomeApiResourceFilter()
{
_logger = LogManager.GetCurrentClassLogger();
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
_logger.Debug(context.ActionDescriptor.DisplayName + "- OnResourceExecuted");
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
_logger.Debug(context.ActionDescriptor.DisplayName + "- OnResourceExecuting");
//var body = context.HttpContext.Request.Body;
HttpRequestRewindExtensions.EnableBuffering(context.HttpContext.Request);
var injectedRequestStream = new MemoryStream();
try
{
string clientSystem = "Unknown";
var userClaims = context.HttpContext.User.Claims;
if (userClaims != null && userClaims.Count()>0)
{
clientSystem = userClaims.First(c => c.Type == ClaimTypes.Name).Value;
}
else
{
if (context.HttpContext.Connection.RemoteIpAddress != null &&
context.HttpContext.Connection.RemoteIpAddress.ToString().Length > 0)
{
clientSystem += " " + context.HttpContext.Connection.RemoteIpAddress.ToString();
}
}
var requestLog = clientSystem + " | " + context.HttpContext.Request.Method + " "
+ context.HttpContext.Request.Path + context.HttpContext.Request.QueryString.Value;
using (var bodyReader = new StreamReader(context.HttpContext.Request.Body))
{
var bodyAsText = bodyReader.ReadToEnd();
if (string.IsNullOrWhiteSpace(bodyAsText) == false)
{
requestLog += $" | {bodyAsText}";
}
var bytesToWrite = Encoding.UTF8.GetBytes(bodyAsText);
injectedRequestStream.Write(bytesToWrite, 0, bytesToWrite.Length);
injectedRequestStream.Seek(0, SeekOrigin.Begin);
context.HttpContext.Request.Body = injectedRequestStream;
}
_logger.Info(requestLog);
}
catch(Exception ex)
{
_logger.Error(ex, "Unable to generate token");
}
finally
{
//injectedRequestStream.Dispose();
}
}
}
}
I am working on a ASP.NET Core version 3.0, and I was following a tutorial based on version 2.x and while setting up Startup.cs, I was told to setup UseMvcWithDefaultRoute(), but since this is not version 2.x, I found this info and tried any of those methods. Also, I did setup AddScoped<>() in Startup.cs. While testing in Postman, I used POST to send json data for Profile properties and also tried GET verb to get the list on http://localhost:5000/Profile. And both get the same error message on Postman:
System.InvalidOperationException: Unable to resolve service for type 'VueJsNetCoreWeb.Models.ProfileAdmin' while attempting to activate 'VueJsNetCoreWeb.Controllers.ProfileController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Cache-Control: no-cache
Connection: keep-alive
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip, deflate, br
Host: localhost:5000
User-Agent: PostmanRuntime/7.24.1
Content-Length: 66
Startup.cs
public Startup(IConfiguration configuration) //AppSettings
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<ApplicationDbContext>(o =>
o.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IProfileRepo, ProfileAdmin>();
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder =>
{
builder
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
.WithOrigins("http://localhost:8080");
});
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//IssuerSigningKey = key,
ValidateAudience = true,
ValidateIssuer = true
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dbContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
dbContext.Database.EnsureCreated();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
ProfileAdmin.cs
public interface IProfileRepo
{
IEnumerable<Profile> Profiles { get; }
void AddProfile(Profile profile);
}
public class ProfileAdmin : IProfileRepo
{
private List<Profile> profiles = new List<Profile>
{
new Profile { Id = 1, FirstName = "Omar", LastName = "McMillon", Age = 23 }
};
public IEnumerable<Profile> Profiles => profiles;
private int Id { get; set; }
public ProfileAdmin()
{
profiles = new List<Profile>();
//Id = 1;
}
public List<Profile> GetProfiles() =>
profiles;
public Profile GetProfile(int id) =>
profiles.FirstOrDefault(p => p.Id == id);
public Profile GetProfile(string name) =>
profiles.FirstOrDefault(p => p.FirstName == name);
public void AddProfile(Profile profile)
{
profile.Id = Id++;
profiles.Add(profile);
}
public void UpdateProfile(Profile profile)
{
var currentProfile = GetProfile(profile.Id);
currentProfile.FirstName = profile.FirstName;
currentProfile.LastName = profile.LastName;
currentProfile.Age = profile.Age;
}
public void DeleteProfile(int id) =>
profiles.RemoveAll(p => p.Id == id);
}
ProfileController.cs
namespace VueJsNetCoreWeb.Controllers
{
[Route("[controller]")] //name Profile
[ApiController] //model binding uses json
public class ProfileController : Controller
{
private ProfileAdmin _profileAdmin;
public ProfileController(ProfileAdmin profileAdmin)
{
_profileAdmin = profileAdmin;
}
[HttpGet]
public List<Profile> GetProfiles()
{
return _profileAdmin.GetProfiles();
}
[HttpGet("{name}")]
public IActionResult GetProfile(string name)
{
var profile = _profileAdmin.GetProfile(name);
if (profile == null)
return NoContent();
else
return Ok(profile);
}
[HttpPost] //If no [ApiController], use [FromBody]
public Profile CreateProfile(Profile profile)
{
_profileAdmin.AddProfile(profile);
return profile;
}
[HttpPut]
public IActionResult UpdateProfile(Profile profile)
{
_profileAdmin.UpdateProfile(profile);
return Ok();
}
[HttpDelete]
public IActionResult DeleteProfile(int id)
{
_profileAdmin.DeleteProfile(id);
return Ok();
}
}
}
From the stack trace, it seems that your controller is receiving a parameter of type ProfileAdmin where it should be receiving a IProfileRepo, which is what you registered.
I am getting an error in net core 2.1:
Bearer was not authenticated.
Failure message: No SecurityTokenValidator available for token: null
The asp net output window is:
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[7]
Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token: null
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
Policy execution successful.
The accounts controller code is here:
namespace quiz_backend.Controllers
{
public class Credentials
{
public string Email { get; set; }
public string Password { get; set; }
}
[Produces("application/json")]
[Route("api/Account")]
public class AccountController : Controller
{
readonly UserManager<IdentityUser> userManager;
readonly SignInManager<IdentityUser> signInManager;
public AccountController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
{
this.userManager = userManager;
this.signInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Register([FromBody] Credentials credentials)
{
var user = new IdentityUser {
UserName = credentials.Email,
Email = credentials.Email
};
var result = await userManager.CreateAsync(user, credentials.Password);
if (!result.Succeeded)
return BadRequest(result.Errors);
await signInManager.SignInAsync(user, isPersistent: false);
// create a token
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is the secret phrase"));
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
var jwt = new JwtSecurityToken(signingCredentials: signingCredentials);
return Ok(new JwtSecurityTokenHandler().WriteToken(jwt));
}
}
}
Here is the startup.cs
namespace quiz_backend
{
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.AddCors(options => options.AddPolicy("Cors", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddDbContext<QuizContext>(opt =>opt.UseInMemoryDatabase("quiz"));
services.AddDbContext<UserDbContext>(opt => opt.UseInMemoryDatabase("user"));
services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<UserDbContext>();
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("this is the secret phrase"));
services.AddAuthentication(options =>{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(cfg => {
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = signingKey,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
});
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("Cors");
app.UseMvc();
}
}
}
This is the front end auth code to attach the token to the header in ts:
export class AuthInterceptor implements HttpInterceptor {
constructor() {}
intercept(req, next) {
var token = localStorage.getItem('token')
var authRequest = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
})
return next.handle(authRequest)
}
}
Based on your code, it seems that the issue is that the token received is not valid (NULL).
Failure message: No SecurityTokenValidator available for token: null
First of all, you should make sure the token arrives as expected.