Quartz - .NET Core - Null Reference Exception - asp.net-core

I'm trying to implement the Quartz for .NET Core.
At the moment I have the following:
public class Startup
{
**private IScheduler _scheduler { get; set; }//quartz**
public Startup(IConfiguration configuration)
{
Configuration = configuration;
**_scheduler = ConfigureQuartz();//quartz**
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<Context>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("notebook14"));
});
...
...
...
**#region for Quartz DI
services.AddScoped<Job>();
services.AddSingleton(provider => _scheduler);
#endregion**
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
});
}
**#region for Quartz
private IScheduler ConfigureQuartz()
{
NameValueCollection properties = new NameValueCollection()
{
{"quartz.serializer.type","binary"}
};
StdSchedulerFactory factory = new StdSchedulerFactory(properties);
_scheduler = factory.GetScheduler().Result;
_scheduler.Start();
return _scheduler;
}
#endregion**
...and Program.cs because I would like to start a schedule at first deploy and then run the task every day:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
UserManager<AppUser> userManager = services.GetRequiredService<UserManager<AppUser>>();
RoleManager<AppRole> roleManager = services.GetRequiredService<RoleManager<AppRole>>();
**IScheduler scheduler = services.GetRequiredService<IScheduler>();
Start.StartSchedule(scheduler);**
Init.AssignAdmin(userManager, roleManager).Wait();
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
...and Start.cs, where I have created the job and the trigger :
public class Start
{
public static Context _context { get; set; }
public Start(Context context)
{
_context = context;
}
public async static void StartSchedule(IScheduler _scheduler)
{
IJobDetail job = JobBuilder.Create<Job>().WithIdentity("Generate", "FreeSlots").Build();
ITrigger trigger = TriggerBuilder.Create().WithIdentity("Trigger", "FreeSlots").StartNow()
.WithDailyTimeIntervalSchedule(t=>t.StartingDailyAt(new TimeOfDay(10,59)))
.Build();
await _scheduler.ScheduleJob(job, trigger);
}
}
...and finally, the Job itself:
public class Job : IJob
{
public Task Execute(IJobExecutionContext context)
{
try
{
Console.WriteLine("TRIGGERED!");
List<AppUser> doctors = Start._context.Users.Where(x => x.Type == AppUser.UserType.Doctor).ToList();
DateTime First = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 8, 0, 0);
List<Appointments> appointments = new List<Appointments>()
{
new Appointments(){Date=First, Time=First,Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(1),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(2),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(3),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(4),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(5),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(6),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(7),Status=Appointments.SlotStatus.Free},
new Appointments(){Date=First, Time=First.AddHours(8),Status=Appointments.SlotStatus.Free},
};
foreach (AppUser doc in doctors)
{
foreach (Appointments slot in appointments)
{
slot.DoctorId = doc.Id;
Start._context.Appointments.Add(slot);
Start._context.SaveChanges();
var message = "Slot for " + slot.DoctorId.ToString() + " " + slot.Time + " " + slot.Status;
Console.WriteLine(message);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return Task.CompletedTask;
}
}
The problem is that I get a null reference exception when the Job is executed:
Does anybody have any ideas? Is there a way to make this work? Thank you in advance!

Related

Authorized API is not working even when passing a JWT bearer token

The loginWithJWT() method works fine, the user login normally and the token is created.
enter image description here
but when I try to access the GetAllCountry() method that is [Authorized] after passing the token . An unauthorized response is fired.
enter image description here
This is the JWT description :
enter image description here
Not sure what I have missed.
here is my start up class :
namespace HotelListing
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
}
public void ConfigureServices(IServiceCollection services)
{
// Db conn string
services.AddDbContext<ApplicationDbContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("sqlServerConnection")));
//Identity
services.AddAuthentication();
services.AddIdentity<MyIdentityUser, IdentityRole>(options =>
{
options.User.RequireUniqueEmail = true;
}).AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//enabling JWT
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = (Configuration.GetSection("Jwt")).GetSection("Issuer").Value,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("SecretTokenKeyValue")))
};
});
// Mapper
services.AddAutoMapper(typeof(ApplicationMapper));
//DI interfaces and classes
services.AddScoped<ICountryServices, CountrySevices>();
services.AddScoped<IHotelServices, HotelServices>();
services.AddScoped<IUserAuthenticationManager, UserAuthenticationManager>();
//Swagger config
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "HotelListing", Version = "v1" });
});
//Adding Controllers + JSON self refrencing config
services.AddControllers().AddNewtonsoftJson(opt =>
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "HotelListing v1"));
}
app.UseHttpsRedirection();
app.UseCors("AllowAll");
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
here is my UserAuthenticationManager Class:
namespace HotelListing.Services
{
public class UserAuthenticationManager : IUserAuthenticationManager
{
private MyIdentityUser _user;
private UserManager<MyIdentityUser> _userManager;
private IConfiguration _configuration;
public UserAuthenticationManager(UserManager<MyIdentityUser> userManager, IConfiguration configuration)
{
_userManager = userManager;
_configuration= configuration;
}
public async Task<bool> ValidateUser(LoginUserDto userDto)
{
_user = await _userManager.FindByNameAsync(userDto.Email);
if (_user != null && await _userManager.CheckPasswordAsync(_user, userDto.Password))
return true;
else
return false;
}
public async Task<string> CreateToken()
{
var signingCredentials = GetSigningCredentials();
var claims = await GetClaims();
var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
return new JwtSecurityTokenHandler().WriteToken(tokenOptions);
}
private SigningCredentials GetSigningCredentials()
{
var key = Environment.GetEnvironmentVariable("SecretTokenKeyValue");
var secret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
}
private async Task<List<Claim>> GetClaims()
{
var claimList = new List<Claim>
{
new Claim(ClaimTypes.Name, _user.UserName)
};
var roles = await _userManager.GetRolesAsync(_user);
foreach(var role in roles){
claimList.Add(new Claim(ClaimTypes.Role, role));
}
return claimList;
}
private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCrenditals, List<Claim> claimList)
{
var jwtSettings = _configuration.GetSection("Jwt");
var token = new JwtSecurityToken(
issuer: jwtSettings.GetSection("Issuer").Value,
claims: claimList,
expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings.GetSection("lifetime").Value)),
signingCredentials: signingCrenditals);
return token;
}
}
}
here is my UserApiController:
namespace HotelListing.APIs
{
[Route("api/[controller]")]
[ApiController]
public class UserApiController : ControllerBase
{
private UserManager<MyIdentityUser> _userManager { get; }
private IUserAuthenticationManager _userAuthenticationManager { get; }
private IMapper _mapper { get; }
public UserApiController(UserManager<MyIdentityUser> userManager,
IUserAuthenticationManager userAuthenticationManager,
IMapper mapper)
{
_userManager = userManager;
_userAuthenticationManager = userAuthenticationManager;
_mapper = mapper;
}
[HttpPost]
[Route("register")]
public async Task<IActionResult> Register([FromBody] UserDTO userDTO)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
var user = _mapper.Map<MyIdentityUser>(userDTO);
user.UserName = userDTO.Email;
var result = await _userManager.CreateAsync(user, userDTO.Password);
if (!result.Succeeded)
{
foreach(var error in result.Errors)
{
ModelState.AddModelError(error.Code, error.Description);
}
return BadRequest(ModelState);
}
await _userManager.AddToRolesAsync(user, userDTO.roles);
return Accepted();
}catch(Exception ex)
{
return StatusCode(500, ex.Message + "Internal server error");
}
}
[HttpPost]
[Route("loginWithJWT")]
public async Task<IActionResult> LoginWithJWT([FromBody] LoginUserDto userDTO)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
var result = await _userAuthenticationManager.ValidateUser(userDTO);
if (result != true)
{
return Unauthorized(userDTO);
}
return Accepted(new { Token = await _userAuthenticationManager.CreateToken()});
}
catch (Exception ex)
{
return Problem($"Something went wrong in {nameof(LoginWithJWT)} error is {ex.Message}", statusCode:500);
}
}
}
}
Iam trying to access the authorized GetAllCountries() method in CountryApi class:
namespace HotelListing.APIs
{
[Route("api/[controller]")]
[ApiController]
public class CountryApiController : ControllerBase
{
private ICountryServices _countryServices { get; }
private IMapper _mapper { get; }
public CountryApiController(ICountryServices countryServices, IMapper mapper)
{
_countryServices = countryServices;
_mapper = mapper;
}
**// GET: api/<CountryApiController>
[HttpGet]
[Authorize]
public async Task<IActionResult> GetAllCountries()
{
try{
var countries = await _countryServices.GetAllCountriesAsync();
return Ok(_mapper.Map<List<CountryDTO>>(countries));
}
catch(Exception ex)
{
return StatusCode(500, ex.Message + "Internal server error");
}
}**
// GET: api/<CountryApiController>/id
[HttpGet("{id:int}")]
public async Task<IActionResult> GetCountryById(int id)
{
try
{
var country = await _countryServices.GetCountryByIdAsync(id);
return Ok(_mapper.Map<CountryDTO>(country));
}
catch (Exception ex)
{
return StatusCode(500, ex.Message + "Internal server error");
}
}
}
}

