{"id":28448267,"url":"https://github.com/spinframework/spin-dotnet-sdk","last_synced_at":"2025-06-30T15:30:41.957Z","repository":{"id":59138089,"uuid":"512952046","full_name":"spinframework/spin-dotnet-sdk","owner":"spinframework","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-10T23:17:45.000Z","size":610,"stargazers_count":46,"open_issues_count":12,"forks_count":11,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-06-06T13:06:45.623Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spinframework.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-07-12T00:53:42.000Z","updated_at":"2025-05-02T19:45:39.000Z","dependencies_parsed_at":"2023-01-27T05:01:30.302Z","dependency_job_id":"a1a334f5-9f77-4448-894c-01d8af34f59b","html_url":"https://github.com/spinframework/spin-dotnet-sdk","commit_stats":null,"previous_names":["spinframework/spin-dotnet-sdk"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/spinframework/spin-dotnet-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spinframework%2Fspin-dotnet-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spinframework%2Fspin-dotnet-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spinframework%2Fspin-dotnet-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spinframework%2Fspin-dotnet-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spinframework","download_url":"https://codeload.github.com/spinframework/spin-dotnet-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spinframework%2Fspin-dotnet-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262800522,"owners_count":23366378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-06T13:06:43.516Z","updated_at":"2025-06-30T15:30:41.691Z","avatar_url":"https://github.com/spinframework.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spin SDK for .NET Preview\n\nAn experimental SDK for building Spin application components using .NET.\n\n### Features\n\n* Handle HTTP requests using the Spin executor\n* Make outbound HTTP requests\n* Access Postgres databases\n* Make outbound Redis calls\n* Fast startup by preparing the .NET runtime during Wasm compilation (via Wizer)\n\n### Prerequisites\n\nYou'll need the following to build Spin applications using this SDK:\n\n- [Spin](https://spin.fermyon.dev) v0.5.0 or above\n- [.NET 8+](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)\n- [Wizer](https://github.com/bytecodealliance/wizer/releases) - download and place it on your PATH\n  - If you have Rust installed, you can install Wizer by running `make bootstrap` in the root of the SDK repo\n\n### Getting the Spin SDK\n\nYou can get the SDK itself from NuGet via `dotnet add package Fermyon.Spin.Sdk --prerelease`, or use\nthe provided template - see below for details.\n\n### Building the \"hello world\" sample\n\nTo build and run the `hello-world` sample, clone this repo and run:\n\n```\n$ cd samples/hello-world\n$ spin build --up\n```\n\nIf everything worked, you should see a Spin \"serving routes\" message:\n\n```\nServing http://127.0.0.1:3000\nAvailable Routes:\n  hello: http://127.0.0.1:3000 (wildcard)\n```\n\nYou should be able to curl the address and get a response along the lines of:\n\n```\n$ curl -v 127.0.0.1:3000\n// outbound trace omitted\n\u003c HTTP/1.1 200 OK\n\u003c content-type: text/plain\n\u003c x-testheader: this is a test\n\u003c content-length: 451\n\u003c date: Thu, 21 Jul 2022 03:11:15 GMT\n\u003c\nCalled with method Get on URL /\nHeader 'host' had value '127.0.0.1:3000'\n// ... more headers info ...\nHeader 'spin-component-route' had value ''\nThe body was empty\n```\n\n### Installing the Spin application template\n\nThe SDK includes a Spin template for C# projects.  To install it, run:\n\n```\nspin templates install --git https://github.com/fermyon/spin-dotnet-sdk --branch main --update\n```\n\nYou can then run `spin new -t http-csharp \u003cproject-name\u003e` to create a new Spin C# application.\n\n\u003e If you're creating a project without using the Spin template, add a reference the Spin SDK with the command\n\u003e `dotnet add package Fermyon.Spin.Sdk --prerelease`\n\n### Handling HTTP requests\n\nYour .NET project should contain a method with the `Fermyon.Spin.Sdk.HttpHandler` attribute.\nThis method must be `static`, and must take one argument of type `Fermyon.Spin.Sdk.HttpRequest`\nand return a `Fermyon.Spin.Sdk.HttpResponse`.\n\n```csharp\nusing Fermyon.Spin.Sdk;\n\npublic static class MyHandler\n{\n    [HttpHandler]\n    public static HttpResponse HandleHttpRequest(HttpRequest request)\n    {\n        // ...\n    }\n}\n```\n\nYour `spin.toml` file should reference the compiled Wasm file built from the project.\n\n```toml\n[component.test]\nsource = \"bin/Release/net8.0/MyApplication.wasm\"\n```\n\n### Making outbound HTTP requests\n\nTo make outbound HTTP requests, use the `HttpOutbound.Send()` method.\n\nFor an example of constructing an outbound request, see the `UseOutboundHttp` method\nin the `hello-world` sample.\n\n### Making Redis requests\n\nTo make outbound Redis requests, use the methods of the `RedisOutbound` class -\n`Get`, `Set` and `Publish`.\n\nFor examples of making Redis requests, see the `UseRedis` method\nin the `hello-world` sample.\n\n### Working with Postgres\n\nTo access Postgres databases, use the methods of the `PostgresOutbound` class -\n`Query` for statements that return database values (`SELECT`), and `Execute`\nfor statements that modify the database (`INSERT`, `UPDATE`, `DELETE`).\n\nFor examples of making Postgres requests, see the `UsePostgresQuery` and\n`UsePostgresExec` methods in the `hello-world` sample, or see the\n`Fermyon.PetStore` sample.\n\n### Accessing Spin configuration\n\nTo access Spin configuration, use the `SpinConfig.Get()` method.\n\n\u003e It is not expected that a Spin component will try to access config entries\n\u003e that don't exist. At the moment, the only way to detect if a config setting\n\u003e is missing is to catch the exception from `Get`.\n\nFor examples of accessing configuration, see the samples.\n\n### Working with Buffers\n\nBoth HTTP and Redis represent payload blobs using the `Buffer` type, and Postgres also\nuses `Buffer` for values of `binary` (aka 'blob') type. Buffer represents\nan unmanaged span of Wasm linear memory.  The SDK provides several convenience methods\nto make it easier to work with.  For example:\n\n* Use `HttpRequest.Body.AsString()` and `HttpRequest.Body.AsBytes()` to read a request\n  body as text or a binary blob.\n* Use `Buffer.ToUTF8String()` to read an arbitrary Buffer as string.\n* Use `HttpResponse.BodyAsString` and `HttpResponse.BodyAsBytes` to set the body of\n  a HTTP response.\n* Use `Buffer.FromString()` to write a string into a buffer using the UTF-8 encoding.\n* Use `Buffer.FromBytes()` to write any sequence of bytes into a buffer.\n\n### Fast startup using Wizer\n\nIf your project file (`.csproj`) contains `\u003cUseWizer\u003etrue\u003c/UseWizer\u003e`, then `dotnet build`\nwill run [Wizer](https://github.com/bytecodealliance/wizer) to pre-initialise your\nWasm file.  Wizer will run a request through your application _at compile time_ and snapshot\nthe state of your Wasm module at the end of the request.  This means that the resulting\nWasm module contains the .NET runtime in a state where it is already loaded (and the\ninterpreter has already seen your code), saving startup time when a request comes in at runtime.\n\n\u003e You must run install [Wizer](https://github.com/bytecodealliance/wizer/releases) and place\n\u003e it on your path (or run `make bootstrap`).\n\nUsing Wizer has certain observable impacts:\n\n* You should not (and in some cases cannot) call external services from the warmup request\n  handler.  If your handler talks to HTTP or Redis, you _must skip those calls at warmup time_.\n  If the warmup code fails, then the build will fail.\n* Static constructors and static member initialisation happens at warmup time (at least for\n  any type used on the warmup path).  For example, if your handler type has a static\n  `Random` member, and this gets initialised during warmup, then _the same state of the random\n  number generator_ will be used in all requests!\n\nYou can identify if a request is the warmup request because the URL will be `/warmupz`.\nYou can override this in the `HttpHandler` attribute.  However, it is not currently possible\nto have Wizer initialise the runtime but omit calling your handler.\n\nIf your handler logic doesn't require any external services then you don't need any special\nwarmup handling.  Otherwise, you'll need to guard those calls, or skip your real handler\naltogether, e.g.:\n\n```csharp\n[HttpHandler]\npublic static HttpResponse HandleHttpRequest(HttpRequest request)\n{\n    if (request.Url == Warmup.DefaultWarmupUrl)\n    {\n        return new HttpResponse\n        {\n            StatusCode = HttpStatusCode.OK,\n            Headers = new Dictionary\u003cstring, string\u003e\n            {\n                { \"Content-Type\", \"text/plain\" },\n            },\n            BodyAsString = \"warmup\",\n        };\n    }\n\n    // ... real handler goes here ...\n}\n```\n\n## Known issues\n\nThe Spin .NET SDK is a preview, built on an implementation of .NET that is currently experimental.\nThere are several known issues, of which the most severe are:\n\n* Some static methods and properties cause a \"indirect call type mismatch\" error when Wizer is turned\n  on - we have seen this on numeric parse methods and `StringComparer` properties.\n  You can work around this by turning Wizer off for affected modules. To do this, change\n  `\u003cUseWizer\u003etrue\u003c/UseWizer\u003e` in the `.csproj` to `\u003cUseWizer\u003efalse\u003c/UseWizer\u003e`.\n* In some cases, unhandled exceptions also cause \"indirect call type mismatch\" instead of being\n  returned as 500 Internal Server Error responses. You can work around this by catching problematic\n  exceptions and returning error responses manually.\n\nYou can track issues or report problems at https://github.com/fermyon/spin-dotnet-sdk/issues.\n\n## What's next\n\nThe initial version of the SDK closely mirrors the underlying low-level Spin interop interfaces.\nThis maximises performance but doesn't provide an idiomatic experience for .NET developers.\nWe'll be aiming to improve that over future releases, and welcome contributions or suggestions!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspinframework%2Fspin-dotnet-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspinframework%2Fspin-dotnet-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspinframework%2Fspin-dotnet-sdk/lists"}