Logging All Exceptions in ASP.NET and WCF

I find it useful to log all uncaught exception centrally in ASP.NET web applications and WCF services. In ASP.NET web applications, it is relatively easy – just put logging code in Global.asax.cs like this:

        protected void Application_Error(object sender, EventArgs e)
        {
            var ex = Server.GetLastError();
            if (ex is HttpUnhandledException && ex.InnerException != null)
                ex = ex.InnerException;

            var httpException = ex as HttpException;
            if (httpException != null && httpException.GetHttpCode() == 404)
            {
                // Log this
                Uri urlReferrer = null;
                try
                {
                    urlReferrer = Request.UrlReferrer;
                }
                catch (Exception)
                {
                    // ignored
                }
                Log.WarnFormat("{0} (Client address={1}, UrlReferrer={2})", ex.Message, Request.UserHostAddress, urlReferrer);
            }
            else
                Log.Error(ex.Message, ex);
        }

One thing to note is that uncaught exceptions are wrapped in an HttpUnhandledException – that is why I extract the inner exception. Another thing to note is that you may not want to log 404 not found or as here, log it with a different level.

With WCF, it is (as always) a little more complicated. Putting code in Application_Error in Global won’t work. You have to write one or two classes that implement System.ServiceModel.Dispatcher.IErrorHandler and System.ServiceModel.Description.IServiceBehavior, and do some configuration work. There are different ways to do this. See e.g. http://codeidol.com/csharp/wcf/Faults/Error-Handling-Extensions/. But here is my simplistic solution:

using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using log4net;

namespace MyNamespace
{
    public class ErrorHandler : IErrorHandler, IServiceBehavior
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(ErrorHandler));

        #region IErrorHandler Members

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            var faultException = new FaultException("Error caught in API error handler. Please see API server log for details.");
            var messageFault = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }

        public bool HandleError(Exception error)
        {
            Log.Error(error.Message, error);
            return false;
        }

        #endregion

        #region IServiceBehavior Members

        // This behavior modifies no binding parameters.
        public void AddBindingParameters(
            ServiceDescription description,
            ServiceHostBase serviceHostBase,
            Collection<ServiceEndpoint> endpoints,
            BindingParameterCollection parameters
            )
        {
        }

        // This behavior is an IErrorHandler implementation and must be applied to each ChannelDispatcher.
        public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
            {
                chanDisp.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }

        #endregion
    }

    public class ErrorHandlerBehavior : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }

        public override Type BehaviorType
        {
            get { return typeof(ErrorHandler); }
        }
    }
}

In ProvideFault, which executes on the request thread, I return a generic error to the client (for security reasons). It is logged in HandleError, which executes after the response has been sent.

Here is part of web.config to use this error handler:

  </system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="ErrorHandler" type="MyNamespace.ErrorHandlerBehavior, MyNamespace" />
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyBehavior">
          <!-- ... -->
          <ErrorHandler/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Fix for Windows 10 “account settings are out-of-date” / ”kontoinställningarna är inaktuella”

I recently got the dreaded “account settings are out-of-date” / ”kontoinställningarna är inaktuella” error message in Windows 10 e-mail and calender apps. After some Binging I found Don Cuthbert’s solution in an Windows Insider question, and it worked for me. I did not have to boot into repair mode – I could just delete the Comms folder using explorer after logging out and then logging back in.

Here are the steps involved:

  1. Uninstall the e-mail and calendar apps using this PowerShell commands:
    Get-AppxPackage | Where-Object -Property Name -eq ‘microsoft.windowscommunicationsapps’ | Remove-AppxPackage
  2. Log out
  3. Log in again
  4. Delete the %localappdata%\Comms folder.
  5. In Settings –> Accounts, change to log in with a local account. This will prevent the offending data in the Comms folder to synchronize back from the cloud.
  6. Re-install the e-mail and calendar apps from Store.
  7. Still in Settings –> Accounts, delete the Microsoft account(s) for which you get the error message.
  8. Switch back to log in with your Microsoft account.
  9. Log out
  10. Log in with your Microsoft account.
  11. Launch the e-mail or calendar app.
  12. Add back your e-mail account(s).