Aspect Oriented Programming in ASP.NET MVC - c#

Im currently developing an MVC application in ASP.NET and I'm trying to separate concerns so that I end up with cleaner and more maintanable code.
So, as a starting point, I was thinking of a logging aspect.
My idea is to log (initially) the calling and returning of every method in every controller.
I would have this logic on a separate class, dedicated to logging, so I don't mess my code with logging statements everywhere.
I would also need to have access to the Http Request so I can obtain client information.
Is there an integrated way to do this? Can ASP.NET MVC be used with aspect files just like AspectJ in Java?
Also, can it later be configured to log methods that satisfies certain conditions? (like signature, returning value, exception throwing, etc.)
Thanks very much in advance!

You can use attributes to implement a feature in an aspect-oriented way. Action methods that you want to surround with your functionality then only need to be decorated with your attribute:
[CustomLogger]
public ActionResult Index()
{
// Doing something here ...
return View();
}
You can either decorate a single action method with an attribute, an entire controller, or even apply the attribute globally through ASP.NET MVC's GlobalFilterCollection.
Here's how you'd declare your attribute:
public class CustomLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
// Here goes your logic
}
// ...
}
The ActionFilterAttribute class allows you to override a couple of methods so you can hook into ASP.NET MVC's action execution pipeline:
OnActionExecuting
OnActionExecuted
OnResultExecuting
OnResultExecuted
You can access request variables through the parameters (like ActionExecutedContext) that are passed to the above methods.

Related

What is the proper way of getting the HTTP request method in an AuthorizationHandler<T>?

Simplified version of what I'm trying to do: I want to write an authorization policy that will block requests that aren't GET if a flag is set in the database. I registered my policy, the handler code runs fine for my controller, but I'm not sure what the best way of getting the HTTP method type is.
Controller looks like this:
[Authorize(Policy = "Test")]
public class MyController : ControllerBase
{
// ...
}
My handler looks like this:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext ctx, MyRequirement req)
{
// Fetch some flag from db
if (!flag)
{
ctx.Succeed(req);
return;
}
var method = GetRequestMethodFromCtx(ctx.Resource);
if (method == HttpMethods.Get)
{
ctx.Succeed(req);
}
else
{
ctx.Fail();
}
}
I noticed that for a single request my handler gets called multiple times and that ctx.Resource is not always the same type. First time it is a RouteEndpoint, after which it is an AuthorizationFilterContextSealed.
Should I just extract the HTTP method from the RouteEndpoint and ignore the second call? Also, why are there multiple calls to the handler?
In order to access to HttpContext object you can use the IHttpContextAccessor service.
You can simply require it as a dependency of your authorization handler class and the ASP.NET core dependency injection will provide the service for you.
In order to register it with the dependency injection you need to call services.AddHttpContextAccessor() in the ConfigureServices method of your Startup class.
From the HttpContext you will have access to the Request and then to the Method property (see here).
Refer to the official documentation for the details.
I don't know exactly your requirements, but in order to prevent an action method being called with a specific HTTP verb there is a much simpler way. You just need to use the built in routing attributes, you can find more information here.

How to 'Logging' without adding a line to every method

