Dotnet

by appwriteab3c90b37c95No license10 starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 7 weeks ago

Appwrite .NET SDK skill. Use when building server-side C# or .NET applications with Appwrite, including ASP.NET and Blazor integrations. Covers user management, database/table CRUD, file storage, and functions via API keys.

Instructions onlySoftware Development
AI-generated overview

Reference for building server-side C#/.NET apps with the Appwrite SDK, covering users, tables, storage, teams, functions and SSR auth.

What it does
Provides C# code examples and guidance for using the Appwrite .NET SDK: client setup, user management, table and row CRUD with query helpers, file storage, teams and memberships, serverless functions, and SSR authentication for ASP.NET and Blazor. It also documents string column types, error handling, and permission and role strings. The deliverable is reference documentation and snippets rather than generated files.
When to use it
Use when writing or reviewing server-side C# or .NET code that integrates Appwrite, including ASP.NET and Blazor server-rendered authentication flows. Also useful when choosing column types, building queries, or setting row and file permissions.
Requirements
No scripts are shipped; it is instructions only. Using the examples requires the .NET SDK and the Appwrite NuGet package, an Appwrite endpoint, project ID, and API key or session cookie, plus network access to the Appwrite instance.

Appwrite .NET SDK

Installation

bash
dotnet add package Appwrite

Setting Up the Client

csharp
using Appwrite;using Appwrite.Services;using Appwrite.Models;
var client = new Client()    .SetEndpoint("https://<REGION>.cloud.appwrite.io/v1")    .SetProject(Environment.GetEnvironmentVariable("APPWRITE_PROJECT_ID"))    .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"));

Code Examples

User Management

csharp
var users = new Users(client);
// Create uservar user = await users.Create(ID.Unique(), "[email protected]", null, "password123", "User Name");
// List usersvar list = await users.List(new List<string> { Query.Limit(25) });
// Get uservar fetched = await users.Get("[USER_ID]");
// Delete userawait users.Delete("[USER_ID]");

Database Operations

Note: Use TablesDB (not the deprecated Databases class) for all new code. Only use Databases if the existing codebase already relies on it or the user explicitly requests it.

Tip: Prefer named arguments (e.g., databaseId: "...") for all SDK method calls. Only use positional arguments if the existing codebase already uses them or the user explicitly requests it.

csharp
var tablesDB = new TablesDB(client);
// Create databasevar db = await tablesDB.Create(ID.Unique(), "My Database");
// Create rowvar doc = await tablesDB.CreateRow("[DATABASE_ID]", "[TABLE_ID]", ID.Unique(),    new Dictionary<string, object> { { "title", "Hello World" } });
// Query rowsvar results = await tablesDB.ListRows("[DATABASE_ID]", "[TABLE_ID]",    new List<string> { Query.Equal("title", "Hello World"), Query.Limit(10) });
// Get rowvar row = await tablesDB.GetRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]");
// Update rowawait tablesDB.UpdateRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]",    new Dictionary<string, object> { { "title", "Updated" } });
// Delete rowawait tablesDB.DeleteRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]");
String Column Types

Note: The legacy string type is deprecated. Use explicit column types for all new columns.

TypeMax charactersIndexingStorage
varchar16,383Full index (if size ≤ 768)Inline in row
text16,383Prefix onlyOff-page
mediumtext4,194,303Prefix onlyOff-page
longtext1,073,741,823Prefix onlyOff-page
  • varchar is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers.
  • text, mediumtext, and longtext are stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget. size is not required for these types.
csharp
// Create table with explicit string column typesawait tablesDB.CreateTable("[DATABASE_ID]", ID.Unique(), "articles",    new List<object> {        new { key = "title",    type = "varchar",    size = 255, required = true  },  // inline, fully indexable        new { key = "summary",  type = "text",                   required = false },  // off-page, prefix index only        new { key = "body",     type = "mediumtext",             required = false },  // up to ~4 M chars        new { key = "raw_data", type = "longtext",               required = false },  // up to ~1 B chars    });

Query Methods

