Search code examples
c#asp.net-coreserilogasp.net-core-2.2

Serilog does not write log to file while using InProcess hosting model in ASP.NET Core 2.2


If I use newly introduced InProcess hosting model in ASP.NET Core 2.2 as follows:

<PropertyGroup>
  <TargetFramework>netcoreapp2.2</TargetFramework>
  <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

Serilog does not write log to file. but if I remove <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel> from .csproj everything works as expected.

My Serilog configuration in the Program class as follows:

public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information() // Set the minimun log level
            .WriteTo.File("Logs\\log-.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7) // this is for logging into file system
            .CreateLogger();

        try
        {
            Log.Information("Starting web host");
            CreateWebHostBuilder(args).Build().Run();
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Host terminated unexpectedly");
        }
        finally
        {
            Log.CloseAndFlush();
        }

    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .ConfigureLogging(logging => { logging.ClearProviders(); }) // clearing all other logging providers
            .UseSerilog(); // Using serilog 
}

Any thought from the expert please!


Solution

  • As suggested in the comments on your question itself, when running using the InProcess hosting model, the current directory for the application is different to the OutOfProcess hosting model. For InProcess, this directory is the location of IIS itself - e.g. C:\Program Files\IIS Express, which means that your log files are being written to C:\Program Files\IIS Express\Logs\log-.txt (assuming that the relevant permissions are set).

    A workaround for this is detailed in this GitHub issue, which provides a helper class (CurrentDirectoryHelpers) for setting the correct current directory. The SetCurrentDirectory static method uses PInvoke, determining whether or not the application is running from within IIS and if it is, it sets the current directory according to the full application path. Using this approach looks like this:

    public class Program
    {
        public static void Main(string[] args)
        {
            CurrentDirectoryHelpers.SetCurrentDirectory();
    
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Information() // Set the minimun log level
                .WriteTo.File("Logs\\log-.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7) // this is for logging into file system
                .CreateLogger();
    
            ...
        }
    }
    

    Here's CurrentDirectoryHelpers for completeness:

    using System;
    
    namespace SampleApp
    {
        internal class CurrentDirectoryHelpers
        {
            internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll";
    
            [System.Runtime.InteropServices.DllImport("kernel32.dll")]
            private static extern IntPtr GetModuleHandle(string lpModuleName);
    
            [System.Runtime.InteropServices.DllImport(AspNetCoreModuleDll)]
            private static extern int http_get_application_properties(ref IISConfigurationData iiConfigData);
    
            [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
            private struct IISConfigurationData
            {
                public IntPtr pNativeApplication;
                [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
                public string pwzFullApplicationPath;
                [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
                public string pwzVirtualApplicationPath;
                public bool fWindowsAuthEnabled;
                public bool fBasicAuthEnabled;
                public bool fAnonymousAuthEnable;
            }
    
            public static void SetCurrentDirectory()
            {
                try
                {
                    // Check if physical path was provided by ANCM
                    var sitePhysicalPath = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH");
                    if (string.IsNullOrEmpty(sitePhysicalPath))
                    {
                        // Skip if not running ANCM InProcess
                        if (GetModuleHandle(AspNetCoreModuleDll) == IntPtr.Zero)
                        {
                            return;
                        }
    
                        IISConfigurationData configurationData = default(IISConfigurationData);
                        if (http_get_application_properties(ref configurationData) != 0)
                        {
                            return;
                        }
    
                        sitePhysicalPath = configurationData.pwzFullApplicationPath;
                    }
    
                    Environment.CurrentDirectory = sitePhysicalPath;
                }
                catch
                {
                    // ignore
                }
            }
        }
    }