Десериализация 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;
    }
Другие вопросы по тегам