c# – Catastrophic Failure attaching to IISExpress


Are you running more than one site within the same application pool?
I was having the same problem and believe that separating the app sites into different application pools fixed the issue.

Additionally I had issue when the wrong start-up project was selected in Visual studio. Make sure the correct start-up project is selected before attaching, though I can’t see why this should matter.

Also I created a controller for the debugger to be launched from the application, which no only makes it much easier, also appears to have less issues.

    #if DEBUG
    public virtual ActionResult Attach()
    {
        System.Diagnostics.Debugger.Launch();
        return new EmptyResult();
    }
    #endif 

ios – Visual Studio 2022 (MAUI/Xamarin) can’t import Apple .p12 (password accepted, no cert added) and doesn’t show Xcode/manual certificates


I’m building iOS apps with Visual Studio 2022 (MAUI/Xamarin) on Windows paired to a Mac.

In Tools → Apple Accounts → View Details → Certificates, Visual Studio only shows:

But it does not show:

Also, when I click Import Certificate and select my exported .p12, VS asks for the password. After entering it, the dialog closes and nothing is added (no error, still not listed). The .p12 was exported from Keychain → My Certificates, so it should include the private key. Xcode is latest.

Questions:

  1. Does VS only list Development certs created via App Store Connect API (and ignore Xcode/manual “legacy” certs)?

  2. Why would .p12 import fail silently in VS 2022?

  3. Any known workaround (e.g., converting the .p12 format, importing on the Mac build host only, or placing cert/profile files in specific Xamarin folders)?

I’ve followed these ones
https://docs.purplepublish.com/experience/create-an-ios-distribution-certificate-p12
https://www.reddit.com/r/Xamarin/comments/145a14v/comment/jo4a22v

PS: My colleague also tried this issue with VS 2026 and a different mac but we both have same issues.

c# – How to open new “ASP.NET Web Application” from visual studio 2015 community edition?


This is exactly what you’ve already chosen (Web Application).
Basically, you can choose that option and get an ASP.NET project with templates or choose ‘Empty’ which equivalent to ‘ASP.NET Empty Web Application’. This option gives you an ASP.NET application without any template.

About the second question, you can fine some details here.

Basically the main improvement, in VS2015, is that Microsoft has added a lot of components in order to enable mobile development via VS2015. Now, with VS2015 you can develop application for mobile like Android based system, IOS etc… Just like we could do by Android Studio.

Additionally, with VS2015 we can develop cross platform applications for Mac OS, Linux, etc…

If you are going to do so, consider installing “Visual Studio Code” on your target machine.

Unlock language-specific rich symbol context using new find_symbol tool


Refactoring at scale is a time-consuming and error-prone process for developers. In large codebases, developers have relied on manual searches and incremental edits across multiple files to accomplish these tasks.

Modern development workflows depend on fast and accurate code navigation to avoid these pitfalls. When developers refactor existing code, explore unfamiliar areas of a large codebase, or make targeted changes, they naturally rely on IDE language service features such as Find All References, Go to Definition, and Go to Implementation to understand how code is structured and connected.

Agent mode now has access to these same language-aware capabilities through the new find_symbol tool. This goes beyond traditional text or file search traditionally available in agent mode by enabling symbol-level reasoning powered by enterprise-grade language services.

Find symbol tool selected in VS Copilot Chat

What is find_symbol?

Find_symbol exposes rich, language-specific symbol information to Copilot Agent Mode, allowing the agent to reason about symbols (including functions, classes, interfaces, and variables).

Specifically, this tool allows Copilot agent mode to:

  • View all references of a given symbol across the entire codebase
  • Understand symbol metadata such as type, declaration, implementation, and scope

The find_symbol tool is available today in the latest Visual Studio 2026 Insiders version 18.4. Supported languages include: C++, C#, Razor, TypeScript, and any other language for which you have a supported Language Server Protocol (LSP) extension installed.

For best results, write clear prompts and use AI models that support tool-calling. Learn more at AI model comparison – GitHub Docs