DatabaseContext object is disposed ASP.NET Core

When I try to retrieve data from a table from database using Entity Framework Core in class, I get an exception:
System.ObjectDisposedException: 'Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
My code looks like this:
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<DatabaseContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DatabaseContextConection")));
services.AddIdentity<ApplicationUser, IdentityRole>(config => {
config.User.RequireUniqueEmail = true;
config.Password.RequiredLength = 8;
config.Password.RequireNonAlphanumeric = false;
config.Password.RequireUppercase = false;
config.Password.RequireLowercase = false;
// config.COO
}).AddEntityFrameworkStores<DatabaseContext>();
services.AddScoped<IDatabaseChangeNotificationService, SqlDependencyService>();
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IDatabaseChangeNotificationService notificationService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name:"",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapHub<ChatHub>("/ChatHub");
});
notificationService.Config();
}
}
DatabaseContext.cs:
public class DatabaseContext: IdentityDbContext<ApplicationUser> ,IApplicationDbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options):base(options)
{
}
public DbSet<Message> Messages { get; set; }
public new async Task<int> SaveChanges()
{
return await base.SaveChangesAsync();
}
}
SqlDependencyService.cs:
public interface IDatabaseChangeNotificationService
{
void Config();
}
public class SqlDependencyService : IDatabaseChangeNotificationService
{
private UserManager<ApplicationUser> _userManager;
public string FullName;
public string UserId;
private readonly IConfiguration configuration;
private readonly IHubContext<ChatHub> chatHub;
private DatabaseContext _DBContext;
public SqlDependencyService(DatabaseContext DbContext, IConfiguration _configuration, IHubContext<ChatHub> _chatHub, UserManager<ApplicationUser> userManager)
{
_DBContext = DbContext;
configuration = _configuration;
chatHub = _chatHub;
_userManager = userManager;
}
public void Config()
{
TableUsersAvailabilitySensor();
}
private void TableUsersAvailabilitySensor()
{
string connectionString = configuration.GetConnectionString("DatabaseContextConection");
using (var conn = new SqlConnection(connectionString))
{
if (conn.State != System.Data.ConnectionState.Open)
{
conn.Open();
}
using (var cmd = new SqlCommand(#"Select IsActive from [dbo].AspNetUsers", conn))
{
cmd.Notification = null;
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += TableUsersChanged;
SqlDependency.Start(connectionString);
cmd.ExecuteReader();
}
}
}
List<string> AvailableUsers = new List<string>();
private void TableUsersChanged(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
string text = checkAvailabilityChanged(e);
if (text == "Updated" || text == "Inserted")
{
var list = _DBContext.Users.Where(a => a.IsActive == true).ToList();
AvailableUsers.AddRange(list.Select(a => a.UserName));
var currentUserId = _userManager.GetUserId(AccountController.currentUser);
var _currentUser = _DBContext.Users.Find(currentUserId);
FullName = _currentUser.FirstName + " " + _currentUser.LastName;
UserId = currentUserId;
chatHub.Clients.Clients(AvailableUsers).SendAsync("AddMeToYourContacts", FullName, UserId);
}
}
TableUsersAvailabilitySensor();
}
private string checkAvailabilityChanged(SqlNotificationEventArgs e)
{
switch (e.Info)
{
case SqlNotificationInfo.Update:
return "Updated";
case SqlNotificationInfo.Delete:
return "Deleted";
case SqlNotificationInfo.Insert:
return "Inserted";
default:
return "Nothing occurred";
}
}
}
The exception is thrown on this line of code:
var list = _DBContext.Users.Where(a => a.IsActive == true).ToList();

Value cannot be null - In-Memory Database .Net

I am trying to use a In-Memory Database, but I get this message:
System.ArgumentNullException: 'Value cannot be null. (Parameter
'source')'
I read a lot some similar question related with this issue, but every article is related with the connection String, and I think I must not use a ConnectionString because is a In-Memory Database. What Do I do wrong? I leave my code:
DbInitializer.cs - In this class appears the error
public static class DbInitializer
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var _context = new AppDBContext(serviceProvider.GetRequiredService<DbContextOptions<AppDBContext>>()))
{
if (_context.AgentsRole.Any()) //In this line appears the error
return;
_context.AgentsRole.AddRange(
new Agent { Id = 1, Role_Name = "David Lopez", Is_Active = true, Role_Description = "This is a test for David Lopez" },
new Agent { Id = 2, Role_Name = "James Norris", Is_Active = false, Role_Description = "This is a test for James Norris" },
new Agent { Id = 3, Role_Name = "Jhon Norris", Is_Active = true, Role_Description = "This is a test for Jhon Norris" },
new Agent { Id = 4, Role_Name = "James Norr", Is_Active = true, Role_Description = "This is a test for James Norr" }
);
_context.SaveChanges();
}
}
}
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDBContext>(options=> options.UseInMemoryDatabase(databaseName: "InMemory_DB"));
services.AddControllers();
services.AddSwaggerGen();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Test1 Api v1");
});
}
}
Program.cs:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<AppDBContext>();
DbInitializer.Initialize(services);
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Controller.cs:
[ApiController]
[Route("api/[controller]")]
public class AgentRoleController : ControllerBase
{
private readonly ILogger<AgentRoleController> _logger;
private readonly AppDBContext _context;
public AgentRoleController(ILogger<AgentRoleController> logger, AppDBContext context)
{
_logger = logger;
_context = context;
}
[HttpGet]
[SwaggerOperation("GetAgentsRole")]
[SwaggerResponse((int)HttpStatusCode.OK)]
[SwaggerResponse((int)HttpStatusCode.NotFound)]
public IEnumerable<Agent> Get()
{
return _context.AgentsRole;
}
}
AppDBContext.cs:
public class AppDBContext : DbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options)
:base(options)
{
}
public DbSet<Agent> AgentsRole;
}
The solution is in AppDBContext.cs, I missed the initialization of AgentsRole, the solution is:
public class AppDBContext : DbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options)
:base(options)
{
}
public DbSet<Agent> AgentsRole { get; set; } // I added this Part!
}

