---
title: "How can you maintain conversation history and context across multiple chat messages in a .NET application?"  
description: "How can you maintain conversation history and context across multiple chat messages in a .NET application?"  
author: "Manish Kumar"  
published: 2026-08-06  
updated: 2026-08-10  
canonical: https://answers.mindstick.com/qa/117027/how-can-you-maintain-conversation-history-and-context-across-multiple-chat-messages-in-a-dot-net-application  
category: "asp.net"  
tags: ["asp.net", ".net programming", "c#", "ai agent"]  
reading_time: 6 minutes  

---

# How can you maintain conversation history and context across multiple chat messages in a .NET application?

**How can you maintain conversation history and context across multiple chat messages in a .NET application?**

## Answers

### Answer by Anubhav Sharma

The key is to **persist conversation state outside the LLM** and rebuild the relevant context for every request.

A good .NET architecture looks like this:

```plaintext
User
  │
  ▼
ASP.NET Core API
  │
  ├── Conversation ID
  │
  ▼
Conversation Service
  │
  ├── Load recent messages
  ├── Load conversation summary
  ├── Retrieve relevant knowledge (RAG)
  │
  ▼
Context Builder
  │
  ├── System instructions
  ├── Conversation summary
  ├── Recent messages
  └── Retrieved context
  │
  ▼
LLM
  │
  ▼
Assistant response
  │
  ▼
Persist user + assistant messages
```

### 1. Give every conversation a persistent ID

For example:

```cs
public class Conversation
{
    public Guid Id { get; set; }
    public string UserId { get; set; } = "";
    public DateTime CreatedAt { get; set; }
    public string? Summary { get; set; }
}
```

The frontend stores the `ConversationId` and sends it with subsequent messages.

```plaintext
POST /api/conversations/{conversationId}/messages
```

This allows the server to know which history belongs to the current conversation.

### 2. Store messages in a database

For example, with Entity Framework Core:

```cs
public class ChatMessage
{
    public Guid Id { get; set; }
    public Guid ConversationId { get; set; }

    public string Role { get; set; } = "";
    public string Content { get; set; } = "";

    public DateTime CreatedAt { get; set; }
}
```

You might have:

```plaintext
Conversations
--------------------------------
Id
UserId
CreatedAt
Summary

ChatMessages
--------------------------------
Id
ConversationId
Role
Content
CreatedAt
```

A conversation could therefore look like:

```plaintext
Conversation: 8f32...

User:
  "What is dependency injection?"

Assistant:
  "Dependency injection is..."

User:
  "How does it work in .NET?"

Assistant:
  "In .NET, dependency injection..."

User:
  "Show me an example."

Assistant:
  "Here's an example..."
```

The important part is that **the application owns this history**, not the model.

### 3. Reconstruct context for each LLM call

When the next message arrives:

```cs
var history = await db.ChatMessages
    .Where(x => x.ConversationId == conversationId)
    .OrderBy(x => x.CreatedAt)
    .ToListAsync();
```

Then construct the model request:

```cs
var messages = new List<ChatMessage>
{
    new(ChatRole.System,
        "You are a helpful .NET development assistant.")
};

foreach (var message in history)
{
    messages.Add(new ChatMessage(
        message.Role == "user"
            ? ChatRole.User
            : ChatRole.Assistant,
        message.Content));
}

messages.Add(new ChatMessage(
    ChatRole.User,
    userMessage));
```

The model receives the relevant conversation context and can therefore answer:

> "What about the previous example?"

without requiring the user to repeat everything.

### 4. Don't send the entire history forever

This becomes important as conversations grow.

Suppose the user has 500 messages. Sending all 500 messages to the LLM on every request can become expensive and eventually exceed the model's context window.

Instead, use a **context-management strategy**:

```plaintext
                    Conversation
                         │
             ┌───────────┴───────────┐
             │                       │
       Recent messages          Older messages
             │                       │
             │                 Summarize
             │                       │
             ▼                       ▼
        Keep verbatim          Conversation
                               summary
             │                       │
             └───────────┬───────────┘
                         ▼
                   Context Builder
                         │
                         ▼
                        LLM
```

For example:

```plaintext
System instructions
+
Conversation summary
+
Last 10 messages
+
Relevant RAG results
+
Current user message
```

This is usually much more scalable than sending the entire conversation.

### 5. Use summaries for long conversations

You can periodically summarize older messages:

```cs
public class Conversation
{
    public Guid Id { get; set; }

    public string? Summary { get; set; }

    public DateTime UpdatedAt { get; set; }
}
```

