Десериализация BSON ReadBsonType может быть вызвана только тогда, когда State имеет тип
У меня есть следующий код:
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using MongoDBTest;
using ServiceStack;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace protocol.server.API.Clients
{
public class ClientService : ServiceStack.Service
{
class CylinderSerializer : SerializerBase<Cylinder>
{
public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, Cylinder value)
{
var wr = context.Writer;
wr.WriteStartDocument();
wr.WriteName("_id");
wr.WriteObjectId(ObjectId.GenerateNewId());
wr.WriteName("description");
wr.WriteString(value.description.type);
context.Writer.WriteEndDocument();
}
public override Cylinder Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
context.Reader.ReadStartDocument();
Cylinder a = new Cylinder();
a.Id = context.Reader.ReadObjectId();
while (context.Reader.State != BsonReaderState.Type && context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
a.description.type = context.Reader.ReadString();
a.description.kind = context.Reader.ReadString();
a.description.year = (short)context.Reader.ReadInt32();
a.description.producer = context.Reader.ReadString();
}
return a;
}
public async Task<List<Cylinder>> Get(GetObjects request)
{
MongoDB.Bson.Serialization.BsonSerializer.RegisterSerializer(typeof(Cylinder), new CylinderSerializer());
IMongoCollection<Cylinder> collection = Connect._database.GetCollection<Cylinder>("Cylinders");
var results = await collection.Find(_ => true).ToListAsync();
return results;
}
}
}
и получите ошибку:
ReadBsonType может быть вызван только когда State является Type, а не когда State является Value
в соответствии:
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
Я хочу десериализовать мои объекты, они выглядят так:
{
"_id" : ObjectId("5826010eb831ee1c70df5f16"),
"description" : {
"type" : "Cylinder",
"kind" : "rgdgg",
"year" : NumberInt(1997),
"producer" : "hnnghng",
"brands" : [
"trhr"
],
"model" : [
"Baws"
],
"internalproducerdesignation" : "tw6",
"origin" : "Greece"
},
"elements" : {
"nonspringelements" : NumberInt(0),
"springelements" : NumberInt(11),
"discelements" : NumberInt(0),
"magneticelements" : NumberInt(0),
"activeelements" : NumberInt(11),
"passiveelements" : NumberInt(0),
"totalelements" : NumberInt(11)
},
"profiles" : [
"d1",
"d11"
],
"certifications" : [
"",
""
],
"colors" : [
"brown",
"chrome"
],
"specialfittings" : [
"gf",
"hrthr",
"hgnn",
"ngnn",
"hngngn",
"nghnnn"
],
"cutdepths" : NumberInt(7),
"rareness" : "rare",
"value" : {
"new" : "0",
"used" : "$50"
},
"Blaw" : {
"tgtgt" : 10.0,
"hzhz" : true
},
"availableat" : "gtgtgtgt",
"specialabout" : "jujujuju",
"development" : {
"predecessor" : "",
"follower" : "rfrfr"
},
"media" : [
]
}
Мой Clinder.cs:
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Attributes;
using System;
using System.Collections.Generic;
using System.Globalization;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace protocol.server.API.Clients
{
public class Cylinder
{
[BsonSerializer(typeof(ProductAttributeSerializer))]
public class ProductAttributeSerializer : IBsonSerializer, IBsonArraySerializer
{
public Type ValueType { get { return typeof(List<string>); } }
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var type = context.Reader.GetCurrentBsonType();
List<String> items = new List<String>();
switch (type)
{
case BsonType.Document:
case BsonType.Array:
context.Reader.ReadStartArray();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
items.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
return new mode(items);
default:
throw new NotImplementedException($"No implementation to deserialize {type}");
}
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
var d = value;
var attributes = value as List<string>;
if (attributes != null)
{
context.Writer.WriteStartArray();
foreach (string attr in attributes)
{
context.Writer.WriteString(attr);
}
context.Writer.WriteEndArray();
}
}
public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
{
string elementName = null;
var serializer = BsonSerializer.LookupSerializer(typeof(string));
var nominalType = typeof(string);
serializationInfo = new BsonSerializationInfo(elementName, serializer, nominalType);
return true;
}
}
[BsonId]
public ObjectId Id { get; set; }
[BsonSerializer(typeof(ProductAttributeSerializer))]
public class mode
{
public mode(List<String> pItems)
{
this.items = new List<String>();
this.items.Clear();
this.items.AddRange(pItems);
}
public List<String> items { get; set; }
}
public class des
{
public string type { get; set; }
public string kind { get; set; }
public short year { get; set; }
public string producer { get; set; }
public List<string> brands { get; set; }
public string internalproducerdesignation { get; set; }
public string origin { get; set; }
public mode model { get; set; }
}
public class elem
{
public short nonspringelements { get; set; }
public short springelements { get; set; }
public short discelements { get; set; }
public short magneticelements { get; set; }
public short activeelements { get; set; }
public short passiveelements { get; set; }
public short totalelements { get; set; }
}
public des description = new des();
public elem elements = new elem();
public IEnumerable<string> profiles { get; set; }
public IEnumerable<string> certifications { get; set; }
public IEnumerable<string> colors { get; set; }
public IEnumerable<string> specialfittings { get; set; }
public short cutdepths { get; set; }
public string rareness { get; set; }
public class val
{
public String @new { get; set; }
public String used { get; set; }
}
public val value = new val();
public class Pi
{
public Double difficulty { get; set; }
public bool alreadypicked { get; set; }
}
public Pi Picking = new Pi();
public string availableat { get; set; }
public string specialabout { get; set; }
public class devel
{
public string predecessor { get; set; }
public string follower { get; set; }
}
public devel development = new devel();
public Object[] media;
}
}
Как предотвратить эту ошибку? Я просто хочу десериализовать свои объекты...
3 ответа
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
должно быть
while (context.Reader.State != BsonReaderState.Type || context.Reader.ReadBsonType() != BsonType.EndOfDocument)
Будет ли проверить тип, если состояние является типом. Если это не тип, вы пройдете, а не проверить тип
Не уверен, зачем использовать цикл while, если вы просто хотите заполнить свойства одного объекта (описание). Вы можете сделать это так:
public override Cylinder Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) {
context.Reader.ReadStartDocument();
Cylinder a = new Cylinder();
a.Id = context.Reader.ReadObjectId();
context.Reader.ReadStartDocument();
a.description.type = context.Reader.ReadString();
a.description.kind = context.Reader.ReadString();
a.description.year = (short) context.Reader.ReadInt32();
a.description.producer = context.Reader.ReadString();
return a;
}
Тест (файл bson.txt дословно скопирован из вашего вопроса):
static void Main(string[] args) {
var cylinder = new CylinderSerializer().Deserialize(BsonDeserializationContext.CreateRoot(new BsonDocumentReader(BsonDocument.Parse(File.ReadAllText(@"G:\tmp\bson.txt")))));
Console.ReadKey();
}
Так много написано для написания собственного сериализатора. Вот как я сделал для цилиндра. Мне удалось десериализовать ваш образец таким образом.
Обратите внимание, что существует один простой метод справки для десериализации массива строк. У вас нет класса для "бла" данных, поэтому я читаю его в неиспользуемых переменных.
public override Cylinder Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
context.Reader.ReadStartDocument();
Cylinder a = new Cylinder {Id = context.Reader.ReadObjectId()};
context.Reader.ReadStartDocument();
a.description.type = context.Reader.ReadString();
a.description.kind = context.Reader.ReadString();
a.description.year = (short)context.Reader.ReadInt32();
a.description.producer = context.Reader.ReadString();
context.Reader.ReadStartArray();
a.description.brands = new List<string>();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
a.description.brands.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
context.Reader.ReadStartArray();
a.description.model = new Cylinder.mode(new List<string>());
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
a.description.model.items.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
a.description.internalproducerdesignation = context.Reader.ReadString();
a.description.origin = context.Reader.ReadString();
context.Reader.ReadEndDocument();
context.Reader.ReadStartDocument();
a.elements = new Cylinder.elem
{
nonspringelements = (short) context.Reader.ReadInt32(),
springelements = (short) context.Reader.ReadInt32(),
discelements = (short) context.Reader.ReadInt32(),
magneticelements = (short) context.Reader.ReadInt32(),
activeelements = (short) context.Reader.ReadInt32(),
passiveelements = (short) context.Reader.ReadInt32(),
totalelements = (short) context.Reader.ReadInt32()
};
context.Reader.ReadEndDocument();
a.profiles = readStringArray(context);
a.certifications = readStringArray(context);
a.colors = readStringArray(context);
a.specialfittings = readStringArray(context);
a.cutdepths = (short) context.Reader.ReadInt32();
a.rareness = context.Reader.ReadString();
context.Reader.ReadStartDocument();
a.value = new Cylinder.val
{
@new = context.Reader.ReadString(),
used = context.Reader.ReadString()
};
context.Reader.ReadEndDocument();
context.Reader.ReadStartDocument();
var blawInt = context.Reader.ReadDouble();
var blawBool = context.Reader.ReadBoolean();
context.Reader.ReadEndDocument();
a.availableat = context.Reader.ReadString();
a.specialabout = context.Reader.ReadString();
context.Reader.ReadStartDocument();
a.development = new Cylinder.devel
{
predecessor = context.Reader.ReadString(),
follower = context.Reader.ReadString()
};
context.Reader.ReadEndDocument();
var objects=new List<object>();
context.Reader.ReadStartArray();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
objects.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
a.media = objects.ToArray();
context.Reader.ReadEndDocument();
return a;
}
private static IEnumerable<string> readStringArray(BsonDeserializationContext context)
{
context.Reader.ReadStartArray();
var strings = new List<string>();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
strings.Add(context.Reader.ReadString());
}
context.Reader.ReadEndArray();
return strings;
}