Skip to main content

Refactoring for AI: Architectural Patterns for Integrating LLMs into Legacy .NET Applications




For those of us who have spent years, or even decades, maintaining and extending large, legacy .NET applications, the current AI boom presents a fascinating, yet daunting, challenge. The business sees the "magic" of AI and, naturally, wants to sprinkle it into our existing products. The request is often simple: "Can we add AI to do X?". But as architects and developers, we know it's never that simple. Bolting a modern, stateless, and often slow-to-respond Large Language Model (LLM) onto a battle-hardened, stateful ASP.NET Web Forms application is a classic case of architectural impedance mismatch.

A direct API call from a code-behind file during a postback is a recipe for disaster. It will lead to hanging UI, terrible user experience, and a maintenance nightmare. So, how do we bridge the gap between our monolithic, reliable workhorses and the brave new world of generative AI? The answer isn't a rewrite; it's smart architecture. Here are a couple of patterns I've been exploring.

The Sidecar Pattern for Asynchronous AI Tasks

One of the cleanest ways to introduce AI is to avoid calling it from the main application thread at all. The Sidecar pattern is perfect for this. The idea is to build a small, separate service that runs alongside your main web application. This "sidecar" is responsible for all AI-related heavy lifting.

Your main application communicates with the sidecar asynchronously, typically via a message queue (like RabbitMQ or Azure Service Bus) or a simple, local-first API.

When to use it: This is ideal for tasks that don't need to be completed in real-time.

  • Summarizing long pieces of user-generated text.
  • Classifying or tagging incoming data.
  • Generating reports in the background.

Conceptual VB.NET Example (in your legacy app):

' This code doesn't call the LLM directly.

' It just sends a message to the sidecar service.

Public Sub ProcessUserContent(contentId As Integer)

    Dim message As New MessagePacket With {

        .ContentId = contentId,

        .Task = "SummarizeText"

    }

    

    ' Fire and forget: The sidecar will pick this up.

    MessageQueueService.Publish("ai_tasks", message)

End Sub

The sidecar service, written in any modern .NET stack, would listen for this message, perform the expensive LLM call, and write the result back to the database where the main application can find it later.

The Strangler Fig Pattern for Augmenting UI

What about when you *do* need to affect the user experience in near real-time? The Strangler Fig pattern, traditionally used for incremental rewrites, can be adapted for AI. Instead of replacing a whole page, we "strangle" a small piece of functionality by routing it through a new AI-aware layer.

This layer is often an API Gateway or a reverse proxy. It sits between the user and your legacy application. For most requests, it just passes them through. But for specific routes, it intercepts the request, calls an LLM to augment it, and then forwards a modified request to the application, or returns the AI-generated data directly to the user via a modern front-end component.

When to use it:

  • Adding a natural language search feature on top of a structured data page.
  • Providing an "AI-powered suggestion" for a form field.
  • Implementing a smart chatbot that can answer questions about the current page.

This approach lets you build new, AI-powered UI components using a modern stack (like React or Vue) that live alongside your existing Web Forms pages, providing a seamless experience without touching the old code.

Conclusion

Integrating AI into our legacy systems isn't about finding the right API endpoint. It's about respecting the architecture we have while intelligently and safely introducing new capabilities. By using patterns like the Sidecar and Strangler Fig, we can avoid the dreaded "big rewrite" and deliver the AI-powered features the business is asking for, without sacrificing the stability of the applications we've worked so hard to maintain. It’s an architectural evolution, not a revolution.

 Suggested Further Reading

  On Architectural Patterns:

       This is the canonical source for the Strangler Fig pattern, written by the person who coined the term. It's a must-read for understanding the pattern's origin and core principles.
       An excellent and detailed explanation of the Sidecar pattern from Microsoft's official cloud architecture documentation. It provides context, use cases, and implementation considerations.
    This article explains the role of API Gateways in a microservices architecture, which is highly relevant to implementing the Strangler Fig pattern for AI augmentation.

  On Integrating AI & Modernizing .NET:

       * Description: While less technical, this paper from Microsoft provides a high-level business and architectural view on preparing organizations for AI integration, which can be good for setting a broader context.
         guidance)
    While the article advocates for avoiding a full rewrite, providing a link to Microsoft's official migration guidance is valuable for readers considering their long-term strategy. It shows you've considered the alternative.

  On Asynchronous Communication:

       The official "getting started" page for RabbitMQ. It's a great starting point for readers unfamiliar with message brokers.

Comments

Popular posts from this blog

On sleep deprivation and Incan Monkey Gods

From: Dilbert comic strip for 08/03/1992 from the official Dilbert comic strips archive. I was trying to show this strip to a coworker who is dangerously toying with the harsh mistress that is Insomnia. What shocked me is how quickly I was able to look up the strip, which was published when he was just 11 years old, and two weeks before my just-out-of-college ass shipped out to US Army Basic Training.

The Black Hole

If this was a minigolf hole, you can't reach B from A. Ever. If this was a room lined with mirrors, and you lit a candle at point A, you can't see it from B, not even reflected.  Update: I guess I didn't explain this all the way through. You can't reach B from A with just one stroke, there's no direct line between them, and there is no way to bounce the ball (assuming perfect conditions). Thanks to Ben for pointing this obvious error.