diff --git a/src/KissLog.AspNet.Mvc/KissLog.AspNet.Mvc.nuspec b/src/KissLog.AspNet.Mvc/KissLog.AspNet.Mvc.nuspec index a64b45f..cc66e2f 100644 --- a/src/KissLog.AspNet.Mvc/KissLog.AspNet.Mvc.nuspec +++ b/src/KissLog.AspNet.Mvc/KissLog.AspNet.Mvc.nuspec @@ -2,7 +2,7 @@ KissLog.AspNet.Mvc - 3.4.0 + 3.4.1 KissLog.net KissLog.net https://opensource.org/licenses/BSD-3-Clause @@ -10,12 +10,12 @@ https://kisslog.net/cdn/KissLog/logos/32.png false KissLog ASP.NET MVC package. Install this package on ASP.NET MVC web applications. - Adapted to KissLog 3.4.0 improvements + General improvements Copyright 2019 KissLog, MVC, AspNet - + diff --git a/src/KissLog.AspNet.Mvc/Properties/AssemblyInfo.cs b/src/KissLog.AspNet.Mvc/Properties/AssemblyInfo.cs index ac49b8c..c5d83b4 100644 --- a/src/KissLog.AspNet.Mvc/Properties/AssemblyInfo.cs +++ b/src/KissLog.AspNet.Mvc/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.4.0.0")] -[assembly: AssemblyFileVersion("3.4.0.0")] +[assembly: AssemblyVersion("3.4.1.0")] +[assembly: AssemblyFileVersion("3.4.1.0")] diff --git a/src/KissLog.AspNet.Web/KissLog.AspNet.Web.nuspec b/src/KissLog.AspNet.Web/KissLog.AspNet.Web.nuspec index b57f433..e6ccaf6 100644 --- a/src/KissLog.AspNet.Web/KissLog.AspNet.Web.nuspec +++ b/src/KissLog.AspNet.Web/KissLog.AspNet.Web.nuspec @@ -2,7 +2,7 @@ KissLog.AspNet.Web - 3.4.0 + 3.4.1 KissLog.net KissLog.net https://opensource.org/licenses/BSD-3-Clause @@ -10,7 +10,7 @@ https://kisslog.net/cdn/KissLog/logos/32.png false KissLog Web package. You should not manually install this package, as it will be installed as a dependency. - Adapted to KissLog 3.4.0 improvements + General improvements Copyright 2019 KissLog diff --git a/src/KissLog.AspNet.Web/KissLogHttpModule.cs b/src/KissLog.AspNet.Web/KissLogHttpModule.cs index 875ff29..4cf811b 100644 --- a/src/KissLog.AspNet.Web/KissLogHttpModule.cs +++ b/src/KissLog.AspNet.Web/KissLogHttpModule.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Security.Claims; +using System.Text; using System.Web; namespace KissLog.AspNet.Web @@ -152,6 +153,12 @@ private void EndRequest(object sender, EventArgs e) } WebRequestProperties properties = (WebRequestProperties)HttpContext.Current.Items[Constants.HttpRequestPropertiesKey]; + if(properties == null) + { + // IIS redirect bypasses the BeginRequest() event + properties = WebRequestPropertiesFactory.Create(ctx.Request); + } + properties.EndDateTime = DateTime.UtcNow; ResponseProperties response = WebResponsePropertiesFactory.Create(ctx.Response); @@ -169,24 +176,7 @@ private void EndRequest(object sender, EventArgs e) if (sniffer != null) { - using (sniffer.MirrorStream) - { - sniffer.MirrorStream.Position = 0; - - if (InternalHelpers.PreFilterShouldLogResponseBody(logger, sniffer.MirrorStream, response)) - { - using (TemporaryFile tempFile = new TemporaryFile()) - { - using (var fs = File.OpenWrite(tempFile.FileName)) - { - sniffer.MirrorStream.CopyTo(fs); - } - - string responseFileName = InternalHelpers.ResponseFileName(properties.Response.Headers); - logger.LogFile(tempFile.FileName, responseFileName); - } - } - } + LogResponse(logger, properties, response, sniffer); } logger.DataContainer.WebRequestProperties = properties; @@ -216,6 +206,39 @@ private static void SetFactory() factoryProperty.SetValue(Logger.Factory, loggerFactory, null); } } + + private static void LogResponse(Logger logger, WebRequestProperties properties, ResponseProperties response, ResponseSniffer sniffer) + { + try + { + using (sniffer.MirrorStream) + { + sniffer.MirrorStream.Position = 0; + + if (InternalHelpers.PreFilterShouldLogResponseBody(logger, sniffer.MirrorStream, response)) + { + using (TemporaryFile tempFile = new TemporaryFile()) + { + using (var fs = File.OpenWrite(tempFile.FileName)) + { + sniffer.MirrorStream.CopyTo(fs); + } + + string responseFileName = InternalHelpers.ResponseFileName(properties.Response.Headers); + logger.LogFile(tempFile.FileName, responseFileName); + } + } + } + } + catch(Exception ex) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Error logging HTTP Response Content as file"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); + } + } } } diff --git a/src/KissLog.AspNet.Web/Properties/AssemblyInfo.cs b/src/KissLog.AspNet.Web/Properties/AssemblyInfo.cs index 20a0451..cc87145 100644 --- a/src/KissLog.AspNet.Web/Properties/AssemblyInfo.cs +++ b/src/KissLog.AspNet.Web/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.4.0.0")] -[assembly: AssemblyFileVersion("3.4.0.0")] +[assembly: AssemblyVersion("3.4.1.0")] +[assembly: AssemblyFileVersion("3.4.1.0")] diff --git a/src/KissLog.AspNet.WebApi/KissLog.AspNet.WebApi.nuspec b/src/KissLog.AspNet.WebApi/KissLog.AspNet.WebApi.nuspec index f48c58b..08caf80 100644 --- a/src/KissLog.AspNet.WebApi/KissLog.AspNet.WebApi.nuspec +++ b/src/KissLog.AspNet.WebApi/KissLog.AspNet.WebApi.nuspec @@ -2,7 +2,7 @@ KissLog.AspNet.WebApi - 3.4.0 + 3.4.1 KissLog.net KissLog.net https://opensource.org/licenses/BSD-3-Clause @@ -10,12 +10,12 @@ https://kisslog.net/cdn/KissLog/logos/32.png false KissLog ASP.NET WebApi package. Install this package on ASP.NET WebApi applications. - Adapted to KissLog 3.4.0 improvements + General improvements Copyright 2019 KissLog, WebApi, AspNet - + diff --git a/src/KissLog.AspNet.WebApi/Properties/AssemblyInfo.cs b/src/KissLog.AspNet.WebApi/Properties/AssemblyInfo.cs index 82d0b5b..cbbbe54 100644 --- a/src/KissLog.AspNet.WebApi/Properties/AssemblyInfo.cs +++ b/src/KissLog.AspNet.WebApi/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.4.0.0")] -[assembly: AssemblyFileVersion("3.4.0.0")] +[assembly: AssemblyVersion("3.4.1.0")] +[assembly: AssemblyFileVersion("3.4.1.0")] diff --git a/src/KissLog.AspNetCore/KissLog.AspNetCore.csproj b/src/KissLog.AspNetCore/KissLog.AspNetCore.csproj index 7a3c1d0..56b2c8e 100644 --- a/src/KissLog.AspNetCore/KissLog.AspNetCore.csproj +++ b/src/KissLog.AspNetCore/KissLog.AspNetCore.csproj @@ -12,21 +12,21 @@ Install this package on ASP.NET Core web applications. https://kisslog.net/cdn/KissLog/logos/32.png KissLog, AspNetCore, NetCore, Core True - 2.4.0 - 2.4.0.0 - 2.4.0.0 - Adapted to KissLog 3.4.0 improvements + 2.4.2 + 2.4.2.0 + 2.4.2.0 + Adapted to .NET Core 3.0 KissLog.AspNetCore https://github.com/KissLog-net/KissLog.Sdk git - - - + + + - + diff --git a/src/KissLog.AspNetCore/KissLogMiddleware.cs b/src/KissLog.AspNetCore/KissLogMiddleware.cs index 6f83a4e..10007f4 100644 --- a/src/KissLog.AspNetCore/KissLogMiddleware.cs +++ b/src/KissLog.AspNetCore/KissLogMiddleware.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Text; using System.Threading.Tasks; namespace KissLog.AspNetCore @@ -41,8 +42,8 @@ public async Task Invoke(HttpContext context) await _next(context); - responseBodyFile = new TemporaryFile(); - await ReadResponse(context.Response, responseBodyFile.FileName); + responseBodyFile = await ReadResponseAsync(context.Response); + contentLength = responseStream.Length; if (CanWriteToResponseBody(context.Response)) @@ -96,21 +97,42 @@ public async Task Invoke(HttpContext context) } } - private async Task ReadResponse(HttpResponse response, string destinationFilePath) + private async Task ReadResponseAsync(HttpResponse response) { + TemporaryFile responseBodyFile = null; + try { + responseBodyFile = new TemporaryFile(); + response.Body.Seek(0, SeekOrigin.Begin); - using (var fs = File.OpenWrite(destinationFilePath)) + using (var fs = File.OpenWrite(responseBodyFile.FileName)) { await response.Body.CopyToAsync(fs); } } + catch(Exception ex) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("KissLogMiddleware.ReadResponseAsync error"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); + + if(responseBodyFile != null) + { + responseBodyFile.Dispose(); + } + + responseBodyFile = null; + } finally { response.Body.Seek(0, SeekOrigin.Begin); } + + return responseBodyFile; } private bool CanWriteToResponseBody(HttpResponse response) diff --git a/src/KissLog.AspNetCore/PackageInit.cs b/src/KissLog.AspNetCore/PackageInit.cs index b1d48ff..cd26a9b 100644 --- a/src/KissLog.AspNetCore/PackageInit.cs +++ b/src/KissLog.AspNetCore/PackageInit.cs @@ -1,6 +1,9 @@ -using KissLog.Internal; +using KissLog.AspNetCore.ReadInputStream; +using KissLog.Internal; using System; +using System.Linq; using System.Reflection; +using System.Text; namespace KissLog.AspNetCore { @@ -8,6 +11,8 @@ internal static class PackageInit { private const string SdkName = "KissLog.AspNetCore"; + internal static IReadInputStreamProvider ReadInputStreamProvider = new NullReadInputStreamProvider(); + static string GetSdkVersion() { try @@ -24,6 +29,7 @@ static string GetSdkVersion() public static void Init() { SetFactory(); + SetReadInputStreamProvider(); InternalHelpers.SdkName = SdkName; InternalHelpers.SdkVersion = GetSdkVersion(); @@ -36,5 +42,93 @@ private static void SetFactory() PropertyInfo factoryProperty = typeof(Logger).GetProperty("Factory"); factoryProperty.SetValue(Logger.Factory, loggerFactory, null); } + + private static void SetReadInputStreamProvider() + { + bool hasEnableBuffering = HasEnableBuffering(); + if(hasEnableBuffering) + { + ReadInputStreamProvider = new EnableBufferingReadInputStreamProvider(); + KissLog.Internal.InternalHelpers.Log($"ReadInputStreamProvider: {nameof(EnableBufferingReadInputStreamProvider)}", LogLevel.Information); + + return; + } + + bool hasEnableRewind = HasEnableRewind(); + if(hasEnableRewind) + { + ReadInputStreamProvider = new EnableRewindReadInputStreamProvider(); + KissLog.Internal.InternalHelpers.Log($"ReadInputStreamProvider: {nameof(EnableRewindReadInputStreamProvider)}", LogLevel.Information); + + return; + } + + ReadInputStreamProvider = new NullReadInputStreamProvider(); + KissLog.Internal.InternalHelpers.Log($"ReadInputStreamProvider: {nameof(NullReadInputStreamProvider)}", LogLevel.Warning); + } + + private static bool HasEnableBuffering() + { + bool result = false; + + try + { + string assemblyName = "Microsoft.AspNetCore.Http"; + string typeName = "Microsoft.AspNetCore.Http.HttpRequestRewindExtensions"; + string assemblyQualifiedName = Assembly.CreateQualifiedName(assemblyName, typeName); + + Type type = Type.GetType(assemblyQualifiedName, false); + if (type != null) + { + var enableBuffering = type + .GetMethods(BindingFlags.Static | BindingFlags.Public) + .FirstOrDefault(m => m.Name == "EnableBuffering"); + + result = enableBuffering != null; + } + } + catch(Exception ex) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Error trying to calculate HasEnableBuffering()"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); + } + + return result; + } + + private static bool HasEnableRewind() + { + bool result = false; + + try + { + string assemblyName = "Microsoft.AspNetCore.Http"; + string typeName = "Microsoft.AspNetCore.Http.Internal.BufferingHelper"; + string assemblyQualifiedName = Assembly.CreateQualifiedName(assemblyName, typeName); + + Type type = Type.GetType(assemblyQualifiedName, false); + if (type != null) + { + var enableRewind = type + .GetMethods(BindingFlags.Static | BindingFlags.Public) + .FirstOrDefault(m => m.Name == "EnableRewind"); + + result = enableRewind != null; + } + } + catch (Exception ex) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Error trying to calculate HasEnableRewind()"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); + } + + return result; + } } } diff --git a/src/KissLog.AspNetCore/ReadInputStream/EnableBufferingReadInputStreamProvider.cs b/src/KissLog.AspNetCore/ReadInputStream/EnableBufferingReadInputStreamProvider.cs new file mode 100644 index 0000000..d0e293c --- /dev/null +++ b/src/KissLog.AspNetCore/ReadInputStream/EnableBufferingReadInputStreamProvider.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.IO; +using System.Text; + +namespace KissLog.AspNetCore.ReadInputStream +{ + internal class EnableBufferingReadInputStreamProvider : IReadInputStreamProvider + { + public string ReadInputStream(HttpRequest request) + { + string content = string.Empty; + + try + { + if (request.Body.CanRead == false) + return content; + + // Allows using several time the stream in ASP.Net Core + request.EnableBuffering(); + + // Arguments: Stream, Encoding, detect encoding, buffer size + // AND, the most important: keep stream opened + using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true)) + { + var task = reader.ReadToEndAsync(); + task.Wait(); + + content = task.Result; + } + + request.Body.Position = 0; + } + catch (Exception ex) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Error reading Request.InputStream"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); + } + + return content; + } + } +} diff --git a/src/KissLog.AspNetCore/ReadInputStream/EnableRewindReadInputStreamProvider.cs b/src/KissLog.AspNetCore/ReadInputStream/EnableRewindReadInputStreamProvider.cs new file mode 100644 index 0000000..318aad9 --- /dev/null +++ b/src/KissLog.AspNetCore/ReadInputStream/EnableRewindReadInputStreamProvider.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; +using System; +using System.IO; +using System.Text; + +namespace KissLog.AspNetCore.ReadInputStream +{ + internal class EnableRewindReadInputStreamProvider : IReadInputStreamProvider + { + public string ReadInputStream(HttpRequest request) + { + string content = string.Empty; + + try + { + if (request.Body.CanRead == false) + return content; + + // Allows using several time the stream in ASP.Net Core + request.EnableRewind(); + + // Arguments: Stream, Encoding, detect encoding, buffer size + // AND, the most important: keep stream opened + using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true)) + { + content = reader.ReadToEnd(); + } + + request.Body.Position = 0; + } + catch (Exception ex) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Error reading Request.InputStream"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); + } + + return content; + } + } +} diff --git a/src/KissLog.AspNetCore/ReadInputStream/IReadInputStreamProvider.cs b/src/KissLog.AspNetCore/ReadInputStream/IReadInputStreamProvider.cs new file mode 100644 index 0000000..8a360b1 --- /dev/null +++ b/src/KissLog.AspNetCore/ReadInputStream/IReadInputStreamProvider.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Http; + +namespace KissLog.AspNetCore.ReadInputStream +{ + internal interface IReadInputStreamProvider + { + string ReadInputStream(HttpRequest request); + } +} diff --git a/src/KissLog.AspNetCore/ReadInputStream/NullReadInputStreamProvider.cs b/src/KissLog.AspNetCore/ReadInputStream/NullReadInputStreamProvider.cs new file mode 100644 index 0000000..9dae059 --- /dev/null +++ b/src/KissLog.AspNetCore/ReadInputStream/NullReadInputStreamProvider.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Http; + +namespace KissLog.AspNetCore.ReadInputStream +{ + internal class NullReadInputStreamProvider : IReadInputStreamProvider + { + public string ReadInputStream(HttpRequest request) + { + return string.Empty; + } + } +} diff --git a/src/KissLog.AspNetCore/WebRequestPropertiesFactory.cs b/src/KissLog.AspNetCore/WebRequestPropertiesFactory.cs index 6813960..e87537a 100644 --- a/src/KissLog.AspNetCore/WebRequestPropertiesFactory.cs +++ b/src/KissLog.AspNetCore/WebRequestPropertiesFactory.cs @@ -1,17 +1,14 @@ -using KissLog.Web; +using KissLog.Internal; +using KissLog.Web; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Http.Internal; using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Security.Claims; using System.Text; -using KissLog.Internal; -using Microsoft.AspNetCore.Http.Features; namespace KissLog.AspNetCore { @@ -165,31 +162,20 @@ private static string GetMachineName() private static string ReadInputStream(HttpRequest request) { - string content = string.Empty; - try { - if (request.Body.CanRead == false) - return content; - - // Allows using several time the stream in ASP.Net Core - request.EnableRewind(); - - // Arguments: Stream, Encoding, detect encoding, buffer size - // AND, the most important: keep stream opened - using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true)) - { - content = reader.ReadToEnd(); - } - - request.Body.Position = 0; + return PackageInit.ReadInputStreamProvider.ReadInputStream(request); } - catch + catch(Exception ex) { - // ignored + StringBuilder sb = new StringBuilder(); + sb.AppendLine("Error on WebRequestPropertiesFactory.ReadInputStream()"); + sb.AppendLine(ex.ToString()); + + KissLog.Internal.InternalHelpers.Log(sb.ToString(), LogLevel.Error); } - return content; + return string.Empty; } public static List> ToDictionary(ClaimsIdentity identity)