I have a C# web api project, basically I need to log everytime a method is getting called (ie. method name, parameters passed, result, stacktrace (if error occured), etc).
Right now, I did this by adding few lines to every method and it seems bloated, is there more efficient way to achieve this?
Any help will be appreciated.
Thank you
Middleware is one approach, or you can also create a Filter that lets you perform 'before' and 'after' operations,
https://www.tutorialsteacher.com/webapi/web-api-filters
[Code from the above link]
public class LogDemoAttribute : Attribute, IActionFilter
{
public LogDemoAttribute()
{
}
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
Trace.WriteLine(string.Format("Action Method {0} executing at {1}", actionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs");
var result = await continuation();
Trace.WriteLine(string.Format("Action Method {0} executed at {1}", actionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web API Logs");
return result;
}
public bool AllowMultiple
{
get { return true; }
}
}
This does let you add to the Global Filters (in which case, you might as well use a Middleware), or add it selectively to certain endpoints, e.g
[ApiController]
public class PeopleController : ControllerBase
{
[LogDemo]
[HttpGet("demo/endpoint")]
public IActionResult GetAll()
{
}
}
This has the advantage that you might want to pass in some parameters to the attribute, that let you perform certain context specific behaviours.
If you want to add logging to non-controller code, then you can take this approach further to an Aspect Orientated / Decorator pattern.
https://learn.microsoft.com/en-us/archive/msdn-magazine/2014/february/aspect-oriented-programming-aspect-oriented-programming-with-the-realproxy-class
I generally find logging parameters at the controller level is good enough, and something like Application Insights that generates telemetry that shows you what the request looks like is actually the useful bit of information.
When you're saying "method" I'm unsure if you mean literally every method or just whenever a controller is being hit. But middleware would probably be the way to go. The documentation on adding custom middleware is here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1
And here is an example of error handling middleware, where you could place your logging: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-3.1

Run code when action is called in specific controller asp.net core

Say for example I have an admin controller and I want to perform additional custom checks when the user who calls any of the actions of the admin controller.
How do I execute some code within the controller class when any action is called for the controller only?
Since you are not asking for a specific programming example I will just refer you to the .net core documentation of Service Filters.
I have used these before to create something like an activity tracker for logged in users, so say it was an admin, and I wanted to see how long ago the user has performed an action, this filter would check the users last activity in a session before allowing access to the method.
Here is a generic example:
public class MyFilter : ActionFilterAttribute
{
public MyFilter()
{
}
//After Method execution
public override void OnActionExecuted(ActionExecutedContext context)
{
//Do stuff
}
//Before Method execution
public override void OnActionExecuting(ActionExecutingContext context)
{
//Do stuff
}
}
In Startup: services.AddScoped<MyFilter>();
And above controller/action: [ServiceFilter(typeof(MyFilter))]
If you want to verify user when accessing any method withing the controller, decorate your controller with [Authorize] attribute.
If you want to restrict only certain actions, you could leave your controller as is and just decorate desired methods with [Authorize] attribute.
If you wish to leave only certain methods unauthorized within controller, decorate controller with [Authorize] attribute, and the methods that you want to be accessed by anonymous users will need to be decorated using [AllowAnonymous] attribute.
Would this help? If you have specific requirements, please include them in question.

How do I implement AOP in an Azure Mobile App Services client?

On an Azure Mobile App Services server side app using MVC 5, Web API 2.0, and EF Core 1.0, controllers can be decorated like so to implement token based authentication:
// Server-side EF Core 1.0 / Web API 2 REST API
[Authorize]
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
DomainManager = new EntityDomainManager<TodoItem>(context, Request);
}
// GET tables/TodoItem
public IQueryable<TodoItem> GetAllTodoItems()
{
return Query();
}
...
}
I want to be able to do something similar on the client side where I decorate a method with something like [Authorize] from above, perhaps with a, [Secured], decoration, below:
public class TodoItem
{
string id;
string name;
bool done;
[JsonProperty(PropertyName = "id")]
public string Id
{
get { return id; }
set { id = value;}
}
[JsonProperty(PropertyName = "text")]
public string Name
{
get { return name; }
set { name = value;}
}
[JsonProperty(PropertyName = "complete")]
public bool Done
{
get { return done; }
set { done = value;}
}
[Version]
public string Version { get; set; }
}
// Client side code calling GetAllTodoItems from above
[Secured]
public async Task<ObservableCollection<TodoItem>> GetTodoItemsAsync()
{
try
{
IEnumerable<TodoItem> items = await todoTable
.Where(todoItem => !todoItem.Done)
.ToEnumerableAsync();
return new ObservableCollection<TodoItem>(items);
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(#"Invalid sync operation: {0}", msioe.
}
catch (Exception e)
{
Debug.WriteLine(#"Sync error: {0}", e.Message);
}
return null;
}
Where [Secured] might be defined something like this:
public class SecuredFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Check if user is logged in, if not, redirect to the login page.
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Check some globally accessible member to see if user is logged out.
}
}
Unfortunately, the above code only works in Controllers in MVC 1.0 applications and above according to the Microsoft article on "Creating Custom Action Filters": https://msdn.microsoft.com/en-us/library/dd381609(v=vs.100).aspx
How do I implement something like a "Custom Action Filter" that allows me to use the "[Secured]" decoration in a Mobile App Service client instead of the server? The answer will help me create custom authentication from the client side and keep the code in one location without complicating the implementation, i.e., it is a cross-cutting concern like performance metrics, custom execution plans for repeated attempts, logging, etc.
Complicating the scenario, the client also implements Xamarin.Forms for iOS and has to be a functional Ahead of Time pattern due to iOS's requirement for native code, JIT is not yet possible.
The reason attributes work in the scenarios you describe is because other code is responsible for actually invoking the methods or reading the properties, and this other code will look for the attributes and modify behaviour accordingly. When you are just running C# code, you don't normally get that; there isn't a native way to, say, execute the code in an attribute before a method is executed.
From what you are describing, it sounds like you are after Aspect Oriented Programming. See What is the best implementation for AOP in .Net? for a list of frameworks.
In essence, using an appropriate AOP framework, you can add attributes or other markers and have code executed or inserted at compile time. There are many approaches to it, hence why I am not being very specific, sorry.
You do need to understand that the AOP approach is different from how things like ASP.Net MVC works as AOP will typically modify your runtime code (in my understanding anyway and I'm sure there are variations on that as well).
As to whether AOP is really the way to go will depend on your requirements, but I would proceed with caution - it's not for the faint of heart.
One completely alternative solution to this problem is to look at something like Mediatr or similar to break your logic into a set of commands, which you can call via a message bus. The reason that helps is that you can decorate your message bus (or pipeline) with various types of logic, including authorization logic. That solution is very different from what you are asking for - but may be preferable anyway.
Or just add a single-line authorisation call as the first line inside each method instead of doing it as an attribute...
What you are more generally describing in known by a few different names/terms. The first that comes to mind is "Aspect Oriented Programming" (or AOP for short). It deals with what are known as cross cutting concerns. Im willing to bet you want to do one of two things
Log exceptions/messages in a standardized meaningful way
Record times/performance of areas of your system
And in the generala sense, yes C# is able to do such things. There will be countless online tutorials on how to do so, it is much too broad to answer in this way.
However, the authors of asp.net MVC have very much thought of these things and supply you with many attributes just as you describe, which can be extended as you please, and provide easy access to the pipeline to provide the developer with all the information they need (such as the current route, any parameters, any exception, any authorization/authentication request etc etc)
This would be a good place to start: http://www.strathweb.com/2015/06/action-filters-service-filters-type-filters-asp-net-5-mvc-6/
This also looks good: http://www.dotnetcurry.com/aspnet-mvc/976/aspnet-mvc-custom-action-filter

Async GET/POST and action name conflicts in ASP.NET MVC

The recommended way to make an edit page for ASP.NET MVC is to have two methods on a controller called Edit: one GET action and one POST action, both sharing the same name but overloaded differently. Validation errors are shown on the POST action if the edit fails. Then the user can share or bookmark the URL even if it's off of a POST: the URL goes to the GET version on the return.
So far, so good. But then there's the ASP.NET async pattern on controllers. You have EditAsync and EditCompleted. On the two different EditCompleted methods, how do you tell the GET apart from the POST? If you rename the POST action, you lose the nice behavior discussed earlier.
Is there a nice way to get these two patterns to work together?
Generally the XyzAsync() method provides the XyzCompleted() method some state object that tells it what unit of work is being performed, so the XyzCompleted() method can inspect this object and do the right thing. However, if you want to have a different Completed method for each verb, this is possible via the following:
[ActionName("Edit"), HttpGet]
public void EditGetAsync() { }
public ActionResult EditGetCompleted() { }
[ActionName("Edit"), HttpPost]
public void EditPostAsync() { }
public ActionResult EditPostCompleted() { }

Categories

Resources