Example scenarios

All examples below were showcased using bullet3, an open-source C++ physics simulation engine.

Adding additional functionality to existing code

As applications evolve, you often need to enhance existing functions without breaking current behavior. This can include adding logging or performance metrics.

These tools help the agent quickly identify all relevant references, ensuring complete and accurate updates for feature additions.

Find symbol references found 4 references to growtable

API Refactoring

Refactoring an API, such as hardening it, requires deep understanding of how the API is consumed across a codebase. With symbol-level insight, the agent can discover all usages, distinguish between call paths, and propose safe refactors with minimal breakage.

find symbol able to find 18 references to a hash table and reoslve accesses

Tell us what you think

We appreciate the time you’ve spent reporting issues/suggestions and hope you continue to give us feedback when using Visual Studio on what you like and what we can improve. You can share feedback with us via Developer Community: report any bugs or issues via report a problem and share your suggestions for new features or improvements to existing ones.

Stay connected with the Visual Studio team by following us on YouTube, X, LinkedInTwitch and on Microsoft Learn

 

c# – AssemblyVersion using * fails with error “wildcards, which are not compatible with determinism?”


Add <Deterministic> tag with false value and use * for the 3’rd part of AssemblyVersion inside <PropertyGroup> in .csproj file:

<PropertyGroup>
    <ProduceReferenceAssembly>true</ProduceReferenceAssembly>
    <Version>1.0.0</Version>
    <AssemblyVersion>1.0.*</AssemblyVersion>
    <Deterministic>false</Deterministic>
</PropertyGroup>

“Deterministic” means something like – the compiler will use the same versions of the files if no changes have happened resulting in faster builds.

It is the AssemblyVersion (not AssemblyFileVersion) that you should use a wildcard in. If you provide AssemblyVersion with wildcard, just don’t include AssemblyFileVersion at all.


Note also: There are two forms. One where the asterisk wildcard is in the third position (x.y.*) and one where it is in the fourth position (x.y.z.*).

x.y.* auto-generates the BUILD and REVISION numbers. BUILD is the “number of days since 1st January 2000” thus it only changes once each day. and REVISION is “half the number of seconds since 00:00”.

Today, for example, an AssemblyVersion of '1.0.*' will generate a specific '7472', e.g. '1.0.7472.20737'. The 5-digit final number will be different every build, at least if changes.

This may be better than 1.0.0.* for support as it indicates age (.7300 would be almost 6 months old). The example, 1.0.7472.20737, means “this assembly was built on 2020-06-16 at 11:31:14”.

c# – VS Installer Solution warning errors: ‘DLL file is under Windows System File Protection’ during Compile


I’m building an Installer Solution for a Visual Studio project in C#.
During the compile process I get the following warnings:

WARNING: 'System.Linq.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Linq\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Linq.dll' is under Windows System File Protection.
WARNING: 'System.Net.Http.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.dll' is under Windows System File Protection.
WARNING: 'System.Collections.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Collections\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Collections.dll' is under Windows System File Protection.
WARNING: 'System.Runtime.Serialization.Primitives.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization.Primitives\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.Serialization.Primitives.dll' is under Windows System File Protection.
WARNING: 'System.Diagnostics.Debug.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Diagnostics.Debug\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Diagnostics.Debug.dll' is under Windows System File Protection.
WARNING: 'System.Threading.Tasks.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Threading.Tasks\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Threading.Tasks.dll' is under Windows System File Protection.
WARNING: 'System.Runtime.Extensions.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Extensions\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.Extensions.dll' is under Windows System File Protection.
WARNING: 'System.IO.Compression.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.IO.Compression\v4.0_4.0.0.0__b77a5c561934e089\System.IO.Compression.dll' is under Windows System File Protection.
WARNING: 'System.Reflection.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Reflection\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Reflection.dll' is under Windows System File Protection.
WARNING: 'System.Net.Http.WebRequest.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Net.Http.WebRequest\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Net.Http.WebRequest.dll' is under Windows System File Protection.
WARNING: 'System.Runtime.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll' is under Windows System File Protection.
WARNING: 'System.Reflection.Extensions.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Reflection.Extensions\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Reflection.Extensions.dll' is under Windows System File Protection.
WARNING: 'System.Threading.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Threading\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Threading.dll' is under Windows System File Protection.
WARNING: 'System.Text.Encoding.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Text.Encoding\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Text.Encoding.dll' is under Windows System File Protection.
WARNING: 'System.Diagnostics.Tracing.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Diagnostics.Tracing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Diagnostics.Tracing.dll' is under Windows System File Protection.
WARNING: 'System.IO.dll' should be excluded because its source file 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.IO\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.IO.dll' is under Windows System File Protection.

