diff --git a/New_Extensibility_Model/Samples/EncodeDecodeBase64/.vsextension/string-resources.json b/New_Extensibility_Model/Samples/EncodeDecodeBase64/.vsextension/string-resources.json
new file mode 100644
index 00000000..b71b6997
--- /dev/null
+++ b/New_Extensibility_Model/Samples/EncodeDecodeBase64/.vsextension/string-resources.json
@@ -0,0 +1,3 @@
+{
+ "EncodeDecodeBase64.EncodeDecodeBase64Command.DisplayName": "Encode / Decode Base64"
+}
\ No newline at end of file
diff --git a/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64.csproj b/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64.csproj
new file mode 100644
index 00000000..c8e240df
--- /dev/null
+++ b/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64.csproj
@@ -0,0 +1,13 @@
+
+
+ net8.0-windows8.0
+ enable
+ 12
+ en-US
+
+
+
+
+
+
+
diff --git a/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64Command.cs b/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64Command.cs
new file mode 100644
index 00000000..a59d3a33
--- /dev/null
+++ b/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64Command.cs
@@ -0,0 +1,89 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace EncodeDecodeBase64;
+
+using System;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.VisualStudio.Extensibility;
+using Microsoft.VisualStudio.Extensibility.Commands;
+using Microsoft.VisualStudio.Extensibility.Editor;
+
+///
+/// Command handler to encode or decode a base64 text from the currently selected text.
+///
+///
+/// Initializes a new instance of the class.
+///
+/// Trace source instance to utilize.
+[VisualStudioContribution]
+internal class EncodeDecodeBase64Command(TraceSource traceSource) : Command
+{
+ private readonly TraceSource logger = traceSource;
+
+ ///
+ public override CommandConfiguration CommandConfiguration => new("%EncodeDecodeBase64.EncodeDecodeBase64Command.DisplayName%")
+ {
+ Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu],
+ Icon = new(ImageMoniker.KnownValues.ConvertPartition, IconSettings.IconAndText),
+ VisibleWhen = ActivationConstraint.SolutionState(SolutionState.FullyLoaded),
+ EnabledWhen = ActivationConstraint.ClientContext(ClientContextKey.Shell.ActiveEditorContentType, "csharp"),
+ };
+
+ ///
+ ///
+ /// Get the active text and replace it by its equivalent in base64 or plain text.
+ ///
+ public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
+ {
+ using ITextViewSnapshot? textView = await context.GetActiveTextViewAsync(cancellationToken);
+ if (textView is null)
+ {
+ this.logger.TraceInformation("There was no active text view when command is executed.");
+ return;
+ }
+
+ await this.Extensibility.Editor().EditAsync(
+ batch =>
+ {
+ ITextDocumentEditor textDocumentEditor = textView.Document.AsEditable(batch);
+
+ var selections = textView.Selections;
+
+ for (int i = 0; i < selections.Count; i++)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ var selection = selections[i];
+ if (selection.IsEmpty)
+ {
+ continue;
+ }
+
+ // For each selection, we will replace the selected text with its base64 or plain text equivalent
+ string newText = this.EncodeOrDecode(selection.Extent.CopyToString());
+ textDocumentEditor.Replace(selection.Extent, newText);
+ }
+ },
+ cancellationToken);
+ }
+
+ private string EncodeOrDecode(string text)
+ {
+ // Try to decode the string, maybe it's Base64?
+ Span buffer = stackalloc byte[text.Length];
+ if (Convert.TryFromBase64String(text, buffer, out int bytesWritten))
+ {
+ return Encoding.UTF8.GetString(buffer.Slice(0, bytesWritten));
+ }
+ else
+ {
+ // Seems like the input was not Base64, let's try to encode it to Base64 then.
+ byte[] data = Encoding.UTF8.GetBytes(text);
+ return Convert.ToBase64String(data);
+ }
+ }
+}
diff --git a/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64Extension.cs b/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64Extension.cs
new file mode 100644
index 00000000..3851048f
--- /dev/null
+++ b/New_Extensibility_Model/Samples/EncodeDecodeBase64/EncodeDecodeBase64Extension.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace EncodeDecodeBase64;
+
+using Microsoft.VisualStudio.Extensibility;
+
+///
+/// Extension entry point for the EncodeDecodeBase64 extension.
+///
+[VisualStudioContribution]
+internal class EncodeDecodeBase64Extension : Extension
+{
+ ///
+ public override ExtensionConfiguration ExtensionConfiguration => new()
+ {
+ Metadata = new(
+ id: "EncodeDecodeBase64.87525EE0-4B75-4DF5-BB0E-C9EA1A5D2E15",
+ version: this.ExtensionAssemblyVersion,
+ publisherName: "Microsoft",
+ displayName: "Encode or Decode Base64 Sample Extension",
+ description: "Sample extension demonstrating encoding and decoding base64 text in the current document"),
+ };
+}
diff --git a/New_Extensibility_Model/Samples/EncodeDecodeBase64/README.md b/New_Extensibility_Model/Samples/EncodeDecodeBase64/README.md
new file mode 100644
index 00000000..8d869977
--- /dev/null
+++ b/New_Extensibility_Model/Samples/EncodeDecodeBase64/README.md
@@ -0,0 +1,90 @@
+---
+title: Encode / Decode Base64 Extension Sample reference
+description: A reference for Encode / Decode Base64 sample
+date: 2025-4-3
+---
+
+# Walkthrough: Encode / Decode Base64 Extension Sample
+
+This extension is a simple extension that shows how a command that modifies an open editor window can be quickly added to Visual Studio.
+
+## Command definition
+
+The extension contains a code file that defines a command and its properties starting with the `VisualStudioContribution` class attribute which makes the command available to Visual Studio:
+
+```csharp
+[VisualStudioContribution]
+internal class EncodeDecodeBase64Command : Command
+{
+```
+
+The `VisualStudioContribution` attribute registers the command using the class full type name `EncodeDecodeBase64.EncodeDecodeBase64Command` as its unique identifier.
+
+The `CommandConfiguration` property defines information about the command that are available to Visual Studio even before the extension is loaded:
+
+```csharp
+ public override CommandConfiguration CommandConfiguration => new("%EncodeDecodeBase64.EncodeDecodeBase64Command.DisplayName%")
+ {
+ Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu],
+ Icon = new(ImageMoniker.KnownValues.ConvertPartition, IconSettings.IconAndText),
+ VisibleWhen = ActivationConstraint.SolutionState(SolutionState.FullyLoaded),
+ EnabledWhen = ActivationConstraint.ClientContext(ClientContextKey.Shell.ActiveEditorContentType, "csharp"),
+ };
+```
+
+The command is placed in `Extensions` top menu and uses `ConvertPartition` icon moniker.
+
+The `VisibleWhen` and `EnabledWhen` properties defines when the command is visible and enabled in the `Extensions` menu. You can refer to [Activation Constraints](https://learn.microsoft.com/visualstudio/extensibility/visualstudio.extensibility/inside-the-sdk/activation-constraints) to learn about different options that you can use to determine command visibility and state. In this case, the command is visible anytime a solution is fully loaded in the IDE, but enabled only when the active editor is a C# document.
+
+## Getting the active editor view
+
+Once user executes the command, SDK will route execution to `ExecuteCommandAsync` method. `IClientContext` instance contains information about the state of IDE at the time of command execution and can be used in conjunction with `VisualStudioExtensibility` object.
+
+In our example, we utilize `GetActiveTextViewAsync` method to get the active text view at the time of command execution which includes information about document being open, version of the document and the selection.
+
+```csharp
+using var textView = await context.GetActiveTextViewAsync(cancellationToken);
+```
+
+## Mutating the text in active view
+
+Once we have the active text view, we can edit the document attached to the view to replace the selection with a new guid string as below.
+
+```csharp
+ITextViewSnapshot textDocumentEditor = await textView.GetTextDocumentAsync(cancellationToken);
+await this.Extensibility.Editor().EditAsync(
+ batch =>
+ {
+ ITextDocumentEditor textDocumentEditor = textView.Document.AsEditable(batch);
+ // [...]
+ },
+ cancellationToken);
+```
+
+## Accessing every selections in the active view
+
+The `ITextViewSnapshot` instance contains a `Selections` property that can be used to get the current selections in the view. There can be empty or [multiple selections](https://learn.microsoft.com/en-us/visualstudio/ide/finding-and-replacing-text?view=vs-2022#multi-caret-selection).
+```csharp
+ITextDocumentEditor textDocumentEditor = textView.Document.AsEditable(batch);
+var selections = textView.Selections;
+
+for (int i = 0; i < selections.Count; i++)
+{
+ var selection = selections[i];
+ if (selection.IsEmpty)
+ {
+ continue;
+ }
+
+ string newText = this.EncodeOrDecode(selection.Extent.CopyToString());
+ textDocumentEditor.Replace(selection.Extent, newText);
+}
+```
+
+## Logging errors
+
+Each extension part including command sets is assigned a `TraceSource` instance that can be utilized to log diagnostic errors. Please see [Logging](https://learn.microsoft.com/visualstudio/extensibility/visualstudio.extensibility/inside-the-sdk/logging) section for more information.
+
+## Usage
+
+Once deployed, the Encode / Decode Base64 command can be used when editing any C# document. The command by default will be under Extensions menu.
diff --git a/New_Extensibility_Model/Samples/Samples.sln b/New_Extensibility_Model/Samples/Samples.sln
index 0c6aa5f1..5741aef0 100644
--- a/New_Extensibility_Model/Samples/Samples.sln
+++ b/New_Extensibility_Model/Samples/Samples.sln
@@ -73,6 +73,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompositeExtension", "Compo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaggersSample", "TaggersSample\TaggersSample.csproj", "{F7631680-13DF-42EC-AA87-C29FD4BE2273}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EncodeDecodeBase64", "EncodeDecodeBase64\EncodeDecodeBase64.csproj", "{4E6E513B-0690-4B75-8F45-8DFB73D630CC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -185,6 +187,10 @@ Global
{F7631680-13DF-42EC-AA87-C29FD4BE2273}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7631680-13DF-42EC-AA87-C29FD4BE2273}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7631680-13DF-42EC-AA87-C29FD4BE2273}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4E6E513B-0690-4B75-8F45-8DFB73D630CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4E6E513B-0690-4B75-8F45-8DFB73D630CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4E6E513B-0690-4B75-8F45-8DFB73D630CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4E6E513B-0690-4B75-8F45-8DFB73D630CC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE