# Resources | WinForms Controls | DevExpress Documentation

The [AI Chat Control](/WindowsForms/405218/ai-powered-extensions/ai-chat-control) can access external or dynamically generated data through resources. A resource is an instance of the [AIChatResource](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource) class that supplies text or binary content to the AI model at request time.

Resources extend the chat context with additional input (for example, local documents, logs, or images). The AI model uses this data to generate more accurate and context-aware responses.

After you assign resources, the `AIChatControl` displays the “Attach Context” (+) button. Users can select one or more resources to include in the chat request. A built-in search box helps users quickly find the desired items when the resource list is long.

![Resource - WinForms AI CHat Control, DevExpress](/WindowsForms/images/25-2-winforms-ai-chat-resources.gif)

Tip

The **Resources** feature is primarily designed to integrate with resources provided by MCP (Model Context Protocol) servers. Use the MCP client SDK to retrieve these resources:

```
McpClient = await McpClientFactory.CreateAsync(transport);
var mcpResources = await McpClient.ListResourcesAsync();
Resources = mcpResources.Select(x => new AIChatResource(x.Uri, x.Name, LoadResourceData, x.MimeType, x.Description));
```

## Define Resources

1. Create a collection of [AIChatResource](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource) objects.
2. Use the `SetResources` method to assign resources to the `AIChatControl`.

Note

Large PDFs or images may impact performance and token consumption.

- C#
- VB.NET

<section id="tabpanel_K0H-1IqcLl_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;/ (System)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system&quot;,&quot;/ (System.Collections.Generic)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.collections.generic&quot;,&quot;/ (System.IO)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.io&quot;,&quot;/ (System.Text)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.text&quot;,&quot;/ (System.Threading)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.threading&quot;,&quot;/ (System.Threading.Tasks)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.threading.tasks&quot;,&quot;/ (DevExpress.AIIntegration.Blazor.Chat)(?:;|$)/&quot;:&quot;/Blazor/DevExpress.AIIntegration.Blazor.Chat&quot;,&quot;/ (DevExpress.XtraBars.Ribbon)(?:;|$)/&quot;:&quot;/WindowsForms/DevExpress.XtraBars.Ribbon&quot;}" class="lang-csharp">using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DevExpress.AIIntegration.Blazor.Chat;
using DevExpress.XtraBars.Ribbon;
using Microsoft.Extensions.AI;
using UglyToad.PdfPig;

namespace DXWinFormsChatApp {
    public partial class RibbonForm1 : RibbonForm {
        static readonly IReadOnlyList&lt;AIChatResource&gt; Resources = new List&lt;AIChatResource&gt; {
            new AIChatResource(
                &quot;access.txt&quot;,
                &quot;Access Log&quot;,
                GetLogResourceAsync,
                &quot;text/plain&quot;,
                &quot;Contains web server access records collected over the last 24 hours.&quot;
                ),
            new AIChatResource(
                &quot;restaurantmenu.pdf&quot;,
                &quot;Restaurant Menu&quot;, 
                GetPdfResourceAsync, 
                &quot;application/pdf&quot;, 
                &quot;Displays New York Steakhouse&#39;s current menu.&quot;
                ),
            new AIChatResource(
                &quot;dashboard.jpg&quot;,
                &quot;Dashboard (Screenshot)&quot;,
                GetImageResourceAsync, 
                &quot;image/jpeg&quot;, 
                &quot;A dashboard screenshot that displays the latest real-time analytics data.&quot;
                ),
            new AIChatResource(
                &quot;dxaichat.md&quot;, 
                &quot;AI Chat Documentation&quot;, 
                GetDocsResourceAsync, 
                &quot;text/markdown&quot;, 
                &quot;Includes reference documentation that describes AI Chat functionality and usage guidelines.&quot;
                )
        };

        public RibbonForm1() {
            InitializeComponent();
            aiChatControl1.SetResources(Resources);
        }

        // Load a text log file and return it as a single text content block.
        static async Task&lt;IList&lt;AIContent&gt;&gt; GetLogResourceAsync(AIChatResource resource, CancellationToken ct) {
            if (!File.Exists(resource.Uri))
                return new List&lt;AIContent&gt; { new TextContent(&quot;Log file not found.&quot;) };

            string text = await File.ReadAllTextAsync(resource.Uri, ct).ConfigureAwait(false);
            return new List&lt;AIContent&gt; { new TextContent(text) };
        }

        // Load an image file as binary content.
        static async Task&lt;ReadOnlyMemory&lt;byte&gt;&gt; GetImageResourceAsync(AIChatResource resource, CancellationToken ct) {
            if (!File.Exists(resource.Uri))
                return ReadOnlyMemory&lt;byte&gt;.Empty;

            byte[] data = await File.ReadAllBytesAsync(resource.Uri, ct).ConfigureAwait(false);
            return new ReadOnlyMemory&lt;byte&gt;(data);
        }

