.NET Core控制台程序调用ServiceThread报空引用异常的解决方法
Alright, let's break down why you're hitting that System.NullReferenceException and get it fixed up quickly.
The Root Cause
Take a look at the static property in your Program class:
private static IServiceThread ServiceThread { get; }
This property is never initialized—it's just a declaration with no assigned value. When you call ServiceThread.Start("Started") in the non-service execution path, you're trying to invoke a method on a null object, which directly triggers the null reference exception.
On top of that, you've already registered IServiceThread (and its dependencies like IServiceWorker) with the dependency injection (DI) container. You shouldn't be using an uninitialized static property here—you need to retrieve the properly injected instance from the DI container instead.
The Fix
Modify the non-service branch of your code to build the host first, retrieve the IServiceThread instance from the DI container, then safely call Start(). Here's the updated Main method code:
static async Task Main(string[] args) { var asService = !(Debugger.IsAttached || args.Contains("--console")); var builder = Host .CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => config .SetBasePath(Directory.GetParent(AppContext.BaseDirectory).FullName) .AddJsonFile("appSettings.json", false)) .ConfigureServices((context, services) => { services.AddHostedService<MonitoringService>(); services.AddSingleton<IHelpersAppService, HelpersAppService>(); services.AddSingleton<IRestMethods, RestMethods>(); services.AddSingleton<ISymphonyCloudCommunicator, SymphonyCloudCommunicator>(); services.AddSingleton<IServiceThread, ServiceThread>(); services.AddSingleton<IServiceWorker, ServiceWorker>(); services.AddSingleton<IWsConnector, WsConnector>(); }) .UseEnvironment(asService ? EnvironmentName.Production : EnvironmentName.Development); if (asService) { await builder.RunAsServiceAsync(); } else { // Build the host to initialize the DI container and all registered services var host = builder.Build(); // Retrieve the fully injected IServiceThread instance from the container using var serviceScope = host.Services.CreateScope(); var serviceProvider = serviceScope.ServiceProvider; var serviceThread = serviceProvider.GetRequiredService<IServiceThread>(); // Now safely call Start() on the initialized instance serviceThread.Start("Started"); await host.RunConsoleAsync(); } }
Key Changes Explained
- Build the host first:
builder.Build()creates the host and initializes all registered services, ensuring dependencies likeIServiceWorkerare properly injected into yourServiceThreadinstance. - Use a service scope: Even though your services are singletons, using
CreateScope()follows DI best practices and keeps your code consistent for future changes to service lifetimes. - Retrieve via DI:
GetRequiredService<IServiceThread>()fetches the fully initialized instance from the container—no morenullreferences here!
Quick Sanity Check
While we're at it, your ServiceThread constructor looks correct for dependency injection:
public ServiceThread(IServiceWorker serviceWorker) { _serviceWorker = serviceWorker; }
Since you've registered IServiceWorker as a singleton, the DI container will inject it properly when resolving IServiceThread, so you won't run into null issues there either.
内容的提问来源于stack exchange,提问作者Eugene Sukh

