简体   繁体   中英

Cosmos DB Newtonsoft Deserialization Issue

I am having a strange issue with CosmosDb unable to deserialise my class.

The error I am getting is

Could not create an instance of type TestApp.Entities.IVisitItem. Type is an interface or abstract class and cannot be instantiated

I have the following code in my startup class

 JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.Auto
        };

And when I look in the Data Explorer and look at my document, I can see that the type information is saved correctly

  "VisitItems": [
            {
                "$type": "TestApp.Entities.NoteVisitItem, TestApp.Entities",
                "Note": "fsfsdfdsfsdf",
                "VisitId": "22931c75-efb4-59ea-5b1b-7533bd8bb570",
                "VisitItemType": "Note",
                "Created": "0001-01-01T00:00:00",
                "CreatedById": null,
                "CreatedByName": null,
                "Id": "1e6233cf-e970-4b9f-b60b-a8fb62c94c81"
            }
        ]

If anyone can shed any light on what else I need to be doing to get this to deserialise correctly it would be appreciated.

BTW this is a .net core 2.1 project using Microsoft.Azure.DocumentDB/2.0.0-preview2.

I am using NewtonsoftJson 11.0.2 on all projects and this looks to be the same version the DocumentDB libraries are using.

Update -- here is my data access code

  public class CosmosDocumentDbClient : IDbClient
{
    private readonly ConcurrentDictionary<string,Uri> _collectionLinks = new ConcurrentDictionary<string, Uri>();
    private readonly IList<IDisposable> _disposables = new List<IDisposable>();
    private DocumentClient _client;
    private string _databaseId;

    public CosmosDocumentDbClient(IConfigurationRegister configurationRegister)
    {
        var subscription = configurationRegister.Configuration<CosmosDbConfiguration>().Subscribe(c =>
        {
            this._databaseId = c.DatabaseId;
            this._client = new DocumentClient(new Uri(c.EndpointUri), c.Key);

            this.InitialiseDb(this._client, c.DatabaseId, "Case", "Owner").Wait();
        });

        _disposables.Add(subscription);
    }

    public async Task Initialise()
    {
    }

    public IQueryable<TEntity> GetCollection<TEntity>()
    {
        return this._client.CreateDocumentQuery<TEntity>(GetCollectionLink(typeof(TEntity).Name));
    }

    public async Task<List<TEntity>> ToListAsync<TEntity>(Func<IQueryable<TEntity>, IQueryable<TEntity>> items)
    {
        return  await items.Invoke(
            this._client.CreateDocumentQuery<TEntity>(GetCollectionLink(typeof(TEntity).Name)))
            .ToListAsync();
    }

    public async Task<TEntity> FirstOrDefaultAsync<TEntity>(IQueryable<TEntity> query)
    {
        return (await query.Take(1).ToListAsync()).FirstOrDefault();
    }

    public async Task<TEntity> Get<TEntity>(string id)
    {           
       var docUri = UriFactory.CreateDocumentUri(_databaseId, typeof(TEntity).Name,id);
       return await _client.ReadDocumentAsync<TEntity>(docUri);
    }

    public async Task Insert<TEntity>(TEntity entity) where TEntity : IEntity
    {
        await _client.UpsertDocumentAsync(GetCollectionLink(typeof(TEntity).Name), entity);
    }

    public  async Task Update<TEntity>(TEntity entity) where TEntity : IEntity
    {
        try
        {
            var docUri = UriFactory.CreateDocumentUri(_databaseId, typeof(TEntity).Name,entity.Id);
            await _client.ReplaceDocumentAsync(docUri, entity);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }

    }

    private async Task InitialiseDb(DocumentClient client, string databaseId, params string[] collectionIds)
    {
        await client.CreateDatabaseIfNotExistsAsync(new Database() {Id = databaseId});

        foreach (var collectionId in collectionIds)
        {
            await client.CreateDocumentCollectionIfNotExistsAsync(
                UriFactory.CreateDatabaseUri(databaseId), new DocumentCollection {Id = collectionId});
        }
    }

    private Uri GetCollectionLink(string collectionName)
    {
        if (!_collectionLinks.ContainsKey(collectionName))
        {
            _collectionLinks.TryAdd(collectionName,
                UriFactory.CreateDocumentCollectionUri(_databaseId, collectionName));
        }
        return _collectionLinks[collectionName];
    }

So, as we concluded through comments.

The DocumentClient of CosmosDB has it's own JsonSerialiser settings object which is where you need to configure the TypeNameHandling setting.

Setting it only on the JsonConvert.DefaultSettings level will make it work on serialisation but it fails during deserialisation.

Adding it at the DocumentClient level will fix the issue.

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