Skip to content

Commit 1cb498b

Browse files
committed
feat: custom exception handler
1 parent c3b5e3d commit 1cb498b

File tree

6 files changed

+149
-39
lines changed

6 files changed

+149
-39
lines changed
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1-
namespace Bookmark.Application
1+
using AutoMapper;
2+
using FluentValidation;
3+
using MediatR;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using System.Reflection;
6+
7+
namespace Bookmark.Application
28
{
3-
public class ApplicationServicesExtensions
9+
public static class ApplicationServicesExtensions
410
{
11+
public static void AddApplication(this IServiceCollection services)
12+
{
13+
services.AddMediatR(Assembly.GetExecutingAssembly());
14+
services.AddAutoMapper(Assembly.GetExecutingAssembly());
15+
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
16+
17+
18+
//services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
519

20+
}
621
}
722
}
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
namespace Bookmark.Application.Common.Exceptions
1+
using System;
2+
3+
namespace Bookmark.Application.Common.Exceptions
24
{
3-
public class BadRequestException
5+
public class BadRequestException : Exception
46
{
5-
7+
public BadRequestException(string message)
8+
: base(message)
9+
{
10+
}
611
}
712
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using Bookmark.Application.Common.Exceptions;
2+
using Microsoft.AspNetCore.Http;
3+
using Microsoft.Extensions.Logging;
4+
using Newtonsoft.Json;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Net;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
12+
namespace Bookmark.Application.Common.Middleware
13+
{
14+
public class CustomExceptionHandlerMiddleware
15+
{
16+
private readonly RequestDelegate _next;
17+
private readonly ILogger<CustomExceptionHandlerMiddleware> _logger;
18+
public CustomExceptionHandlerMiddleware(RequestDelegate next,
19+
ILogger<CustomExceptionHandlerMiddleware> logger)
20+
{
21+
_next = next;
22+
_logger = logger;
23+
}
24+
25+
public async Task Invoke(HttpContext context)
26+
{
27+
try
28+
{
29+
await _next(context);
30+
}
31+
catch (Exception exceptionObj)
32+
{
33+
await HandleExceptionAsync(context, exceptionObj, _logger);
34+
}
35+
}
36+
37+
private static Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger<CustomExceptionHandlerMiddleware> logger)
38+
{
39+
int code;
40+
var result = exception.Message;
41+
42+
switch (exception)
43+
{
44+
case ValidationException validationException:
45+
code = (int)HttpStatusCode.BadRequest;
46+
result = JsonConvert.SerializeObject(validationException.Failures);
47+
break;
48+
case ApiException apiException:
49+
code = (int)HttpStatusCode.BadRequest;
50+
result = apiException.Message;
51+
break;
52+
case BadRequestException badRequestException:
53+
code = (int)HttpStatusCode.BadRequest;
54+
result = badRequestException.Message;
55+
break;
56+
case DeleteFailureException deleteFailureException:
57+
code = (int)HttpStatusCode.BadRequest;
58+
result = deleteFailureException.Message;
59+
break;
60+
case NotFoundException _:
61+
code = (int)HttpStatusCode.NotFound;
62+
break;
63+
default:
64+
code = (int)HttpStatusCode.InternalServerError;
65+
break;
66+
}
67+
68+
logger.LogError(result);
69+
70+
context.Response.ContentType = "application/json";
71+
context.Response.StatusCode = code;
72+
return context.Response.WriteAsync(JsonConvert.SerializeObject(new { StatusCode = code, ErrorMessage = exception.Message }));
73+
}
74+
}
75+
76+
}

src/Bookmark.Infrastructure/Bookmark.Infrastructure.csproj

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,22 @@
44
<TargetFramework>netcoreapp3.1</TargetFramework>
55
</PropertyGroup>
66

7-
<ItemGroup>
8-
<ProjectReference Include="..\Bookmark.Application\Bookmark.Application.csproj" />
9-
<ProjectReference Include="..\Bookmark.Common\Bookmark.Common.csproj" />
10-
</ItemGroup>
7+
118

129
<ItemGroup>
1310
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.7" />
1411
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="3.1.7" />
1512
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.7" />
1613
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.7" />
14+
<PackageReference Include="microsoft.extensions.dependencyinjection" Version="3.1.7" />
1715
<PackageReference Include="MimeKit" Version="2.9.1" />
1816
<PackageReference Include="MailKit" Version="2.8.0" />
17+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.7" />
18+
</ItemGroup>
19+
20+
21+
<ItemGroup>
22+
<ProjectReference Include="..\Bookmark.Application\Bookmark.Application.csproj" />
23+
<ProjectReference Include="..\Bookmark.Common\Bookmark.Common.csproj" />
1924
</ItemGroup>
20-
2125
</Project>

