Skip to content

Commit 81430d6

Browse files
committed
Added ASP.NET Core MVC filters
1 parent 0c2e292 commit 81430d6

File tree

8 files changed

+129
-51
lines changed

8 files changed

+129
-51
lines changed
Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,49 @@
11
using asp_net_core_filters.Filters;
2-
using asp_net_core_filters.Models;
3-
using Microsoft.AspNetCore.Http;
42
using Microsoft.AspNetCore.Mvc;
5-
using Microsoft.Extensions.Caching.Memory;
63
using Microsoft.Extensions.Logging;
74
using System;
8-
using System.Diagnostics;
9-
using System.Runtime.CompilerServices;
5+
using System.Data.SqlTypes;
106

117
namespace asp_net_core_filters.Controllers
128
{
139
public class HomeController : Controller
1410
{
1511
private readonly ILogger<HomeController> _logger;
16-
private readonly IMemoryCache _memoryCache;
17-
12+
1813
public HomeController(ILogger<HomeController> logger)
1914
{
2015
_logger = logger;
2116
}
2217

18+
19+
public IActionResult ThrowSomeException()
20+
{
21+
throw new SqlNullValueException();
22+
}
23+
2324
[ServiceFilter(typeof(AuthorizeIPAddress))]
25+
[ServiceFilter(typeof(AddResultFilter))]
2426
public IActionResult Index()
2527
{
2628
return View();
2729
}
28-
29-
[CacheResourceFilter]
30+
31+
[ServiceFilter(typeof(CacheResourceFilter))]
3032
public IActionResult Message()
3133
{
3234
return Content("This content was generated at " + DateTime.Now);
3335
}
3436

37+
[ServiceFilter(typeof(TimeTaken))]
3538
public IActionResult Privacy()
3639
{
3740
return View();
3841
}
3942

40-
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
43+
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
4144
public IActionResult Error()
4245
{
43-
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
46+
return View();
4447
}
4548
}
4649
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Microsoft.AspNetCore.Mvc.Filters;
2+
3+
namespace asp_net_core_filters.Filters
4+
{
5+
public class AddResultFilter : IResultFilter
6+
{
7+
public void OnResultExecuting(ResultExecutingContext filterContext)
8+
{
9+
filterContext.HttpContext.Response.Headers.Add(
10+
"AppID",
11+
"Geeks App header was added by result filter.");
12+
}
13+
14+
public void OnResultExecuted(ResultExecutedContext filterContext)
15+
{
16+
17+
}
18+
}
19+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using asp_net_core_filters.Models;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.AspNetCore.Mvc.Filters;
4+
using Microsoft.AspNetCore.Mvc.ModelBinding;
5+
using Microsoft.AspNetCore.Mvc.ViewFeatures;
6+
7+
namespace asp_net_core_filters.Filters
8+
{
9+
public class AppExceptionHandler : IExceptionFilter
10+
{
11+
private readonly IModelMetadataProvider _modelMetadataProvider;
12+
public AppExceptionHandler(
13+
IModelMetadataProvider modelMetadataProvider)
14+
{
15+
_modelMetadataProvider = modelMetadataProvider;
16+
}
17+
18+
public void OnException(ExceptionContext context)
19+
{
20+
ErrorViewModel errorViewModel = new ErrorViewModel();
21+
errorViewModel.ErrorMessage = context.Exception.Message;
22+
errorViewModel.Source = context.Exception.StackTrace;
23+
24+
ViewResult errorViewResult = new ViewResult
25+
{
26+
ViewName = "error",
27+
ViewData = new ViewDataDictionary(_modelMetadataProvider,
28+
context.ModelState)
29+
{
30+
Model = errorViewModel
31+
}
32+
};
33+
context.ExceptionHandled = true;
34+
context.Result = errorViewResult;
35+
}
36+
}
37+
}

asp-net-core-filters/Filters/CacheResourceFilter.cs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,47 @@
11
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.AspNetCore.Mvc.Filters;
3+
using Microsoft.Extensions.Caching.Memory;
34
using System;
4-
using System.Collections.Generic;
55

66
namespace asp_net_core_filters.Filters
77
{
8-
public class CacheResourceFilter : Attribute, IResourceFilter
8+
public class CacheResourceFilter : IResourceFilter
99
{
10-
public CacheResourceFilter()
11-
{
10+
private readonly IMemoryCache _memoryCache;
11+
private string _cacheKey;
1212

13+
public CacheResourceFilter()
14+
{
15+
this._memoryCache = new MemoryCache(new MemoryCacheOptions());
1316
}
1417

15-
private static readonly Dictionary<string, object> _cache
16-
= new Dictionary<string, object>();
17-
private string _cacheKey;
1818
public void OnResourceExecuting(ResourceExecutingContext context)
1919
{
2020
_cacheKey = context.HttpContext.Request.Path.ToString();
21-
if (_cache.ContainsKey(_cacheKey))
21+
22+
string contentResult = string.Empty;
23+
24+
contentResult = _memoryCache.Get<string>(_cacheKey);
25+
26+
if(!string.IsNullOrEmpty(contentResult))
2227
{
23-
var cachedValue = _cache[_cacheKey] as string;
24-
if (cachedValue != null)
25-
{
26-
context.Result = new ContentResult()
27-
{ Content = cachedValue };
28-
}
28+
context.Result = new ContentResult()
29+
{ Content = contentResult };
2930
}
3031
}
32+
3133
public void OnResourceExecuted(ResourceExecutedContext context)
3234
{
33-
if (!string.IsNullOrEmpty(_cacheKey) && !_cache.ContainsKey(_cacheKey))
35+
if (!string.IsNullOrEmpty(_cacheKey))
3436
{
3537
var result = context.Result as ContentResult;
3638
if (result != null)
37-
{
38-
_cache.Add(_cacheKey, result.Content);
39+
{
40+
var cacheEntryOptions = new MemoryCacheEntryOptions()
41+
.SetAbsoluteExpiration(TimeSpan.FromDays(1));
42+
43+
_memoryCache.Set(_cacheKey, result.Content,
44+
cacheEntryOptions);
3945
}
4046
}
4147
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.Filters;
3+
using System.Diagnostics;
4+
5+
namespace asp_net_core_filters.Filters
6+
{
7+
public class TimeTaken : IActionFilter
8+
{
9+
private Stopwatch timer;
10+
public void OnActionExecuting(ActionExecutingContext context)
11+
{
12+
timer = Stopwatch.StartNew();
13+
}
14+
15+
public void OnActionExecuted(ActionExecutedContext context)
16+
{
17+
timer.Stop();
18+
string result = " Elapsed time: " + $"{timer.Elapsed.TotalMilliseconds} ms";
19+
Debug.WriteLine(result, "Action Filter Log");
20+
}
21+
}
22+
}

asp-net-core-filters/Models/ErrorViewModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ namespace asp_net_core_filters.Models
44
{
55
public class ErrorViewModel
66
{
7-
public string RequestId { get; set; }
7+
public string Source { get; set; }
88

9-
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
9+
public string ErrorMessage { get; set; }
1010
}
1111
}

asp-net-core-filters/Startup.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
using asp_net_core_filters.Filters;
22
using Microsoft.AspNetCore.Builder;
33
using Microsoft.AspNetCore.Hosting;
4-
using Microsoft.AspNetCore.Http;
5-
using Microsoft.AspNetCore.HttpsPolicy;
64
using Microsoft.Extensions.Configuration;
75
using Microsoft.Extensions.DependencyInjection;
86
using Microsoft.Extensions.Hosting;
9-
using System;
10-
using System.Collections.Generic;
11-
using System.Linq;
12-
using System.Threading.Tasks;
137

148
namespace asp_net_core_filters
159
{
@@ -25,7 +19,13 @@ public Startup(IConfiguration configuration)
2519
// This method gets called by the runtime. Use this method to add services to the container.
2620
public void ConfigureServices(IServiceCollection services)
2721
{
28-
services.AddControllersWithViews();
22+
services.AddControllersWithViews(config =>
23+
config.Filters.Add(typeof(AppExceptionHandler)));
24+
25+
services.AddMemoryCache();
26+
services.AddSingleton<CacheResourceFilter>();
27+
services.AddScoped<TimeTaken>();
28+
services.AddScoped<AddResultFilter>();
2929
services.AddScoped<AuthorizeIPAddress>(container =>
3030
{
3131
//test for valid authorization
@@ -34,6 +34,8 @@ public void ConfigureServices(IServiceCollection services)
3434
//test for invalid authorization
3535
//return new AuthorizeIPAddress("000.0.0.0");
3636
});
37+
38+
3739
}
3840

3941
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

asp-net-core-filters/Views/Shared/Error.cshtml

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,12 @@
33
ViewData["Title"] = "Error";
44
}
55

6-
<h1 class="text-danger">Error.</h1>
76
<h2 class="text-danger">An error occurred while processing your request.</h2>
87

9-
@if (Model.ShowRequestId)
10-
{
11-
<p>
12-
<strong>Request ID:</strong> <code>@Model.RequestId</code>
13-
</p>
14-
}
15-
16-
<h3>Development Mode</h3>
178
<p>
18-
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
9+
<b>Message:</b> @Model.ErrorMessage
1910
</p>
2011
<p>
21-
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
22-
It can result in displaying sensitive information from exceptions to end users.
23-
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
24-
and restarting the app.
12+
<b>Soruce:</b> @Model.Source
2513
</p>
14+

0 commit comments

Comments
 (0)