# IAttachmentStorage

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.iattachmentstorage/
> Summary: IAttachmentStorage: The extension point that stores attachment content in an external store (S3, Blob).

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

The extension point that stores attachment content in an external store (S3, Blob).

```csharp
public interface IAttachmentStorage
```

## Remarks

When it is not registered the content lives in the database, so nothing has to be set up first.
Tracon takes no dependency on any cloud SDK; the consumer writes the
implementation.

**DI lifetime — singleton, optional.** No default implementation is
registered. A consumer that registers one must register it as a singleton (or
hand it to `IServiceProvider.GetService<IAttachmentStorage>`'s
caller, itself resolved once as a singleton dependency, for example
`InMemoryAttachmentStore`) — never scoped, which would be a captive
dependency.

## Methods

### <a id="Tracon_IAttachmentStorage_DeleteAsync_System_Uri_System_Threading_CancellationToken_"></a> DeleteAsync\(Uri, CancellationToken\)

Deletes the content in the external store.

```csharp
ValueTask DeleteAsync(Uri uri, CancellationToken cancellationToken = default)
```

#### Parameters

`uri` Uri

The location returned by [IAttachmentStorage.WriteAsync](/api/tracon.iattachmentstorage/#Tracon_IAttachmentStorage_WriteAsync_System_String_System_Guid_System_IO_Stream_System_String_System_Threading_CancellationToken_).

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask)

A task that completes when the content is gone.

#### Remarks

**Must be idempotent.** Deleting a location that no longer
exists succeeds and does not throw. Tracon deletes the content BEFORE the
metadata row, so a retry after a partial failure — or two deletes that
race — calls this method again for content that is already gone.

Throw only when the content may still exist. The attachment store, the
retention policy, and data subject erasure then keep the metadata row,
because it is the only record of where the content is: a single delete
and an erasure fail, and retention retries the row on its next run.

### <a id="Tracon_IAttachmentStorage_ReadAsync_System_Uri_System_Threading_CancellationToken_"></a> ReadAsync\(Uri, CancellationToken\)

Reads the content from the external store.

```csharp
ValueTask<Stream?> ReadAsync(Uri uri, CancellationToken cancellationToken = default)
```

#### Parameters

`uri` Uri

The location returned by [IAttachmentStorage.WriteAsync](/api/tracon.iattachmentstorage/#Tracon_IAttachmentStorage_WriteAsync_System_String_System_Guid_System_IO_Stream_System_String_System_Threading_CancellationToken_).

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[Stream](https://learn.microsoft.com/dotnet/api/system.io.stream)?\>

A readable stream, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) when the location no longer exists.

#### Remarks

**Stream ownership.** The CALLER owns the returned stream and
must dispose it.

### <a id="Tracon_IAttachmentStorage_WriteAsync_System_String_System_Guid_System_IO_Stream_System_String_System_Threading_CancellationToken_"></a> WriteAsync\(string, Guid, Stream, string, CancellationToken\)

Writes the content to the external store.

```csharp
ValueTask<Uri> WriteAsync(string tenantId, Guid id, Stream content, string mediaType, CancellationToken cancellationToken = default)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The tenant id.

`id` [Guid](https://learn.microsoft.com/dotnet/api/system.guid)

The attachment id.

`content` [Stream](https://learn.microsoft.com/dotnet/api/system.io.stream)

The content to write.

`mediaType` [string](https://learn.microsoft.com/dotnet/api/system.string)

The MIME type of the content.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<Uri\>

The location of the content in the external store.

#### Remarks

**Stream ownership.** The CALLER owns `content`
and disposes it; this method reads from it but does not dispose it.
