diff --git a/src/TriunniaLabs.Arch.Sample.Server/Controllers/ProtectedMemorySampleController.cs b/src/TriunniaLabs.Arch.Sample.Server/Controllers/ProtectedMemorySampleController.cs
new file mode 100644
index 0000000..ade7685
--- /dev/null
+++ b/src/TriunniaLabs.Arch.Sample.Server/Controllers/ProtectedMemorySampleController.cs
@@ -0,0 +1,90 @@
+using TriunniaLabs.Arch.Microservice;
+using TriunniaLabs.Memory.Protected;
+
+namespace TriunniaLabs.Arch.Sample.Server
+{
+ ///
+ /// A controller that shows how to work with the Protected Memory system.
+ ///
+ public class ProtectedMemorySampleController : ArchControllerBase
+ {
+ // Services
+ private readonly IProtectorFactory _protectorFactory;
+ private readonly IProtector _stringProtector;
+
+ ///
+ /// Constructor.
+ ///
+ /// Reference to the microservice context.
+ /// Reference to the protector factory.
+ /// Reference to the string protector.
+ public ProtectedMemorySampleController(IMicroserviceContext microserviceContext,
+ IProtectorFactory protectorFactory,
+ [FromKeyedServices("MyProtectorServiceKey")] IProtector stringProtector)
+ : base(microserviceContext)
+ {
+ _stringProtector = stringProtector ?? throw new ArgumentNullException(nameof(stringProtector));
+ _protectorFactory = protectorFactory ?? throw new ArgumentNullException(nameof(protectorFactory));
+ }
+
+ ///
+ /// A sample method that shows how to work with the Protected Memory system.
+ ///
+ internal async Task SampleAsync()
+ {
+ // In Arch, all data is encrypted in memory via the Protected type. This encryption extends to the database and data transfer objects.
+ var myString = "My String Value";
+ var myProtectedString = new Protected(myString);
+
+ // The hash of a protected type's value is available for equality checking without exposing the encrypted value
+ var hash = myProtectedString.Hash;
+
+ // Decrypt the protected type to get its value
+ var value = myProtectedString.GetDecryptedValue(); // "My String Value"
+
+ // Or decrypt just enough to get the bytes (from the byte array converter) without restoring the actual value.
+ var bytes = myProtectedString.GetDecryptedValueAsBytes();
+
+ // The protected type can be serialized just by calling ToString(), and this is what is used in appsettings.json or in the database.
+ // The serialized string is completely encrypted. It cannot be decrypted without a matching configuration.
+ var serializedString = myProtectedString.ToString();
+
+ // The static FromEncrypted method can be used to deserialize
+ myProtectedString = Protected.FromEncrypted(serializedString);
+
+ // Custom protections can be specified as well. This specific arrangement is called Standard Protection.
+ // It is the default that is used when no other algorithms are specified.
+ var byteArrayConverter = MessagePackByteArrayConverter.Instance;
+ var sha256HashAlgorithm = Sha256HashAlgorithm.Instance;
+ var aesEncryption = AesHashEncryptionAlgorithm.Instance;
+ var stringConverter = Base64StringConverter.Instance;
+ myProtectedString = new Protected(myString, byteArrayConverter, sha256HashAlgorithm, [aesEncryption], stringConverter);
+
+ // Use Protectors to protect values with pre-defined custom configurations
+ var protector = _protectorFactory.CreateProtector(MessagePackByteArrayConverter.ServiceKey,
+ Sha256HashAlgorithm.ServiceKey, [AesEncryptionAlgorithm.ServiceKey],
+ Base64StringConverter.ServiceKey);
+
+ // Protect the value using the protector
+ myProtectedString = protector.Protect(myString);
+
+ // Protectors are also used to receive serialized data
+ myProtectedString = protector.Receive(serializedString);
+ myProtectedString = _stringProtector.Receive(serializedString); // They can also be injected
+ }
+
+ private class MyProtectedSample
+ {
+ ///
+ /// Protector definitions are automatically scanned by the library and added to the service container.
+ /// If an algorithm or converter isn't specified, the default is used.
+ ///
+ [ByteArrayConverter("MessagePackByteArrayConverter.ServiceKey")]
+ [HashAlgorithm(HmacSha512HashAlgorithm.ServiceKey)]
+ [EncryptionAlgorithm(AesEncryptionAlgorithm.ServiceKey, Order = 1)]
+ [StringConverter(Base64StringConverter.ServiceKey)]
+ [Protector("MyProtectorServiceKey")] // Identifies the protector in the service collection
+ public string Value { get; set; } = "";
+ }
+ }
+}