src/Bookmark.Infrastructure/Services/AccountService.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,18 @@ public async Task<Response<AuthenticationResponse>> AuthenticateAsync(Authentica
4747
{
4848
throw new ApiException($"No Accounts Registered with {request.Email}.");
4949
}
50-
var result = await _signInManager.PasswordSignInAsync(user.UserName, request.Password, false, lockoutOnFailure: false);
51-
if (!result.Succeeded)
52-
{
53-
throw new ApiException($"Invalid Credentials for '{request.Email}'.");
54-
}
55-
if (!user.EmailConfirmed)
56-
{
57-
throw new ApiException($"Account Not Confirmed for '{request.Email}'.");
58-
}
50+
51+
//TODO: Need to check below code
52+
//var result = await _signInManager.PasswordSignInAsync(user.UserName, request.Password, false, lockoutOnFailure: false);
53+
//if (!result.Succeeded)
54+
//{
55+
// throw new ApiException($"Invalid Credentials for '{request.Email}'.");
56+
//}
57+
58+
//if (!user.EmailConfirmed)
59+
//{
60+
// throw new ApiException($"Account Not Confirmed for '{request.Email}'.");
61+
//}
5962
JwtSecurityToken jwtSecurityToken = await GenerateJWToken(user);
6063
AuthenticationResponse response = new AuthenticationResponse();
6164
response.Id = user.Id;

src/Bookmark.WebApi/Startup.cs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using System.Reflection;
1818
using Microsoft.OpenApi.Models;
1919
using System.Collections.Generic;
20+
using Bookmark.Application.Common.Middleware;
2021

2122
namespace Bookmark.WebApi
2223
{
@@ -38,11 +39,11 @@ public void ConfigureServices(IServiceCollection services)
3839
opt.UseSqlServer(Configuration.GetConnectionString("BookmarkConn")
3940
));
4041

41-
42+
4243
services.AddIdentityInfrastructure(Configuration);
4344
services.AddTransient<IEmailService, MailService>();
44-
45-
45+
46+
4647
services.AddSwaggerGen(setupAction =>
4748
{
4849
setupAction.SwaggerDoc(
@@ -64,14 +65,14 @@ public void ConfigureServices(IServiceCollection services)
6465
Url = new Uri("https://opensource.org/licenses/MIT")
6566
}
6667
});
67-
setupAction.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
68-
{
69-
Type = SecuritySchemeType.Http,
70-
Scheme = "bearer",
71-
BearerFormat = "JWT",
72-
Description = $"Input your Bearer token in this format - Bearer token to access this API",
73-
});
74-
setupAction.AddSecurityRequirement(new OpenApiSecurityRequirement
68+
setupAction.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
69+
{
70+
Type = SecuritySchemeType.Http,
71+
Scheme = "bearer",
72+
BearerFormat = "JWT",
73+
Description = $"Input your Bearer token in this format - Bearer token to access this API",
74+
});
75+
setupAction.AddSecurityRequirement(new OpenApiSecurityRequirement
7576
{
7677
{
7778
new OpenApiSecurityScheme
@@ -98,7 +99,7 @@ public void ConfigureServices(IServiceCollection services)
9899
config.ReportApiVersions = true;
99100
});
100101

101-
102+
102103
}
103104

104105
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory log)
@@ -108,17 +109,16 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
108109
app.UseDeveloperExceptionPage();
109110
}
110111

111-
log.AddSerilog();
112+
app.UseCors(options =>
113+
options.WithOrigins("http://localhost:3000")
114+
.AllowAnyHeader()
115+
.AllowAnyMethod());
112116

113-
//app.UseMiddleware<CustomExceptionHandlerMiddleware>();
117+
log.AddSerilog();
114118

115-
app.UseSwagger();
119+
log.AddSerilog();
116120

117-
app.UseSwaggerUI(setupAction =>
118-
{
119-
setupAction.SwaggerEndpoint("/swagger/OpenAPISpecification/swagger.json", "Clean Architecture WebAPI");
120-
setupAction.RoutePrefix = "OpenAPI";
121-
});
121+
app.UseMiddleware<CustomExceptionHandlerMiddleware>();
122122

123123
app.UseHttpsRedirection();
124124

@@ -128,6 +128,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
128128

129129
app.UseAuthorization();
130130

131+
app.UseSwagger();
132+
133+
app.UseSwaggerUI(setupAction =>
134+
{
135+
setupAction.SwaggerEndpoint("/swagger/OpenAPISpecification/swagger.json", "Clean Architecture WebAPI");
136+
setupAction.RoutePrefix = "OpenAPI";
137+
});
131138
app.UseEndpoints(endpoints =>
132139
{
133140
endpoints.MapControllers();

0 commit comments

Comments
 (0)