Use case
Angular Firebase application that uses firestore as a form of persistence needs to communicate with a Discord Bot. I've built a synchronizer bot to mediate between the existing external bot and the web application. There is sufficient information for document to be found and update to occur.
Problem
Update does not happen due to problem with conversion.
Exception: Unable to create converter for type Models.Participant
Question
After attempting several solutions, mostly using json conversion, I've simplified the code in order to get/give a better grasp of the situation. I'm assuming something obvious is lacking but due to my inexperience with firebase (firestore) I'm unable to see what at this point.
public async Task<bool> NextTurn(string encounterName)
{
var encounterSnapshotQuery = await _encountersCollection.WhereEqualTo("name", encounterName).GetSnapshotAsync();
foreach (DocumentSnapshot encounterSnapshot in encounterSnapshotQuery.Documents)
{
Dictionary<string, object> data = encounterSnapshot.ToDictionary();
var name = data["name"].ToString();
if (name == encounterName)
{
var participants = data["participants"].ToParticipants();
var orderedParticipants = participants.OrderByDescending(x => x.initiative + x.roll).ToList();
var current = orderedParticipants.Single(x => x.isCurrent != null && x.isCurrent is bool && (bool)x.isCurrent);
var currentIndex = orderedParticipants.FindIndex(x => x.characterName == current.characterName);
var next = orderedParticipants[currentIndex + 1];
current.hasPlayedThisTurn = true;
current.isCurrent = false;
next.isCurrent = true;
var updates = new Dictionary<FieldPath, object>
{
{ new FieldPath("participants"), orderedParticipants }
};
try
{
await encounterSnapshot.Reference.UpdateAsync(updates);
}
catch (Exception ex)
{
_logger.LogError(new EventId(), ex, "Update failed.");
}
}
}
return true;
}
If there are obvious mistakes in approach suggestions are also welcome.
Update
Full exception message:
at Google.Cloud.Firestore.Converters.ConverterCache.CreateConverter(Type targetType)
at Google.Cloud.Firestore.Converters.ConverterCache.<>c.<GetConverter>b__1_0(Type t)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Google.Cloud.Firestore.Converters.ConverterCache.GetConverter(Type targetType)
at Google.Cloud.Firestore.SerializationContext.GetConverter(Type targetType)
at Google.Cloud.Firestore.ValueSerializer.Serialize(SerializationContext context, Object value)
at Google.Cloud.Firestore.Converters.ListConverterBase.Serialize(SerializationContext context, Object value)
at Google.Cloud.Firestore.ValueSerializer.Serialize(SerializationContext context, Object value)
at Google.Cloud.Firestore.WriteBatch.<>c__DisplayClass12_0.<Update>b__1(KeyValuePair`2 pair)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
at Google.Cloud.Firestore.WriteBatch.Update(DocumentReference documentReference, IDictionary`2 updates, Precondition precondition)
at Google.Cloud.Firestore.DocumentReference.UpdateAsync(IDictionary`2 updates, Precondition precondition, CancellationToken cancellationToken)
Participant Model
public class Participant
{
public string playerName { get; set; }
public int experience { get; set; }
public int level { get; set; }
public string characterName { get; set; }
public string playerUid { get; set; }
public object joined { get; set; }
public string type { get; set; }
public object abilities { get; set; }
public int roll { get; set; }
public bool? isCurrent { get; set; }
public int sizeModifier { get; set; }
public int initiative { get; set; }
public bool? hasPlayedThisTurn { get; set; }
public string portraitUrl { get; set; }
}
Participant typescript interface used to create the model on firestore
export interface Participant {
playerName: string,
characterName: string,
initiative: number,
roll: number,
playerUid: string,
joined: Date,
portraitUrl: string,
level: number,
experience: number,
isCurrent: boolean,
sizeModifier: number,
type: string,
abilities: {
strength: number,
dexterity: number,
constitution: number,
intelligence: number,
wisdom: number,
charisma: number
},
hasPlayedThisTurn: boolean
}
Do note that I've played around with changing the C# model to try and fix this. This is the current state. Message was the same regardless of what changes I've made.