        // Load markdown documentation as a string.
        static async Task&lt;string&gt; GetDocsResourceAsync(AIChatResource resource, CancellationToken ct) {
            if (!File.Exists(resource.Uri))
                return &quot;Documentation file not found.&quot;;

            return await File.ReadAllTextAsync(resource.Uri, ct).ConfigureAwait(false);
        }

        // Extract all text from a PDF file using the PdfPig library.
        static async Task&lt;string&gt; GetPdfResourceAsync(AIChatResource resource, CancellationToken ct) {
            if (!File.Exists(resource.Uri))
                return &quot;PDF file not found.&quot;;

            return await Task.Run(() =&gt; {
                var sb = new StringBuilder();
                try {
                    using var pdf = PdfDocument.Open(resource.Uri);
                    foreach (var page in pdf.GetPages()) {
                        sb.AppendLine(page.Text);
                    }
                }
                catch (Exception ex) {
                    return $&quot;[Error reading PDF: {ex.Message}]&quot;;
                }
                return sb.ToString();
            }, ct).ConfigureAwait(false);
        }
    }
}
</code></pre></section>
<section id="tabpanel_K0H-1IqcLl_tabid-vb" role="tabpanel" data-tab="tabid-vb" aria-hidden="true" hidden="hidden">
<pre><code data-code-links="{&quot;/ (System)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system&quot;,&quot;/ (System.Collections.Generic)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.collections.generic&quot;,&quot;/ (System.IO)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.io&quot;,&quot;/ (System.Text)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.text&quot;,&quot;/ (System.Threading)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.threading&quot;,&quot;/ (System.Threading.Tasks)(?:;|$)/&quot;:&quot;https://learn.microsoft.com/dotnet/api/system.threading.tasks&quot;,&quot;/ (DevExpress.AIIntegration.Blazor.Chat)(?:;|$)/&quot;:&quot;/Blazor/DevExpress.AIIntegration.Blazor.Chat&quot;,&quot;/ (DevExpress.XtraBars.Ribbon)(?:;|$)/&quot;:&quot;/WindowsForms/DevExpress.XtraBars.Ribbon&quot;}" class="lang-vb">Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks
Imports DevExpress.AIIntegration.Blazor.Chat
Imports DevExpress.XtraBars.Ribbon
Imports Microsoft.Extensions.AI
Imports UglyToad.PdfPig

