diff --git a/csharp/random-writer/.gitignore b/csharp/random-writer/.gitignore
new file mode 100644
index 000000000..dbd103469
--- /dev/null
+++ b/csharp/random-writer/.gitignore
@@ -0,0 +1,2 @@
+src/*/bin/
+src/*/obj/
diff --git a/csharp/random-writer/README.md b/csharp/random-writer/README.md
new file mode 100644
index 000000000..71f5dc6ae
--- /dev/null
+++ b/csharp/random-writer/README.md
@@ -0,0 +1,29 @@
+# RandomWriter
+
+## Overview
+This sample application demonstrates some essential mechanisms of the *AWS Cloud
+Development Kit* (*AWS CDK*) for .NET (in this case, using **C#**):
+- Creating a user-defined *construct*
+- Having this *construct* implement a feature interface
+ (`Amazon.CDK.AWS.Events.IRuleTarget`) to bring specific capabilities to the
+ *construct*
+- Granting permissions (for a *Lambda* function to write into a *DynamoDB*
+ table) using the `.Grant*` methods.
+
+## Application Resources
+> All resources provisioned by this application are *[free-tier] eligible* or
+> generally free to provision and use.
+
+The application provisions the following elements (shown in their hierarchical
+presentation withing the *CDK construct tree*):
+
+- A *stack* named `RandomWriterStack`
+ - A user-defined *construct* named `RandomWriter`
+ - A *DynamoDB* table (the physical name of which is to be determined by
+ *AWS CloudFormation* upon creation)
+ - A *Lambda* function
+ * It writes a random hash into the *DynamoDB* table when invoked
+ - A *CloudWatch* event rule that triggers an execution of the *Lambda*
+ function *every minute*.
+
+[free-tier]: https://aws.amazon.com/free/
diff --git a/csharp/random-writer/cdk.json b/csharp/random-writer/cdk.json
new file mode 100644
index 000000000..ac6692e9a
--- /dev/null
+++ b/csharp/random-writer/cdk.json
@@ -0,0 +1,3 @@
+{
+ "app": "dotnet run --project src/RandomWriter/RandomWriter.csproj"
+}
diff --git a/csharp/random-writer/src/RandomWriter.sln b/csharp/random-writer/src/RandomWriter.sln
new file mode 100644
index 000000000..692f6b306
--- /dev/null
+++ b/csharp/random-writer/src/RandomWriter.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RandomWriter", "RandomWriter\RandomWriter.csproj", "{0B87A53B-C322-4A64-9C52-7A047E296339}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Debug|x64.Build.0 = Debug|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Debug|x86.Build.0 = Debug|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Release|x64.ActiveCfg = Release|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Release|x64.Build.0 = Release|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Release|x86.ActiveCfg = Release|Any CPU
+ {0B87A53B-C322-4A64-9C52-7A047E296339}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/csharp/random-writer/src/RandomWriter/Program.cs b/csharp/random-writer/src/RandomWriter/Program.cs
new file mode 100644
index 000000000..e4bde383e
--- /dev/null
+++ b/csharp/random-writer/src/RandomWriter/Program.cs
@@ -0,0 +1,14 @@
+using Amazon.CDK;
+
+namespace RandomWriter
+{
+ public sealed class Program
+ {
+ public static void Main(string[] args)
+ {
+ var app = new App();
+ new RandomWriterStack(app, "RandomWriterStack");
+ app.Synth();
+ }
+ }
+}
diff --git a/csharp/random-writer/src/RandomWriter/RandomWriter.csproj b/csharp/random-writer/src/RandomWriter/RandomWriter.csproj
new file mode 100644
index 000000000..975e31751
--- /dev/null
+++ b/csharp/random-writer/src/RandomWriter/RandomWriter.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ netcoreapp3.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csharp/random-writer/src/RandomWriter/RandomWriterStack.cs b/csharp/random-writer/src/RandomWriter/RandomWriterStack.cs
new file mode 100644
index 000000000..1c9e5cb0d
--- /dev/null
+++ b/csharp/random-writer/src/RandomWriter/RandomWriterStack.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using Amazon.CDK;
+using Amazon.CDK.AWS.DynamoDB;
+using Amazon.CDK.AWS.Events;
+using Amazon.CDK.AWS.Events.Targets;
+using Amazon.CDK.AWS.Lambda;
+
+namespace RandomWriter
+{
+ internal sealed class RandomWriterStack : Stack
+ {
+ public RandomWriterStack(Construct parent, string id, IStackProps props = null) : base(parent, id, props)
+ {
+ // The code that defines your stack goes here
+ var randomWriter = new RandomWriter(this, "RandomWriter");
+ new Rule(this, "Trigger", new RuleProps()
+ {
+ Description = "Triggers a RandomWrite every minute",
+ Schedule = Schedule.Rate(Duration.Minutes(1)),
+ Targets = new [] { randomWriter }
+ });
+ }
+ }
+
+ internal sealed class RandomWriter : Construct, IRuleTarget
+ {
+ private IFunction Function { get; }
+
+ public RandomWriter(Construct scope, string id): base(scope, id)
+ {
+ var table = new Table(this, "Table", new TableProps
+ {
+ PartitionKey = new Attribute
+ {
+ Name = "ID",
+ Type = AttributeType.STRING
+ }
+ });
+
+ Function = new Function(this, "Lambda", new FunctionProps
+ {
+ Runtime = Runtime.NODEJS_10_X,
+ Handler = "index.handler",
+ Code = Code.FromAsset("src/RandomWriter/resources"),
+ Environment = new Dictionary
+ {
+ { "TABLE_NAME", table.TableName }
+ }
+ });
+
+ table.GrantReadWriteData(Function);
+ }
+
+ public IRuleTargetConfig Bind(IRule rule, string id = null)
+ {
+ return new LambdaFunction(Function).Bind(rule, id);
+ }
+ }
+}
diff --git a/csharp/random-writer/src/RandomWriter/resources/index.js b/csharp/random-writer/src/RandomWriter/resources/index.js
new file mode 100644
index 000000000..b16cfad14
--- /dev/null
+++ b/csharp/random-writer/src/RandomWriter/resources/index.js
@@ -0,0 +1,26 @@
+const { DynamoDB } = require('aws-sdk');
+const crypto = require('crypto');
+
+/**
+ * This Lambda event handler expects the name of a DynamoDB table to be passed
+ * in the `TABLE_NAME` environment variable. The Lambda function must be granted
+ * WRITE permissions on the DynamoDB table (for it will add new items in the
+ * table).
+ *
+ * The DynamoDB table must have a hash-only primary key, where the hash key is
+ * named `ID` and is of type STRING.
+ */
+exports.handler = async function handler(event, context) {
+ console.log(JSON.stringify(event, undefined, 2));
+
+ var seed = `${Date.now}${Math.random()}`;
+ const id = crypto.createHash('sha1').update(seed).digest('hex');
+
+ const ddb = new DynamoDB();
+ await ddb.putItem({
+ TableName: process.env.TABLE_NAME,
+ Item: {
+ ID: { S: id }
+ }
+ }).promise();
+};