.NET Core API Endpoint gives 404 only in deployed version

I am building a .NET Core (3.1) Web API which is being hosted in IIS.
I have 2 endpoints:
/api/status
/api/widget/config/{id}
Both endpoints work perfectly when running locally. The /api/status endpoint works in my deployed version too. But the other endpoint gives a 404 error in the deployed version. As it works locally, I believe this to be an issue with how it is deployed. Please can you help me understand the issue?
Here are my 2 controllers code:
[Route("api/[controller]")]
[ApiController]
public class StatusController : ControllerBase
{
[HttpGet]
public ActionResult Get()
{
return Ok("API is available");
}
}
and
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet]
[Route("~/api/[controller]/[action]/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
and below is my Program.cs and Startup.cs:
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedDatabase.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occured seeding the DB");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
webBuilder.UseIIS();
webBuilder.UseStartup<Startup>();
});
and
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(opts => opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection"),
options => options.MigrationsAssembly("MyProject")));
services.AddIdentity<ApplicationUser, IdentityRole>(opt =>
{
opt.Password.RequiredLength = 8;
opt.Password.RequireDigit = true;
opt.Password.RequireUppercase = true;
opt.Password.RequireNonAlphanumeric = true;
opt.SignIn.RequireConfirmedAccount = false;
opt.SignIn.RequireConfirmedAccount = false;
opt.SignIn.RequireConfirmedPhoneNumber = false;
}).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddScoped<IWidgetService, WidgetService>();
services.AddCors(o => o.AddPolicy("CorsPolicy", builder => {
builder
.WithMethods("GET", "POST")
.AllowAnyHeader()
.AllowAnyOrigin();
}));
services.AddMvc()
.AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Change your controller code to this:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet("Config/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
Change your code like below:-
Startup.cs
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Controller:-
[ApiController]
[Route("api/[controller]")]
public class WidgetController : ControllerBase
{
private readonly IWidgetService service;
public WidgetController(IWidgetService _service)
{
service = _service;
}
[HttpGet("Config/{id}")]
public ActionResult Config(Guid id)
{
return Ok(service.GetWidgetConfig(id));
}
}
Also try your write connection string in appsettings.Development.json file.
It will resolve your issue.

Blazor application logging with Serilog

In a blazor application I have start-up logging configured in main as follows;
public static void Main(string[] args)
{
var assembly = Assembly.GetExecutingAssembly().GetName();
var appInsightsTelemetryConfiguration = TelemetryConfiguration.CreateDefault();
appInsightsTelemetryConfiguration.InstrumentationKey = "aa11aa11aa-a1a1-a1-aa-a111-aa11";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", $"{assembly.Name}")
.WriteTo.Console()
.WriteTo.Seq(serverUrl: "http://myseqserver.inthecloud.azurecontainer.io:5341/")
.WriteTo.ApplicationInsights(appInsightsTelemetryConfiguration, TelemetryConverter.Traces)
.CreateLogger();
try
{
Log.Information(Constants.Logging.Messages.SERVICE_STARTED, assembly.Name);
var host = CreateHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<MyDbContext>();
context.Database.Migrate(); // apply outstanding migrations automatically
}
host.Run();
return;
}
catch (Exception ex)
{
Log.Fatal(ex, Constants.Logging.Messages.SERVICE_STARTED, assembly.Name);
return;
}
finally
{
// make sure all batched messages are written.
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
and request logging in StartUp Configure;
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddApplicationInsightsTelemetry("aa11aa11aa-a1a1-a1-aa-a111-aa11");
//...
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
/// ...
// Add this line; you'll need `using Serilog;` up the top, too
app.UseSerilogRequestLogging();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
On my blazor pages I cannot get this working;
#inject ILogger<ThisRazorPage> Logger
#code{
protected override void OnInitialized()
{
Logger.LogTrace("Log something. Please!");
}
}
But this does work;
#inject ILoggerFactory LoggerFactory
#code{
protected override void OnInitialized()
{
var logger = LoggerFactory.CreateLogger<Incident>();
logger.LogTrace("Log something. Please!");
}
}
According to this the .UseSerilog() method adds the DI for ILoggerFactory. Is there a way for me to do something similar for ILogger<T> within the DI framework so that ILogger<T> can be used, rather than having to explicitly create a LoggerFactory on every page.
Static method works for me.
#using Serilog
#code {
Log.Information("Log something. Please!");
}
You need:
add Serilog.Extensions.Logging
add in your Main()
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
// ...
builder.Services.AddTransient<AccountsViewModel>();
var levelSwitch = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.Enrich.WithProperty("InstanceId", Guid.NewGuid().ToString("n"))
.CreateLogger();
// ------------- this is what you'r looking for
builder.Logging.AddSerilog();
// ...
await builder.Build().RunAsync();
}
and in your ViewModel
public class AccountsViewModel
{
private readonly ILogger<AccountsViewModel> Logger;
private readonly HttpClient Http;
public AccountsViewModel(
ILogger<AccountsViewModel> logger,
HttpClient http
)
{
Http = http;
Logger = logger;
Logger.LogInformation("AccountsViewModel()");
}
}
or in your razor-page:
#inject ILogger<ThisRazorPage> logger;