Namespace DXWinFormsChatApp
    Public Partial Class RibbonForm1
        Inherits RibbonForm

        Private Shared ReadOnly Resources As IReadOnlyList(Of AIChatResource) = New List(Of AIChatResource) From {
            New AIChatResource(
                &quot;access.txt&quot;,
                &quot;Access Log&quot;,
                AddressOf GetLogResourceAsync,
                &quot;text/plain&quot;,
                &quot;Contains web server access records collected over the last 24 hours.&quot;),
            New AIChatResource(
                &quot;restaurantmenu.pdf&quot;,
                &quot;Restaurant Menu&quot;,
                AddressOf GetPdfResourceAsync,
                &quot;application/pdf&quot;,
                &quot;Displays New York Steakhouse&#39;s current menu.&quot;),
            New AIChatResource(
                &quot;dashboard.jpg&quot;,
                &quot;Dashboard (Screenshot)&quot;,
                AddressOf GetImageResourceAsync,
                &quot;image/jpeg&quot;,
                &quot;A dashboard screenshot that displays the latest real-time analytics data.&quot;),
            New AIChatResource(
                &quot;dxaichat.md&quot;,
                &quot;AI Chat Documentation&quot;,
                AddressOf GetDocsResourceAsync,
                &quot;text/markdown&quot;,
                &quot;Includes reference documentation that describes AI Chat functionality and usage guidelines.&quot;)
        }

        Public Sub New()
            InitializeComponent()
            aiChatControl1.SetResources(Resources)
        End Sub

        &#39; Load a text log file and return it as a single text content block.
        Private Shared Async Function GetLogResourceAsync(resource As AIChatResource, ct As CancellationToken) As Task(Of IList(Of AIContent))
            If Not File.Exists(resource.Uri) Then
                Return New List(Of AIContent) From { New TextContent(&quot;Log file not found.&quot;) }
            End If
            Dim text = Await File.ReadAllTextAsync(resource.Uri, ct).ConfigureAwait(False)
            Return New List(Of AIContent) From { New TextContent(text) }
        End Function

        &#39; Load an image file as binary content.
        Private Shared Async Function GetImageResourceAsync(resource As AIChatResource, ct As CancellationToken) As Task(Of ReadOnlyMemory(Of Byte))
            If Not File.Exists(resource.Uri) Then
                Return ReadOnlyMemory(Of Byte).Empty
            End If
            Dim data = Await File.ReadAllBytesAsync(resource.Uri, ct).ConfigureAwait(False)
            Return New ReadOnlyMemory(Of Byte)(data)
        End Function

        &#39; Load markdown documentation as a string.
        Private Shared Async Function GetDocsResourceAsync(resource As AIChatResource, ct As CancellationToken) As Task(Of String)
            If Not File.Exists(resource.Uri) Then
                Return &quot;Documentation file not found.&quot;
            End If
            Return Await File.ReadAllTextAsync(resource.Uri, ct).ConfigureAwait(False)
        End Function

        &#39; Extract all text from a PDF file using the PdfPig library.
        Private Shared Async Function GetPdfResourceAsync(resource As AIChatResource, ct As CancellationToken) As Task(Of String)
            If Not File.Exists(resource.Uri) Then
                Return &quot;PDF file not found.&quot;
            End If
            Return Await Task.Run(Function()
                                      Dim sb = New StringBuilder()
                                      Try
                                          Using pdf = PdfDocument.Open(resource.Uri)
                                              For Each page In pdf.GetPages()
                                                  sb.AppendLine(page.Text)
                                              Next
                                          End Using
                                      Catch ex As Exception
                                          Return $&quot;[Error reading PDF: {ex.Message}]&quot;
                                      End Try
                                      Return sb.ToString()
                                  End Function, ct).ConfigureAwait(False)
        End Function
    End Class
End Namespace
</code></pre></section>

## Resource Parameters

| Parameter | Description |
| --- | --- |
| [Uri](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource.Uri) | Gets or sets the resource identifier (for example, a file name, local path, or external URI). |
| [Guid](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource.Guid) | Gets the unique, autogenerated identifier. |
| [Name](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource.Name) | Gets or sets the resource name displayed in the chat UI. |
| [MimeType](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource.MimeType) | Gets or sets the resource content type (for example, `text/plain`, `application/pdf`, `image/jpeg`). |
| [Description](/Blazor/DevExpress.AIIntegration.Blazor.Chat.AIChatResource.Description) | Gets or sets the resource description displayed in a tooltip. |

## Customize Resource Appearance

Use the `AIChatControl.SetResourceItemTemplate` method to supply a Razor-based template for resource items displayed in the chat’s “Attach Context” dropdown:

![Customize Resource Appearance - WinForms AI Chat Control, DevExpress](/WindowsForms/images/ai-chat-resource-item-template.png)

```
aiChatControl1.SetResourceItemTemplate(resource => builder => {
    builder.OpenComponent<Resource>(0);
    builder.AddAttribute(1, "resource", resource);
    builder.CloseComponent();
});
```

The *Resource.razor* file:

```
@using Microsoft.AspNetCore.Components.Web
@using DevExpress.AIIntegration.Blazor.Chat

<div class="resource-item">
    <div class="resource-name">@resource.Name</div>
    <div class="resource-meta">
        <span class="resource-type">@resource.MimeType</span>
        <span class="resource-desc">@resource.Description</span>
    </div>
</div>

@code {
    [Parameter]
    public AIChatResource resource { get; set; }
}

<style>
    .resource-item {
        background-color: #f0f9ff;
        border-radius: 10px;
        padding: 12px 16px;
        margin: 6px 0;
        box-shadow: 0 2px 6px rgba(0,0,0,0.1);
        transition: transform 0.2s, box-shadow 0.2s;
        cursor: pointer;
    }

    .resource-item:hover {
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    }

    .resource-name {
        font-weight: 600;
        font-size: 1rem;
        color: #0b3d91;
        margin-bottom: 4px;
    }

    .resource-meta {
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
        gap: 10px;
        font-size: 0.7rem;
        color: #555;
    }

    .resource-type {
        background-color: #dbeafe;
        padding: 2px 6px;
        border-radius: 4px;
        font-weight: 500;
    }

    .resource-desc {
        flex: 1;
        color: #333;
        overflow: hidden;
        text-overflow: ellipsis;
        word-break: break-word;
    }
</style>
```

## Best Practices

- Use short and scannable resource names.
- Specify consistent MIME types (incorrect values can reduce model relevance).
- Avoid sending confidential resources unless necessary.
- Enforce size limits on resources to prevent excessive token usage.
- Log resource access for auditing (for example, when dealing with sensitive or compliance-related data).

See Also

[AI Chat Control](/WindowsForms/405218/ai-powered-extensions/ai-chat-control)