/// <summary> /// Execute an <paramref name="asyncMethod"/> in the background. /// </summary> /// <param name="asyncMethod">The action to run in the background.</param> /// <param name="token">Propagates notification that operations should be canceled</param> /// <returns>The created thread.</returns> public static Thread FireAndForget(Func <CancellationToken, Task> asyncMethod, CancellationToken token = default) { FulcrumApplication.ValidateButNotInProduction(); var messageIfException = $"Background thread failed."; return(FulcrumApplication.Setup.ThreadHandler.FireAndForget(ct => CallAsyncFromSync(asyncMethod, messageIfException, ct), token)); }
/// <summary> /// Execute an <paramref name="asyncMethod"/> in the background. /// </summary> /// <param name="asyncMethod">The action to run in the background.</param> /// <param name="token">Propagates notification that operations should be canceled</param> /// <returns>The created thread.</returns> public static Thread FireAndForgetWithExpensiveStackTracePreservation(Func <CancellationToken, Task> asyncMethod, CancellationToken token = default) { FulcrumApplication.ValidateButNotInProduction(); var context = new StackTracePreservation(); return(FireAndForget(ct => context.ExecuteActionFailSafeAsync(asyncMethod, ct), token)); }
/// <summary> /// Execute an <paramref name="action"/> in the background. /// </summary> /// <param name="action">The action to run in the background.</param> /// <returns>The created thread.</returns> public static Thread FireAndForget(Action action) { FulcrumApplication.ValidateButNotInProduction(); var messageIfException = $"Background thread failed."; return(FulcrumApplication.Setup.ThreadHandler.FireAndForget(ct => ExecuteActionFailSafe(action, messageIfException))); }
/// <summary> /// Execute an <paramref name="asyncMethod"/> in the background. /// </summary> /// <param name="asyncMethod">The action to run in the background.</param> /// <returns>The created thread.</returns> public static Thread FireAndForgetWithExpensiveStackTracePreservation(Func <Task> asyncMethod) { FulcrumApplication.ValidateButNotInProduction(); var context = new StackTracePreservation(); return(FireAndForget(() => context.ExecuteActionFailSafeAsync(asyncMethod))); }
/// <summary> /// Execute an <paramref name="action"/> in the background. /// </summary> /// <param name="action">The action to run in the background.</param> /// <returns>The created thread.</returns> public static Thread FireAndForgetWithExpensiveStackTracePreservation(Action action) { FulcrumApplication.ValidateButNotInProduction(); var context = new StackTracePreservation(); return(FireAndForget(() => context.ExecuteActionFailSafe(action))); }
/// <summary> /// This method will be called indirectly from the program's Main method to configure the services /// </summary> /// <remarks> /// Don't override this method unless you really know what you are doing. /// First see if the following methods could be good enough for your needs: /// Always override <see cref="GetSynchronousFastLogger"/> to establish your preferred way of logging. /// Always override <see cref="DependencyInjectServices(IServiceCollection)"/> to inject your own services. /// Override <see cref="ConfigureServicesInitialUrgentPart"/> if you have things that needs to be initialized early. /// Override <see cref="ConfigureServicesSwagger"/> if you want to change how swagger is set up. /// </remarks> public virtual void ConfigureServices(IServiceCollection services) { try { FulcrumApplication.Validate(); ConfigureServicesInitialUrgentPart(services); FulcrumApplication.ValidateButNotInProduction(); InternalContract.RequireValidated(this, GetType().FullName); ConfigureServicesSwagger(services); DependencyInjectServices(services); using (var serviceScope = services.BuildServiceProvider().CreateScope()) { ValueTranslatorFilter valueTranslatorFilter = null; var serviceProvider = serviceScope.ServiceProvider; DependencyInjectServicesAdvanced(services, serviceProvider); if (IsBusinessApi) { var translatorService = serviceProvider.GetService <ITranslatorService>(); if (translatorService == null) { Log.LogWarning($"Could not resolve {nameof(ITranslatorService)}"); } else { ValueTranslatorHttpSender.TranslatorService = translatorService; valueTranslatorFilter = new ValueTranslatorFilter( translatorService, () => FulcrumApplication.Context?.ClientPrincipal?.Identity?.Name); } } var mvc = services.AddMvc(opts => { if (IsBusinessApi && valueTranslatorFilter != null) { opts.Filters.Add(valueTranslatorFilter); } if (!FulcrumApplication.IsInDevelopment) { return; } Log.LogWarning($"Anonymous service usage is allowed, due to development mode."); opts.Filters.Add(new AllowAnonymousFilter()); }); mvc .SetCompatibilityVersion(CompatibilityVersion) .ConfigureApplicationPartManager(apm => apm.FeatureProviders.Add(new RemoveRedundantControllers(_controllersToKeep))); AddControllersToMvc(services, mvc); } Log.LogInformation($"{nameof(StartupBase)}.{nameof(ConfigureServices)} succeeded."); } catch (Exception e) { Log.LogCritical( $"{nameof(StartupBase)}.{nameof(ConfigureServices)} failed. The application {FulcrumApplication.Setup?.Name} needs to be restarted.: {e.Message}", e); throw; } }
/// <summary> /// This logging is done with simple methods like local logging. The <paramref name="message"/> will be extended with application information and possibly exception information. /// </summary> /// <param name="severityLevel">The severity level for this log.</param> /// <param name="message">The message to log.</param> /// <param name="exception">An optional exception that will have it's information incorporated in the message.</param> /// <param name="memberName">Method or property name of the caller</param> /// <param name="filePath">Full path of the source file that contains the caller. This is the file path at compile time.</param> /// <param name="lineNumber">Line number in the source file at which the method is called</param> public static void FallbackSafeLog( LogSeverityLevel severityLevel, string message, Exception exception = null, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { try { var hideStackTrace = severityLevel < LogSeverityLevel.Error; // ReSharper disable ExplicitCallerInfoArgument var location = LocationToLogString(memberName, filePath, lineNumber); // ReSharper restore ExplicitCallerInfoArgument var messageWithLogInfo = $"{severityLevel}: {message}"; messageWithLogInfo += $"\r{FulcrumApplication.ToLogString()}"; messageWithLogInfo += ContextToLogString(); messageWithLogInfo += $"\r{location}"; if (exception != null) { messageWithLogInfo += $"\r{exception.ToLogString(hideStackTrace)}"; } FulcrumApplication.Setup.FallbackLogger.SafeLog(severityLevel, messageWithLogInfo); } catch (Exception) { // We give up } }
/// <summary> /// Sets the recommended application setup for a Web Api. /// </summary> /// <param name="name">The name of the application.</param> /// <param name="tenant">The tenant that the application itself runs in.</param> /// <param name="level">The run time level for the application itself.</param> public static void WebBasicSetup(string name, Tenant tenant, RunTimeLevelEnum level) { FulcrumApplication.Initialize(name, tenant, level); FulcrumApplication.Setup.ThreadHandler = ThreadHelper.RecommendedForRuntime; FulcrumApplication.Setup.SynchronousFastLogger = LogHelper.RecommendedSyncLoggerForRuntime; FulcrumApplication.Setup.FallbackLogger = LogHelper.RecommendedFallbackLoggerForRuntime; FulcrumApplication.AppSettings = new AppSettings(new ConfigurationManagerAppSettings()); }
/// <summary> /// /// </summary> /// <remarks>See https://docs.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics</remarks> public ApplicationInsightsTelemetryHandler(string contextDeviceId = null, string contextUserId = null) { FulcrumApplication.ValidateButNotInProduction(); TelemetryClient = new TelemetryClient(); if (!string.IsNullOrWhiteSpace(contextDeviceId)) { TelemetryClient.Context.Device.Id = contextDeviceId; } if (!string.IsNullOrWhiteSpace(contextUserId)) { TelemetryClient.Context.User.Id = contextUserId; } }
public void FallbackSafeLog() { const LogSeverityLevel expectedLevel = LogSeverityLevel.Error; const string exceptionMessage = "ExceptionMessage"; const string message = "TestMessage"; try { throw new TestException(exceptionMessage); } catch (Exception expectedException) { // ReSharper disable ExplicitCallerInfoArgument LogHelper.FallbackSafeLog(expectedLevel, message, expectedException, "memberName", "filePath", 42); // ReSharper restore ExplicitCallerInfoArgument UT.Assert.AreEqual(expectedLevel, _loggedSeverityLevel); UT.Assert.IsNotNull(_loggedMessage); // ReSharper disable ExplicitCallerInfoArgument UT.Assert.IsTrue(_loggedMessage.Contains(LogHelper.LocationToLogString("memberName", "filePath", 42))); // ReSharper restore ExplicitCallerInfoArgument UT.Assert.IsTrue(_loggedMessage.Contains(FulcrumApplication.ToLogString())); } }
/// <summary> /// Constructor /// </summary> public LogRequestAndResponse() { FulcrumApplication.ValidateButNotInProduction(); }
/// <summary> /// Execute an <paramref name="asyncMethod"/> in the background. /// </summary> /// <param name="asyncMethod">The action to run in the background.</param> /// <param name="token">Propagates notification that operations should be canceled</param> /// <returns>The created thread.</returns> public static Thread FireAndForgetResetContext(Func <CancellationToken, Task> asyncMethod, CancellationToken token = default) { FulcrumApplication.ValidateButNotInProduction(); return(FireAndForget(async() => await ResetBeforeCall(asyncMethod, token))); }
/// <summary> /// Execute an <paramref name="asyncMethod"/> in the background. /// </summary> /// <param name="asyncMethod">The action to run in the background.</param> /// <returns>The created thread.</returns> public static Thread FireAndForgetResetContext(Func <Task> asyncMethod) { FulcrumApplication.ValidateButNotInProduction(); return(FireAndForget(async() => await ResetBeforeCall(asyncMethod))); }
/// <summary> /// Execute an <paramref name="action"/> in the background. /// </summary> /// <param name="action">The action to run in the background.</param> /// <returns>The created thread.</returns> public static Thread FireAndForgetResetContext(Action action) { FulcrumApplication.ValidateButNotInProduction(); return(FireAndForget(() => ResetBeforeCall(action))); }