dotnet add package Signalbird.SdkSignalbird.Sdk - .NET / ASP.NET Core
Üç yüzey taşır: Telsiz (log), Gönderim (e-posta/SMS/push) ve Yönetim (proje, sohbet gelen kutusu, uygulama).
Kurulum
dotnet add package Signalbird.Sdknet8.0 ve netstandard2.1 hedefler. Tek dış bağımlılık DI uzantısı içindir
(Microsoft.Extensions.Http) ve ASP.NET Core uygulamasında zaten yüklüdür;
çekirdek istemciler onu kullanmaz - konsol uygulaması ya da Azure Function
gereksiz paket çekmesin.
Kayıt (DI)
// Program.cs
builder.Services.AddSignalbird(options =>
{
options.DomainKey = builder.Configuration["Signalbird:RadioKey"]!; // sb_secret_live_…
options.Source = "api-01";
});
builder.Services.AddSignalbirdMessaging(options =>
options.DomainKey = builder.Configuration["Signalbird:DomainKey"]!); // sb_…
builder.Services.AddSignalbirdManagement(options =>
options.DomainKey = builder.Configuration["Signalbird:DomainKey"]!);Üçü de IHttpClientFactory üzerinden kurulur. Her istemcinin kendi
HttpClient'ını new'lemesi soket tükenmesinin klasik sebebidir ve .NET'te en
sık yapılan hatadır - SDK bunu sizin için doğru yapar.
DI kullanmıyorsanız:
var radio = new SignalbirdClient(new SignalbirdOptions { DomainKey = "sb_secret_live_…" });Telsiz - log ve olay
public class PaymentService(SignalbirdClient signalbird)
{
public async Task ChargeAsync(Order order, CancellationToken ct)
{
try
{
await _gateway.ChargeAsync(order, ct);
await signalbird.InfoAsync("odeme", $"Sipariş #{order.Id} başarılı", ct: ct);
}
catch (Exception error)
{
await signalbird.CriticalAsync("critical", error.Message,
new Dictionary<string, object?>
{
["order"] = order.Id,
["gateway"] = "iyzico",
}, ct);
throw; // Log göndermek hatayı yutmaz
}
}
}Beş seviye: DebugAsync, InfoAsync, WarnAsync, ErrorAsync,
CriticalAsync. Seviye vermeden LogAsync çağırırsanız kanalın kendi
varsayılanı geçerlidir.
Toplu gönderim
await signalbird.BatchAsync(new[]
{
new LogEvent { Channel = "deploy", Message = "v2.4.0 yayında", Level = SignalbirdLevel.Info },
new LogEvent { Channel = "critical", Message = "kuyruk doldu" },
});En fazla 100 kayıt; kısmi başarı normaldir ve başarısız satırlar yeniden denenmez.
Gönderim - e-posta, SMS, push
var result = await messaging.SendEmailAsync(new
{
to = "ahmet@example.com",
@class = "transactional", // `class` ayrılmış sözcük - @ ile kaçılır
subject = "Siparişiniz yola çıktı",
body = "<p>Kargo takip no: 1234</p>",
});
if (!result.Ok)
{
logger.LogWarning("signalbird: {Code} - {Message}", result.Code, result.Message);
}
classalanı zorunludur ve varsayılanı yoktur:transactional(işlemsel) ya dacommercial(ticari). Bu hukuki bir kapıdır, kararı SDK veremez.
await messaging.SendSmsAsync(new { to = "+905551112233", @class = "transactional", body = "Kodunuz: 123456" });
await messaging.PreviewSmsAsync("Merhaba, siparişiniz hazır."); // kota harcamaz
await messaging.SendPushAsync(new { to = "contact:42", @class = "transactional", subject = "Sipariş", body = "Yola çıktı" });Kişiler
await messaging.ListContactsAsync(new Dictionary<string, object?> { ["q"] = "ahmet" });
await messaging.CreateContactAsync(new { email = "ahmet@example.com", first_name = "Ahmet" });
await messaging.UpdateContactAsync(contactId, new { phone = "+905551112233" });
await messaging.DeleteContactAsync(contactId);
// 1000'lik parçalar, SIRAYLA
await messaging.BulkContactsAsync(rows, new Dictionary<string, object?>
{
["list_id"] = 42,
["consent_source"] = "web_form",
});Kampanyalar
await messaging.CreateCampaignAsync(new
{
name = "Ağustos bülteni",
channel = "email",
list_id = 42,
subject = "Bu ay neler oldu?",
body = "<h1>Merhaba</h1>",
});
// Sayfa sayfa gezer; tüm listeyi belleğe almaz
await foreach (var message in messaging.IterateCampaignMessagesAsync(batchId))
{
Reconcile(message.GetProperty("external_ref").GetString());
}Webhook doğrulama
// Program.cs - ham gövdeyi okuyabilmek için
app.Use(async (context, next) =>
{
context.Request.EnableBuffering();
await next();
});
// Controller
[HttpPost("/webhooks/signalbird")]
public async Task<IActionResult> Handle()
{
Request.Body.Position = 0;
using var reader = new StreamReader(Request.Body);
var rawBody = await reader.ReadToEndAsync();
// HAM gövde: modeli deserialize edip yeniden serialize etmek imzayı bozar
if (!Webhook.Verify(rawBody, Request.Headers["X-Signalbird-Signature"], _secret))
{
return Unauthorized();
}
return Ok();
}Yönetim - kendi projenizi kurun
// Ortam kurulumu (deploy adımı ya da yönetim komutu)
var created = await management.CreateModuleKeyAsync("logger", new Dictionary<string, object?> { ["title"] = "Ödeme hataları" });
// `secret` YALNIZ burada döner; sunucuda yalnız özeti saklanır
var secret = created.Data?.GetProperty("secret").GetString();
var projectId = created.Data?.GetProperty("project").GetProperty("id").GetInt32();
await management.CreateRadioChannelAsync(projectId!, new
{
key = "odeme",
name = "Ödeme",
level = "critical",
notify_push = true,
quiet_from = 0,
quiet_to = 7,
});
// Sohbet gelen kutusu botu
var inbox = await management.ListConversationsAsync(
new Dictionary<string, object?> { ["status"] = "open" });
await management.ReplyAsync(conversationId, new { body = "Merhaba! Birazdan dönüyoruz." });
await management.SetConversationStatusAsync(conversationId, "pending");Anahtarınızın radio:*, chat:*, apps:* kapsamlarını taşıması gerekir.
Ayrıntı: Yönetim dokümanı.
Sonuç biçimi
public sealed class SbResult
{
public bool Ok { get; }
public int Status { get; }
public JsonElement? Data { get; }
public string? Code { get; }
public string? Message { get; }
public T? Into<T>(); // gövdeyi tipinize çözer
}var result = await management.GetAppAsync(id);
var app = result.Into<AppRecord>();ThrowOnError = true iken SignalbirdException fırlatılır (Code, Status,
Body).
Ziyaretçi kimliği doğrulaması - identityHash
Sohbet widget'ı ve uygulama SDK'sı oturum açmış kullanıcıyı external_id ile
tanıtır. Açık anahtar sayfada durduğu için Signalbird bu kimliği ancak
yanında sizin sunucunuzda üretilmiş geçerli bir hash varsa güvenilir sayar
(2.7.0). Hash olmadan ziyaretçi kişi kaydına bağlanmaz, cihazı o kullanıcıya
push hedefi olarak bağlanmaz ve kanal ajanının araçları kimliği yalnız
visitor.unverified altında görür.
// SignalbirdClient DI'dan
var hash = signalbird.IdentityHash(user.Id);Gizli anahtarı zaten tutan Telsiz istemcisinin üzerindedir; ayrı kurulum gerekmez. Algoritma (her dilde aynı çıktı):
identity_hash = hex( HMAC-SHA256( hex(SHA-256(sb_secret_live_…)), external_id ) )Anahtar gizli anahtarın SHA-256 özetidir (sunucu anahtarı düz saklamaz). Kullanım: Widget - Kimlik doğrulaması, Uygulama SDK'sı.
Sürüm bildirimi
SDK her istekte sürümünü bildirir: X-Signalbird-Sdk: dotnet/<sürüm>. Yeni bir
sürüm yayınlandığında API yanıtında Signalbird-Sdk-Status: outdated (ya da
artık desteklenmiyorsa unsupported) döner ve SDK süreç başına bir kez
uyarı yazar (Console.Error). Uyarı hata değildir: isteğin sonucu değişmez.
Panelde Domainler → [domain] → Anahtarlar her anahtarın hangi SDK sürümüyle kullanıldığını gösterir; eski sürümdeki anahtarlar için panelin tepesinde bir uyarı şeridi ve bildirim çıkar. Güncellemek için:
dotnet add package Signalbird.SdkHata kodları
| Kod | Anlamı |
|---|---|
NO_KEY / WRONG_KEY_TYPE |
Kurulum anında yakalanır |
INVALID_KEY |
Anahtar yok, yanlış ya da proje pasif |
API_KEY_SCOPE |
Anahtarda gereken kapsam yok |
MODULE_DISABLED |
Paketinizde bu modül yok |
LIMIT_REACHED |
Aylık limitiniz doldu |
VALIDATION_ERROR |
422 |
NETWORK_ERROR / TIMEOUT |
Ağ (status 0) |
Davranış kuralları
- Sessiz hata varsayılandır. Signalbird erişilemezse
Ok = falsedöner, istisna fırlatılmaz. - Retry yoktur. Yeniden deneme kararı sizindir;
PollykullanıyorsanızIHttpClientFactorykaydına kendi politikanızı ekleyin. - Alan adları API ile birebir (snake_case) - SDK yeniden adlandırmaz.
CancellationTokenher metodun son parametresidir.