Added NLog, Added UserService, Added database and seed seed
This commit is contained in:
@ -11,12 +11,18 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
@ -23,12 +24,14 @@ namespace Birdmap.Controllers
|
||||
private readonly IAuthService _service;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
|
||||
public AuthController(IAuthService service, IConfiguration configuration, IMapper mapper)
|
||||
public AuthController(IAuthService service, IConfiguration configuration, IMapper mapper, ILogger<AuthController> logger)
|
||||
{
|
||||
_service = service;
|
||||
_configuration = configuration;
|
||||
_mapper = mapper;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
@ -36,7 +39,12 @@ namespace Birdmap.Controllers
|
||||
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> AuthenticateAsync([FromBody] AuthenticateRequest model)
|
||||
{
|
||||
_logger.LogInformation($"Authenticating user [{model.Username}] with password [*******]...");
|
||||
|
||||
var user = await _service.AuthenticateUserAsync(model.Username, model.Password);
|
||||
|
||||
_logger.LogInformation($"Authenticated user [{user.Name}]. Returning token...");
|
||||
|
||||
var expiresInSeconds = TimeSpan.FromHours(2).TotalSeconds;
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(_configuration["Secret"]);
|
||||
@ -60,5 +68,17 @@ namespace Birdmap.Controllers
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("register")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> RegisterAsync([FromBody] RegisterRequest model)
|
||||
{
|
||||
_logger.LogInformation($"Registering user [{model.Username}]...");
|
||||
var created = await _service.RegisterUserAsync(model.Username, model.Password);
|
||||
|
||||
_logger.LogInformation($"Registered user [{created.Id}.");
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
Birdmap/DTOs/RegisterRequest.cs
Normal file
17
Birdmap/DTOs/RegisterRequest.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Birdmap.API.DTOs
|
||||
{
|
||||
public class RegisterRequest
|
||||
{
|
||||
[Required(AllowEmptyStrings = false, ErrorMessage = "Username is required.")]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Required(AllowEmptyStrings = false, ErrorMessage = "Password is required."), DataType(DataType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required(AllowEmptyStrings = false, ErrorMessage = "Please confirm password.")]
|
||||
[DataType(DataType.Password), Compare(nameof(Password), ErrorMessage = "Passwords did not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
}
|
56
Birdmap/Middlewares/ExceptionHandlerMiddleware.cs
Normal file
56
Birdmap/Middlewares/ExceptionHandlerMiddleware.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using Birdmap.BLL.Exceptions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Birdmap.API.Middlewares
|
||||
{
|
||||
public class ExceptionHandlerMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
|
||||
|
||||
public ExceptionHandlerMiddleware(RequestDelegate next, ILogger<ExceptionHandlerMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await HandleException(context, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Task HandleException(HttpContext context, Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "");
|
||||
|
||||
var code = ex switch
|
||||
{
|
||||
AuthenticationException _ => HttpStatusCode.Unauthorized,
|
||||
EntityNotFoundException _ => HttpStatusCode.NotFound,
|
||||
ArgumentException _ => HttpStatusCode.BadRequest,
|
||||
DbUpdateConcurrencyException _ => HttpStatusCode.Conflict,
|
||||
_ => HttpStatusCode.InternalServerError,
|
||||
};
|
||||
|
||||
var result = JsonConvert.SerializeObject(new { error = ex.Message, exception = ex.ToString() });
|
||||
|
||||
context.Response.ContentType = "application/json";
|
||||
context.Response.StatusCode = (int)code;
|
||||
|
||||
return context.Response.WriteAsync(result);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
@page
|
||||
@model ErrorModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Birdmap.Pages
|
||||
{
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public class ErrorModel : PageModel
|
||||
{
|
||||
private readonly ILogger<ErrorModel> logger;
|
||||
|
||||
public ErrorModel(ILogger<ErrorModel> _logger)
|
||||
{
|
||||
logger = _logger;
|
||||
}
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
@using Birdmap
|
||||
@namespace Birdmap.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog;
|
||||
using NLog.Web;
|
||||
using System;
|
||||
|
||||
namespace Birdmap
|
||||
{
|
||||
@ -13,7 +11,22 @@ namespace Birdmap
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
var logger = NLogBuilder.ConfigureNLog("NLog.config").GetCurrentClassLogger();
|
||||
|
||||
try
|
||||
{
|
||||
logger.Debug("Main called...");
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, "Exception occurred in Main.");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogManager.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
@ -21,6 +34,12 @@ namespace Birdmap
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}).ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.AddConsole();
|
||||
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
|
||||
})
|
||||
.UseNLog();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using AutoMapper;
|
||||
using Birdmap.API.Middlewares;
|
||||
using Birdmap.BLL;
|
||||
using Birdmap.BLL.Interfaces;
|
||||
using Birdmap.DAL;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
@ -34,6 +35,8 @@ namespace Birdmap
|
||||
services.ConfigureBLL(Configuration);
|
||||
services.ConfigureDAL(Configuration);
|
||||
|
||||
services.AddAutoMapper(typeof(Startup));
|
||||
|
||||
var key = Encoding.ASCII.GetBytes(Configuration["Secret"]);
|
||||
services.AddAuthentication(opt =>
|
||||
{
|
||||
@ -70,9 +73,7 @@ namespace Birdmap
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/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.UseMiddleware<ExceptionHandlerMiddleware>();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
@ -86,6 +87,7 @@ namespace Birdmap
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapHealthChecks("/health").RequireAuthorization();
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
|
||||
|
@ -8,24 +8,5 @@
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Secret": "7vj.3KW.hYE!}4u6",
|
||||
"LocalDbConnectionString": null,
|
||||
"Default": {
|
||||
"Users": [
|
||||
{
|
||||
"Username": "user",
|
||||
"Password": "pass",
|
||||
"Role": "User"
|
||||
},
|
||||
{
|
||||
"Username": "admin",
|
||||
"Password": "pass",
|
||||
"Role": "Admin"
|
||||
}
|
||||
],
|
||||
"Endpoints": [
|
||||
"",
|
||||
"",
|
||||
""
|
||||
]
|
||||
}
|
||||
"LocalDbConnectionString": "Data Source=DESKTOP-A6JQ6B5\\SQLEXPRESS;Initial Catalog=Birdmap;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
|
||||
}
|
||||
|
35
Birdmap/nlog.config
Normal file
35
Birdmap/nlog.config
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
autoReload="true"
|
||||
internalLogLevel="Info"
|
||||
internalLogFile="${basedir}Log/internal-nlog.txt"
|
||||
throwConfigExceptions="true">
|
||||
|
||||
<!-- enable asp.net core layout renderers -->
|
||||
<extensions>
|
||||
<add assembly="NLog.Web.AspNetCore"/>
|
||||
</extensions>
|
||||
|
||||
<!-- the targets to write to -->
|
||||
<targets async="true">
|
||||
<default-target-parameters xsi:type="File" keepFileOpen="false" maxArchiveFiles="10" archiveAboveSize="1048576"/>
|
||||
<target xsi:type="File" name="allfile" fileName="${basedir}Log/birdmap-all-${shortdate}.log"
|
||||
layout="${longdate} [${event-properties:item=EventId_Id}] ${uppercase:${level}} ${logger} - ${message} ${exception:format=tostring}" />
|
||||
|
||||
<!-- another file log, only own logs. Uses some ASP.NET core renderers -->
|
||||
<target xsi:type="File" name="ownFile" fileName="${basedir}Log/birdmap-own-${shortdate}.log"
|
||||
layout="${longdate} [${event-properties:item=EventId_Id}] ${uppercase:${level}} ${callsite} - ${message} ${exception:format=tostring} (url: ${aspnet-request-url})(action: ${aspnet-mvc-action})" />
|
||||
</targets>
|
||||
|
||||
<!-- rules to map from logger name to target +-->
|
||||
<rules>
|
||||
<!--All logs, including from Microsoft-->
|
||||
<logger name="*" minlevel="Trace" writeTo="allfile" />
|
||||
|
||||
<!--Skip non-critical Microsoft logs and so log only own logs-->
|
||||
<logger name="Microsoft.*" maxlevel="Info" final="true" />
|
||||
<!-- BlackHole without writeTo -->
|
||||
<logger name="*" minlevel="Trace" writeTo="ownFile" />
|
||||
</rules>
|
||||
</nlog>
|
Reference in New Issue
Block a user