unable to save log into windows azure table storage? - c#

I have used following code to save trace log into table storage.
I'm using windows azure skd version 2.2
System.Diagnostics.Trace.TraceError("START Log");
also added listener in web.config
<system.diagnostics>
<trace>
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>
</system.diagnostics>
also added code in webrole.cs
public override bool OnStart()
{
StartDiagnostics();
return base.OnStart();
}
private void StartDiagnostics()
{
DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();
TimeSpan tsOneMinute = TimeSpan.FromMinutes(1);
// Transfer logs to storage every minute
dmc.Logs.ScheduledTransferPeriod = tsOneMinute;
// Transfer verbose, critical, etc. logs
dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Information;
// Start up the diagnostic manager with the given configuration.
try
{
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", dmc);
}
catch (Exception exp)
{
}
}
Still getting error : 500 internal server error

Related

Can't register listeners to System.Diagnostics.Tracing.EventSource

I have a component that is used by different applications.
In this component we might need logging so I thought I'd use an EventSource.
The component is netstandard2.0, the application using the component is .NET Framework 4.6.1.
This is what I have so far in my component:
public class XEvents
{
public const int BeforeSendingRequest = 1;
public const int AfterSendingRequest = 2;
}
[EventSource(Name = "XEventSource")]
public class XEventSource : EventSource
{
public static XEventSource Log = new XEventSource();
[Event(XEvents.BeforeSendingRequest, Message = "Request: {0}", Level = EventLevel.Verbose, Keywords = EventKeywords.WdiDiagnostic)]
public void BeforeSendingRequest(string request) { if (IsEnabled()) WriteEvent(XEvents.BeforeSendingRequest, request); }
[Event(XEvents.AfterSendingRequestToCsam, Message = "Response: {0}", Level = EventLevel.Verbose, Keywords = EventKeywords.WdiDiagnostic)]
public void AfterSendingRequest(string response) { if (IsEnabled()) WriteEvent(XEvents.AfterSendingRequest, response); }
}
And in the application I added the following to the app.config:
<system.diagnostics>
<sources>
<source name="NamespaceOfEventSource.XEventSource" switchValue="Verbose">
<listeners>
<add name="XEventSourceListener" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="XEventSourceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="X.log" traceOutputOptions="ProcessId, DateTime" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
But when I run the application there is no X.log inside the bin folder.
When I debug to the eventsource of the component I see that Enabled() returns false.
I suspect the listeners arent beeing bound to the EventSource. But I don't really see what I'm doing wrong.
Thanks in advance for any information you can give me!
I ended up using TraceSource instead of EventSource.
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.tracesource?view=netcore-3.1

Trace & Log to file using TraceSource

I'm working on ASP.Net MVC web app, using System.Diagnostics.TraceSource to trace and log to file. Added following to web.config
<system.diagnostics>
<trace autoflush="false" indentsize="4"></trace> // what's this for?
<sources>
<source name ="WebAppLog">
<listeners>
<add name="FileLog" type="System.Diagnostics.TextWriterTraceListener" initializeData="PartialView_WebApp.log" traceOutputOptions="DateTime,ThreadId,ProcessId,Timestamp,LogicalOperationStack,Callstack">
<filter initializeData="All" type="System.Diagnostics.EventTypeFilter"/>
</add>
<remove name="Default"/>
</listeners>
</source>
</sources>
</system.diagnostics>
Added Log.cs to application to log mesages to file.
public class Log
{
static TraceSource source = new TraceSource("WebAppLog");
public static void Message(TraceEventType traceEventType, string message)
{
short id;
switch (traceEventType)
{
case TraceEventType.Information:
id = 3;
break;
case TraceEventType.Verbose:
id = 4;
break;
default:
id = -1;
break;
}
source.TraceEvent(traceEventType, id, message);
source.Flush();
}
}
Home controller.cs
public ActionResult Index()
{
try
{
Log.Message(System.Diagnostics.TraceEventType.Information, "Index Action Start");
// Do work
Log.Message(System.Diagnostics.TraceEventType.Information, "Index Action End");
return View();
}
catch (Exception ex)
{
throw;
}
}
After executing, i'm able to generate log file but couldn't write anything, always the file size is 0 bytes. What could be the possible mistake.?
The Switch on a TraceSource determines whether any output gets generated.
By default, if it is not configured, there will be no output.
The value for the Switch matches the log levels that should appear in the output.
It can be set via code:
static TraceSource source = new TraceSource("WebAppLog");
source.Switch.Level = SourceLevels.Verbose;
Or via configuration, which is more flexible.
Your configuration will look like:
<system.diagnostics>
<trace autoflush="false" indentsize="4"></trace>
<sources>
<source name ="WebAppLog" switchName="mySwitch">
<listeners>
<add name="FileLog" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\tmp\trace.log" traceOutputOptions="DateTime,ThreadId,ProcessId,Timestamp,LogicalOperationStack,Callstack">
<filter initializeData="All" type="System.Diagnostics.EventTypeFilter"/>
</add>
<remove name="Default"/>
</listeners>
</source>
</sources>
<switches>
<add name="mySwitch" value="Verbose" />
</switches>
</system.diagnostics>
Regarding your question about
<trace autoflush="false" indentsize="4"></trace>
With autoflush=true you don't have to call source.Flush() explicitly.
The indentsize gets applied in the log output, notice the leading whitespace starting from line 2 in the output fragment below.
WebAppLog Information: 3: Index Action Start
ProcessId=7416
LogicalOperationStack=
ThreadId=1