As well as these which I believe are related:

WARNING: Two or more objects have the same target location ('[targetdir]\system.reflection.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.reflection.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.net.http.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.net.http.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.runtime.extensions.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.runtime.extensions.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.threading.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.threading.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.diagnostics.debug.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.diagnostics.debug.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.threading.tasks.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.threading.tasks.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.runtime.serialization.primitives.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.runtime.serialization.primitives.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.io.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.io.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.text.encoding.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.text.encoding.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.io.compression.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.io.compression.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.diagnostics.tracing.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.diagnostics.tracing.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.reflection.extensions.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.reflection.extensions.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.linq.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.linq.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.collections.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.collections.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.runtime.dll')
WARNING: Two or more objects have the same target location ('[targetdir]\system.runtime.dll')

Reading some related posts I believe I should remove these DLLs from the Installer itself, meaning from the Primary Output of the Installer Solution…? Is this correct or is the issue somewhere else?

A further question is – will this harm any functionality on a user’s machine? Do all of these DLLs exist on standard Windows and will work without being compiled?

How to install specific version of Visual Studio 2022


I found a possible solution for getting specific version of VS 2022 Community, even with generating offline layout.

  1. Go to Microsoft’s Visual Studio 2022 Release History page and scroll down to Fixed version bootstrappers.
  2. Choose any LTSC version you’d want to install. For example, in my case I wanted to get 17.10.17, then download “Professional” bootstrapper. You’ll get a vs_Professional.exe, but don’t worry, it will work for Community too!
  3. Make a batch file, name it to for example get_layout.cmd, open it in any text editor, and put the layout generation command there. My command was:
vs_professional.exe --layout ".\layout" --lang en-US --add Microsoft.VisualStudio.Workload.ManagedDesktop --add Microsoft.VisualStudio.Workload.NetWeb --add Microsoft.NetCore.Component.Runtime.6.0 --add microsoft.net.runtime.mono.tooling.net6 --add wasm.tools.net6 --add Microsoft.Net.Component.3.5.DeveloperTools ---add Microsoft.VisualStudio.Component.LinqToSql --add Microsoft.Net.Component.4.6.2.TargetingPack --add Microsoft.Net.ComponentGroup.4.6.2-4.7.1.DeveloperTools --add Microsoft.VisualStudio.Component.AspNet --add Microsoft.VisualStudio.Component.AspNet45 --add Microsoft.VisualStudio.Component.Wcf.Tooling --add Microsoft.VisualStudio.ComponentGroup.AdditionalWebProjectTemplates --add Microsoft.VisualStudio.ComponentGroup.IISDevelopment --add Microsoft.VisualStudio.Web.Mvc4.ComponentGroup --includeRecommended --includeOptional

You can choose any workloads listed on the Visual Studio Component directory page. Some workloads or components might not work on newer or older versions.

  1. Run the batch file, which will create a local layout for the version you had chosen.
  2. After the local layout was created, enter to layout directory, open Layout.json and Response.json files in any text editor. Find this part: "productId": "Microsoft.VisualStudio.Product.Professional" in these files, replace it to "productId": "Microsoft.VisualStudio.Product.Community", then save the files.
  3. Create another batch file in the layout directory with the next parameters, and all workloads and components which was put into the layout generator batch file:
vs_setup.exe --installCatalogUri %~dp0Catalog.json --installChannelUri %~dp0ChannelManifest.json --noUpdateInstaller --channelId VisualStudio.17.Release.LTSC.17.10 --productId Microsoft.VisualStudio.Product.Community --add Microsoft.VisualStudio.Workload.ManagedDesktop --add Microsoft.VisualStudio.Workload.NetWeb --add Microsoft.NetCore.Component.Runtime.6.0 --add microsoft.net.runtime.mono.tooling.net6 --add wasm.tools.net6 --add Microsoft.Net.Component.3.5.DeveloperTools ---add Microsoft.VisualStudio.Component.LinqToSql --add Microsoft.Net.Component.4.6.2.TargetingPack --add Microsoft.Net.ComponentGroup.4.6.2-4.7.1.DeveloperTools --add Microsoft.VisualStudio.Component.AspNet --add Microsoft.VisualStudio.Component.AspNet45 --add Microsoft.VisualStudio.Component.Wcf.Tooling --add Microsoft.VisualStudio.ComponentGroup.AdditionalWebProjectTemplates --add Microsoft.VisualStudio.ComponentGroup.IISDevelopment --add Microsoft.VisualStudio.Web.Mvc4.ComponentGroup --includeRecommended --includeOptional --noWeb --nocache

The most important arguments are:

  • –installCatalogUri %~dp0Catalog.json (forces installer to use Catalog.json form the local layout)
  • –installChannelUri %~dp0ChannelManifest.json (forces installer to use ChannelManifest.json form the local layout)
  • –noUpdateInstaller (disallowing installer to be updated to the latest version)
  • –channelId VisualStudio.17.Release.LTSC.17.10 (forcing channel id., this might change to version you’d like to install)
  • –productId Microsoft.VisualStudio.Product.Community (forcing product id. to Community edition instead of professional)
  • –noWeb (forcing installer to use install only from downloaded packages)
  • –nocache (forcing installer not to create a local cache – less disk space used, because you already have the packages in the local layout directory)
  1. Start the newly created batch file, and you’ll see an installer starting, displaying the older version you’d like to install. vs2022 installerChoose the components you’d like to install, and wait for it finishes.
  2. (optional step) .NET SDK’s will be older than the latest available, so I recommend downloading the latest version from https://dotnet.microsoft.com/en-us/download/dotnet

c# – Visual Studio Error CS0433: The type exists in both… (Unity-Accord.net)


It’s possible this is related to: Where does error CS0433 “Type ‘X’ already exists in both A.dll and B.dll ” come from?

In summary:
This can sometimes happen when Visual Studio fails to correctly clear out cached state as part of rebuilding. I have noticed it occurring more frequently with recent updates of VS2019.

Try the following steps and see if it helps:

  1. Delete all bin/obj directories for your solution using File Explorer
  2. Close VisualStudio and restart PC (this seems odd and unnecessary, but have found it can help)
  3. Reopen VisualStudio and do a full rebuild

It is also possible, although much more unlikely, that you genuinely have two references to the same package / dll with different hint paths. One retrieving a signed version, and one not (although if this is an external package it seems unlikely you’d have an unsigned version available). If the above steps don’t work, check your project file for duplicate references.

Fast Client-Side Search with Rust and WebAssembly


January 15, 2026 by João Moreno

If you’ve visited the VS Code website recently, you might have noticed something new: a fast, responsive search experience that feels almost instant.

Behind that experience is docfind, a search engine we built that runs entirely in your browser using WebAssembly. In this post, I want to share the story of how docfind came to be: a journey that took me from a decade-old blog post about automata theory to patching WebAssembly binaries.

The problem

I’m currently a Software Engineering Manager on the VS Code team, so these days I don’t get much time to write code. When I do, it’s rarely in unfamiliar territory. But some problems just nag at you until you do something about them.