csharp
// FilteringQuery.Equal("field", "value")             // == (or pass array for IN)Query.NotEqual("field", "value")          // !=Query.LessThan("field", 100)             // <Query.LessThanEqual("field", 100)        // <=Query.GreaterThan("field", 100)          // >Query.GreaterThanEqual("field", 100)     // >=Query.Between("field", 1, 100)           // 1 <= field <= 100Query.IsNull("field")                    // is nullQuery.IsNotNull("field")                 // is not nullQuery.StartsWith("field", "prefix")      // starts withQuery.EndsWith("field", "suffix")        // ends withQuery.Contains("field", "sub")           // containsQuery.Search("field", "keywords")        // full-text search (requires index)
// SortingQuery.OrderAsc("field")Query.OrderDesc("field")
// PaginationQuery.Limit(25)                          // max rows (default 25, max 100)Query.Offset(0)                          // skip N rowsQuery.CursorAfter("[ROW_ID]")            // cursor pagination (preferred)Query.CursorBefore("[ROW_ID]")
// Selection & LogicQuery.Select(new List<string> { "field1", "field2" })Query.Or(new List<string> { Query.Equal("a", 1), Query.Equal("b", 2) })   // ORQuery.And(new List<string> { Query.GreaterThan("age", 18), Query.LessThan("age", 65) })  // AND (default)

File Storage

csharp
var storage = new Storage(client);
// Upload filevar file = await storage.CreateFile("[BUCKET_ID]", ID.Unique(), InputFile.FromPath("/path/to/file.png"));
// List filesvar files = await storage.ListFiles("[BUCKET_ID]");
// Delete fileawait storage.DeleteFile("[BUCKET_ID]", "[FILE_ID]");
InputFile Factory Methods
csharp
using Appwrite.Models;
InputFile.FromPath("/path/to/file.png")                          // from filesystem pathInputFile.FromBytes(byteArray, "file.png", "image/png")          // from byte[]InputFile.FromStream(stream, "file.png", "image/png", size)      // from Stream (size required)

Teams

csharp
var teams = new Teams(client);
// Create teamvar team = await teams.Create(ID.Unique(), "Engineering");
// List teamsvar list = await teams.List();
// Create membership (invite user by email)var membership = await teams.CreateMembership(    teamId: "[TEAM_ID]",    roles: new List<string> { "editor" },    email: "[email protected]");
// List membershipsvar members = await teams.ListMemberships("[TEAM_ID]");
// Update membership rolesawait teams.UpdateMembership("[TEAM_ID]", "[MEMBERSHIP_ID]", new List<string> { "admin" });
// Delete teamawait teams.Delete("[TEAM_ID]");

Role-based access: Use Role.Team("[TEAM_ID]") for all team members or Role.Team("[TEAM_ID]", "editor") for a specific team role when setting permissions.

Serverless Functions

csharp
var functions = new Functions(client);
// Execute functionvar execution = await functions.CreateExecution("[FUNCTION_ID]", body: "{\"key\": \"value\"}");
// List executionsvar executions = await functions.ListExecutions("[FUNCTION_ID]");
Writing a Function Handler (.NET runtime)
csharp
// src/Main.cs — Appwrite Function entry pointusing System.Text.Json;
public async Task<RuntimeOutput> Main(RuntimeContext context){    // context.Req.Body        — raw body (string)    // context.Req.BodyJson    — parsed JSON (JsonElement)    // context.Req.Headers     — headers (Dictionary)    // context.Req.Method      — HTTP method    // context.Req.Path        — URL path    // context.Req.Query       — query params (Dictionary)
    context.Log($"Processing: {context.Req.Method} {context.Req.Path}");
    if (context.Req.Method == "GET")        return context.Res.Json(new { message = "Hello from Appwrite Function!" });
    return context.Res.Json(new { success = true });      // JSON    // context.Res.Text("Hello");                         // plain text    // context.Res.Empty();                               // 204    // context.Res.Redirect("https://...");               // 302}

Server-Side Rendering (SSR) Authentication

SSR apps using .NET frameworks (ASP.NET, Blazor Server, etc.) use the server SDK to handle auth. You need two clients:

  • Admin client — uses an API key, creates sessions, bypasses rate limits (reusable singleton)
  • Session client — uses a session cookie, acts on behalf of a user (create per-request, never share)
csharp
using Appwrite;using Appwrite.Services;
// Admin client (reusable)var adminClient = new Client()    .SetEndpoint("https://<REGION>.cloud.appwrite.io/v1")    .SetProject("[PROJECT_ID]")    .SetKey(Environment.GetEnvironmentVariable("APPWRITE_API_KEY"));
// Session client (create per-request)var sessionClient = new Client()    .SetEndpoint("https://<REGION>.cloud.appwrite.io/v1")    .SetProject("[PROJECT_ID]");
var session = Request.Cookies["a_session_[PROJECT_ID]"];if (session != null){    sessionClient.SetSession(session);}
Email/Password Login (ASP.NET Minimal API)
csharp
app.MapPost("/login", async (HttpContext ctx, LoginRequest body) =>{    var account = new Account(adminClient);    var session = await account.CreateEmailPasswordSession(body.Email, body.Password);
    // Cookie name must be a_session_<PROJECT_ID>    ctx.Response.Cookies.Append("a_session_[PROJECT_ID]", session.Secret, new CookieOptions    {        HttpOnly = true,        Secure = true,        SameSite = SameSiteMode.Strict,        Path = "/",    });
    return Results.Ok(new { success = true });});
Authenticated Requests
csharp
app.MapGet("/user", async (HttpContext ctx) =>{    var session = ctx.Request.Cookies["a_session_[PROJECT_ID]"];    if (session == null) return Results.Unauthorized();
    var sessionClient = new Client()        .SetEndpoint("https://<REGION>.cloud.appwrite.io/v1")        .SetProject("[PROJECT_ID]")        .SetSession(session);
    var account = new Account(sessionClient);    var user = await account.Get();    return Results.Ok(user);});
OAuth2 SSR Flow
csharp
// Step 1: Redirect to OAuth providerapp.MapGet("/oauth", async () =>{    var account = new Account(adminClient);    var redirectUrl = await account.CreateOAuth2Token(        provider: OAuthProvider.Github,        success: "https://example.com/oauth/success",        failure: "https://example.com/oauth/failure"    );    return Results.Redirect(redirectUrl);});
// Step 2: Handle callback — exchange token for sessionapp.MapGet("/oauth/success", async (HttpContext ctx, string userId, string secret) =>{    var account = new Account(adminClient);    var session = await account.CreateSession(userId, secret);
    ctx.Response.Cookies.Append("a_session_[PROJECT_ID]", session.Secret, new CookieOptions    {        HttpOnly = true, Secure = true, SameSite = SameSiteMode.Strict, Path = "/",    });
    return Results.Ok(new { success = true });});

