FirebaseCoreSDK is .net core library for interacting with firebase database, Cloud Messaging and storage. Library is supposed to be used in server side apps. This code is based on https://github.com/shoaibshakeel381/FirebaseCoreAdmin But it has improved code organization with additional fixes and enhancements. It supports
- Firebase Cloud Messaging (Tested Basic, Android and APNs Messaging modes, WebPush should work, but is untested)
- Firebase Realtime Database (Basic Crud, no Offline or Streaming support)
- Firebase Storage
- Authentication (Generate Custom Token, no user management)
- Logging (You can provide logger in
FirebaseSDKConfiguration
) - Support for plugging custom HttpClient for supprting Mocks,
IHttpClientFactory
, Polly etc
Supports both json and p12 config files. In order to give permissions to FirebaseCoreSdk to use your firebase project you need to first create private key in [service account] tab on (https://console.cloud.google.com/iam-admin/serviceaccounts). After creating service account you will be propmted to download either json file or p12 file, recommended is json file. Download that file and attach to your project.
- Json file
var configuration = new FirebaseSDKConfiguration {
Credentials = new JsonServiceAccountCredentials("your-file.json")
};
var firebaseClient = new FirebaseClient(configuration);
- Json string
var configuration = new FirebaseSDKConfiguration {
Credentials = new JsonServiceAccountCredentials("your-json-string", false)
};
var firebaseClient = new FirebaseClient(configuration);
- P12 file
var configuration = new FirebaseSDKConfiguration {
Credentials = new P12ServiceAccountCredentials("your-file.p12", "your-secret", "your-service-account", "your-database")
};
var firebaseClient = new FirebaseClient(configuration);
Create token for some userId
which should be used by client to authenticate against firebase database, that token could be used in client sdks by calling firebase.auth().signInWithCustomToken(token)
var token = firebaseClient.Auth.CreateCustomToken(userId);
Developers will need to first get access token from google before actually calling any Firebase api. This can be done as follows:
await firebaseClient.Auth.AuthenticateAsync();
SDK will cache the access token in FirebaseSDKConfiguration
object provided during initialization. SDK will then try to use it in every Firebase API call. Developers need to make sure that FirebaseSDKConfiguration
object provided earlier is a singleton so they don't have to re-login every time a Firebase API needs to be called. If token is expired SDK will throw an Exception.
Getting reference on some node of database use firebaseClient.Database.Ref("endpoint")
for example firebaseClient.Database.Ref("users/12/details")
For getting data
- GetAsync
- GetWithKeyInjectedAsync
Examples:
Let's say you have this structure in firebase
-users/{userId}/events
--EventKey1
---- CodeId: 1
---- IsRead: true,
---- Timestamp: 1502047422150
--EventKey2
---- CodeId: 2
---- IsRead: false,
---- Timestamp: 1502047422279
Let's assume we have UserHistory class
class UserHistory {
public int CodeId { get; set; }
public bool IsRead { get; set; }
public long Timestamp { get; set; }
}
and can query via
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Database.Ref("users/330/events/EventKey2")
.GetAsync<UserHistory>();
var queryBuilder = QueryBuilder.New()
.Shallow(true)
.StartAt("startvalu")
.OrderBy("asd")
.LimitToLast(1);
var result1 = await client.Database.Ref("users/330/events/EventKey2").GetAsync<T>(queryBuilder);
We can inject key into model by inheriting UserHistory: KeyEntity
and instead of calling .GetAsync<UserHistory>()
call .GetWithKeyInjectedAsync<UserHistory>()
like:
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Database.Ref("users/330/eventsEventKey2")
.GetWithKeyInjectedAsync<UserHistory>();
- PushAsync
- SetAsync
- UpdateAsync
- DeleteAsync
Methods are functioning exactly like their counterparts in NodeJs or Java sdks.
Examples:
Push
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Database.Ref("/users/30/details").PushAsync(new Detail())
Bulk update
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Database.Ref("/users/30/details").UpdateAsync(new Dictionary<string, object>() {
{ "codeId", 20 } ,
{ "info","info"} ,
{ "sub/info","subinfo"} ,
});
Set
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Database.Ref("/test").SetAsync(new Test1());
Delete
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Database.Ref("/test").DeleteAsync();
Following storage methods are supported
- GetPublicUrl
- GetSignedUrl
- RemoveObjectAsync
- GetObjectMetaDataAsync
- MoveObjectAsync
Examples:
await firebaseClient.Auth.AuthenticateAsync();
var result = await firebaseClient.Storage.GetObjectMetaDataAsync("test/my-image");
var publicUrl = firebaseClient.Storage.GetPublicUrl("my-image");
var signedUrl = firebaseClient.Storage.GetSignedUrl(new Firebase.Storage.SigningOption()
{
Action = Firebase.Storage.SigningAction.Write,
Path = "my-image",
ContentType = "image/jpeg",
ExpireDate = DateTime.Now + new TimeSpan(0, 0, 0, 0, 60000000)
});
- SendCloudMessageAsync
Example:
await firebaseClient.Auth.AuthenticateAsync();
var message = new FirebasePushMessage();
var result = await firebaseClient.CloudMessaging.SendCloudMessageAsync(message);
It is now possible to provide custom HTTP request handler by providing an implementation for IHttpClientProxy
in FirebaseSDKConfiguration
. SDK comes with a default implementation as TransientHttpClientProxy
, clients can override it if need to. A sample implementation for using Polly is given below. In ASP.NET Core >= 2.1, it is recomended to also use IHttpRequestFactory
to create instances of HttpClient
.
Polly Sample Code:
public class FirebaseHttpClientProxy : TransientHttpClientProxy
{
private readonly AsyncRetryPolicy<HttpResponseMessage> _retryPolicy;
public FirebaseHttpClientProxy()
{
_retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<FirebaseHttpException>(StatusCodeShouldBeRetried)
.WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt))));
}
/// <inheritdoc />
public override async Task<string> SendAsync(Func<HttpRequestMessage> request)
{
var response = await _retryPolicy.ExecuteAsync(() => SendAsync(request()));
return await GetResponseContent(response);
}
private async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
var uri = request.RequestUri;
using (var client = new HttpClient()) // TODO: Use IHttpClientFactory here
{
var response = await client.SendAsync(request);
await EnsureSuccessStatusCodeAsync(response, request, null).ConfigureAwait(false);
return response;
}
}
private static bool StatusCodeShouldBeRetried(FirebaseHttpException r)
{
if (r.ResponseMessage?.StatusCode < HttpStatusCode.InternalServerError)
{
return r.ResponseMessage.StatusCode == HttpStatusCode.RequestTimeout;
}
return true;
}
}
Instance of this class can be provided in FirebaseSDKConfiguration
which will be passed to FirebaseClient
constructor.
var sdkConfiguration = new FirebaseSDKConfiguration
{
HttpClientProxy = new FirebaseHttpClientProxy(),
Credentials = new JsonServiceAccountCredentials("json-service-account-credentials-string", false);
};
var firebaseClient = new FirebaseClient(sdkConfiguration);