Until recently, our website still had that basic search experience: you’d type a query, and it would redirect you to search results powered by a traditional search engine. Not quite what developers are used to today. I wanted those search results to appear instantly as you type, similar to many other websites out there. It should be something as snappy as VS Code’s Quick Open (Ctrl+P).

Together with my colleague Nick Trogh, we researched the alternatives. The landscape looked something like this:

  • Algolia: State of the art search-as-a-service. But I wanted a pure client-side solution.
  • TypeSense: Powerful open-source search, but requires server-side code, just like Algolia. Plus, it’d be another service to maintain and monitor.
  • Lunr.js: Client-side search in JavaScript, which sounded promising. We tried it with our docs (~3 MB of markdown), but it produced index files around 10 MB. Too large.
  • Stork Search: WebAssembly-powered client-side search with a nice demo. But when we tested it, the indexes were still quite large, and the project appeared to be unmaintained.

None of these options hit the sweet spot: fast, client-side, compact, and easy to host and operate. I started to wonder if we could build something ourselves.

The inspiration

Thinking about client-side search reminded me of a blog post I’d read years ago. It was written by Andrew Gallant (burntsushi), the creator of ripgrep, and it’s titled Index 1,600,000,000 Keys with Automata and Rust. Published nearly a decade ago, it explains how to use Finite State Transducers (FSTs) to index massive amounts of string data in a compact binary format that supports fast lookups, including regex and fuzzy matching.

The key insight is that FSTs can store sorted string keys in a state machine that’s both memory-efficient and fast to query. Better yet, Andrew had published a Rust library called fst that implements exactly this.

What if we could use FSTs to index keywords extracted from our documentation? The user types a query, we match it against keywords using the FST, and we get back a list of relevant documents, all in the browser, with no server round-trip.

But how could we get these document keywords? And wouldn’t this just create a very large index file, given all the strings would need to be in memory? Could we use compression to create the smallest possible index? This led me to two more pieces of the puzzle:

  • RAKE (Rapid Automatic Keyword Extraction): An algorithm for extracting meaningful keywords and phrases from text. Feed it a document, and it returns keywords ranked by importance.
  • FSST (Fast Static Symbol Table): A compression algorithm optimized for short strings. Since we’d need to store document titles, categories, and snippets in memory, compression would help keep the index small.

With FST for fast keyword lookup, RAKE for keyword extraction, and FSST for string compression, I had the technical foundations. Now I just needed to build it in Rust, a language I’m not particularly experienced with, during the limited time I could carve out from my day job.

The solution

I ended up creating a single CLI tool, docfind, meant to create an index file from our website documents whenever we build the website itself. Users of this CLI tool shouldn’t need any external dependencies other than docfind itself in order to create index files. That index file ended up being a single WebAssembly module, easily served to visitors via HTTP. When visitors come to our website, their browser downloads the WebAssembly module in the background and is used to empower the search functionality.

Building the index

Here’s a diagram of how docfind transforms a collection of documents (documents.json) into the respective index file (docfind_bg.wasm):

A diagram showing the flow of data in docfind

Docfind first reads a JSON file containing information about your documents (title, category, URL, body text). For each document, it extracts keywords using RAKE, assigns relevance scores, and builds an FST that maps keywords to document indices. All the document strings are compressed using FSST. Both the FST and the compressed strings are then packed into a binary blob, representing the actual index.

A visual explanation of what is a document, what are keywords and how are they represented in the index

The data structure representing the index is surprisingly simple:

pub struct Index {
    /// FST mapping keywords to document indices
    fst: Vec<u8>,

    /// FSST-compressed document strings (title, category, href, body)
    document_strings: FsstStrVec,

    /// For each keyword index, a list of (document_index, score) pairs
    keyword_to_documents: Vec<Vec<(usize, u8)>>,
}

The index stores keywords and maps them to indices into keyword_to_documents. Each entry there points to the relevant documents with their relevance scores. Document strings are stored compressed and decompressed only when needed for display.

