<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx" -->

---
title: Writing a .NET profiler in C# - Part 1 | daily.dev
description: A deep technical walkthrough explains how to build a .NET profiler in C# using NativeAOT, a Microsoft tool that compiles .NET code into a standalone native...
canonical: https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Writing a .NET profiler in C# - Part 1 | daily.dev
og:description: A deep technical walkthrough explains how to build a .NET profiler in C# using NativeAOT, a Microsoft tool that compiles .NET code into a standalone native...
og:url: https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx
og:image: https://api.daily.dev/og/posts/ftpFUVwjX.png
og:image:alt: Writing a .NET profiler in C# - Part 1
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.

# Writing a .NET profiler in C# - Part 1

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

## Summary

A deep technical walkthrough explains how to build a .NET profiler in C# using NativeAOT, a Microsoft tool that compiles .NET code into a standalone native library with its own runtime. Traditionally profilers had to be written in C++ because a managed profiler would end up profiling itself and load too early for the runtime to execute .NET code. The piece covers creating a .NET 6 class library with Microsoft.DotNet.ILCompiler, exporting a DllGetClassObject function via UnmanagedCallersOnly, and manually constructing a C++-style vtable in C# using NativeMemory.Alloc and unmanaged function pointers to fake an IClassFactory COM interface. It ends with CreateInstance being successfully invoked, setting up the next article to implement ICorProfilerCallback's nearly 70 methods.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://minidump.net/writing-a-net-profiler-in-c-part-1-d3978aae9b12>

## Questions this post answers

### Can I write a .NET profiler using the CLR Profiling API in C# instead of C++?

Yes, this is now possible using NativeAOT, a Microsoft tool that compiles a .NET library into a standalone native library with its own runtime, garbage collector, and threadpool. Previously a managed profiler would recursively trigger JITCompilationStarted events on itself and load too early for .NET code to run, making C++ the only practical option.

_Developers exploring native interop edge cases can track NativeAOT developments on daily.dev._

### How do you simulate a C++ COM interface like IClassFactory in C# without a built-in equivalent?

You manually build a vtable by allocating a chunk of unmanaged memory with NativeMemory.Alloc, storing a pointer to the vtable as the first entry, then filling subsequent slots with addresses of static methods decorated with UnmanagedCallersOnly, cast to unmanaged function pointers. The native caller treats this memory chunk as both the instance and its vtable, matching the C++ compiler's convention of a hidden vtable pointer field.

_Anyone wiring managed code into native COM-style callbacks can revisit interop patterns like this via daily.dev._

### What environment variables are needed to load a custom CLR profiler DLL for testing?

Set CORECLR_ENABLE_PROFILING=1 to tell the runtime to load a profiler, CORECLR_PROFILER to a GUID uniquely identifying it, and CORECLR_PROFILER_PATH to the full path of the published native profiler DLL (or .so on Linux). Then launching any .NET console application triggers the profiler's DllGetClassObject export during startup.

_Engineers debugging profiler loading issues can keep notes on these CLR env vars handy via daily.dev._

## Similar posts on daily.dev

- [Creating a .NET CLR profiler using C\# and NativeAOT with Silhouette](https://daily.dev/posts/creating-a-net-clr-profiler-using-c-and-nativeaot-with-silhouette-nxp8lsqgl) · .NET Escapades · 6 upvotes · 0 comments
- [Making Reflection Native AOT Safe in .NET 10: DynamicallyAccessedMembers Guide](https://daily.dev/posts/making-reflection-native-aot-safe-in-net-10-dynamicallyaccessedmembers-guide-xpy12bjep) · We Are .NET · 3 upvotes · 0 comments
- [C\# Reflection: The Complete .NET 10 Guide](https://daily.dev/posts/c-reflection-the-complete-net-10-guide-xjtayoxme) · We Are .NET · 2 upvotes · 0 comments

---

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

[View this post on daily.dev](https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx)

```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":"Writing a .NET profiler in C# - Part 1","url":"https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx"},"datePublished":"2026-10-04T13:07:02.572Z","dateModified":"2026-10-04T13:17:30.708Z","description":"A deep technical walkthrough explains how to build a .NET profiler in C# using NativeAOT, a Microsoft tool that compiles .NET code into a standalone native...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/66cc859f5915e6159ba51a9dbe83159a?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/66cc859f5915e6159ba51a9dbe83159a?_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/writing-a-net-profiler-in-c---part-1-ftpfuvwjx","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":".net,c#","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":"Writing a .NET profiler in C# - Part 1"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/writing-a-net-profiler-in-c---part-1-ftpfuvwjx#faq","mainEntity":[{"@type":"Question","name":"Can I write a .NET profiler using the CLR Profiling API in C# instead of C++?","acceptedAnswer":{"@type":"Answer","text":"Yes, this is now possible using NativeAOT, a Microsoft tool that compiles a .NET library into a standalone native library with its own runtime, garbage collector, and threadpool. Previously a managed profiler would recursively trigger JITCompilationStarted events on itself and load too early for .NET code to run, making C++ the only practical option. Developers exploring native interop edge cases can track NativeAOT developments on daily.dev."}},{"@type":"Question","name":"How do you simulate a C++ COM interface like IClassFactory in C# without a built-in equivalent?","acceptedAnswer":{"@type":"Answer","text":"You manually build a vtable by allocating a chunk of unmanaged memory with NativeMemory.Alloc, storing a pointer to the vtable as the first entry, then filling subsequent slots with addresses of static methods decorated with UnmanagedCallersOnly, cast to unmanaged function pointers. The native caller treats this memory chunk as both the instance and its vtable, matching the C++ compiler's convention of a hidden vtable pointer field. Anyone wiring managed code into native COM-style callbacks can revisit interop patterns like this via daily.dev."}},{"@type":"Question","name":"What environment variables are needed to load a custom CLR profiler DLL for testing?","acceptedAnswer":{"@type":"Answer","text":"Set CORECLR_ENABLE_PROFILING=1 to tell the runtime to load a profiler, CORECLR_PROFILER to a GUID uniquely identifying it, and CORECLR_PROFILER_PATH to the full path of the published native profiler DLL (or .so on Linux). Then launching any .NET console application triggers the profiler's DllGetClassObject export during startup. Engineers debugging profiler loading issues can keep notes on these CLR env vars handy via daily.dev."}}]}
```

