C#客户端库
supabase在 GitHub 上查看本参考文档记录了 Supabase 的 C# 库中可用的每个对象和方法,supabase。您可以使用 Supabase 与您的 Postgres 数据库交互,监听数据库更改,调用 Deno Edge 函数,构建登录和用户管理功能,以及管理大型文件。
C# 客户端库由 Supabase 社区创建和维护,并非官方库。请对库仍在开发中的区域表示宽容,并且——与所有库一样——欢迎您在发现问题时随时贡献。
衷心感谢官方维护者,Joseph Schultz。以及 Will Iverson、Ben Randall 和 Rhuan Barros 提供了他们的帮助。
安装
从 NuGet 安装#
您可以从 nuget.org 安装 Supabase 包
1dotnet add package supabase初始化
初始化新的客户端非常简单。从管理面板中找到您的项目 URL 和公共密钥,并将其传递给您的客户端初始化函数。
Supabase 严重依赖从 BaseModel 派生的模型。要与 API 交互,必须指定关联的模型(参见示例)。
利用 Table、PrimaryKey 和 Column 属性来指定与 C# 版本不同的类/属性名称。
1var url = Environment.GetEnvironmentVariable("SUPABASE_URL");2var key = Environment.GetEnvironmentVariable("SUPABASE_KEY");34var options = new Supabase.SupabaseOptions5{6 AutoConnectRealtime = true7};89var supabase = new Supabase.Client(url, key, options);10await supabase.InitializeAsync();获取数据
执行使用 SELECT 的垂直过滤。
- LINQ 表达式当前不支持解析嵌入式资源列。在这种情况下,需要使用
string。 - 在使用字符串列名选择时,它们必须与数据库中的名称匹配,而不是模型属性上指定的名称。
- 有关建模 + 查询联接和内联接的更多信息,请参见
postgrest-csharp README - 默认情况下,Supabase 项目将返回最多 1,000 行。 可以在项目 API 设置中更改此设置。 建议将其保持较低,以限制意外或恶意请求的有效负载大小。 您可以使用
range()查询来分页您的数据。 From()可以与 修饰符 结合使用From()可以与 过滤器 结合使用- 如果使用 Supabase 托管平台,
apikey在技术上是一个保留关键字,因为 API 网关会将其提取出来用于身份验证。 应避免将其用作列名。
1// Given the following Model (City.cs)2[Table("cities")]3class City : BaseModel4{5 [PrimaryKey("id")]6 public int Id { get; set; }78 [Column("name")]9 public string Name { get; set; }1011 [Column("country_id")]12 public int CountryId { get; set; }1314 //... etc.15}1617// A result can be fetched like so.18var result = await supabase.From<City>().Get();19var cities = result.Models插入数据
执行表中的 INSERT。
1[Table("cities")]2class City : BaseModel3{4 [PrimaryKey("id", false)]5 public int Id { get; set; }67 [Column("name")]8 public string Name { get; set; }910 [Column("country_id")]11 public int CountryId { get; set; }12}1314var model = new City15{16 Name = "The Shire",17 CountryId = 55418};1920await supabase.From<City>().Insert(model);更新数据
执行表中的 UPDATE。
Update()通常使用模型作为参数或从已填充的模型调用。
1var update = await supabase2 .From<City>()3 .Where(x => x.Name == "Auckland")4 .Set(x => x.Name, "Middle Earth")5 .Update();更新或插入数据
执行表中的 UPSERT。
- 为了使更新正常工作,数据负载中应包含主键。
- 主键必须是自然主键,而不是代理主键。但是,存在代理主键的解决方法。
1var model = new City2{3 Id = 554,4 Name = "Middle Earth"5};67await supabase.From<City>().Upsert(model);删除数据
执行表中的 DELETE。
Delete()应该始终与 过滤器 结合使用,以定位您想要删除的项目。
1await supabase2 .From<City>()3 .Where(x => x.Id == 342)4 .Delete();调用 Postgres 函数
您可以将存储过程作为“远程过程调用”来调用。
这是一种花哨的说法,即您可以将一些逻辑放入数据库中,然后从任何地方调用它。当逻辑很少更改时,这尤其有用——例如密码重置和更新。
1await supabase.Rpc("hello_world", null);使用过滤器
过滤器允许你仅返回匹配特定条件的行。
过滤器可用于 Select()、Update() 和 Delete() 查询。
注意:LINQ 表达式当前不支持解析嵌入式资源列。在这种情况下,需要使用 string。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Where(x => x.Name == "The Shire")4 .Single();列等于一个值
查找指定 column 上的值与指定的 value 完全匹配的所有行。
1var result = await supabase.From<City>()2 .Where(x => x.Name == "Bali")3 .Get();列不等于一个值
查找所有 column 的值与指定的 value 不匹配的行。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Where(x => x.Name != "Bali")4 .Get();列大于一个值
查找所有 column 的值大于指定的 value 的行。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Where(x => x.CountryId > 250)4 .Get();列大于或等于一个值
查找所有 column 的值大于或等于指定的 value 的行。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Where(x => x.CountryId >= 250)4 .Get();列小于一个值
查找所有 column 的值小于指定的 value 的行。
1var result = await supabase.From<City>()2 .Select("name, country_id")3 .Where(x => x.CountryId < 250)4 .Get();列小于或等于一个值
查找所有 column 的值小于或等于指定的 value 的行。
1var result = await supabase.From<City>()2 .Where(x => x.CountryId <= 250)3 .Get();列匹配一个模式
查找所有 column 的值与提供的 pattern 匹配的行(区分大小写)。
1var result = await supabase.From<City>()2 .Filter(x => x.Name, Operator.Like, "%la%")3 .Get();列匹配一个不区分大小写的模式
查找所有 column 的值与提供的 pattern 匹配的行(不区分大小写)。
1await supabase.From<City>()2 .Filter(x => x.Name, Operator.ILike, "%la%")3 .Get();列是一个值
用于精确相等性(null、true、false)的检查,查找所有 column 的值与指定的 value 完全匹配的行。
1var result = await supabase.From<City>()2 .Where(x => x.Name == null)3 .Get();列在一个数组中
查找所有 column 的值在指定的 values 中找到的行。
1var result = await supabase.From<City>()2 .Filter(x => x.Name, Operator.In, new List<object> { "Rio de Janiero", "San Francisco" })3 .Get();列包含数组中的每个元素
1var result = await supabase.From<City>()2 .Filter(x => x.MainExports, Operator.Contains, new List<object> { "oil", "fish" })3 .Get();包含在值中
1var result = await supabase.From<City>()2 .Filter(x => x.MainExports, Operator.ContainedIn, new List<object> { "oil", "fish" })3 .Get();匹配一个字符串
查找指定 column 上的 tsvector 值与 to_tsquery(query) 匹配的所有行。
1var result = await supabase.From<Quote>()2 .Select(x => x.Catchphrase)3 .Filter(x => x.Catchphrase, Operator.FTS, new FullTextSearchConfig("'fat' & 'cat", "english"))4 .Get();匹配关联值
- 查找给定类别的模型(在填充模型和与数据库关联时很有用)
- 查找其列与指定的
Dictionary<string, string>对象匹配的所有行。
1var city = new City2{3 Id = 224,4 Name = "Atlanta"5};67var model = supabase.From<City>().Match(city).Single();不匹配过滤器
查找不满足过滤器的所有行。
1var result = await supabase.From<Country>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Where(x => x.Name != "Paris")4 .Get();匹配至少一个过滤器
查找满足至少一个过滤器的所有行。
1var result = await supabase.From<Country>()2 .Where(x => x.Id == 20 || x.Id == 30)3 .Get();使用修饰符
过滤器在行级别起作用——它们允许您仅返回匹配特定条件的行,而不会更改行的形状。修饰符是所有不符合该定义的内容——允许您更改响应的格式(例如,设置限制或偏移量)。
对结果进行排序
使用指定的列对结果进行排序。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Order(x => x.Id, Ordering.Descending)4 .Get();限制返回的行数
使用指定的计数限制结果。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Limit(10)4 .Get();将查询限制在一个范围内
将结果限制在指定的范围内,包括边界。
1var result = await supabase.From<City>()2 .Select("name, country_id")3 .Range(0, 3)4 .Get();检索一行数据
从结果中检索一行。结果必须是一行(例如,使用限制),否则将导致错误。
1var result = await supabase.From<City>()2 .Select(x => new object[] { x.Name, x.CountryId })3 .Single();创建新用户
创建一个新用户。
- 默认情况下,用户需要在登录前验证其电子邮件地址。要关闭此功能,请在 您的项目 中禁用 **确认电子邮件**。
- **确认电子邮件** 确定用户在注册后是否需要确认其电子邮件地址。
- 如果启用了 **确认电子邮件**,则会返回一个 `user`,但 `session` 为 null。
- 如果禁用了 **确认电子邮件**,则会同时返回 `user` 和 `session`。
- 当用户确认其电子邮件地址时,默认情况下他们将被重定向到
SITE_URL。您可以在 您的项目中修改SITE_URL或添加其他重定向 URL。 - 如果调用了已确认的现有用户的 SignUp()
- 当在 您的项目 中同时启用 **确认电子邮件** 和 **确认电话**(即使电话提供程序已禁用)时,将返回一个混淆/虚假的用户对象。
- 当 **确认电子邮件** 或 **确认电话**(即使电话提供程序已禁用)中的任何一个被禁用时,将返回错误消息 `User already registered`。
1var session = await supabase.Auth.SignUp(email, password);监听认证事件
每当发生身份验证事件时,都会收到通知。
- 身份验证事件类型:
AuthState.SignedIn、AuthState.SignedOut、AuthState.UserUpdated、AuthState.PasswordRecovery、AuthState.TokenRefreshed
1supabase.Auth.AddStateChangedListener((sender, changed) =>2{3 switch (changed)4 {5 case AuthState.SignedIn:6 break;7 case AuthState.SignedOut:8 break;9 case AuthState.UserUpdated:10 break;11 case AuthState.PasswordRecovery:12 break;13 case AuthState.TokenRefreshed:14 break;15 }16});登录用户
使用电子邮件或电话号码和密码登录现有用户。
- 需要电子邮件和密码或电话号码和密码。
1var session = await supabase.Auth.SignIn(email, password);通过 OTP 登录用户
1var options = new SignInOptions { RedirectTo = "http://myredirect.example" };2var didSendMagicLink = await supabase.Auth.SendMagicLink("joseph@supabase.io", options);通过 OAuth 登录用户
使用第三方 OAuth 提供商登录用户。
- 此方法用于使用第三方提供程序登录。
- Supabase 支持许多不同的 第三方提供程序。
1var signInUrl = supabase.Auth.SignIn(Provider.Github);注销用户
注销当前用户(如果有已登录用户)。
- 为了使用
SignOut()方法,用户需要先登录。
1await supabase.Auth.SignOut();通过 OTP 验证并登录
VerifyOtp方法接受不同类型的验证。如果使用电话号码,则类型可以是sms或phone_change。如果使用电子邮件地址,则类型可以是以下之一:signup、magiclink、recovery、invite或email_change。- 应根据在调用
VerifyOtp注册/登录用户之前调用的相应身份验证方法来确定使用的验证类型。
1var session = await supabase.Auth.VerifyOTP("+13334445555", TOKEN, MobileOtpType.SMS);获取会话
如果存在活动会话,则返回会话数据。
1var session = supabase.Auth.CurrentSession;获取用户
如果存在已登录用户,则返回用户数据。
1var user = supabase.Auth.CurrentUser;更新用户
更新用户数据(如果有已登录用户)。
- 为了使用
UpdateUser()方法,用户需要先登录。 - 默认情况下,电子邮件更新会向用户的当前电子邮件和新电子邮件发送确认链接。要仅向用户的新的电子邮件发送确认链接,请在您的项目的 电子邮件身份验证提供程序设置中禁用 安全电子邮件更改。
1var attrs = new UserAttributes { Email = "new-email@example.com" };2var response = await supabase.Auth.Update(attrs);调用 Supabase 边缘函数。
1var options = new InvokeFunctionOptions2{3 Headers = new Dictionary<string, string> {{ "Authorization", "Bearer 1234" }},4 Body = new Dictionary<string, object> { { "foo", "bar" } }5};67await supabase.Functions.Invoke("hello", options: options);订阅频道
订阅数据库中的实时更改。
- 实时默认情况下为新项目禁用,以提高数据库性能和安全性。您可以通过 管理复制 来启用它。
- 如果您想接收更新和删除的“先前”数据,则需要将
REPLICA IDENTITY设置为FULL,如下所示:ALTER TABLE your_table REPLICA IDENTITY FULL;
1class CursorBroadcast : BaseBroadcast2{3 [JsonProperty("cursorX")]4 public int CursorX {get; set;}56 [JsonProperty("cursorY")]7 public int CursorY {get; set;}8}910var channel = supabase.Realtime.Channel("any");11var broadcast = channel.Register<CursorBroadcast>();12broadcast.AddBroadcastEventHandler((sender, baseBroadcast) =>13{14 var response = broadcast.Current();15});1617await channel.Subscribe();1819// Send a broadcast20await broadcast.Send("cursor", new CursorBroadcast { CursorX = 123, CursorY = 456 });取消订阅频道
取消订阅并从实时客户端中删除实时通道。
- 删除频道是维护项目实时服务性能以及数据库性能的好方法(如果你正在侦听 Postgres 更改)。Supabase 会在客户端断开连接 30 秒后自动处理清理,但未使用的频道可能会导致更多客户端同时订阅而导致性能下降。
1var channel = await supabase.From<City>().On(ChannelEventType.All, (sender, change) => { });2channel.Unsubscribe();34// OR56var channel = supabase.Realtime.Channel("realtime", "public", "*");7channel.Unsubscribe()获取所有频道
返回所有实时通道。
1var channels = supabase.Realtime.Subscriptions;文件存储
本节包含处理文件存储桶的方法。
列出所有存储桶
检索现有产品中的所有存储桶的详细信息。
- 策略权限要求
buckets权限:selectobjects权限:无
1var buckets = await supabase.Storage.ListBuckets();检索存储桶
检索现有的存储存储桶的详细信息。
- 策略权限要求
buckets权限:selectobjects权限:无
1var bucket = await supabase.Storage.GetBucket("avatars");创建存储桶
创建一个新的存储存储桶
- 策略权限要求
buckets权限:insertobjects权限:无
1var bucket = await supabase.Storage.CreateBucket("avatars");清空存储桶
删除单个存储桶中的所有对象。
- 策略权限要求
buckets权限:selectobjects权限:select和delete
1var bucket = await supabase.Storage.EmptyBucket("avatars");更新存储桶
更新新的存储桶
- 策略权限要求
buckets权限:updateobjects权限:无
1var bucket = await supabase.Storage.UpdateBucket("avatars", new BucketUpsertOptions { Public = false });删除存储桶
删除现有的存储桶。如果存储桶内存在现有对象,则无法删除存储桶。你必须首先 empty() 存储桶。
- 策略权限要求
buckets权限:select和deleteobjects权限:无
1var result = await supabase.Storage.DeleteBucket("avatars");上传文件
将文件上传到现有的存储桶。
- 策略权限要求
buckets权限:无objects权限:insert
1var imagePath = Path.Combine("Assets", "fancy-avatar.png");23await supabase.Storage4 .From("avatars")5 .Upload(imagePath, "fancy-avatar.png", new FileOptions { CacheControl = "3600", Upsert = false });替换现有文件
用新文件替换指定路径处的现有文件。
- 策略权限要求
buckets权限:无objects权限:update和select
1var imagePath = Path.Combine("Assets", "fancy-avatar.png");2await supabase.Storage.From("avatars").Update(imagePath, "fancy-avatar.png");移动现有文件
移动现有文件,同时可以选择重命名它。
- 策略权限要求
buckets权限:无objects权限:update和select
1await supabase.Storage.From("avatars")2 .Move("public/fancy-avatar.png", "private/fancy-avatar.png");创建签名 URL
创建签名 URL 以在无需权限的情况下下载文件。此 URL 在设定的秒数内有效。
- 策略权限要求
buckets权限:无objects权限:select
1var url = await supabase.Storage.From("avatars").CreateSignedUrl("public/fancy-avatar.png", 60);检索公共 URL
检索公共存储桶中的资产 URL
- 存储桶需要设置为公共存储桶,可以通过 UpdateBucket() 或通过转到 supabase.com/dashboard、单击存储桶上的溢出菜单并选择“设为公共存储桶”来实现。
- 策略权限要求
buckets权限:无objects权限:无
1var publicUrl = supabase.Storage.From("avatars").GetPublicUrl("public/fancy-avatar.png");下载文件
下载文件。
- 策略权限要求
buckets权限:无objects权限:select
1var bytes = await supabase.Storage.From("avatars").Download("public/fancy-avatar.png");删除存储桶中的文件
删除同一存储桶中的文件
- 策略权限要求
buckets权限:无objects权限:delete和select
1await supabase.Storage.From("avatars").Remove(new List<string> { "public/fancy-avatar.png" });列出存储桶中的所有文件
列出存储桶中的所有文件。
- 策略权限要求
buckets权限:无objects权限:select
1var objects = await supabase.Storage.From("avatars").List();发行说明
1.0.0 - 2024-04-21#
- 程序集名称已更改为
Supabase.dll - 更新依赖项:
postgrest-csharp@5.0.0- [MAJOR] 将命名空间从
Postgrest移动到Supabase.Postgrest - 回复:#135 更新 nuget 包名称
postgrest-csharp为Supabase.Postgrest
- [MAJOR] 将命名空间从
- 更新依赖项:
gotrue-csharp@5.0.0 - 更新依赖项:
realtime-csharp@7.0.0 - 更新依赖项:
storage-csharp@2.0.0- 回复:#135 更新 nuget 包名称
storage-csharp为Supabase.Storage
- 回复:#135 更新 nuget 包名称
- 更新依赖项:
functions-csharp@2.0.0- 回复:#135 更新 nuget 包名称
functions-csharp为Supabase.Functions
- 回复:#135 更新 nuget 包名称
- 更新依赖项:
core-csharp@1.0.0- 回复:#135 更新 nuget 包名称
supabase-core为Supabase.Core
- 回复:#135 更新 nuget 包名称
- 添加对剩余未记录代码的注释。