Now, we could dump that index data structure to a binary file, serve it up to our website visitors and have some WebAssembly module on the site which would parse it and use the FST library to perform the search operations. But here’s where things get interesting. Rather than shipping the index as a separate binary file, docfind embeds it directly into the search library WebAssembly module, allowing visitors to fetch a single HTTP resource whenever they intend to search on the website.

Searching the index

So what happens client-side? When the user types a query, the WebAssembly module is loaded in memory (code and document index) to execute that query as a search operation by going through the FST data structure. We’ve found it useful to use a Levenshtein automaton (for typo tolerance) and prefix matching, to get more relevant matches. Finally, search results are produced by combining scores from multiple matching keywords, decompressing the relevant document strings on demand, and returning ranked results as JavaScript objects.

The challenge

The trickiest part of this project wasn’t the search algorithm or the keyword extraction, it was embedding the index into the WebAssembly binary.

The naive approach would be to use Rust’s include_bytes! macro to bake the index into the WebAssembly module at compile-time. But that would mean recompiling the WebAssembly module every time the documentation changes. Instead, I wanted a pre-compiled WASM “template” that the CLI tool could patch with an updated index.

This meant I needed to statically create a WebAssembly module template, with an empty index, and embed that in docfind. Then, docfind could:

  1. Parse the embedded WebAssembly module to understand its structure
  2. Find the memory section and calculate how much additional space the index needs
  3. Add the index as a new data segment, updating the data count section accordingly
  4. Locate placeholder global variables and patch them with the actual index location
  5. Write out a valid WebAssembly module

The WebAssembly module template declares two placeholder globals with a distinctive marker value:

#[unsafe(no_mangle)]
pub static mut INDEX_BASE: u32 = 0xdead_beef;

#[unsafe(no_mangle)]
pub static mut INDEX_LEN: u32 = 0xdead_beef;

At run-time, the search function uses these to locate the embedded index and parse it from the raw bytes:

static INDEX: OnceLock<Index> = OnceLock::new();

pub fn search(query: &str, max_results: Option<usize>) -> Result<JsValue, JsValue> {
    let index = INDEX.get_or_init(|| {
        let raw_index = unsafe {
            std::slice::from_raw_parts(INDEX_BASE as *const u8, INDEX_LEN as usize)
        };
        Index::from_bytes(raw_index).expect("Failed to deserialize index")
    });
    // ... perform search
}

The CLI tool scans the WASM template’s export section to find these globals, reads the global section to get their memory addresses, then patches the data segment that contains those 0xdead_beef values with the actual index base address and length:

// Patch the data if it contains the INDEX_BASE or INDEX_LEN addresses
if index_base_global_address >= &start && index_base_global_address < &end {
    data[base_relative_offset..base_relative_offset + 4]
        .copy_from_slice(&(index_base as i32).to_le_bytes());
    data[length_relative_offset..length_relative_offset + 4]
        .copy_from_slice(&(raw_index.len() as i32).to_le_bytes());
}

// Add index as new data segment
data_section.active(
    0,
    &ConstExpr::i32_const(index_base as i32),
    raw_index.iter().copied(),
);

This was, to put it mildly, not straightforward. Understanding the WASM binary format, figuring out how globals are stored and referenced, calculating memory offsets. These are the kinds of problems that can easily derail a side project.

The breakthrough

I have to be honest, it’s unlikely that I would have finished this project without using GitHub Copilot agents. As a manager who doesn’t code daily anymore, tackling a project in Rust, a language known for its steep learning curve, was ambitious. I’m not a Rust expert. I don’t have the muscle memory for the borrow checker. And I certainly didn’t have deep knowledge of the WebAssembly binary format. But I did have a general sense of direction of where I wanted to go with all of this. Copilot helped me fill in the blanks and tackle the hard problems.

Research and exploration. When I was evaluating FST, RAKE, and FSST, I used Copilot to understand how these libraries worked, ask clarifying questions, and bounce ideas around. It was like having a knowledgeable colleague available at any hour.

Efficient Rust development. This was perhaps the biggest win. Copilot’s Next Edit Suggestions turned me into a productive Rust programmer. I no longer spent mental energy fighting the borrow checker or looking up syntax. Copilot handled the mechanical parts, letting me focus on the logic.

Scaffolding the WASM target. When I asked Copilot to add a WebAssembly output target to the project, it didn’t just add the configuration, it inferred that I wanted a search function exported and scaffolded the entire lib.rs with the right wasm-bindgen annotations. It even told me which command to run to build it.

The docfind library. Copilot helped me scaffold the repository for docfind, including creating a working demo page, with performance vanity numbers.

Getting past the hard parts. The WASM binary manipulation was the technical crux of this project. Understanding how to locate globals, patch data segments, and update memory sections required diving into details I’d never encountered before. Copilot helped me understand the WASM binary format, suggested the right wasmparser and wasm-encoder APIs, and helped debug issues when my patched binaries weren’t valid.

I’m confident this project would have taken me considerably longer without Copilot, and that’s assuming I wouldn’t have given up somewhere along the way. When you’re time-constrained and working outside your expertise, I’ve found that having an AI assistant that can fill knowledge gaps and handle boilerplate isn’t just convenient, it’s the difference between shipping and abandoning.

The results

Today, docfind powers the search experience on the VS Code documentation website. You can see the current performance metrics in the docfind README, which includes an interactive demo searching through 50,000 news articles entirely in your browser.

For the VS Code website (~3 MB of markdown, ~3,700 documents partitioned by heading):

  • Index size: ~5.9 MB uncompressed, ~2.7 MB with Brotli compression
  • Search speed: ~0.4ms per query, on my M2 MacBook Air
  • Network: Single WebAssembly module, downloaded only when the user shows intention to search

No servers to maintain. No API keys to manage. No ongoing costs. Just a self-contained WebAssembly module that runs entirely in the browser, created at build time.

Try it yourself

We’ve open-sourced docfind, and you can use it for your own static sites today. Installation is straightforward:

curl -fsSL https://microsoft.github.io/docfind/install.sh | sh

Or, if you’re on Windows:

irm https://microsoft.github.io/docfind/install.ps1 | iex

Prepare a JSON file with your documents, run docfind documents.json output, and you’ll get a docfind.js and docfind_bg.wasm ready to use in your site. You need to bring your own client-side UI to show the search results (you can always create one using GitHub Copilot 😉).

Building docfind was a reminder of why I became an engineer in the first place: the joy of solving a real problem with elegant technology. And it was a testament to how AI tools like Copilot are changing what’s possible, letting us tackle projects that would have been out of reach given our constraints of time and expertise. Finally, a quick shout-out to the rust-analyzer VS Code extension, a must-have if you’re working with Rust in VS Code.

If you have questions or feedback, feel free to open an issue on the docfind repository. We’d love to hear how you’re using it.

Happy coding! 💙

keyboard shortcuts – Why doesn’t Delete key work in Visual Studio 2022 Property pane?


If I create a Windows Forms .Net 4.8 project in Microsoft Visual Studio Community 2022 (64-bit) Version 17.10.1, then click into the Properties pane to modify a property, such as the “Text” property of the form, I can use the Backspace key to remove characters from the Text property, but if I press the Delete key on the keyboard, nothing happens, whether I have the cursor at the beginning, middle, or end of the property value, and whether or not I have highlighted any text in the property value.

This also occurs within Collection editors, such as the ListViewItem Collection editor.

NOTE that I am editing String properties, so they should support the Delete key if they support the Backspace key.

Is the Delete key intentionally disabled, or is this a bug?

Maybe nobody else uses the Delete key, but sometimes it makes sense to use it based on cursor position, and I automatically press it out of habit.

Can anyone explain why this happens and/or how to fix it?