简体   繁体   中英

Firestore real-time-updates in c#

I'm trying to subscribe to real-time updates with Cloud Firestore in c# using Google.Cloud.Firestore.V1Beta1 . I'm using the following code, which receives updates for a short time, until the stream is closed. Has anyone got FirestoreClient.Listen to work?

// Create client
FirestoreClient firestoreClient = FirestoreClient.Create();

// Initialize streaming call, retrieving the stream object
FirestoreClient.ListenStream duplexStream = firestoreClient.Listen();

// Create task to do something with responses from server
Task responseHandlerTask = Task.Run(async () =>
{
    IAsyncEnumerator<ListenResponse> responseStream = duplexStream.ResponseStream;
    while (await responseStream.MoveNext())
    {
        ListenResponse response = responseStream.Current;
        Console.WriteLine(response);
    }
});

// Send requests to the server

var citiesPath = string.Format("projects/{0}/databases/{1}/documents/cities/CJThcwCipOtIEAm2tEMY", projectId, databaseId);

// Initialize a request
var dt = new DocumentsTarget { };
dt.Documents.Add(citiesPath);

ListenRequest request = new ListenRequest
{
    Database = new DatabaseRootName(projectId, databaseId).ToString(),
    AddTarget = new Target
    {
        Documents = dt
    }
};
// Stream a request to the server
await duplexStream.WriteAsync(request);

// Await the response handler.
// This will complete once all server responses have been processed.
Console.WriteLine("Awaiting responseHandlerTask");
await responseHandlerTask;

Edit 1: I've tried setting the expiration explicitly to never expire, but still no luck, I get 5 minutes in then receive a RST_STREAM.

//Setup no expiration for the listen
CallSettings listenSettings = CallSettings.FromCallTiming(CallTiming.FromExpiration(Expiration.None));

// Initialize streaming call, retrieving the stream object
FirestoreClient.ListenStream duplexStream = firestoreClient.Listen(listenSettings); 

Edit 2: It seems like a bit of a kludge, but I found it works to keep track of the last resetToken, catch the exception, then restart the request with the request token. I've updated the code that makes the original request to take an optional resumeToken.

ListenRequest request = new ListenRequest
{
    Database = new DatabaseRootName(projectId, databaseId).ToString(),
    AddTarget = new Target
    {
        Documents = dt
    }
};

if (resumeToken != null)
{
    Console.WriteLine(string.Format("Resuming a listen with token {0}", resumeToken.ToBase64()));
    request.AddTarget.ResumeToken = resumeToken;
}

// Stream a request to the server
await duplexStream.WriteAsync(request); 

It's not perfect, but I think it's the way Google implemented it in Node.js. It does result in an API call every 5 minutes, so there is some expense to it. Maybe that's the why it works this way?

Thanks

Until Jon finishes the official support, you can use something I put together if you need it right away. https://github.com/cleversolutions/FirebaseDotNetRamblings/blob/master/FirebaseDocumentListener.cs Its an extension method you can drop into your project and use like this:

//Create our database connection
FirestoreDb db = FirestoreDb.Create(projectId);

//Create a query
CollectionReference collection = db.Collection("cities");
Query qref = collection.Where("Capital", QueryOperator.Equal, true);

//Listen to realtime updates
FirebaseDocumentListener listener = qref.AddSnapshotListener();

//Listen to document changes
listener.DocumentChanged += (obj, e) =>
{
    var city = e.DocumentSnapshot.Deserialize<City>();
    Console.WriteLine(string.Format("City {0} Changed/Added with pop {1}", city.Name, city.Population));
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM