• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Aldaviva / Unfucked / 24047187514

06 Apr 2026 07:22PM UTC coverage: 43.559% (-1.7%) from 45.265%
24047187514

push

github

Aldaviva
Make lambdas static where possible for better performance. Use concrete types instead of interfaces where possible to avoid virtual calls, also for perceived performance. Add more extensions to easily create ConcurrentDictionaries with atomic mutable values. Make mutable value holders in ConcurrentDictionary not equatable except for reference equality to avoid instances getting lost in the dictionary when the value and therefore hashcode changes. Added overloads to ConcurrentDictionary addition-aware upserting to take a valueFactory argument, to allow callers to not have to create a closure for their valueFactory if they already had a value they wanted to pass to it. Removed usage of array pool when converting special URL characters to their URL-encoded form, because the arrays are short enough (4 bytes) that it's faster to allocate and collect with GC than to borrow and return to a pool.

645 of 1560 branches covered (41.35%)

65 of 148 new or added lines in 22 files covered. (43.92%)

86 existing lines in 7 files now uncovered.

1143 of 2624 relevant lines covered (43.56%)

177.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/DI/DependencyInjectionExtensions.cs
1
using Microsoft.Extensions.Configuration;
2
using Microsoft.Extensions.Configuration.Json;
3
using Microsoft.Extensions.DependencyInjection;
4
using Microsoft.Extensions.DependencyInjection.Extensions;
5
using Microsoft.Extensions.FileProviders;
6
using Microsoft.Extensions.Hosting;
7
using Unfucked.DI;
8
#if !NET6_0_OR_GREATER
9
using System.Reflection;
10
using System.Diagnostics;
11
#endif
12

13
namespace Unfucked;
14

15
/// <summary>
16
/// Methods that make it easier to work with the <c>Microsoft.Extensions.Hosting</c> dependency injection/inversion of control library, which is used in the Generic Host and ASP.NET Core.
17
/// </summary>
18
public static partial class DependencyInjectionExtensions {
19

20
    /// <summary>
21
    /// <para>By default, the .NET host only looks for configuration files in the working directory, not the installation directory, which breaks when you run the program from any other directory.</para>
22
    /// <para>Fix this by also looking for JSON configuration files in the same directory as this executable.</para>
23
    /// </summary>
24
    /// <param name="builder">see <c>HostApplicationBuilder.Configuration</c></param>
25
    /// <returns>the same <see cref="IConfigurationBuilder"/> for chaining</returns>
26
    // ExceptionAdjustment: M:System.Collections.Generic.IList`1.Insert(System.Int32,`0) -T:System.NotSupportedException
27
    // ExceptionAdjustment: P:System.Diagnostics.Process.MainModule get -T:System.ComponentModel.Win32Exception
28
    public static IConfigurationBuilder AlsoSearchForJsonFilesInExecutableDirectory(this IConfigurationBuilder builder) {
29
        string? installationDir;
30
        try {
31
            string? processPath =
1✔
32
#if NET6_0_OR_GREATER
1✔
33
                Environment.ProcessPath;
1✔
34
#else
35
                Assembly.GetEntryAssembly()?.Location;
36
            if (processPath == null) {
37
                using Process currentProcess = Process.GetCurrentProcess();
38
                processPath = currentProcess.MainModule!.FileName;
39
            }
40
#endif
41
            installationDir = Path.GetDirectoryName(processPath);
1✔
42
        } catch (PathTooLongException) {
1✔
43
            return builder;
×
44
        }
45

46
        if (installationDir != null) {
1✔
47
            PhysicalFileProvider fileProvider = new(installationDir);
1✔
48

49
            IEnumerable<(int index, IConfigurationSource source)> sourcesToAdd = builder.Sources.SelectMany<IConfigurationSource, (int, IConfigurationSource)>((src, oldIndex) =>
1✔
50
                src is JsonConfigurationSource { Path: {} path } source
2!
51
                    ? [
2✔
52
                        (oldIndex, new JsonConfigurationSource {
2✔
53
                            FileProvider   = fileProvider,
2✔
54
                            Path           = path,
2✔
55
                            Optional       = true,
2✔
56
                            ReloadOnChange = source.ReloadOnChange,
2✔
57
                            ReloadDelay    = source.ReloadDelay
2✔
58
                        })
2✔
59
                    ]
2✔
60
                    : []).ToList();
2✔
61

62
            int sourcesAdded = 0;
1✔
63
            foreach ((int index, IConfigurationSource source) in sourcesToAdd) {
4✔
64
                builder.Sources.Insert(index + sourcesAdded++, source);
1✔
65
            }
66
        }
67

68
        return builder;
1✔
69
    }
×
70

71
    /// <summary>
72
    /// <para>Declarative injection of dependencies with shorter lifetimes into dependents with longer lifetimes, like <c>javax.inject.Provider&lt;T&gt;</c>, without the complication of creating scopes, so you don't have a inject an <see cref="IServiceProvider"/> and imperatively request everything, which isn't very DI-like.</para>
73
    /// <para>Configure dependency injection context to allow you to inject <see cref="Provider{T}"/> instances into your dependent services.</para>
74
    /// <para>This allows you to inject not an instance of a dependency service into your consumer, but rather a factory method that lazily provides the dependency service when called in your dependent service.</para>
75
    /// <para>This is useful when the lifetime of the dependent is longer than the lifetime of the dependency, and you want the dependency to get cleaned up. For example, a singleton may depend on a prototype-scoped service that must be eagerly cleaned up after it's used to avoid leaking memory, or because the dependency cannot be reused.</para>
76
    /// <para>Register: <c>
77
    /// appBuilder.Services
78
    ///     .AddInjectableProviders()
79
    ///     .AddTransient&lt;MyDependency&gt;()
80
    ///     .AddSingleton&lt;MyDependent&gt;();
81
    /// </c></para>
82
    /// <para>Inject: <c>
83
    /// public class MyDependent(Provider&lt;MyDependency&gt; dependencyProvider) {
84
    ///     public void Start() {
85
    ///         using MyDependency dependency = dependencyProvider.Get();
86
    ///         dependency.Run();
87
    ///     }
88
    /// }
89
    /// </c></para>
90
    /// </summary>
91
    /// <param name="services">Application builder's <see cref="HostApplicationBuilder.Services"/>.</param>
92
    public static IServiceCollection AddInjectableProviders(this IServiceCollection services) {
93
        services.TryAddSingleton(typeof(Provider<>), typeof(MicrosoftDependencyInjectionServiceProvider<>));
1✔
94
        services.TryAddSingleton(typeof(OptionalProvider<>), typeof(MicrosoftDependencyInjectionServiceProvider<>));
1✔
95
        return services;
1✔
96
    }
97

98
    /// <summary>
99
    /// <para>By default in .NET 6 and later, an uncaught exception in a <see cref="BackgroundService"/> will log a critical error and cause the host application to exit with status code 0. This makes it very difficult to automatically determine if the application crashed, such as when it's run from a script or Task Scheduler.</para>
100
    /// <para>This extension allows you to change the exit code returned by this program when it exits due to a <see cref="BackgroundService"/> throwing an exception. By default, this will return 1 on exceptions, but you can customize the exit code too. The exit code is only changed if a <see cref="BackgroundService"/> threw an exception, so the program will still exit with 0 normally.</para>
101
    /// <para>Usage:</para>
102
    /// <para><code>builder.Services.SetExitCodeOnBackgroundServiceException(1);</code></para>
103
    /// </summary>
104
    /// <param name="services">From <see cref="HostApplicationBuilder.Services"/> or similar.</param>
105
    /// <param name="exitCode">The numeric status code you want the application to exit with when a <see cref="BackgroundService"/> throws an uncaught exception. To customize the exit code for different exceptions, use the overload that takes a function for this parameter.</param>
106
    public static IServiceCollection SetExitCodeOnBackgroundServiceException(this IServiceCollection services, int exitCode = 1) => services.SetExitCodeOnBackgroundServiceException(_ => exitCode);
1✔
107

108
    /// <summary>
109
    /// <para>By default in .NET 6 and later, an uncaught exception in a <see cref="BackgroundService"/> will log a critical error and cause the host application to exit with status code 0. This makes it very difficult to automatically determine if the application crashed, such as when it's run from a script or Task Scheduler.</para>
110
    /// <para>This extension allows you to change the exit code returned by this program when it exits due to a <see cref="BackgroundService"/> throwing an exception. By default, this will return 1 on exceptions, but you can customize the exit code too. The exit code is only changed if a <see cref="BackgroundService"/> threw an exception, so the program will still exit with 0 normally.</para>
111
    /// <para>Usage:</para>
112
    /// <para><code>builder.Services.SetExitCodeOnBackgroundServiceException(exception => exception is ApplicationException ? 1 : 2);</code></para>
113
    /// </summary>
114
    /// <param name="services">From <see cref="HostApplicationBuilder.Services"/> or similar.</param>
115
    /// <param name="exitCodeGenerator">A function that takes the <see cref="Exception"/> thrown by the <see cref="BackgroundService"/> and returns the status code to exit this process with.</param>
116
    public static IServiceCollection SetExitCodeOnBackgroundServiceException(this IServiceCollection services, Func<Exception, int> exitCodeGenerator) {
117
        services.AddHostedService(context => new BackgroundServiceExceptionListener(context, exitCodeGenerator));
2✔
118
        return services;
1✔
119
    }
120

121
    internal sealed class BackgroundServiceExceptionListener(IServiceProvider services, Func<Exception, int> exitCodeGenerator): BackgroundService {
1✔
122

123
        protected override Task ExecuteAsync(CancellationToken stoppingToken) {
NEW
124
            IEnumerable<BackgroundService> backgroundServices =
×
NEW
125
                services.GetServices<IHostedService>().OfType<BackgroundService>().Where(static service => service is not BackgroundServiceExceptionListener);
×
126

UNCOV
127
            services.GetRequiredService<IHostApplicationLifetime>().ApplicationStopped.Register(() => {
×
NEW
128
                if (backgroundServices.Select(static service => service.ExecuteTask?.Exception?.InnerException).FirstOrDefault() is {} exception) {
×
UNCOV
129
                    Environment.ExitCode = exitCodeGenerator(exception);
×
UNCOV
130
                }
×
UNCOV
131
            });
×
132

UNCOV
133
            return Task.CompletedTask;
×
134
        }
135

136
    }
137

138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc