C# Client Library
supabaseView on GitHubThis reference documents every object and method available in Supabase's C# library, supabase-csharp. You can use Supabase to interact with your Postgres database, listen to database changes, invoke Deno Edge Functions, build login and user management functionality, and manage large files.
The C# client library is created and maintained by the Supabase community, and is not an official library. Please be tolerant of areas where the library is still being developed, and — as with all the libraries — feel free to contribute wherever you find issues.
Huge thanks to official maintainer, Joseph Schultz. As well as Will Iverson, Ben Randall, and Rhuan Barros for their help.
Installing
Install from NuGet
You can install Supabase package from nuget.org
1dotnet add package supabase-csharpInitializing
Initializing a new client is pretty straightforward. Find your project url and public key from the admin panel and pass it into your client initialization function.
Supabase is heavily dependent on Models deriving from BaseModel. To interact with the API, one must have the associated model (see example) specified.
Leverage Table, PrimaryKey, and Column attributes to specify names of classes/properties that are different from their C# Versions.
12345678910var url = Environment.GetEnvironmentVariable("SUPABASE_URL");var key = Environment.GetEnvironmentVariable("SUPABASE_KEY");var options = new Supabase.SupabaseOptions{    AutoConnectRealtime = true};var supabase = new Supabase.Client(url, key, options);await supabase.InitializeAsync();Fetch data
Performs vertical filtering with SELECT.
- LINQ expressions do not currently support parsing embedded resource columns. For these cases, stringwill need to be used.
- When using string Column Names to select, they must match names in database, not names specified on model properties.
- Additional information on modeling + querying Joins and Inner Joins can be found in the postgrest-csharp README
- By default, Supabase projects will return a maximum of 1,000 rows. This setting can be changed in Project API Settings. It's recommended that you keep it low to limit the payload size of accidental or malicious requests. You can use range()queries to paginate through your data.
- From()can be combined with Modifiers
- From()can be combined with Filters
- If using the Supabase hosted platform apikeyis technically a reserved keyword, since the API gateway will pluck it out for authentication. It should be avoided as a column name.
12345678910111213141516171819// Given the following Model (City.cs)[Table("cities")]class City : BaseModel{    [PrimaryKey("id")]    public int Id { get; set; }    [Column("name")]    public string Name { get; set; }    [Column("country_id")]    public int CountryId { get; set; }    //... etc.}// A result can be fetched like so.var result = await supabase.From<City>().Get();var cities = result.ModelsInsert data
Performs an INSERT into the table.
1234567891011121314151617181920[Table("cities")]class City : BaseModel{    [PrimaryKey("id", false)]    public int Id { get; set; }    [Column("name")]    public string Name { get; set; }    [Column("country_id")]    public int CountryId { get; set; }}var model = new City{  Name = "The Shire",  CountryId = 554};await supabase.From<City>().Insert(model);Update data
Performs an UPDATE on the table.
- Update()is typically called using a model as an argument or from a hydrated model.
12345var update = await supabase  .From<City>()  .Where(x => x.Name == "Auckland")  .Set(x => x.Name, "Middle Earth")  .Update();Upsert data
Performs an UPSERT into the table.
- Primary keys should be included in the data payload in order for an update to work correctly.
- Primary keys must be natural, not surrogate. There are however, workarounds for surrogate primary keys.
1234567var model = new City{  Id = 554,  Name = "Middle Earth"};await supabase.From<City>().Upsert(model);Delete data
Performs a DELETE on the table.
- Delete()should always be combined with Filters to target the item(s) you wish to delete.
1234await supabase  .From<City>()  .Where(x => x.Id == 342)  .Delete();Call a Postgres function
You can call stored procedures as a "Remote Procedure Call".
That's a fancy way of saying that you can put some logic into your database then call it from anywhere. It's especially useful when the logic rarely changes - like password resets and updates.
1await supabase.Rpc("hello_world", null);Using filters
Filters allow you to only return rows that match certain conditions.
Filters can be used on Select(), Update(), and Delete() queries.
Note: LINQ expressions do not currently support parsing embedded resource columns. For these cases, string will need to be used.
1234var result = await supabase.From<City>()      .Select(x => new object[] { x.Name, x.CountryId })      .Where(x => x.Name == "The Shire")      .Single();Column is equal to a value
Finds all rows whose value on the stated column exactly matches the specified value.
123var result = await supabase.From<City>()  .Where(x => x.Name == "Bali")  .Get();Column is not equal to a value
Finds all rows whose value on the stated column doesn't match the specified value.
1234var result = await supabase.From<City>()  .Select(x => new object[] { x.Name, x.CountryId })  .Where(x => x.Name != "Bali")  .Get();Column is greater than a value
Finds all rows whose value on the stated column is greater than the specified value.
1234var result = await supabase.From<City>()  .Select(x => new object[] { x.Name, x.CountryId })  .Where(x => x.CountryId > 250)  .Get();Column is greater than or equal to a value
Finds all rows whose value on the stated column is greater than or equal to the specified value.
1234var result = await supabase.From<City>()  .Select(x => new object[] { x.Name, x.CountryId })  .Where(x => x.CountryId >= 250)  .Get();Column is less than a value
Finds all rows whose value on the stated column is less than the specified value.
1234var result = await supabase.From<City>()  .Select("name, country_id")  .Where(x => x.CountryId < 250)  .Get();Column is less than or equal to a value
Finds all rows whose value on the stated column is less than or equal to the specified value.
123var result = await supabase.From<City>()  .Where(x => x.CountryId <= 250)  .Get();Column matches a pattern
Finds all rows whose value in the stated column matches the supplied pattern (case sensitive).
123var result = await supabase.From<City>()  .Filter(x => x.Name, Operator.Like, "%la%")  .Get();Column matches a case-insensitive pattern
Finds all rows whose value in the stated column matches the supplied pattern (case insensitive).
123await supabase.From<City>()  .Filter(x => x.Name, Operator.ILike, "%la%")  .Get();Column is a value
A check for exact equality (null, true, false), finds all rows whose value on the stated column exactly match the specified value.
123var result = await supabase.From<City>()  .Where(x => x.Name == null  .Get();Column is in an array
Finds all rows whose value on the stated column is found on the specified values.
123var result = await supabase.From<City>()  .Filter(x => x.Name, Operator.In, new List<object> { "Rio de Janiero", "San Francisco" })  .Get();Column contains every element in a value
123var result = await supabase.From<City>()  .Filter(x => x.MainExports, Operator.Contains, new List<object> { "oil", "fish" })  .Get();Contained by value
123var result = await supabase.From<City>()  .Filter(x => x.MainExports, Operator.ContainedIn, new List<object> { "oil", "fish" })  .Get();Match a string
Finds all rows whose tsvector value on the stated column matches to_tsquery(query).
1234var result = await supabase.From<Quote>()  .Select(x => x.Catchphrase)  .Filter(x => x.Catchphrase, Operator.FTS, new FullTextSearchConfig("'fat' & 'cat", "english"))  .Get();Match an associated value
- Finds a model given a class (useful when hydrating models and correlating with database)
- Finds all rows whose columns match the specified Dictionary<string, string>object.
1234567var city = new City{    Id = 224,    Name = "Atlanta"};var model = supabase.From<City>().Match(city).Single();Don't match the filter
Finds all rows which doesn't satisfy the filter.
1234var result = await supabase.From<Country>()  .Select(x => new object[] { x.Name, x.CountryId })  .Where(x => x.Name != "Paris")  .Get();Match at least one filter
Finds all rows satisfying at least one of the filters.
123var result = await supabase.From<Country>()  .Where(x => x.Id == 20 || x.Id == 30)  .Get();Using modifiers
Filters work on the row level—they allow you to return rows that only match certain conditions without changing the shape of the rows. Modifiers are everything that don't fit that definition—allowing you to change the format of the response (e.g., setting a limit or offset).
Order the results
Orders the result with the specified column.
1234var result = await supabase.From<City>()  .Select(x => new object[] { x.Name, x.CountryId })  .Order(x => x.Id, Ordering.Descending)  .Get();Limit the number of rows returned
Limits the result with the specified count.
1234var result = await supabase.From<City>()  .Select(x => new object[] { x.Name, x.CountryId })  .Limit(10)  .Get();Limit the query to a range
Limits the result to rows within the specified range, inclusive.
1234var result = await supabase.From<City>()  .Select("name, country_id")  .Range(0, 3)  .Get();Retrieve one row of data
Retrieves only one row from the result. Result must be one row (e.g. using limit), otherwise this will result in an error.
123var result = await supabase.From<City>()  .Select(x => new object[] { x.Name, x.CountryId })  .Single();Create a new user
Creates a new user.
- By default, the user needs to verify their email address before logging in. To turn this off, disable Confirm email in your project.
- Confirm email determines if users need to confirm their email address after signing up.
- If Confirm email is enabled, a useris returned butsessionis null.
- If Confirm email is disabled, both a userand asessionare returned.
 
- If Confirm email is enabled, a 
- When the user confirms their email address, they are redirected to the SITE_URLby default. You can modify yourSITE_URLor add additional redirect URLs in your project.
- If SignUp() is called for an existing confirmed user:
- When both Confirm email and Confirm phone (even when phone provider is disabled) are enabled in your project, an obfuscated/fake user object is returned.
- When either Confirm email or Confirm phone (even when phone provider is disabled) is disabled, the error message, User already registeredis returned.
 
1var session = await supabase.Auth.SignUp(email, password);Listen to auth events
Receive a notification every time an auth event happens.
- Types of auth events: AuthState.SignedIn,AuthState.SignedOut,AuthState.UserUpdated,AuthState.PasswordRecovery,AuthState.TokenRefreshed
12345678910111213141516supabase.Auth.AddStateChangedListener((sender, changed) =>{    switch (changed)    {        case AuthState.SignedIn:            break;        case AuthState.SignedOut:            break;        case AuthState.UserUpdated:            break;        case AuthState.PasswordRecovery:            break;        case AuthState.TokenRefreshed:            break;    }});Sign in a user
Log in an existing user using email or phone number with password.
- Requires either an email and password or a phone number and password.
1var session = await supabase.Auth.SignIn(email, password);Sign in a user through OTP
- Requires either an email or phone number.
- This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number.
- If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP.
- If you're using phone, you can configure whether you want the user to receive a OTP.
- The magic link's destination URL is determined by the SITE_URL. You can modify theSITE_URLor add additional redirect urls in your project.
12var options = new SignInOptions { RedirectTo = "http://myredirect.example" };var didSendMagicLink = await supabase.Auth.SendMagicLink("joseph@supabase.io", options);Sign in a user through OAuth
Signs the user in using third party OAuth providers.
- This method is used for signing in using a third-party provider.
- Supabase supports many different third-party providers.
1var signInUrl = supabase.Auth.SignIn(Provider.Github);Sign out a user
Signs out the current user, if there is a logged in user.
- In order to use the SignOut()method, the user needs to be signed in first.
1await supabase.Auth.SignOut();Verify and log in through OTP
- The VerifyOtpmethod takes in different verification types. If a phone number is used, the type can either besmsorphone_change. If an email address is used, the type can be one of the following:signup,magiclink,recovery,inviteoremail_change.
- The verification type used should be determined based on the corresponding auth method called before VerifyOtpto sign up / sign-in a user.
1var session = await supabase.Auth.VerifyOTP("+13334445555", TOKEN, MobileOtpType.SMS);Retrieve a session
Returns the session data, if there is an active session.
1var session = supabase.Auth.CurrentSession;Retrieve a user
Returns the user data, if there is a logged in user.
1var user = supabase.Auth.CurrentUser;Update a user
Updates user data, if there is a logged in user.
- In order to use the UpdateUser()method, the user needs to be signed in first.
- By Default, email updates sends a confirmation link to both the user's current and new email. To only send a confirmation link to the user's new email, disable Secure email change in your project's email auth provider settings.
12var attrs = new UserAttributes { Email = "new-email@example.com" };var response = await supabase.Auth.Update(attrs);Invokes a Supabase Edge Function.
1234567var options = new InvokeFunctionOptions{    Headers = new Dictionary<string, string> {{ "Authorization", "Bearer 1234" }},    Body = new Dictionary<string, object> { { "foo", "bar" } }};await supabase.Functions.Invoke("hello", options: options);Subscribe to channel
Subscribe to realtime changes in your database.
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by managing replication.
- If you want to receive the "previous" data for updates and deletes, you will need to set REPLICA IDENTITYtoFULL, like this:ALTER TABLE your_table REPLICA IDENTITY FULL;
1234567891011121314151617181920class CursorBroadcast : BaseBroadcast{    [JsonProperty("cursorX")]    public int CursorX {get; set;}    [JsonProperty("cursorY")]    public int CursorY {get; set;}}var channel = supabase.Realtime.Channel("any");var broadcast = channel.Register<CursorBroadcast>();broadcast.AddBroadcastEventHandler((sender, baseBroadcast) =>{    var response = broadcast.Current();});await channel.Subscribe();// Send a broadcastawait broadcast.Send("cursor", new CursorBroadcast { CursorX = 123, CursorY = 456 });Unsubscribe from a channel
Unsubscribes and removes Realtime channel from Realtime client.
- Removing a channel is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed.
1234567var channel = await supabase.From<City>().On(ChannelEventType.All, (sender, change) => { });channel.Unsubscribe();// ORvar channel = supabase.Realtime.Channel("realtime", "public", "*");channel.Unsubscribe()Retrieve all channels
Returns all Realtime channels.
1var channels = supabase.Realtime.Subscriptions;Create a bucket
Creates a new Storage bucket
- Policy permissions required:
- bucketspermissions:- insert
- objectspermissions: none
 
1var bucket = await supabase.Storage.CreateBucket("avatars");Retrieve a bucket
Retrieves the details of an existing Storage bucket.
- Policy permissions required:
- bucketspermissions:- select
- objectspermissions: none
 
1var bucket = await supabase.Storage.GetBucket("avatars");List all buckets
Retrieves the details of all Storage buckets within an existing product.
- Policy permissions required:
- bucketspermissions:- select
- objectspermissions: none
 
1var buckets = await supabase.Storage.ListBuckets();Update a bucket
Updates a new Storage bucket
- Policy permissions required:
- bucketspermissions:- update
- objectspermissions: none
 
1var bucket = await supabase.Storage.UpdateBucket("avatars", new BucketUpsertOptions { Public = false });Delete a bucket
Deletes an existing bucket. A bucket can't be deleted with existing objects inside it. You must first empty() the bucket.
- Policy permissions required:
- bucketspermissions:- selectand- delete
- objectspermissions: none
 
1var result = await supabase.Storage.DeleteBucket("avatars");Empty a bucket
Removes all objects inside a single bucket.
- Policy permissions required:
- bucketspermissions:- select
- objectspermissions:- selectand- delete
 
1var bucket = await supabase.Storage.EmptyBucket("avatars");Upload a file
Uploads a file to an existing bucket.
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- insert
 
12345var imagePath = Path.Combine("Assets", "fancy-avatar.png");await supabase.Storage  .From("avatars")  .Upload(imagePath, "fancy-avatar.png", new FileOptions { CacheControl = "3600", Upsert = false });Download a file
Downloads a file.
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- select
 
1var bytes = await supabase.Storage.From("avatars").Download("public/fancy-avatar.png");List all files in a bucket
Lists all the files within a bucket.
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- select
 
1var objects = await supabase.Storage.From("avatars").List();Replace an existing file
Replaces an existing file at the specified path with a new one.
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- updateand- select
 
12var imagePath = Path.Combine("Assets", "fancy-avatar.png");await supabase.Storage.From("avatars").Update(imagePath, "fancy-avatar.png");Move an existing file
Moves an existing file, optionally renaming it at the same time.
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- updateand- select
 
12await supabase.Storage.From("avatars")  .Move("public/fancy-avatar.png", "private/fancy-avatar.png");Delete files in a bucket
Deletes files within the same bucket
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- deleteand- select
 
1await supabase.Storage.From("avatars").Remove(new List<string> { "public/fancy-avatar.png" });Create a signed URL
Create signed url to download file without requiring permissions. This URL can be valid for a set number of seconds.
- Policy permissions required:
- bucketspermissions: none
- objectspermissions:- select
 
1var url = await supabase.Storage.From("avatars").CreateSignedUrl("public/fancy-avatar.png", 60);Retrieve public URL
Retrieve URLs for assets in public buckets
- The bucket needs to be set to public, either via UpdateBucket() or by going to Storage on supabase.com/dashboard, clicking the overflow menu on a bucket and choosing "Make public"
- Policy permissions required:
- bucketspermissions: none
- objectspermissions: none
 
1var publicUrl = supabase.Storage.From("avatars").GetPublicUrl("public/fancy-avatar.png");Release Notes
0.16.2 - 2024-04-02
- Update dependency: gotrue-csharp@4.2.7- #88 Implement signInAnonymouslyfrom the JS client
- Include additional 3rd party providers in constants.
 
- #88 Implement 
0.16.1 - 2024-03-15
- Update dependency: postgrest-csharp@3.5.1- Re: #147 - Supports Rpcspecifying a generic type for its return.
 
- Re: #147 - Supports 
0.16.0 - 2024-03-12
- Update dependency: postgrest-csharp@3.5.0- Re: #78, Generalize query filtering creation
in Tableso that it matches new generic signatures.
- Move from QueryFilterparameters to a more genericIPosgrestQueryFilterto support constructing new QueryFilters from a LINQ expression.- Note: Lists of QueryFilters will now need to be defined as:new List<IPostgrestQueryFilter> { new QueryFilter(), ... }
 
- Note: Lists of 
- Adjust serialization of timestamps within a QueryFilterto supportDateTimeandDateTimeOffsetusing the ISO-8601 (https://stackoverflow.com/a/115002)
 
- Re: #78, Generalize query filtering creation
in 
- Update dependency: functions-csharp@1.3.2- Re: #5 Add support for specifying Http Timeout
on a function call by adding HttpTimeouttoInvokeFunctionOptions
 
- Re: #5 Add support for specifying Http Timeout
on a function call by adding 
0.15.0 - 2024-01-08
- Update Dependency: gotrue-csharp@4.2.6- #83 Replaces JWTDecoder package with System.IdentityModel.Tokens.Jwt. Thanks @FantasyTeddy!
 
- Update Dependency: postgrest-csharp@3.4.1- Re: #85 Fixes problem when using multiple .Order() methods by merging #86. Thanks @hunsra!
- Re: #81
- [Minor] Removes IgnoreOnInsertandIgnoreOnUpdatefromReferenceAttributeas changing these properties tofalsedoes not currently provide the expected functionality.
- Fixes InsertandUpdatenot working on models that haveReferencespecified on a property with a non-null value.
 
- [Minor] Removes 
 
0.14.0 - 2023-12-15
- Update Dependency: gotrue-csharp@4.2.5
- Update Dependency: postgrest-csharp@3.3.0- Re: #78 Updates signatures for NotandFilterto include generic types for a better development experience.
- Updates internal generic type names to be more descriptive.
- Add support for LINQ predicates on Table<TModel>.Not()signatures
 
- Re: #78 Updates signatures for 
0.13.7 - 2023-11-13
- Update Dependency: postgrest-csharp@3.2.10- Re: #76 Removes the
incorrect ToUniversalTimeconversion in the LINQWhereparser.
 
- Re: #76 Removes the
incorrect 
0.13.6 - 2023-10-12
- Update Dependency: gotrue-csharp@4.2.3
0.13.5 - 2023-10-09
- Update Dependency: postgrest-csharp@3.2.9- Re: supabase-csharp#115 Additional support for a model referencing another model with multiple foreign keys.
- Re: supabase-csharp#115 Adds support for multiple references attached to the same model (foreign keys) on a single C# Model.
 
0.13.4 - 2023-10-08
- Update Dependency: gotrue-csharp@4.2.2- Re: #78 - Implements PKCE flow support
for ResetPasswordForEmail.
 
- Re: #78 - Implements PKCE flow support
for 
0.13.3 - 2023-09-15
- Re: #107 - removes Realtime socket being disconnected on a User sign-out - only the subscriptions should be removed.
0.13.2 - 2023-09-15
- Update dependency: postgrest-csharp@3.2.7- Implements a TableWithCacheforGetrequests that can pull reactive Models from cache before making a remote request.
- Re: supabase-csharp#85 Includes sourcelink support.
- Re: #75 Fix issue with marshalling of stored procedure arguments. Big thank you to @corrideat!
 
- Implements a 
0.13.1 - 2023-08-26
- Update dependency: supabase-storage-csharp@1.4.0- Fixes #11 - Which implements
missing SupabaseStorageExceptionon failure status codes forUpload,Download,Move,CreateSignedUrlandCreateSignedUrls.
 
- Fixes #11 - Which implements
missing 
0.13.0 - 2023-08-26
- Update dependency: gotrue-csharp@4.2.1- #74 - Fixes bug where token refresh interval was not honored by client. Thanks @slater1!
- Minor Breaking changes: #72 - Fixes
Calling SetAuthdoes not actually set Authorization Headers for subsequent requests by implementingSetSession- Removes RefreshToken(string refreshToken)andSetAuth(string accessTokenin favor ofSetSession(string accessToken, string refreshToken)
- Makes RefreshAccessTokenrequireaccessTokenandrefreshTokenas parameters - overrides the authorization headers to use the supplied token
- Migrates project internal times to use DateTime.UtcNowoverDateTime.Now.
 
- Removes 
 
0.12.2 - 2023-07-28
- Update dependency: realtime-csharp@6.0.4- Fixes #29 Where the Realtime client could
disconnect from channels after a few hours and fail to reconnect by removing the case where the IsSubscribeflag is flipped when encountering a channel error.
 
- Fixes #29 Where the Realtime client could
disconnect from channels after a few hours and fail to reconnect by removing the case where the 
- Update dependency: postgrest-csharp@3.2.5- Re: supabase-community/supabase-csharp#81:
Clarifies ReferenceAttributeby changingshouldFilterTopLeveltouseInnerJoinand adds an additional constructor forReferenceAttributewith a shortcut for specifying theJoinType
 
- Re: supabase-community/supabase-csharp#81:
Clarifies 
0.12.1 - 2023-06-29
- Update dependency: gotrue-csharp@4.1.1- #68 Changes Network Status to use the interface instead of client
 
- Update dependency: postgrest-csharp@3.2.4- #70 Minor Unity related fixes
 
0.12.0 - 2023-06-25
- Update dependency: gotrue-csharp@4.1.0
- Update dependency: postgrest-csharp@3.2.3
Thanks @wiverson for the work in this release!
0.11.1 - 2023-06-10
- Update dependencies: functions-csharp@1.3.1,gotrue-csharp@4.0.4,postgrest-csharp@3.2.2,realtime-csharp@6.0.3,supabase-storage-csharp@1.3.2,supabase-core@0.0.3- Namespaces assembly names to make them unique among other dependencies, i.e: Core.dllbecomesSupabase.Core.dllwhich will hopefully prevent future collisions.
 
- Namespaces assembly names to make them unique among other dependencies, i.e: 
0.11.0 - 2023-05-24
- Update dependency: postgrest-csharp@3.2.0
- General codebase and QOL improvements. Exceptions are generally thrown through PostgrestExceptionnow instead ofException. AFailureHint.Reasonis provided with failures if possible to parse.
- AddDebugListeneris now available on the client to help with debugging
- Merges #65 Cleanup + Add better exception handling
- Merges #66 Local test Fixes
- Fixes #67 Postgrest Reference attribute is producing StackOverflow for circular references
 
- General codebase and QOL improvements. Exceptions are generally thrown through 
- Update dependency: gotrue-csharp@4.0.2
- #58 - Add support for the reauthenticationendpoint which allows for secure password changes.
 
- #58 - Add support for the 
- Update dependency: realtime-csharp@6.0.1
- Updates publishing action for future packages, includes README and icon.
- Merges #28 and #30
- The realtime client now takes a "fail-fast" approach. On establishing an initial connection, client will throw
a RealtimeExceptioninConnectAsync()if the socket server is unreachable. After an initial connection has been established, the client will continue attempting reconnections indefinitely until disconnected.
- [Major, New] C# EventHandlershave been changed todelegates. This should allow for cleaner event data access over the previous subclassedEventArgssetup. Events are scoped accordingly. For example, theRealtimeSocketerror handlers will receive events regarding socket connectivity; whereas theRealtimeChannelerror handlers will receive events according toChanneljoining/leaving/etc. This is implemented with the following methods prefixed by ( Add/Remove/Clear):- RealtimeBroadcast.AddBroadcastEventHandler
- RealtimePresence.AddPresenceEventHandler
- RealtimeSocket.AddStateChangedHandler
- RealtimeSocket.AddMessageReceivedHandler
- RealtimeSocket.AddHeartbeatHandler
- RealtimeSocket.AddErrorHandler
- RealtimeClient.AddDebugHandler
- RealtimeClient.AddStateChangedHandler
- RealtimeChannel.AddPostgresChangeHandler
- RealtimeChannel.AddMessageReceivedHandler
- RealtimeChannel.AddErrorHandler
- Push.AddMessageReceivedHandler
 
- [Major, new] ClientOptions.Loggerhas been removed in favor ofClient.AddDebugHandler()which allows for implementing custom logging solutions if desired.- A simple logger can be set up with the following:
 1client.AddDebugHandler((sender, message, exception) => Debug.WriteLine(message));
- [Major] Connect()has been markedObsoletein favor ofConnectAsync()
- Custom reconnection logic has been removed in favor of using the built-in logic from Websocket.Client@4.6.1.
- Exceptions that are handled within this library have been marked as RealtimeExceptions.
- The local, docker-composed test suite has been brought back (as opposed to remotely testing on live supabase servers) to test against.
- Comments have been added throughout the entire codebase and an XMLfile is now generated on build.
 
0.10.0 - 2023-05-14
- Changes options to require Supabase.SupabaseOptions.SessionPersistorfrom usingISupabaseSessionHandlertoIGotrueSessionPersistance<Session>(these are now synchronous operations).
- Update dependency: gotrue-csharp@4.0.1
- #60 - Add interfaces, bug fixes, additional error reason detection. Thanks @wiverson!
- #57 Refactor exceptions, code cleanup, and move to
delegate auth state changes
- Huge thank you to @wiverson for his help on this refactor and release!
- Changes
- Exceptions have been simplified to a single GotrueException. AReasonfield has been added toGotrueExceptionto clarify what happened. This should also be easier to manage as the Gotrue server API & messages evolve.
- The session delegates for Save/Load/Destroyhave been simplified to no longer requireasync.
- Console logging in a few places (most notable the background refresh thread) has been removed
in favor of a notification method. See Client.AddDebugListener()and the test cases for examples. This will allow you to implement your own logging strategy (write to temp file, console, user visible err console, etc).
- The client now more reliably emits AuthState changes.
- There is now a single source of truth for headers in the stateful Client - the Optionsheaders.
 
- Exceptions have been simplified to a single 
- New feature:
- Added a Settingsrequest to the stateless API only - you can now query the server instance to determine if it's got the settings you need. This might allow for things like a visual component in a tool to verify the GoTrue settings are working correctly, or tests that run differently depending on the server configuration.
 
- Added a 
- Implementation notes:
- Test cases have been added to help ensure reliability of auth state change notifications and persistence.
- Persistence is now managed via the same notifications as auth state change
 
 
 
0.9.1 - 2023-04-28
- Update dependency: gotrue-csharp@3.1.1
- Implements SignInWithIdTokenfor Apple/Google signing from LW7. A HUGE thank you to @wiverson!
 
- Implements 
- Update dependency: realtime-csharp@5.0.5
- Re: #27 PostgresChangesOptionswas not settinglistenTypein constructor. Thanks @Kuffs2205
 
- Re: #27 
- Update dependency: supabase-storage-csharp@1.2.10
- Re: #7 Implements a DownloadPublicFilemethod.
 
- Re: #7 Implements a 
0.9.0 - 2023-04-12
- 
Update dependency: gotrue-csharp@3.1.0 - [Minor] Implements PKCE auth flow. SignIn using a provider now returns an instance of ProviderAuthStaterather than astring.
 
- [Minor] Implements PKCE auth flow. SignIn using a provider now returns an instance of 
- 
Update dependency: supabase-storage-csharp@1.2.9 - Implements storage features from LW7:
- feat: custom file size limit and mime types at bucket level supabase/storage-js#151 file size and mime type limits per bucket
- feat: quality option, image transformation supabase/storage-js#145 quality option for image transformations
- feat: format option for webp support supabase/storage-js#142 format option for image transformation
 
 
- Implements storage features from LW7:
0.8.8 - 2023-03-29
- Update dependency: gotrue-csharp@3.0.6
- Supports adding SignInOptions(i.e.RedirectTo) onOAuth ProviderSignIn requests.
 
- Supports adding 
0.8.7 - 2023-03-23
- Update dependency: realtime-csharp@5.0.4
- Re: #26 - Fixes Connect() not returning callback result when the socket isn't null. Thanks @BlueWaterCrystal!
 
0.8.6 - 2023-03-23
- Update dependency: supabase-storage-csharp@1.2.8
- Merge #5 Added search string as an optional search parameter. Thanks @ElectroKnight22!
 
0.8.5 - 2023-03-10
- Update dependency: realtime-csharp@5.0.3
- Re: #25 - Support Channel being resubscribed
after having been unsubscribed, fixes rejoin timer being erroneously called on channel Unsubscribe. Thanks @Kuffs2205!
 
- Re: #25 - Support Channel being resubscribed
after having been unsubscribed, fixes rejoin timer being erroneously called on channel 
0.8.4 - 2023-03-03
- Update dependency: supabase-storage-csharp@1.2.7
- Re: #4 Implementation for ClientOptionswhich supports specifying Upload, Download, and Request timeouts.
 
- Re: #4 Implementation for 
- Update dependency: realtime-csharp@5.0.2
- Re: #24 - Fixes join failing until reconnect happened + adds access token push on channel join. Big thank you to @Honeyhead for the help debugging and identifying!
 
0.8.3 - 2023-02-26
- Update dependency: supabase-storage-csharp@1.2.5
- Provides fix for supabase-community/supabase-csharp#54 - Dynamic headers were always being overwritten by initialized token headers, so the storage client would not receive user's access token as expected.
- Provides fix for upload progress not reporting in supabase-community/storage-csharp#3
 
- Update dependency: gotrue-csharp@3.0.5
- Fixes #44 - refresh timer should automatically
reattempt (interval of 5s) for HTTP exceptions - gracefully exits on invalid refresh and triggers
an AuthState.Changedevent
 
- Fixes #44 - refresh timer should automatically
reattempt (interval of 5s) for HTTP exceptions - gracefully exits on invalid refresh and triggers
an 
0.8.2 - 2023-02-26
- Update dependency: supabase-storage-csharp@1.2.4
- UploadOrUpdatenow appropriately throws request exceptions
 
0.8.1 - 2023-02-06
- Update dependency: realtime-csharp@5.0.1
0.8.0 - 2023-01-31
- Update dependency: realtime-csharp@5.0.0
- Re: #21 Provide API for presence,broadcastandpostgres_changes- [Major, New] Channel.PostgresChangesevent will receive the wildcard*changes event, notChannel.OnMessage.
- [Major] Channel.OnInsert,Channel.OnUpdate, andChannel.OnDeletenow conform to the server's payload ofResponse.Payload.**Data**
- [Major] Channel.OnInsert,Channel.OnUpdate, andChannel.OnDeletenow returnPostgresChangesEventArgs
- [Minor] Rename ChanneltoRealtimeChannel
- Supports better handling of disconnects in RealtimeSocketand adds aClient.OnReconnectevent.
- [Minor] Moves ChannelOptionstoChannel.ChannelOptions
- [Minor] Moves ChannelStateChangedEventArgstoChannel.ChannelStateChangedEventArgs
- [Minor] Moves PushtoChannel.Push
- [Minor] Moves Channel.ChannelStatetoConstants.ChannelState
- [Minor] Moves SocketResponse,SocketRequest,SocketResponsePayload,SocketResponseEventArgs, andSocketStateChangedEventArgstoSocketnamespace.
- [New] Adds RealtimeBroadcast
- [New] Adds RealtimePresence
- [Improvement] Better handling of disconnection/reconnection
 
- [Major, New] 
 
- Re: #21 Provide API for 
- Update dependency: postgrest-csharp@3.1.3
- Another fix for #61 which futher typechecks nullable values.
 
0.7.2 - 2023-01-27
- Update dependency: gotrue-csharp@3.0.4
- Makes Session.CreatedAta publicly settable property, which should fix incorrect dates on retrievedSessions.
 
- Makes 
- Update dependency: postgrest-csharp@3.1.2
- Fix #61 which did not correctly parse
Linq Wherewhen encountering a nullable type.
- Add missing support for transforming for == nulland!= null
 
- Fix #61 which did not correctly parse
Linq 
0.7.1 - 2023-01-17
- Update dependency: postgrest-csharp@3.1.1
- Fix issue from supabase-community/supabase-csharp#48 where boolean model properties would not be evaluated in predicate expressions
 
0.7.0 - 2023-01-16
- Update dependency: postgrest-csharp@3.1.0
- [Minor] Breaking API Change: PrimaryKeyattribute defaults toshouldInsert: falseas most uses will have the Database generate the primary key.
- Merged #60 which Added linq support
for Select,Where,OnConflict,Columns,Order,Update,Set, andDelete
 
- [Minor] Breaking API Change: 
0.6.2 - 2022-11-22
- Update dependency: postgrest-csharp@3.0.4
- GetHeadersis now passed to- ModeledResponseand- BaseModelso that the default- Updateand- Deletemethods use the latest credentials
- GetHeadersis used in- Rpccalls (re: #39)
 
0.6.1 - 2022-11-12
- [Hotfix] GetHeaderswas not passing properly toSupabaseTableandGotrue.Api
0.6.0 - 2022-11-12
[BREAKING CHANGES]
- Clientis no longer a singleton, singleton interactions (if desired) are left to the developer to implement.
- Clientsupports injection of dependent clients after initialization via property:- Auth
- Functions
- Realtime
- Postgrest
- Storage
 
- SupabaseModelcontains no logic but remains for backwards compatibility. (Marked- Obsolete)
- ClientOptions.ShouldInitializeRealtimewas removed (no longer auto initialized)
- ClientOptionsnow references an- ISupabaseSessionHandlerwhich specifies expected functionality for session persistence on Gotrue (replaces- ClientOptions.SessionPersistor,- ClientOptions.SessionRetriever, and- ClientOptions.SessionDestroyer).
- supabase-csharpand all child libraries now have support- nullity
Other Changes:
- Update dependency: functions-csharp@1.2.1
- Update dependency: gotrue-csharp@3.0.2
- Update dependency: postgrest-csharp@3.0.2
- Update dependency: realtime-csharp@4.0.1
- Update dependency: supabase-storage-csharp@1.2.3
- Update dependency: supabase-core@0.0.2
Big thank you to @veleek for his insight into these changes.
0.5.3 - 2022-10-11
- Update dependency: postgrest-csharp@2.1.0
0.5.2 - 2022-9-13
- Update dependency: postgrest-csharp@2.0.12
- Merged #47 which added cancellation token
support to Table<T>methods. Thanks @devpikachu!
 
- Merged #47 which added cancellation token
support to 
0.5.1 - 2022-8-1
- Update dependency: postgrest-csharp@2.0.11
- Update dependency: supabase-storage-csharp@1.1.1
0.5.0 - 2022-7-17
- Update dependency: postgrest-csharp@2.0.9
- Update dependency: realtime-csharp@3.0.1
- Update dependency: supabase-storage-csharp@1.1.0
- API Change [Breaking/Minor] Library no longer uses WebClientand instead leveragesHttpClient. Progress events onUploadandDownloadare now handled withEventHandler<float>instead ofWebClientEventHandlers.
 
- API Change [Breaking/Minor] Library no longer uses 
0.4.4 - 2022-5-24
- Update dependency: gotrue-csharp@2.4.5
- Update dependency: postgrest-csharp@2.0.8
0.4.3 - 2022-5-13
- Update dependency: gotrue-csharp@2.4.4
0.4.2 - 2022-4-30
- Update dependency: gotrue-csharp@2.4.3
0.4.1 - 2022-4-23
- Update dependency: gotrue-csharp@2.4.2
0.4.0 - 2022-4-12
- Add support for functions-csharp@1.0.1, giving access to invoking Supabase's edge functions.
- Update dependency: gotrue-csharp@2.4.1
0.3.5 - 2022-4-11
- Update dependency: postgres-csharp@2.0.7
0.3.4 - 2022-03-28
- Update dependency: gotrue-csharp@2.4.0
0.3.3 - 2022-02-27
- Update dependency: gotrue-csharp@2.3.6
- Update dependency: supabase-storage-csharp@1.0.2
0.3.2 - 2022-02-18
- Update dependency: realtime-csharp@3.0.0
- Exchange existing websocket client: WebSocketSharp for Marfusios/websocket-client which adds support for Blazor WASM apps. Ref: #14
 
0.3.1 - 2022-01-20
- Update dependency: gotrue-csharp@2.3.5
- #23 Added redirect_urloption for MagicLink sign in (Thanks @MisterJimson)
- #21 Added SignOut method to Stateless Client ( Thanks @fplaras)
 
- #23 Added 
0.3.0 - 2021-12-30
- Update dependency: postgrest-csharp@2.0.6
- Add support for NullValueHandlingto be specified on aColumnAttribute and for it to be honored on Inserts and Updates. Defaults to:NullValueHandling.Include.- Implements #38
 
 
- Add support for 
- Update dependency: realtime-csharp@2.0.8
- Implement Upstream Realtime RLS Error Broadcast Handler
- Implements #12
 
- SocketResponsenow exposes a method:- OldModel, that hydrates the- OldRecordproperty into a model.
 
- Implement Upstream Realtime RLS Error Broadcast Handler
0.2.12 - 2021-12-29
- Update dependency: gotrue-csharp@2.3.3
- SignUpwill return a- Sessionwith a populated- Userobject on an unconfirmed signup.- Fixes #19
- Developers who were using a nullcheck onSession.Userwill need to adjust accordingly.
 
 
- Update dependency: postgrest-csharp@2.0.5
0.2.11 - 2021-12-24
- Update dependency: gotrue-csharp@2.3.2 (changes CreateUser parameters to conform to AdminUserAttributes)
- Update dependency: realtime-csharp@2.0.7
- See #13
 
0.2.10 - 2021-12-23
- Update dependency: gotrue-csharp@2.3.0 (adds metadata support for user signup, see #14)
0.2.9 - 2021-12-9
- Separate Storage client from Supabase repo and into storage-csharp,supabase-csharpnow references new repo.
0.2.8 - 2021-12-4
- Update gotrue-csharp to 2.2.4
- Adds support for ListUsers(paginate, sort, filter),GetUserById,CreateUser, andUpdateById
 
- Adds support for 
0.2.7 - 2021-12-2
- Update gotrue-csharp to 2.2.3
- Adds support for sending password resets to users.