FQL v4 will be decommissioned on June 30, 2025. Ensure that you complete your migration from FQL v4 to FQL v10 by that date. For more details, review the migration guide. Contact support@fauna.com with any questions. |
C# driver
The Fauna open source C# driver provides the resources required to interact with Fauna for C# and Mono developers.
Current stable version |
4.2.0 |
Repository |
This section provides a high-level overview of working with the driver. For details on the driver API, see its documentation.
Installation
Install the Nuget package by adding the package reference to your MSBuild project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FaunaDB.Client" Version="0.1.0-beta" />
</ItemGroup>
</Project>
or by using your IDE and searching for FaunaDB.Client
.
Usage
Here is an example demonstrating how to use the C# driver to execute a simple query on Fauna:
Use the correct endpoint value for the Region Group for your database. |
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FaunaDB.Client;
using FaunaDB.Types;
using static FaunaDB.Query.Language;
namespace FaunaDBProject
{
class FaunaDBHelloWorld
{
static readonly string ENDPOINT = "https://db.fauna.com:443";
// NOTE: use the correct endpoint for your database's Region Group.
static readonly string SECRET = "<<YOUR-SECRET-HERE>>";
static void ProcessData(Value[] values)
{
foreach (Value value in values)
{
//do something
}
}
static async Task DoQuery(FaunaClient client)
{
Value result = await client.Query(Paginate(Match(Index("spells"))));
IResult<Value[]> data = result.At("data").To<Value[]>();
data.Match(
Success: value => ProcessData(value),
Failure: reason => Console.WriteLine($"Something went wrong: {reason}")
);
}
public static void Main(string[] args)
{
var client = new FaunaClient(endpoint: ENDPOINT, secret: SECRET);
DoQuery(client).Wait();
}
}
}
How to instantiate a Fauna FaunaClient
var client = new FaunaClient(
endpoint: ENDPOINT,
secret: SECRET,
httpClient: HTTP_CLIENT,
timeout: TIMEOUT
);
secret
is the only required argument. All other arguments are optional.
You can also pass a custom HttpClient
when creating a new
FaunaClient
:
// using System.Net.Http;
var http = new HttpClient();
// The default request headers can be any string values,
// but should be specific to your application.
http.DefaultRequestHeaders.Add("X-Custom-Header", "42");
http.Timeout = TimeSpan.FromSeconds(15);
var client = new FaunaClient(
"secret",
"http://localhost:9090/",
httpClient: http
);
See Connections for more details on creating client connections.
How to execute a query
Value result = await client.Query(Paginate(Match(Index("spells"))));
The Query
method receives an Expr
object. Expr
objects can be
composed with others Expr
to create complex query objects.
FaunaDB.Query.Language
is a helper class where you can find all
available expressions in the library.
You can also pass a TimeSpan queryTimeout
argument as a second
parameter when calling Query
:
Value result = await client.Query(
Paginate(Match(Index("spells"))),
TimeSpan.FromSeconds(42)
);
The queryTimeout
has a resolution of milliseconds. When the timeout
period has elapsed, the server terminates the query and returns an
error.
How to access objects fields and convert to primitive values
Objects fields are accessed through At
methods of Value
class. It is
possible to access fields by names if the value represents an object or
by index if it represents an array. Also, it is possible to convert
Value
class to its primitive correspondent using To
methods
specifying a type.
IResult<Value[]> data = result.At("data").To<Value[]>();
How work with IResult<T>
objects
This object represents the result of an operation and it might be success or a failure. All conversion operations returns an object like this. This way you can avoid checking for null-ability everywhere in the code.
data.Match(
Success: value => ProcessData(value),
Failure: reason => Console.WriteLine($"Something went wrong: {reason}")
);
Optionally, you can transform one IResult<T>
into another IResult<U>
of different type using Map
and FlatMap
.
IResult<int> result = <<...>>;
IResult<string> result.Map(value => value.toString());
If result
represents an failure all calls to Map
and FlatMap
are
ignored. See FaunaDB.Types.Result
.
How to work with user-defined classes
Instead of manually creating your objects using the DSL (for example,
the Obj()
method), you may use the Encoder
class to convert a
user-defined type into the equivalent Value
type.
For example:
class Product
{
[FaunaField("description")]
public string Description { get; set; }
[FaunaField("price")]
public double Price { get; set; }
[FaunaConstructor]
public Product(string description, double price)
{
Description = description;
Price = price;
}
}
To persist an instance of Product
in Fauna:
Product product = new Product("Smartphone", 649.90);
await client.Query(
Create(
Collection("product"),
Obj("data", Encoder.Encode(product))
)
);
To convert from a Value
type back to the Product
type, you can use a
Decoder
:
Value value = await client.Query(Get(Ref(Collection("product"), "123456789")));
Product product = Decoder.Decode<Product>(value.At("data"));
or using the To<T>()
helper method:
Value value = await client.Query(Get(Ref(Collection("product"), "123456789")));
IResult<Product> product = value.At("data").To<Product>();
product.Match(
Success: p => Console.WriteLine("Product loaded: {0}", p.Description),
Failure: reason => Console.WriteLine($"Something went wrong: {reason}")
);
// or even:
Product productLoaded = value.At("data").To<Product>().Value;
Console.WriteLine("Product loaded: {0}", prod.Description);
Note that in this case the return type is IResult<T>
.
There are three attributes that can be used to change the behavior of
the Encoder
and Decoder
:
-
FaunaField
: Used to override a custom field name and/or specify a default value for that field. If this attribute is not provided, the member name is used instead. Can be used on fields, properties and constructor arguments. -
FaunaConstructor
: Used to mark a constructor or a public static method as the method used to instantiate the type. This attribute can be used only once per class. -
FaunaIgnore
: Used to ignore a member. Can be used on fields, properties and constructors arguments. If used on a constructor argument, that argument must have a default value.
Encoder
and Decoder
can currently convert:
-
Primitive scalar types (
int
,long
,string
, and others) -
Primitive arrays, generic collections such as
List<T>
, and their interfaces such asIList<T>
. -
Dictionaries with string keys, such as
Dictionary<string, T>
and its interfaceIDictionary<string, T>
.
Event streaming
This section demonstrates how to subscribe to change events.
The streaming API is built using the Observer pattern, which enables a
subscriber to register with and get notifications from a provider. The
provider is implemented in the StreamingEventHandler
class, and the
subscriber is implemented in the StreamingEventMonitor
class.
There are two kinds of event streaming:
The code required to subscribe to each type is similar. The main difference is the type of Reference involved in the subscription, and the kinds of events that are included in the stream.
There is a cost in compute operations to hold a stream open, or to repeatedly start a stream that fails. See Billing for details. |
Document streaming
The following example subscribes to change events for a document:
Before you run the example:
-
Set the
FAUNADB_SECRET
environment variable, and optionally theFAUNADB_ENDPOINT
environment variable (if you are using Region Groups or Fauna Dev). -
The collection
Scores
must exist.
Once the example is running, you can use the Fauna Dashboard, or another client application, to create or update the target document and watch the events arrive as the changes are made.
For example, if the document does not yet exist, you could run this query in the Fauna Dashboard Shell:
Create(Ref(Collection("Scores"), "1"), { data: { scores: [1, 2, 3] }})
Once the document exists, you could run this query:
Update(Ref(Collection("Scores"), "1"), { data: { scores: [5, 2, 3] }})
The streaming example waits indefinitely for events. Use Ctrl+C to terminate the program.
You can also extend a base class instead of passing lambda functions:
private class MyStreamingMonitor : StreamingEventMonitor
{
// optionally override OnNext event
public override void OnNext(Value value)
{
// process your event
RequestData();
}
// optionally override OnError event
public override void OnError(Exception error)
{
// process an error
}
// optionally override OnCompleted event
public override void OnCompleted()
{
// process completion event
}
}
// creating a subscriber
var monitor = new MyStreamingMonitor();
// subscribe to data provider
monitor.Subscribe(provider);
// clear the subscription
monitor.Unsubscribe();
Set streaming
The following example subscribes to change events for a set:
Before you run the example:
-
Set the
FAUNADB_SECRET
environment variable, and optionally theFAUNADB_ENDPOINT
environment variable (if you are using Region Groups or Fauna Dev). -
The collection
Scores
must exist.
Once the example is running, you can use the Fauna Dashboard, or another client application, to add or delete documents in the "Scores" collection and watch the events arrive as the changes are made. For example, you could run this query in the Fauna Dashboard's Shell:
Create(Collection("Scores"), { data: { scores: [5, 6, 7] }})
The streaming example waits indefinitely for events. Use Ctrl+C to terminate the program.
You can also extend a base class instead of passing lambda functions:
private class MyStreamingMonitor : StreamingEventMonitor
{
// optionally override OnNext event
public override void OnNext(Value value)
{
// process your event
RequestData();
}
// optionally override OnError event
public override void OnError(Exception error)
{
// process an error
}
// optionally override OnCompleted event
public override void OnCompleted()
{
// process completion event
}
}
// creating a subscriber
var monitor = new MyStreamingMonitor();
// subscribe to data provider
monitor.Subscribe(provider);
// clear the subscription
monitor.Unsubscribe();
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!