{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# The `ClockExtension` Sample\n", "\n", "The `ClockExtension` sample walks you through how to create a simple .NET Interactive extension and then package it using NuGet.\n", "\n", "## 1. Build the project\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "dotnet_interactive": { "language": "pwsh" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Determining projects to restore...\n", " All projects are up-to-date for restore.\n", " ClockExtension -> C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\net9.0\\ClockExtension.dll\n", "\n", "Build succeeded.\n", " 0 Warning(s)\n", " 0 Error(s)\n", "\n", "Time Elapsed 00:00:03.44\n", " Determining projects to restore...\n", " All projects are up-to-date for restore.\n", " ClockExtension -> C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\net9.0\\ClockExtension.dll\n", "C:\\Program Files\\dotnet\\sdk\\9.0.200\\Sdks\\NuGet.Build.Tasks.Pack\\build\\NuGet.Build.Tasks.Pack.targets(221,5): warning NU5104: A stable release of a package should not have a prerelease dependency. Either modify the version spec of dependency \"microsoft.dotnet.interactive [1.0.0-beta.24529.1, )\" or update the version field in the nuspec. [C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\ClockExtension.csproj]\n", "C:\\Program Files\\dotnet\\sdk\\9.0.200\\Sdks\\NuGet.Build.Tasks.Pack\\build\\NuGet.Build.Tasks.Pack.targets(221,5): warning NU5104: A stable release of a package should not have a prerelease dependency. Either modify the version spec of dependency \"microsoft.dotnet.interactive.csharp [1.0.0-beta.24529.1, )\" or update the version field in the nuspec. [C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\ClockExtension.csproj]\n", " The package ClockExtension.1.0.0 is missing a readme. Go to https://aka.ms/nuget/authoring-best-practices/readme to learn why package readmes are important.\n", " Successfully created package 'C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\\ClockExtension.1.0.0.nupkg'.\n", "\n", " Directory: C:\\dev\\interactive\\samples\\extensions\\ClockExtension\\bin\\Debug\n", "\n", "\u001b[32;1mMode \u001b[0m\u001b[32;1m LastWriteTime\u001b[0m\u001b[32;1m Length\u001b[0m\u001b[32;1m Name\u001b[0m\n", "\u001b[32;1m---- \u001b[0m \u001b[32;1m -------------\u001b[0m \u001b[32;1m ------\u001b[0m \u001b[32;1m----\u001b[0m\n", "-a--- 2/25/2025 12:52 PM 9673 \u001b[31;1mClockExtension.1.0.0.nupkg\u001b[0m\n", "\n" ] } ], "source": [ "# 1. Build the project\n", "dotnet build ClockExtension\n", "\n", "# Clear any older versions of this extension package from your NuGet cache\n", "rm ~/.nuget/packages/ClockExtension -Force -Recurse -ErrorAction Ignore\n", "\n", "# Pack up the NuGet package. \n", "dotnet pack ClockExtension /p:PackageVersion=1.0.0 -c Debug\n", "\n", "# 3. Check that the package is there\n", "Get-ChildItem -Recurse ClockExtension*.nupkg\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Load the NuGet package \n", "\n", "Now we're ready to install the extension that's packed in the NuGet package we just built.\n", "\n", "First, let's make sure the file is there like we expect after the build.\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [ { "data": { "text/plain": [ "✅ The package is there!" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "using System.IO;\n", "\n", "// Create an absolute path since #i doesn't like \n", "var debugOutputFolder = new DirectoryInfo(@\".\\ClockExtension\\bin\\Debug\\\").FullName;\n", "\n", "if (File.Exists(Path.Combine(debugOutputFolder, \"ClockExtension.1.0.0.nupkg\")))\n", "{\n", " \"✅ The package is there!\".Display();\n", "} \n", "else\n", "{\n", " \"❌ Something must have gone wrong with the build. The package isn't there.\".Display();\n", "}" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "If the package is there, we can include its location as a NuGet source using the `AddPackageSource` command." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [], "source": [ "using Microsoft.DotNet.Interactive;\n", "using Microsoft.DotNet.Interactive.Commands;\n", "\n", "await Kernel.Root.FindKernelByName(\"csharp\").SendAsync(new AddPackageSource(debugOutputFolder));" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now that the package source is added, we can use `#r` to install the package. " ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [ { "data": { "text/html": [ "
Restore sources
Installed Packages
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Loading extension script from `C:\\Users\\josequ\\.nuget\\packages\\clockextension\\1.0.0\\interactive-extensions\\dotnet\\extension.dib`" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
ClockExtension is loaded. It adds visualizations for System.DateTime and System.DateTimeOffset. Try it by running: DateTime.Now
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#r \"nuget:ClockExtension,1.0.0\"" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Try the extension\n", "\n", "As you can see from the output above, when loading the extension is able to explain a bit about what it does. So now we can try it out.\n", "\n", "It adds a custom formatter for `System.DateTime`:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [ { "data": { "text/html": [ "
.NET Interactive
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "DateTime.Now" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "dotnet_interactive": { "language": "csharp" } }, "outputs": [ { "data": { "text/html": [ "
.NET Interactive
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#!clock --hour 12 --minute 34 --second 56" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "outputs": [ { "data": { "text/html": [ "
.NET Interactive
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#!clock " ] } ], "metadata": { "kernelspec": { "display_name": ".NET (C#)", "language": "C#", "name": ".net-csharp" }, "language_info": { "name": "polyglot-notebook" }, "polyglot_notebook": { "kernelInfo": { "defaultKernelName": "csharp", "items": [ { "aliases": [], "name": ".NET" }, { "aliases": [ "C#", "c#" ], "languageName": "C#", "name": "csharp" }, { "aliases": [ "F#", "f#" ], "languageName": "F#", "name": "fsharp" }, { "aliases": [], "languageName": "HTML", "name": "html" }, { "aliases": [], "languageName": "KQL", "name": "kql" }, { "aliases": [], "languageName": "Mermaid", "name": "mermaid" }, { "aliases": [ "powershell" ], "languageName": "PowerShell", "name": "pwsh" }, { "aliases": [], "languageName": "SQL", "name": "sql" }, { "aliases": [], "name": "value" }, { "aliases": [ "frontend" ], "name": "vscode" } ] } } }, "nbformat": 4, "nbformat_minor": 2 }