For example, after enough messages:

```plaintext
Summary:

The user is building an ASP.NET Core AI chatbot.
They are using Azure OpenAI and Azure AI Search.
They want conversation history persisted in SQL Server.
They prefer Clean Architecture.
```

Then the next LLM request receives:

```plaintext
SYSTEM
You are a .NET AI development assistant.

CONVERSATION SUMMARY
The user is building an ASP.NET Core AI chatbot...

RECENT MESSAGES
User: How should I store chat history?
Assistant: ...

CURRENT MESSAGE
User: What about scaling it?
```

### 6. Add RAG for long-term knowledge

Conversation history and application knowledge are actually **two different types of context**.

```plaintext
Conversation memory
        │
        ▼
SQL Server / PostgreSQL
        │
        │
        └──── Recent + summarized conversation

Knowledge
        │
        ▼
Vector / hybrid search
        │
        ▼
Azure AI Search
        │
        └──── Relevant documents
```

For example, if the user previously discussed a company policy, you don't necessarily want to store the entire policy in the conversation history.

Instead:

```plaintext
Conversation history
        +
Relevant company documents
        +
Current question
        ↓
       LLM
```

### 7. Separate short-term and long-term memory

A useful architecture is:

```plaintext
┌───────────────────────────────────────────────┐
│                 Chat Service                  │
├───────────────────────────────────────────────┤
│                                               │
│  Short-term memory                            │
│  ├── Recent messages                          │
│  └── Current conversation                     │
│                                               │
│  Long-term memory                             │
│  ├── Conversation summaries                   │
│  ├── User preferences                         │
│  └── Important facts                          │
│                                               │
│  Knowledge                                    │
│  ├── Documents                                │
│  ├── Vector search                            │
│  └── RAG context                              │
│                                               │
└───────────────────────────────────────────────┘
```

Be careful with **user-specific memory**: only persist facts that are genuinely useful, appropriate, and authorized to retain.

### 8. Redis is useful, but shouldn't necessarily be your source of truth

A common architecture is:

```plaintext
             Chat API
                │
       ┌────────┴────────┐
       ▼                 ▼
    Redis             SQL DB
   (cache)          (durable state)
```

Use Redis for things such as:

- frequently accessed conversations
- session state
- temporary context
- distributed caching

Use SQL/PostgreSQL for durable conversation history.

This also lets multiple ASP.NET Core instances share state:

```plaintext
             Load Balancer
                   │
        ┌──────────┼──────────┐
        ▼          ▼          ▼
    API #1       API #2      API #3
        │          │          │
        └──────────┼──────────┘
                   ▼
             Shared storage
              SQL + Redis
```

### 9. A practical service design

I'd encapsulate this behind a `ConversationService`:

```cs
public interface IConversationService
{
    Task<ConversationContext> GetContextAsync(
        Guid conversationId,
        CancellationToken cancellationToken);

    Task AddMessageAsync(
        Guid conversationId,
        ChatMessage message,
        CancellationToken cancellationToken);
}
```

Then your application service stays clean:

```cs
public async Task<string> ChatAsync(
    Guid conversationId,
    string userMessage,
    CancellationToken cancellationToken)
{
    var context =
        await conversationService.GetContextAsync(
            conversationId,
            cancellationToken);

    var response = await aiService.GenerateAsync(
        context,
        userMessage,
        cancellationToken);

    await conversationService.AddMessageAsync(
        conversationId,
        new ChatMessage("assistant", response),
        cancellationToken);

    return response;
}
```

The controller doesn't need to know how history, summarization, Redis, RAG, or the database work.

### Recommended production approach

For most .NET enterprise chatbots, I'd use:

```plaintext
ASP.NET Core
      │
      ▼
ConversationService
      │
      ├───────────────┐
      ▼               ▼
 SQL Server        Redis
 durable history   caching
      │
      ▼
 Context Builder
      │
      ├── Conversation summary
      ├── Recent messages
      ├── User/session context
      └── RAG results
      │
      ▼
Microsoft.Extensions.AI
      │
      ▼
Azure OpenAI / OpenAI
```

**The main rule:** don't think of "memory" as simply sending the previous chat messages back to the model. Treat memory as a **context-management subsystem** that decides what information is relevant, persistent, authorized, and affordable to put into each LLM request.


---

Original Source: https://answers.mindstick.com/qa/117027/how-can-you-maintain-conversation-history-and-context-across-multiple-chat-messages-in-a-dot-net-application

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
