<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs" -->

---
title: Have some fun with .net core startup hooks | daily.dev
description: Exploring .NET Core 2.2's startup hooks feature—a way to globally register code that executes inside every .NET Core process via the DOTNET_STARTUP_HOOKS...
canonical: https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Have some fun with .net core startup hooks | daily.dev
og:description: Exploring .NET Core 2.2's startup hooks feature—a way to globally register code that executes inside every .NET Core process via the DOTNET_STARTUP_HOOKS...
og:url: https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs
og:image: https://api.daily.dev/og/posts/mfryzCZBs.png
og:image:alt: Have some fun with .net core startup hooks
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Have some fun with .net core startup hooks

**[Kevin Gosse \(minidump.net\)](https://daily.dev/sources/minidump)** · 8 min read · 0 upvotes · 0 comments

## Summary

Exploring .NET Core 2.2's startup hooks feature—a way to globally register code that executes inside every .NET Core process via the DOTNET_STARTUP_HOOKS environment variable—this walkthrough turns the mechanism into elaborate pranks. Examples include reversing all console output, overriding Array.Empty<T> to inject hidden values into params methods, and replacing the default TaskScheduler to intercept and randomize local variables inside async state machines using reflection on internal runtime fields. The piece walks through the internals of ContinuationWrapper, AsyncStateMachineBox, and TPL optimizations that had to be worked around, while noting the tricks are unpredictable and should be used cautiously.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://minidump.net/c-have-some-fun-with-net-core-startup-hooks-498b9ad001e1>

## Questions this post answers

### How do .NET Core startup hooks work and how do you register one with DOTNET_STARTUP_HOOKS?

Startup hooks let you register a method that runs inside every .NET Core process at launch. Create an assembly with a non-namespaced internal class named StartupHook containing a static Initialize method, then set the DOTNET_STARTUP_HOOKS environment variable to point to that assembly. The hook executes inside the target application's own process, giving it full access to that process's state.

_Developers experimenting with process-level runtime hacks can find more deep runtime internals write-ups on daily.dev._

### How can you intercept and modify the local variables of a C# async method at runtime using a custom TaskScheduler?

By replacing TaskScheduler.Default via reflection on the internal s_defaultTaskScheduler field and enabling s_asyncDebuggingEnabled, a custom scheduler's QueueTask can retrieve the task's ContinuationWrapper, then its AsyncStateMachineBox, and finally the StateMachine field holding the compiler-generated state machine object, whose private int fields (the locals) can be overwritten before execution continues.

_Anyone probing async state machine internals in C# can track similar low-level runtime techniques on daily.dev._

## Similar posts on daily.dev

- [Exploring the .NET boot process via host tracing](https://daily.dev/posts/exploring-the-net-boot-process-via-host-tracing-nva4pcq2n) · .NET Escapades · 0 upvotes · 0 comments
- [.NET train keeps rolling with first showing of 2026 release](https://daily.dev/posts/net-train-keeps-rolling-with-first-showing-of-2026-release-i497xhbps) · DEVCLASS · 17 upvotes · 0 comments

---

Tags: [#c#](https://daily.dev/tags/c#), [#.net-core](https://daily.dev/tags/.net-core)

[View this post on daily.dev](https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Have some fun with .net core startup hooks","url":"https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs"},"datePublished":"2026-10-04T13:06:50.085Z","dateModified":"2026-10-04T13:10:13.599Z","description":"Exploring .NET Core 2.2's startup hooks feature—a way to globally register code that executes inside every .NET Core process via the DOTNET_STARTUP_HOOKS...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/96266cc2d56c115a3013842dff429a79?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/96266cc2d56c115a3013842dff429a79?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Kevin Gosse (minidump.net)","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Kevin Gosse (minidump.net)","logo":"https://media.daily.dev/image/upload/s--8KHn1aFB--/f_auto,q_auto/v1791119046/logos/minidump?_a=BAMAMicg0","url":"https://daily.dev/sources/minidump"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"c#,.net-core","timeRequired":"PT8M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Kevin Gosse (minidump.net)","item":"https://daily.dev/sources/minidump"},{"@type":"ListItem","position":3,"name":"Have some fun with .net core startup hooks"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/have-some-fun-with-net-core-startup-hooks-mfryzczbs#faq","mainEntity":[{"@type":"Question","name":"How do .NET Core startup hooks work and how do you register one with DOTNET_STARTUP_HOOKS?","acceptedAnswer":{"@type":"Answer","text":"Startup hooks let you register a method that runs inside every .NET Core process at launch. Create an assembly with a non-namespaced internal class named StartupHook containing a static Initialize method, then set the DOTNET_STARTUP_HOOKS environment variable to point to that assembly. The hook executes inside the target application's own process, giving it full access to that process's state. Developers experimenting with process-level runtime hacks can find more deep runtime internals write-ups on daily.dev."}},{"@type":"Question","name":"How can you intercept and modify the local variables of a C# async method at runtime using a custom TaskScheduler?","acceptedAnswer":{"@type":"Answer","text":"By replacing TaskScheduler.Default via reflection on the internal s_defaultTaskScheduler field and enabling s_asyncDebuggingEnabled, a custom scheduler's QueueTask can retrieve the task's ContinuationWrapper, then its AsyncStateMachineBox, and finally the StateMachine field holding the compiler-generated state machine object, whose private int fields (the locals) can be overwritten before execution continues. Anyone probing async state machine internals in C# can track similar low-level runtime techniques on daily.dev."}}]}
```