Clearing an Enterprise Library Logging log file

How would I delete / clear / wipe / overwrite a log file being written through EL6 logging. I am using a logwriter instance to write to a log file that needs to be overwritten every cycle as my program runs in a continuous loop. I will be writing values then overwriting as new values come through.
There may be other/better ways to attack this, but I was able to clear the log file by temporarily repointing the static LogWriter to a temp file, clearing the log with simple File I/O, and then reconnecting the original LogWriter.
I wrote up a simple C# Console App to demonstrate. There are some hard-coded references to the log file configuration in App.config that could probably be cleaned up by using the ConfigurationSourceBuilder, but hopefully this can get you started.
Programs.cs:
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System;
using System.Diagnostics;
using System.IO;
namespace LogFileClearance
{
public static class Marker
{
public static LogWriter customLogWriter { get; set; }
}
class Program
{
private static object _syncEventId = new object();
private static object locker = new object();
private static int _eventId = 0;
private const string INFO_CATEGORY = "All Events";
static void Main( string [] args )
{
InitializeLogger();
Console.WriteLine( "Enter some input, <Enter> or q to quit, c to clear the log file" );
string input = Console.ReadLine().ToUpper();
while ( ! string.IsNullOrEmpty(input) && input != "Q" )
{
Console.WriteLine( "You entered {0}", input );
if ( input == "C" )
{
ClearLog();
}
else
{
WriteLog( input );
}
Console.WriteLine( "Enter some input, <Enter> or q to quit, c to clear the log file" );
input = Console.ReadLine().ToUpper();
}
}
private static int GetNextEventId()
{
lock ( _syncEventId )
{
return _eventId++;
}
}
public static void InitializeLogger()
{
try
{
lock ( locker )
{
if ( Marker.customLogWriter == null )
{
var writer = new LogWriterFactory().Create();
Logger.SetLogWriter( writer, false );
}
else
{
Logger.SetLogWriter( Marker.customLogWriter, false );
}
}
}
catch ( Exception ex )
{
Debug.WriteLine( "An error occurred in InitializeLogger: " + ex.Message );
}
}
static internal void WriteLog( string message )
{
LogEntry logEntry = new LogEntry();
logEntry.EventId = GetNextEventId();
logEntry.Severity = TraceEventType.Information;
logEntry.Priority = 2;
logEntry.Message = message;
logEntry.Categories.Add( INFO_CATEGORY );
// Always attach the version and username to the log message.
// The writeLog stored procedure will parse these fields.
Logger.Write( logEntry );
}
static internal void ClearLog()
{
string originalFileName = string.Format(#"C:\Logs\LogFileClearance.log");
string tempFileName = originalFileName.Replace( ".log", "(TEMP).log" );
var textFormatter = new FormatterBuilder()
.TextFormatterNamed( "Custom Timestamped Text Formatter" )
.UsingTemplate("{timestamp(local:MM/dd/yy hh:mm:ss.fff tt)} tid={win32ThreadId}: {message}");
#region Set the Logging LogWriter to use the temp file
var builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.LogToCategoryNamed( INFO_CATEGORY ).WithOptions.SetAsDefaultCategory()
.SendTo.FlatFile( "Flat File Trace Listener" )
.ToFile(tempFileName);
using ( DictionaryConfigurationSource configSource = new DictionaryConfigurationSource() )
{
builder.UpdateConfigurationWithReplace(configSource);
Marker.customLogWriter = new LogWriterFactory(configSource).Create();
}
InitializeLogger();
#endregion
#region Clear the original log file
if ( File.Exists(originalFileName) )
{
File.WriteAllText(originalFileName, string.Empty);
}
#endregion
#region Re-connect the original file to the log writer
builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.WithOptions.DoNotRevertImpersonation()
.LogToCategoryNamed( INFO_CATEGORY ).WithOptions.SetAsDefaultCategory()
.SendTo.RollingFile("Rolling Flat File Trace Listener")
.RollAfterSize(1000)
.FormatWith(textFormatter).WithHeader("").WithFooter("")
.ToFile(originalFileName);
using ( DictionaryConfigurationSource configSource = new DictionaryConfigurationSource() )
{
builder.UpdateConfigurationWithReplace( configSource );
Marker.customLogWriter = new LogWriterFactory( configSource ).Create();
}
InitializeLogger();
#endregion
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<loggingConfiguration name="Logging Application Block" tracingEnabled="true" defaultCategory="" logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add fileName="C:\Logs\LogFileClearance.log" footer="" formatter="Timestamped Text Formatter"
header="" rollFileExistsBehavior="Increment"
rollInterval="None" rollSizeKB="1000" timeStampPattern="yyyy-MM-dd"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Log File Listener" />
</listeners>
<formatters>
<add template="{timestamp(local:MM/dd/yy hh:mm:ss tt)} tid={win32ThreadId}: {message}" type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="Timestamped Text Formatter" />
</formatters>
<categorySources>
<add switchValue="Information" name="All Events">
<listeners>
<add name="Log File Listener" />
</listeners>
</add>
<add switchValue="Error" name="Logging Errors & Warnings">
<listeners>
<add name="Log File Listener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="Information" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors & Warnings" />
</specialSources>
</loggingConfiguration>
</configuration>

MVC Error Handle with custom error Messages

I'm building a new Web Application using MVC5 and I need the followings:
Catch errors
Log the details in a file
Send them by email
Add to the detail custom information (for example the Id of the
record I'm trying to read)
Return to the view custom messages to the user
I have found a lot of information regarding the HandleErrorAttribute but none of them allow to add specific details to the error, also I have found information saying that the try catch aproach is too heavy for the server.
For now, I have:
Controller:
public partial class HomeController : Controller
{
private static Logger logger = LogManager.GetCurrentClassLogger();
public virtual ActionResult Index()
{
try
{
return View();
}
catch (Exception e)
{
logger.Error("Error in Index: " + e);
return MVC.Error.Index("Error in Home Controller");
}
}
}
I have found this Extended HandleErrorAttribute that seems complete but don't do everything I need:
private bool IsAjax(ExceptionContext filterContext)
{
return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
}
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
// if the request is AJAX return JSON else view.
if (IsAjax(filterContext))
{
//Because its a exception raised after ajax invocation
//Lets return Json
filterContext.Result = new JsonResult(){Data=filterContext.Exception.Message,
JsonRequestBehavior=JsonRequestBehavior.AllowGet};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
}
else
{
//Normal Exception
//So let it handle by its default ways.
base.OnException(filterContext);
}
// Write error logging code here if you wish.
//if want to get different of the request
//var currentController = (string)filterContext.RouteData.Values["controller"];
//var currentActionName = (string)filterContext.RouteData.Values["action"];
}
Your requirement best fit with Elmah. Very good plugin for logging errors.
ELMAH stands for Error Logging Modules And Handlers
ELMAH provides such a high degree of plugability that even Installation of ELMAH does not require compilation of your application.
ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable. It can be dynamically added to a running ASP.NET web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment.
Reference from the blog of SCOTT HANSELMAN
Just need to copy binary of ELMAH to bin folder of your application and edit web.config file. That's it!
you need to add following to your web.config and make some other changes described in the following links.
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
For example to set up mail account.
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"/>
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah"/>
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah"/>
</sectionGroup>
</configSections>
<elmah>
<errorMail from="test#test.com" to="test#test.com"
subject="Application Exception" async="false"
smtpPort="25" smtpServer="***"
userName="***" password="***">
</errorMail>
</elmah>
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="CustomError.aspx">
<error statusCode="403" redirect="NotAuthorized.aspx" />
<!--<error statusCode="404" redirect="FileNotFound.htm" />-->
</customErrors>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
</httpModules>
</system.web>
</configuration>
Here is some good reference link (that contains detailed reference to installation of ELMAH to your project) for your reference.
https://msdn.microsoft.com/en-us/library/aa479332.aspx
https://code.google.com/p/elmah/wiki/MVC
Update
Add to the detail custom information (for example the Id of the record I'm trying to read)
You can build your own custom exception that derives from Exception.
public class MyException : Exception
{
public MyException(string message, Exception ex) : base(ex.Message, ex)
{
}
}
and then using it like
public virtual ActionResult Index()
{
try
{
return View();
}
catch (Exception e)
{
throw new MyException("detailed exception", e);
}
}
in this way main exception would be wrapped inside the myexception and you can add your detailed custom exception message.
Return to the view custom messages to the user
You just need to add
<system.web>
<customErrors mode="On">
</customErrors>
<sytem.web>
and add Error.cshtml inside the ~/View/Shared folder
Then whenever exception is encountered it will find for Error.cshtml inside view/shared folder and render the content. so you can render there your custom message.
Use Elmah as others have also recommended. I am, and haven't looked back!
It meets all your requirements:
Catches all errors, e.g. 400s, 500s...
Logs to a file, and any other data store you can think of, e.g. database, memory, Azure, more file formats(XML, CSV), RSS feed...
Emails errors: Enable and config mail settings in Web.config - very simple. You can even send emails asynchronously!
Add custom code - in your case add extra details to the error
Use your own custom error pages - custom error node (for 400s, 500s) in web.config and your own error controller
Further on the custom code (2nd last point above), AFAIK you have two options:
1. Create a custom error log implementation.
This isn't that difficult. It's what I did!
Override the default error log data store. For example, taking the SQL Server data store:
In Web.config
<elmah>
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="myCn" applicationName="myAppName" />
</elmah>
Next, create a class "MySQLServerErrorLog" and derive from Elmah.ErrorLog
All that is then required is to override the Log() method.
public override string Log(Error error)
{
// You have access to all the error details - joy!
= error.HostName,
= error.Type,
= error.Message,
= error.StatusCode
= error.User,
= error.Source,
// Call the base implementation
}
In Web.config, replace the default (above) entry with your implementation:
<elmah>
<errorLog type="myProjectName.MySQLServerErrorLog, myProjectName" />
</elmah>
2. You can programmatically log errors
Using the ErrorSignal class, you may logs errors without having to raise unhandled exceptions.
Syntax:
ErrorSignal.FromCurrentContext().Raise(new NotSupportedException());
Example: A custom exception
var customException = new Exception("My error", new NotSupportedException());
ErrorSignal.FromCurrentContext().Raise(customException);
This gives you the option of using your custom logic to programmatically log whatever you require.
I've written functionality for my Elmah instance to logs errors to Azure Cloud Storage Table and Blob (error stack trace details).
FWIW before I used Elmah, I had written my own exception handling mechanism for MVC which used HandleErrorAttribute and Application_Error (in Global.asax). It worked but was too unwieldy IMO.
If it was me, I'd create my own exception handling Attribute which adds required behaviour to the base implementation of HandleErrorAttribute.
I've had quite good results in the past with having attributes "pointed at" various parts of the request that's of interest (am thinking the bit where you say that you want to log specific details) - so you can use these identifiers to pull the request to pieces using reflection:
CustomHandleErrorAttribute(["id", "name", "model.lastUpdatedDate"])
I've used this approach to secure controller actions (making sure that a customer is requesting things that they're allowed to request) - e.g. a parent is requesting info on their children, and not someone else's children.
Or, you could have a configuration set up whereby you'd "chain" handlers together - so lots of little handlers, all doing very specific bits, all working on the same request and request pointers (as above):
ChainedErrorHandling("emailAndLogFile", ["id", "name", "model.lastUpdatedDate"])
Where "emailAndLogFile" creates a chain of error handlers that inherit from FilterAttribute, the last of which, in the chain, is the standard MVC HandleErrorAttribute.
But by far, the simplest approach would be the former of these 2.
HTH
EDITED TO ADD: Example of inheriting custom error handling:
public class CustomErrorAttribute : HandleErrorAttribute
{
public CustomErrorAttribute(string[] requestPropertiesToLog)
{
this.requestPropertiesToLog = requestPropertiesToLog;
}
public string[] requestPropertiesToLog { get; set; }
public override void OnException(ExceptionContext filterContext)
{
var requestDetails = this.GetPropertiesFromRequest(filterContext);
// do custom logging / handling
LogExceptionToEmail(requestDetails, filterContext);
LogExceptionToFile(requestDetails, filterContext);
LogExceptionToElseWhere(requestDetails, filterContext);// you get the idea
// even better - you could use DI (as you're in MVC at this point) to resolve the custom logging and log from there.
//var logger = DependencyResolver.Current.GetService<IMyCustomErrorLoggingHandler>();
// logger.HandleException(requestDetails, filterContext);
// then let the base error handling do it's thang.
base.OnException(filterContext);
}
private IEnumerable<KeyValuePair<string, string>> GetPropertiesFromRequest(ExceptionContext filterContext)
{
// in requestContext is the queryString, form, user, route data - cherry pick bits out using the this.requestPropertiesToLog and some simple mechanism you like
var requestContext = filterContext.RequestContext;
var qs = requestContext.HttpContext.Request.QueryString;
var form = requestContext.HttpContext.Request.Form;
var user = requestContext.HttpContext.User;
var routeDataOfActionThatThrew = requestContext.RouteData;
yield break;// just break as I'm not implementing it.
}
private void LogExceptionToEmail(IEnumerable<KeyValuePair<string, string>> requestDetails, ExceptionContext filterContext)
{
// send emails here
}
private void LogExceptionToFile(IEnumerable<KeyValuePair<string, string>> requestDetails, ExceptionContext filterContext)
{
// log to files
}
private void LogExceptionToElseWhere(IEnumerable<KeyValuePair<string, string>> requestDetails, ExceptionContext filterContext)
{
// send cash to me via paypal everytime you get an exception ;)
}
}
And On the controller action you'd add something like:
[CustomErrorAttribute(new[] { "formProperty1", "formProperty2" })]
public ActionResult Index(){
return View();
}
Firstly, you can define a filter attribute, and you can register it on startup in an MVC application in global.asax, so you can catch any kind of errors that occur while actions are invoking.
Note: Dependency Resolving is changeable. I'm using Castle Windsor for this story. You can resolve dependencies your own IOC container. For example, ILogger dependency. I used for this property injection while action invoking.
Windsor Action Invoker
For Example Filter:
public class ExceptionHandling : FilterAttribute, IExceptionFilter
{
public ILogger Logger { get; set; }
public void OnException(ExceptionContext filterContext)
{
Logger.Log("On Exception !", LogType.Debug, filterContext.Exception);
if (filterContext.Exception is UnauthorizedAccessException)
{
filterContext.Result = UnauthorizedAccessExceptionResult(filterContext);
}
else if (filterContext.Exception is BusinessException)
{
filterContext.Result = BusinessExceptionResult(filterContext);
}
else
{
// Unhandled Exception
Logger.Log("Unhandled Exception ", LogType.Error, filterContext.Exception);
filterContext.Result = UnhandledExceptionResult(filterContext);
}
}
}
This way you can catch everything.
So:
private static ActionResult UnauthorizedAccessExceptionResult(ExceptionContext filterContext)
{
// Send email, fire event, add error messages
// for example handle error messages
// You can seperate the behaviour by: if (filterContext.HttpContext.Request.IsAjaxRequest())
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.Controller.TempData.Add(MessageType.Danger.ToString(), filterContext.Exception.Message);
// So you can show messages using with TempData["Key"] on your action or views
var lRoutes = new RouteValueDictionary(
new
{
action = filterContext.RouteData.Values["action"],
controller = filterContext.RouteData.Values["controller"]
});
return new RedirectToRouteResult(lRoutes);
}
In Global.asax:
protected void Application_Start()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
FilterConfig:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ExceptionHandling());
}
BusinessException:
public class BusinessException : Exception, ISerializable
{
public BusinessException(string message)
: base(message)
{
// Add implemenation (if required)
}
}
So you can access the exception message OnException at ExceptionHandling class with filterContext.Exception.Message
You should use BusinessException on the action after any violated control logic this way: throw new BusinessException("Message").
Why don't you create model that contains your required Error Information and bind data to model when you need to? It will also allow you to create/return view from it
Global error catching with special information can you make with customer exceptions who contains the needed informations (id, tablesname etc.).
In HandleErrorAttribute you "only" have httpContext/ExceptionContext and othe static informations.

httpModules not working on iis7

I have the following module
public class LowerCaseRequest : IHttpModule {
public void Init(HttpApplication context) {
context.BeginRequest += new EventHandler(this.OnBeginRequest);
}
public void Dispose() { }
public void OnBeginRequest(Object s, EventArgs e) {
HttpApplication app = (HttpApplication)s;
if (app.Context.Request.Url.ToString().ToLower().EndsWith(".aspx")) {
if (app.Context.Request.Url.ToString() != app.Context.Request.Url.ToString().ToLower()) {
HttpResponse response = app.Context.Response;
response.StatusCode = (int)HttpStatusCode.MovedPermanently;
response.Status = "301 Moved Permanently";
response.RedirectLocation = app.Context.Request.Url.ToString().ToLower();
response.SuppressContent = true;
response.End();
}
if (!app.Context.Request.Url.ToString().StartsWith(#"http://zeeprico.com")) {
HttpResponse response = app.Context.Response;
response.StatusCode = (int)HttpStatusCode.MovedPermanently;
response.Status = "301 Moved Permanently";
response.RedirectLocation = app.Context.Request.Url.ToString().ToLower().Replace(#"http://zeeprico.com", #"http://www.zeeprico.com");
response.SuppressContent = true;
response.End();
}
}
}
}
the web.config looks like
<system.web>
<httpModules>
<remove name="WindowsAuthentication" />
<remove name="PassportAuthentication" />
<remove name="AnonymousIdentification" />
<remove name="UrlAuthorization" />
<remove name="FileAuthorization" />
<add name="LowerCaseRequest" type="LowerCaseRequest" />
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter" />
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
</system.web>
It works grate on my PC running XP and IIS 5.1
but on my webserver running IIS7 and WS 2008 dosn't works, please help I don't know how to work this out.
Thanks
On IIS7 and higher use
<configuration>
<system.webServer>
<modules>
<add name="CustomModule" type="Samples.CustomModule" />
</modules>
</system.webServer>
</configuration>
Above is correct for IIS 7.5
<modules>
<add name="CustomModule" type="Samples.CustomModule" />
</modules>
the only problem I got, is that instance of application pool for particular application should be set to managed Pipeline = Integrated, not Classic..
or:
Using Classic Mode
If your application is to use Classic mode, then make sure that your application is configured for that type of pool and your modules are configured in system.web section and not in system.webServer section of web.config file.
In IIS go to feature view select module
double click to module then right click and press (Add Managed Module)
then put name and type as defined in web.config
example:
<httpModules>
<add name="CustomModule" type="WebApplication.Security.CustomModule" />
</httpModules>

Categories