Logging Visual Studio MVC5 - c#

I am working on a project that is a web application. The application should have a single button on the page that redirects the user back to the same page. In 1 of every 5 (or thereabout) occasions when you press the button the program should throw some exception and log it.
It should catch the exception and do three things: Send an email, write the error in a file and write it to debug window.
My controller so far:
public class HomeController : Controller
{
public ActionResult Index()
{
try
{
RedirectToAction("Index");
}
catch (ArgumentException e)
{
}
Random RandNumber = new Random();
int rand = RandNumber.Next(1000);
if(rand % 5 == 0)
{
throw new System.ArgumentException("This is a random excpetion");
}
return View();
}
}
The idea is the to have the class Logger that declares a collection of the class LogMedia and loops through all the instances.
Class Logger:
public class Logger
{
List<LogMedia> m_loggers = new List<LogMedia>();
void LogException(Exception ex)
{
foreach(var i in m_loggers)
{
//Loop through all Log Media instances
}
}
Class LogMedia
class LogMedia
{
public virtual void LogMessage(string Message); //virtual function that doesen't do anything
}
class OutputWindowLogMedia:LogMedia
{
public override void LogMessage(string Message)
{
System.Diagnostics.Debug.WriteLine(Message);
}
}
class TextFileLogMedia : LogMedia
{
public override void LogMessage(string Message)
{
File.AppendAllText("c:\\Temp\\Log.txt", Message);
}
}
class EmailLogMedia : LogMedia
{
public override void LogMessage(string Message)
{
//send email
}
}
}
My questions to you are the following:
Will my controller work as it stands now with what I am trying to implement? I am especially skeptical of my try catch..
What is the best way to loop though these three instances?
Do I have the right class declerations for Log Media, i.e. should I create new classes(that inherits LogMedia) for each instance and then a function that overrides the virtual function in LogMedia.

It's unclear if you want this behavior on this particular action, the controller, or the entire app. That said, unless there is some specific recovery code you want to build into your logic, I wouldn't pollute my action code with the try-catch.
There are two options the MVC framework provides to handle errors:
First, you can override OnException in a specific controller:
protected override void OnException(ExceptionContext filterContext)
{
// do your logging here
// set this flag if you want to stop the exception from bubbling
filterContext.ExceptionHandled = true;
}
Second, you can create an error handling filter:
public class MyExceptionFilterAttribute :
System.Web.Mvc.FilterAttribute,
System.Web.Mvc.IExceptionFilter
{
public void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
// same error handling logic as the controller override
}
}
A filter can either be added to the global filters list, or applied to an action method like this:
[MyExceptionFilter]
public ActionResult Index()
{
}
Edit: forgot to mention your logger structure. Your approach of having Logger loop over multiple instances of LogMedia is a good, common approach to supporting multiple logging mechanisms with one common interface (log4net appenders for example). That said, have you considered using an existing, proven framework for your logging needs? You get a thoroughly tested framework to run, and a skill that will carry over to future endeavours.
Edit2: after your comment, I took a closer look at your code instead of your exception trapping approach. In your Index action, you're redirecting to Index with no condition checking. This is going to end up as a constant redirect loop (until IIS stops you). Since this is an assignment, I don't want to give too much away, but you will need some logic on the server side to detect a button click and redirect back to your Index. Consider another Index action method that accepts HttpPost (your current action would be the HttpGet handler).

Related

Log all handles exception

How can I log all handled exceptions?
I want that whenever I catch an exception I should be able to log it
I want it to work globally and not that i should have to write it each time I catch
I tried subscribing to AppDomain.CurrentDomain.FirstChanceException and it did work but I did not have the full stack trace and it called multiple times for each exception (I don't know why)
I also tried wrapping my controller with ActionFilterAttribute like below and it worked on all exception from the controller only and not if the exception was caught in a service that was called from the controller
public class ExceptionLoggingHandler : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if(filterContext.Exception !=null)
{
System.Diagnostics.Debug.WriteLine(filterContext.Exception.Message);
}
base.OnResultExecuted(filterContext);
}
}
In ASP.NET MVC, you can add your filter as a global filter in the RegisterGlobalFilters method inside FilterConfig.cs. It should then catch all exceptions in all controller actions, and in any methods called from those actions - unless of course those methods already have catch blocks inside them which swallow the exception. In that case the caught exception (unless it's then re-thrown) will inevitably go undetected higher up the stack, which is, naturally, the whole point of catching exceptions.
e.g.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new ExceptionLoggingHandler());
}
}
Also, your attribute should inherit from HandleErrorAttribute, not ActionFilterAttribute.
Something like this:
public class ExceptionLoggingHandler : HandleErrorAttribute
{
public ExceptionLoggingHandler() : base()
{
}
public override void OnException(ExceptionContext context)
{
System.Diagnostics.Debug.WriteLine(context.Exception.Message);
context.ExceptionHandled = true;
//.... continue to produce a suitable response
}
}
(In the .... area you can continue to develop the handler to log more sophisticated data, and return a suitable response, perhaps along the lines of this one (other examples are also available online.)

What pattern can I use to avoid instancing unnecessary blocks from pipeline?

My ASP.NET Core application is using our self-designed pipelines to process requests. Every pipeline contains 1+ blocks, and the number of blocks have no any limit. it can be up to 200+ blocks in real instance, the pipeline will go through all blocks by a sequence from a configuration, like:
Pipeline<DoActionsPipeline>().AddBlock<DoActionAddUserBlock>().AddBlock<DoActionAddUserToRoleBlock>()...
Like above example(just an example), and there are 200+ blocks configured in this pipeline, the blocks could be DoActionAddUserBlock, DoActionAddUserToRoleBlock, DoActionAddAddressToUserBlock, and so on. many actions are mixed in one pipeline. (Please don't ask why mix them, it's just an example, it doesn't matter to my question.)
For this example, in each block, we will check the action name first, if match, then run logics. but this is pretty bad, it has to instance all blocks and go throgh all of them to get a request done.
Here is sample code, not very good, but it shows my pain:
public class DoActionAddUserBlock : BaseBlock<User, User, Context>
{
public override User Execute(User arg, Context context)
{
if (context.ActionName != "AddUser")
{
return arg;
}
return AddUser(arg);
}
protected User AddUser(User user)
{
return user;
}
}
public abstract class BaseBlock<TArg, TResult, TContext>
{
public abstract TResult Execute(TArg arg, TContext context);
}
public class Context
{
public string ActionName { get; set; }
}
public class User
{
}
I want to avoid instancing blocks by conditions, I think it should be in pipeline-configuration level. how can I reach this? Attributes? or something others.
[Condition("Action==AddUser")] // or [Action("AddUser")] // or [TypeOfArg("User")]
public class DoActionAddUserBlock : BaseBlock<User, User, Context>
{
public override User Execute(User arg, Context context)
{
return AddUser(arg);
}
//...
}
Please show us the Pipeline<T>() method (is a method or a class?), because it's essential for an accurate answer.
Anyway i want to try my best with the current infos.
Your goal is "i want to conditionally instance blocks", so you have to move your condition in a out-of-instance context, something you can do with attributes:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ActionNameAttribute : Attribute
{
public ActionNameAttribute(string name)
{
this.Name = name;
}
public string Name { get; }
}
[ActionName(nameof(AddUser))]
public class DoActionAddUserBlock : BaseBlock<User, User, Context>
{
public override User Execute(User arg, Context context)
{
return AddUser(arg);
}
}
Then, do the check into the .AddBlock<T>() method (that, i guess, is something like that):
public YourUnknownType<T> AddBlock<TBlock>()
{
var type = typeof(TBlock);
var attributes = attributes.GetCustomAttributes(typeof(ActionNameAttribute), inherit: true); // or false if you don't need inheritation
var attribute = attributes.FirstOrDefault() as ActionNameAttribute;
if (attribute.Name == this.Context.ActioName)
{
// place here the block init
}
return AnythingYouActuallyReturn();
}
Hope this helps!
IMO
you should define different pipelines for different usage. That's a design pattern that should be used only for some particular cases. Maybe it is not good pattern in your case?
I think that it shouldn't be in pipeline responsibility to check the action name and MAYBE run logic. If you define a pipeline for some logic it should just "go with the flow".
Therefore, pipelines should be build once on project startup and initializing whole pipeline just once is good.
Please think about if using pipelines is good in your scenario.
I've built a simple pipeline with builder and steps you can check it here. It's in polish but all the code is in English so you might get the point.

C# AntiForgeryToken attribute causes StackOverflowException in mvc application

I have created a antiforgery attribute class to decorate my GenericBaseController class:
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
// Only validate POSTs
if (request.HttpMethod == WebRequestMethods.Http.Post)
{
// Ajax POSTs and normal form posts have to be treated differently when it comes
// to validating the AntiForgeryToken
if (request.IsAjaxRequest())
{
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null
? antiForgeryCookie.Value
: null;
AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
}
(reference link http://richiban.uk/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/ )
once a normal POST call in application is done (not ajax), I always get a StackOverflowException.
Application without ValidateAntiForgeryTokenAttribute works fine.
If I debug the code inside this class, after a post request, flow keeps going trough the line
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
infinitely.
People in linked article assure that this implementation works, so I'm wondering why I'm getting this problem.
Is it really supposed to create a new ValidateAntiForgeryTokenAttribute when the request is not ajax ?
Boiled down to the problem, your code is:
public class ValidateAntiForgeryTokenAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if ( evaluateCondition() )
{}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
The problem
Your call is recursive in the else block:
The class you are calling the method on is ValidateAntiForgeryTokenAttribute.
In your else block you have
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
which, given that the calling method is
public override void OnAuthorization(AuthorizationContext filterContext)
means that you will keep calling OnAuthorization (i.e. the same method) on new instances of a ValidateAntiForgeryTokenAttribute.
Solution
In the example you posted, the situation was slightly different - the name of the class is ValidateAntiForgeryTokenOnAllPosts whereas yours is ValidateAntiForgeryTokenAttribute, so the call is not recursive since the method is not calling itself with the same arguments.
You have three options - I'm not sure which is best for your situation (I'm thinking the first one):
Change your Attribute name to ValidateAntiForgeryTokenOnAllPosts to match the name in the example you posted.
Explicitly state that you want System.Web.Mvc.ValidateAntiForgeryTokenAttribute by changing the block to say
new System.Web.Mvc.ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
Since you are overriding ValidateAntiForgeryTokenAttribute, you can call the base method, i.e.
else
{
base.OnAuthorization(filterContext);
}

How to move validation handling from a controller action to a decorator

Maintenance Edit
After using this approach for a while I found myself only adding the exact same boilerplate code in every controller so I decided to do some reflection magic. In the meantime I ditched using MVC for my views - Razor is just so tedious and ugly - so I basically use my handlers as a JSON backend. The approach I currently use is to decorate my queries/commands with a Route attribute that is located in some common assembly like this:
[Route("items/add", RouteMethod.Post)]
public class AddItemCommand { public Guid Id { get; set; } }
[Route("items", RouteMethod.Get)]
public class GetItemsQuery : IQuery<GetItemsResponse> { }
// The response inherits from a base type that handles
// validation messages and the like
public class GetItemsResponse : ServiceResponse { }
I then implemented an MVC host that extracts the annotated commands/queries and generates the controllers and handlers for me at startup time. With this my application logic is finally free of MVC cruft. The query responses are also automatically populated with validation messages. My MVC applications now all look like this:
+ MvcApp
+- Global.asax
+- Global.asax.cs - Startup the host and done
+- Web.config
After realizing I really don't use MVC outside the host - and constantly having issues with the bazillion dependencies the framework has - I implemented another host based on NServiceKit. Nothing had to be changed in my application logic and the dependencies are down to System.Web, NServiceKit and NServiceKit.Text that takes good care of the model binding. I know it's a very similar approach to how NServiceKit/ServiceStack does their stuff but I'm now totally decoupled from the web framework in use so in case a better one comes along I just implement another host and that's it.
The situation
I'm currently working on an ASP.NET MVC site that's implementing the businesslogic-view separation via the IQueryHandler and ICommandHandler abstractions (using the almighty SimpleInjector for dependency injection).
The Problem
I've got to attach some custom validation logic to a QueryHandler via a decorator and that's working pretty well in and of itself. The problem is that in the event of validation errors I want to be able to show the same view that the action would have returned but with information on the validation error of course. Here is a sample for my case:
public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;
public ActionResult Index()
{
try
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
return this.View(new HomeViewModel());
}
catch (ValidationException exception)
{
this.ModelState.AddModelErrors(exception);
return this.View(new HomeViewModel());
}
}
}
In this scenario I have some business logic that's handled by the queryHandler that is decorated with a ValidationQueryHandlerDecorator that throws ValidationExceptions when it is appropriate.
What I want it to do
What I want is something along the lines of:
public class HomeController : Controller
{
private readonly IQueryHandler<SomeQuery, SomeTransport> queryHandler;
public ActionResult Index()
{
var dto = this.queryHandler.Handle(new SomeQuery { /* ... */ });
// Doing something awesome with the data ...
// There is a catch-all in place for unexpected exceptions but
// for ValidationExceptions I want to do essentially the same
// view instantiation but with the model errors attached
return this.View(new HomeViewModel());
}
}
I've been thinking about a special ValidationErrorHandlerAttribute but then I'm losing the context and I can't really return the proper view. The same goes with the approach where I just wrap the IQueryHandler<,> with a decorator... I've seen some strange pieces of code that did some string sniffing on the route and then instantiating a new controller and viewmodel via Activator.CreateInstance - that doesn't seem like a good idea.
So I'm wondering whether there is a nice way to do this ... maybe I just don't see the wood from the trees. Thanks!
I don't think there's a way to make the action method oblivious to this, since the action method is in control of the returned view model, and in case of a validation exception you need to return a view model with all the actual data (to prevent the user from losing his changes). What you might be able to do however to make this more convenient is add an extension method for executing queries in an action:
public ActionResult Index()
{
var result = this.queryHandler.ValidatedHandle(this.ModelState, new SomeQuery { });
if (result.IsValid) {
return this.View(new HomeViewModel(result.Data));
}
else
{
return this.View(new HomeViewModel());
}
}
The ValidatedHandle extension method could look like this:
public static ValidatedResult<TResult> ValidatedHandle<TQuery, TResult>(
this IQueryHandler<TQuery, TResult> handler,
TQuery query, ModelStateDictionary modelState)
{
try
{
return new ValidatedResult<TResult>.CreateValid(handler.Handle(query));
}
catch (ValidationException ex)
{
modelState.AddModelErrors(ex);
return ValidatedResult<TResult>.Invalid;
}
}
Do note that you should only catch such validation exception if the validation is on data that the user has entered. If you send a query with parameters that are set programmatically, a validation exception simply means a programming error and you should blog up, log the exception and show a friendly error page to the user.

Proper use of the Factory Pattern?

I am trying to figure out the best solution for getting error messages in between my service layer and WebApi controllers.
I have a class ModelStateDictionaryWrapper that implements an interface IValidationDictionary
ModelStateDictionaryWrapper
public class ModelStateDictionaryWrapper : IValidationDictionary
{
private readonly ModelStateDictionary modelStateDictionary;
public bool IsValid
{
get
{
return this.modelStateDictionary.IsValid;
}
}
public ModelStateDictionaryWrapper(ModelStateDictionary modelStateDictionary)
{
Enforce.ArgumentNotNull(modelStateDictionary, "modelStateDictionary");
this.modelStateDictionary = modelStateDictionary;
}
public void AddError(string key, string message)
{
this.modelStateDictionary.AddModelError(key, message);
}
}
IValidationDictionary
public interface IValidationDictionary
{
bool IsValid { get; }
void AddError(string key, string message);
}
In my api controller, I am doing this:
public class CategoryController : ControllerBase<ICategoryService>
{
private ICategoryService categoryService;
public CategoryController(ICategoryService categoryService)
{
this.categoryService = categoryService;
this.categoryService.ValidationDictionary =
new ModelStateDictionaryWrapper(this.ModelState);
}
public IEnumerable<CategoryViewModel> Get()
{
return Mapper.Map<CategoryViewModel[]>(this.Service.GetCategories());
}
}
The problem I have with this is I am making a new ModelStateDictionaryWrapper in the constructor of the service and I dont like that.
So I was thinking of changing this to take a factory like so:
public interface IModelStateWrapperFactory
{
IValidationDictionary GetModelStateWrapper(ModelStateDictionary modelStateDictionary);
}
public class ModelStateWrapperFactory : IModelStateWrapperFactory
{
public IValidationDictionary GetModelStateWrapper(
ModelStateDictionary modelStateDictionary)
{
return new ModelStateDictionaryWrapper(modelStateDictionary);
}
}
And then the api controller would look like this (constructor):
public CategoryController(ICategoryService categoryService,
IModelStateWrapperFactory modelStateWrapperFactory)
{
this.categoryService = categoryService;
this.categoryService.ValidationDictionary =
modelStateWrapperFactory.GetModelStateWrapper(this.ModelState);
}
I think I have removed the tight coupling. Does this look like a good solution?
Yes,
You have broken the dependencies between the classes, so you can mock the services during Unit Testing.
I don't know if you have used data annotations and a validation filter or not yet. If not, I would suggest you use them. More details from here http://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
An even better approach would be to completely remove this part out of the controller. It should be moved out of the controller, because:
This is effectively a cross-cutting concern and your controller should not be concerned with it; you are violating the Single Responsibility Principle.
Most (if not all) of your controllers will need this construct, which means that you have to repeat it all over the place, making it easy to forget it at some places; you are violating the Don't Repeat Yourself (DRY) principle.
This construct is only possible in the case that the class that needs validation is directly injected into the controller, which might not always be the case. Sometimes you'll need to do validation deeper down the object graph, or you might want to wrap the service with a decorator or interceptor, rendering this approach useless -or at least- extremely troublesome.
There are several solutions to this approach. The first that comes to my mind is to move the setting of the ModelState up, out of the CategoryController's constructor, for instance:
public IHttpController Create(HttpRequestMessage request,
HttpControllerDescriptor descriptor, Type type)
{
var wrapper = new ModelStateDictionaryWrapper();
var controller = new CategoryController(new CategoryService(wrapper));
wrapper.ModelState = controller.ModelState;
return controller;
}
Another -completely different- approach is to to not use the ModelState property at all, but to let your business layer throw specific validation exceptions and catch them higher up the call stack and transform them to Web API status codes.
Throwing exceptions would be a much better approach for the business layer, since this prevents validation errors to go unnoticed. Besides, a design where you fill a dictionary with validation errors is related to Web API and MVC, and is not something that your business layer should be concerned with.
You can do the following in your controller when your BL throws validation exceptions:
public class CategoryController : ControllerBase<ICategoryService>
{
private ICategoryService categoryService;
public CategoryController(ICategoryService categoryService)
{
this.categoryService = categoryService;
}
public HttpResponseMessage Update(CategoryViewModel model)
{
try
{
this.categoryService.Update(model.Category);
}
catch (ValidationException ex)
{
return WebApiValidationHelper.ToResponseCode(ex);
}
}
}
Downside here is of course that your try-catch statements with the calls to the WebApiValidationHelper.ToResponseCode will be duplicated in all your controllers; you'll be violating DRY.
So what you can do instead is extract this code into an DelegatingHandler. My preference would always be to use decorators, but unfortunately Web API makes it impossible to decorate ApiControllers, due to a quirk in its design. So you can inject the following DelegatingHandler into the Web API pipeline:
public class ValidationDelegationHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
return await base.SendAsync(request, cancellationToken);
}
catch (ValidationException ex)
{
return WebApiValidationHelper.ToResponseCode(ex);
}
}
}
This handler can be injected as follows:
config.MessageHandlers.Add(new ValidationDelegationHandler());

Categories

Resources