Cookie security: Always use HttpOnly, Secure, and SameSite = SameSiteMode.Strict to prevent XSS. The cookie name must be a_session_<PROJECT_ID>.

Forwarding user agent: Call sessionClient.SetForwardedUserAgent(ctx.Request.Headers["User-Agent"]) to record the end-user's browser info for debugging and security.

Error Handling

csharp
using Appwrite;
try{    var row = await tablesDB.GetRow("[DATABASE_ID]", "[TABLE_ID]", "[ROW_ID]");}catch (AppwriteException e){    Console.WriteLine(e.Message);    // human-readable message    Console.WriteLine(e.Code);       // HTTP status code (int)    Console.WriteLine(e.Type);       // error type (e.g. "document_not_found")    Console.WriteLine(e.Response);   // full response body}

Common error codes:

CodeMeaning
401Unauthorized — missing or invalid session/API key
403Forbidden — insufficient permissions
404Not found — resource does not exist
409Conflict — duplicate ID or unique constraint
429Rate limited — too many requests

Permissions & Roles (Critical)

Appwrite uses permission strings to control access to resources. Each permission pairs an action (read, update, delete, create, or write which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the row/file level or inherited from the table/bucket settings. Permissions are arrays of strings built with the Permission and Role helpers.

csharp
using Appwrite;// Permission and Role are included in the main namespace

Database Row with Permissions

csharp
var doc = await tablesDB.CreateRow("[DATABASE_ID]", "[TABLE_ID]", ID.Unique(),    new Dictionary<string, object> { { "title", "Hello World" } },    new List<string>    {        Permission.Read(Role.User("[USER_ID]")),     // specific user can read        Permission.Update(Role.User("[USER_ID]")),   // specific user can update        Permission.Read(Role.Team("[TEAM_ID]")),     // all team members can read        Permission.Read(Role.Any()),                 // anyone (including guests) can read    });

File Upload with Permissions

csharp
var file = await storage.CreateFile("[BUCKET_ID]", ID.Unique(),    InputFile.FromPath("/path/to/file.png"),    new List<string>    {        Permission.Read(Role.Any()),        Permission.Update(Role.User("[USER_ID]")),        Permission.Delete(Role.User("[USER_ID]")),    });

When to set permissions: Set row/file-level permissions when you need per-resource access control. If all rows in a table share the same rules, configure permissions at the table/bucket level and leave row permissions empty.

Common mistakes:

  • Forgetting permissions — the resource becomes inaccessible to all users (including the creator)
  • Role.Any() with write/update/delete — allows any user, including unauthenticated guests, to modify or remove the resource
  • Permission.Read(Role.Any()) on sensitive data — makes the resource publicly readable

Source and attribution

Source:appwrite/claude-plugininskills/dotnetat commitab3c90b

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal