{"id":19454608,"url":"https://github.com/fauna/fauna-dotnet","last_synced_at":"2026-02-16T19:39:08.029Z","repository":{"id":222158025,"uuid":"721381374","full_name":"fauna/fauna-dotnet","owner":"fauna","description":"Fauna FQL v10 driver for C#","archived":false,"fork":false,"pushed_at":"2025-01-28T15:00:22.000Z","size":6636,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-07-21T07:32:00.440Z","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":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fauna.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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":"2023-11-21T00:13:54.000Z","updated_at":"2025-01-28T15:00:25.000Z","dependencies_parsed_at":"2024-12-12T23:22:45.845Z","dependency_job_id":"3922c51b-298d-4e0b-9148-11276a499684","html_url":"https://github.com/fauna/fauna-dotnet","commit_stats":null,"previous_names":["fauna/fauna-dotnet"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/fauna/fauna-dotnet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fauna","download_url":"https://codeload.github.com/fauna/fauna-dotnet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fauna%2Ffauna-dotnet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29516176,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T18:37:19.720Z","status":"ssl_error","status_checked_at":"2026-02-16T18:36:46.920Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":"2024-11-10T17:10:25.724Z","updated_at":"2026-02-16T19:39:08.012Z","avatar_url":"https://github.com/fauna.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Official .NET Driver for [Fauna v10](https://fauna.com/) (current)\n\nThis driver can only be used with FQL v10, and is not compatible with earlier versions of FQL. To query your databases with earlier API versions, see [faunadb-csharp](https://github.com/fauna/faunadb-csharp).\n\nSee the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additional information about how to configure and query your databases.\n\n## Features\n\n- Injection-safe query composition with interpolated string templates\n- POCO-based data mapping\n- Async LINQ API for type-safe querying\n\n## Compatibility\n\n- C# ^10.0\n- .NET 8.0\n\n## Installation\n\nUsing the .NET CLI:\n\n```\ndotnet add package Fauna\n```\n\n## API reference\n\nAPI reference documentation for the driver is available at\nhttps://fauna.github.io/fauna-dotnet/. The docs are generated using\n[Doxygen](https://www.doxygen.nl/).\n\n\n## Basic usage\n\n```csharp\nusing Fauna;\nusing Fauna.Exceptions;\nusing static Fauna.Query;\n\nclass Basics\n{\n    static async Task Main()\n    {\n        try\n        {\n            // The client's authentication secret\n            // defaults to the `FAUNA_SECRET` env var.\n            var client = new Client();\n\n            var hi = \"Hello, Fauna!\";\n\n            // The FQL template function safely interpolates values.\n            var helloQuery = FQL($@\"\n                let x = {hi}\n                x\");\n\n            // Optionally specify the expected result type as a type parameter.\n            // If not provided, the value will be deserialized as object?\n            var hello = await client.QueryAsync\u003cstring\u003e(helloQuery);\n\n            Console.WriteLine(hello.Data); // Hello, Fauna!\n            Console.WriteLine(hello.Stats.ToString()); // compute: 1, read: 0, write: 0, ...\n\n            var peopleQuery = FQL($@\"Person.all() {{ first_name }}\");\n\n            // PaginateAsync returns an IAsyncEnumerable of pages\n            var people = client.PaginateAsync\u003cDictionary\u003cstring, object?\u003e\u003e(peopleQuery);\n\n            await foreach (var page in people)\n            {\n                foreach (var person in page.Data)\n                {\n                    Console.WriteLine($\"Hello, {person[\"first_name\"]}!\"); // Hello, John! ...\n                }\n            }\n        }\n        catch (FaunaException e)\n        {\n            // Handle exceptions\n        }\n    }\n}\n```\n\n## Writing more complex queries\n\nThe FQL template DSL supports arbitrary composition of subqueries along with values.\n\n```csharp\nvar client = new Client();\n\nvar predicate = args[0] switch {\n    \"first\" =\u003e FQL($\".first_name == {args[1]}\"),\n    \"last\"  =\u003e FQL($\".last_name\" == {args[1]}),\n    _       =\u003e throw ArgumentException(),\n};\n\n// Single braces are for template variables, so escape them with double braces.\nvar getPerson = FQL($\"Person.firstWhere({predicate}) {{ id, first_name, last_name }}\");\n\n// Documents can be mapped to Dictionaries as well as POCOs (see below)\nvar result = await client.QueryAsync\u003cDictionary\u003cstring, object?\u003e\u003e(getPerson);\n\nConsole.WriteLine(result.Data[\"id\"]);\nConsole.WriteLine(result.Data[\"first_name\"]);\nConsole.WriteLine(result.Data[\"last_name\"]);\n```\n\n## Database contexts and POCO data mapping\n\nFauna.Mapping.Attributes and the Fauna.DataContext class provide the ability to bring your Fauna database schema into your code.\n\n### POCO Mapping\n\nYou can use attributes to map a POCO class to a Fauna document or object shape:\n\n* `[Id]`: Should only be used once per class  on a field that represents the Fauna document ID. It's not encoded unless the isClientGenerated flag is true.\n* `[Ts]`: Should only be used once per class on a field that represents the timestamp of a document. It's not encoded.\n* `[Collection]`: Typically goes unmodeled. Should only be used once per class on a field that represents the collection field of a document. It will never be encoded.\n* `[Field]`: Can be associated with any field to override its name in Fauna.\n* `[Ignore]`: Can be used to ignore fields during encoding and decoding.\n\n```csharp\nusing Fauna.Mapping;\n\nclass Person\n{\n    // Property names are automatically converted to camelCase.\n    [Id]\n    public string? Id { get; set; }\n\n    // Manually specify a name by providing a string.\n    [Field(\"first_name\")]\n    public string? FirstName { get; set; }\n\n    [Field(\"last_name\")]\n    public string? LastName { get; set; }\n\n    public int Age { get; set; }\n}\n```\n\nYour POCO classes can be used to drive deserialization:\n\n```csharp\nvar peopleQuery = FQL($@\"Person.all()\");\nvar people = client.PaginateAsync\u003cPerson\u003e(peopleQuery).FlattenAsync();\n\nawait foreach (var p in people)\n{\n    Console.WriteLine($\"{p.FirstName} {p.LastName}\");\n}\n```\n\nAs well as to write to your database:\n\n```csharp\nvar person = new Person { FirstName = \"John\", LastName = \"Smith\", Age = 42 };\n\nvar result = await client.QueryAsync($@\"Person.create({person}).id\");\nConsole.WriteLine(result.Data); // 69219723210223...\n```\n\n### DataContext\n\nThe DataContext class provides a schema-aware view of your database. Subclass it and configure your collections:\n\n```csharp\nclass PersonDb : DataContext\n{\n    public class PersonCollection : Collection\u003cPerson\u003e\n    {\n        public Index\u003cPerson\u003e ByFirstName(string first) =\u003e Index().Call(first);\n        public Index\u003cPerson\u003e ByLastName(string last) =\u003e Index().Call(last);\n    }\n\n    public PersonCollection Person { get =\u003e GetCollection\u003cPersonCollection\u003e(); }\n    public int AddTwo(int val) =\u003e Fn\u003cint\u003e().Call(val);\n    public async Task\u003cint\u003e TimesTwo(int val) =\u003e await Fn\u003cint\u003e(\"MultiplyByTwo\").CallAsync(val);\n}\n```\n\nDataContext provides Client querying which automatically maps your collections' documents to their POCO equivalents even when type hints are not provided.\n\n```csharp\nvar db = client.DataContext\u003cPersonDb\u003e\n\nvar result = db.QueryAsync($\"Person.all().first()\");\nvar person = (Person)result.Data!;\n\nConsole.WriteLine(person.FirstName);\n```\n\n### LINQ-based queries (preview)\n\n\u003e [!IMPORTANT]\n\u003e This functionality is in preview and may change in future releases.\n\nDataContext provides a LINQ-compatible API for type-safe querying.\n\n```csharp\n// general query\ndb.Person.Where(p =\u003e p.FirstName == \"John\")\n         .Select(p =\u003e new { p.FirstName, p.LastName })\n         .First();\n\n// or start with an index\ndb.Person.ByFirstName(\"John\")\n         .Select(p =\u003e new { p.FirstName, p.LastName })\n         .First();\n```\n\nThere are async variants of methods which execute queries:\n\n```csharp\nvar syncCount = db.Person.Count();\nvar asyncCount = await db.Person.CountAsync();\n```\n\n## Paginating [Fauna Sets](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/)\n\nWhen you wish to paginate a Set, such as a Collection or Index, use `PaginateAsync`.\n\nExample of a query that returns a Set:\n```csharp\nvar query = FQL($\"Person.all()\");\nawait foreach (var page in client.PaginateAsync\u003cPerson\u003e(query))\n{\n    // handle each page\n}\n\nawait foreach (var item in client.PaginateAsync\u003cPerson\u003e(query).FlattenAsync())\n{\n    // handle each item\n}\n```\n\nExample of a query that returns an object with an embedded Set:\n```csharp\nclass MyResult\n{\n    [Field(\"users\")]\n    public Page\u003cPerson\u003e? Users { get; set; }\n}\n\nvar query = FQL($\"{{users: Person.all()}}\");\nvar result = await client.QueryAsync\u003cMyResult\u003e(query);\n\nawait foreach (var page in client.PaginateAsync(result.Data.Users!))\n{\n    // handle each page\n}\n\nawait foreach (var item in client.PaginateAsync(result.Data.Users!).FlattenAsync())\n{\n    // handle each item\n}\n```\n\n## Null Documents\nA null document ([NullDoc](https://docs.fauna.com/fauna/current/reference/fql_reference/types#nulldoc)) can be handled two ways.\n\nOption 1, you can let the driver throw an exception and do something with it.\n```csharp\ntry {\n    await client.QueryAsync\u003cSomeCollDoc\u003e(FQL($\"SomeColl.byId('123')\"))\n} catch (NullDocumentException e) {\n    Console.WriteLine(e.Id); // \"123\"\n    Console.WriteLine(e.Collection.Name); // \"SomeColl\"\n    Console.WriteLine(e.Cause); // \"not found\"\n}\n```\n\nOption 2, you wrap your expected type in a Ref\u003c\u003e or NamedRef\u003c\u003e. Supported types are Dictionary\u003cstring,object\u003e and POCOs.\n```csharp\nvar q = FQL($\"Collection.byName('Fake')\");\nvar r = (await client.QueryAsync\u003cNamedRef\u003cDictionary\u003cstring,object\u003e\u003e\u003e(q)).Data;\nif (r.Data.Exists) {\n    Console.WriteLine(d.Id); // \"Fake\"\n    Console.WriteLine(d.Collection.Name); // \"Collection\"\n    var doc = r.Get(); // A dictionary with id, coll, ts, and any user-defined fields.\n} else {\n    Console.WriteLine(d.Name); // \"Fake\"\n    Console.WriteLine(d.Collection.Name); // \"Collection\"\n    Console.WriteLine(d.Cause); // \"not found\"\n    r.Get() // this throws a NullDocumentException\n}\n\n```\n\n## Event feeds (beta)\n\nThe driver supports [event\nfeeds](https://docs.fauna.com/fauna/current/learn/cdc/#event-feeds).\n\nAn event feed asynchronously polls an [event\nsource](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source)\nfor events.\n\nTo get paginated events, pass an [event\nsource](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source)\nor a query that produces an event source to `EventFeedAsync()`:\n\n```csharp\n// Get an event source from a supported Set\nEventSource eventSource = await client.QueryAsync\u003cEventSource\u003e(FQL($\"Person.all().eventSource()\"));\n\n// Calculate timestamp for 10 minutes ago in microseconds\nlong tenMinutesAgo = DateTimeOffset.UtcNow.AddMinutes(-10).ToUnixTimeMilliseconds() * 1000;\nvar feedOptions = new FeedOptions(startTs: tenMinutesAgo, pageSize: 10);\n\n// Pass the event source and `FeedOptions` to `EventFeedAsync()`:\nvar feed = await client.EventFeedAsync\u003cPerson\u003e(eventSource, feedOptions);\n\n// You can also pass a query that produces an event source directly to `EventFeedAsync()`:\nvar feedFromQuery = await client.EventFeedAsync\u003cPerson\u003e(FQL($\"Person.all().eventsOn({{ .price, .stock }})\"), feedOptions);\n\n// EventFeedAsync() returns a `FeedEnumerable` instance that can act as an `AsyncEnumerator`.\n// Use `foreach()` to iterate through the pages of events.\nawait foreach (var page in feed)\n{\n    foreach (var evt in page.Events)\n    {\n        Console.WriteLine($\"Event Type: {evt.Type}\");\n        Person person = evt.Data;\n        Console.WriteLine($\"First Name: {person.FirstName} - Last Name: {person.LastName} - Age: {person.Age}\");\n    }\n}\n```\n\n## Event streams\n\nThe driver supports [event streams](https://docs.fauna.com/fauna/current/learn/cdc/#event-streaming).\n\nTo start and subscribe to an event stream, pass a query that produces an [event\nsource](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source)\nto `EventStreamAsync()`:\n\n```csharp\nvar stream = await client.EventStreamAsync\u003cPerson\u003e(FQL($\"Person.all().eventSource()\"));\nawait foreach (var evt in stream)\n{\n    Console.WriteLine($\"Received Event Type: {evt.Type}\");\n    if (evt.Data != null) // Status events won't have Data\n    {\n        Person person = evt.Data;\n        Console.WriteLine($\"First Name: {person.FirstName} - Last Name: {person.LastName} - Age: {person.Age}\");\n    }\n}\n```\n\n## Debug logging\n\nTo enable debug logging, set the `FAUNA_DEBUG` environment variable to an integer for the `Microsoft.Extensions.Logging.LogLevel`. For example:\n\n* `0`: `LogLevel.Trace` and higher (all messages)\n* `3`: `LogLevel.Warning` and higher\n\nThe driver logs HTTP request and response details, including headers. For security, the `Authorization` header is redacted in debug logs but is visible in trace logs.\n\n\u003e [!NOTE]\n\u003e As of v1.0.0, the driver only outputs `LogLevel.Debug` messages. Use `0` (Trace) or `1` (Debug) to log these messages.\n\nFor advanced logging, you can use a custom `ILogger` implementation, such as Serilog or NLog. Pass the implementation to the `Configuration` class when instantiating a `Client`.\n\n### Basic example: Serilog\n\nInstall the packages:\n```\n$ dotnet add package Serilog\n$ dotnet add package Serilog.Extensions.Logging\n$ dotnet add package Serilog.Sinks.Console\n$ dotnet add package Serilog.Sinks.File\n```\n\nConfigure and use the logger:\n```csharp\nusing Fauna;\nusing Microsoft.Extensions.Logging;\nusing Serilog;\nusing static Fauna.Query;\n\nLog.Logger = new LoggerConfiguration()\n    .MinimumLevel.Verbose()\n    .WriteTo.Console()\n    .WriteTo.File(\"log.txt\",\n        rollingInterval: RollingInterval.Day,\n        rollOnFileSizeLimit: true)\n    .CreateLogger();\n\nvar logFactory = new LoggerFactory().AddSerilog(Log.Logger);\n\nvar config = new Configuration(\"mysecret\", logger: logFactory.CreateLogger(\"myapp\"));\n\nvar client = new Client(config);\n\nawait client.QueryAsync(FQL($\"1+1\"));\n\n// You should see LogLevel.Debug messages in both the Console and the \"log{date}.txt\" file\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffauna%2Ffauna-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffauna%2Ffauna-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffauna%2Ffauna-dotnet/lists"}