当前位置: 首页 > 知识库问答 >
问题:

使用通用JSON对象的.NET核心Web API和MongoDB驱动程序

时宾实
2023-03-14

我正在创建一个ASP.NET Web API,以便在MongoDB数据库中执行CRUD操作。我已经能够根据以下Microsoft教程创建一个简单的应用程序:使用ASP.NET核心和MongoDB创建一个web API。

与我发现的其他教程一样,本教程都使用定义的数据模型(在上面的教程中是图书模型)。在我的例子中,我需要使用通用JSON对象执行CRUD操作。例如,JSON对象可能是以下任何一个示例:

例1:

{_id: 1, name: 'Jon Snow', address: 'Castle Black', hobbies: 'Killing White Walkers'}
{_id: 2, name: 'Daenerys Targaryen', family: 'House Targaryen', titles: ['Queen of Meereen', 'Khaleesi of the Great Grass Sea', 'Mother of Dragons', 'The Unburnt', 'Breaker of Chains', 'Queen of the Andals and the First Men', 'Protector of the Seven Kingdoms', 'Lady of Dragonstone']}
public class BookService
{
    private readonly IMongoCollection<object> _books;

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);

        _books = database.GetCollection<object>(settings.BooksCollectionName);
    }

    public List<object> Get() => _books.Find(book => true).ToList();

    //public object Get(string id) => _books.Find<object>(book => book.Id == id).FirstOrDefault();

    //public object Create(object book)
    //{
    //    _books.InsertOne(book);
    //    return book;
    //}

    //public void Update(string id, object bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn);

    //public void Remove(object bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id);

    //public void Remove(string id) => _books.DeleteOne(book => book.Id == id);
}

“object”不包含“id”的定义,也找不到接受第一个类型为“object”的参数的可访问扩展方法“id”(您是否缺少using指令或程序集引用?)

InvalidCastException:无法将类型“D__51”的对象强制转换为类型“System.Collections.IdictionaryEnumerator”。

所以,我的问题是,如何将通用JSON数据类型与ASP.NET核心Web API和MongoDB驱动程序一起使用?

我在MongoDB的Github页面上找到了一篇文章,解释了如何在ASP.NET核心驱动程序中使用静态和动态数据。所以我对图书模型做了以下修改

public class Book
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set; }

    public string Category { get; set; }

    public string Author { get; set; }

    [BsonExtraElements]
    public BsonDocument Metadata { get; set; } //new property
}

现在我面临着其他问题,如果我的数据格式与模型完全相同,我就可以列出数据并在数据库中创建新条目。但是,如果我试图用bellow格式创建一个新条目,我会得到一个错误:

{
    "Name": "test 5",
    "Price": 19,
    "Category": "Computers",
    "Author": "Ricky",
    "Metadata": {"Key": "Value"} //not working with this new field
}

System.InvalidCastException:无法将“mongodb.bson.bsonElement”类型的对象强制转换为“mongodb.bson.bsonDocument”类型。

System.InvalidCastException:无法将类型为“mongodb.bson.bsonDocument”的对象强制转换为类型为“mongodb.bson.bsonBoolean”。

基于Mongo文档,BsonExtraElements应该允许将通用/动态数据附加到模型。我在新方法中做错了什么?

更新#2:添加了错误的详细堆栈跟踪

public class BookService
{
    private readonly IMongoCollection<Book> _books;

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);

        _books = database.GetCollection<Book>(settings.BooksCollectionName);
    }

    public List<Book> Get() => _books.Find(book => true).ToList();


    public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault();

    public Book Create(Book book)
    {
        _books.InsertOne(book);
        return book;
    }

    public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn);

    public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id);

    public void Remove(string id) => _books.DeleteOne(book => book.Id == id);
}
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
    private readonly BookService _bookService;

    public BooksController(BookService bookService)
    {
        _bookService = bookService;
    }

    [HttpGet]
    public ActionResult<List<Book>> Get() => _bookService.Get(); // error happens when executing Get()

    [HttpGet("{id:length(24)}", Name = "GetBook")]
    public ActionResult<Book> Get(string id)
    {
        var book = _bookService.Get(id);

        if (book == null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public ActionResult<Book> Create([FromBody] Book book)
    {
        _bookService.Create(book);

        return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
    }

    [HttpPut("{id:length(24)}")]
    public IActionResult Update(string id, Book bookIn)
    {
        var book = _bookService.Get(id);

        if (book == null)
        {
            return NotFound();
        }

        _bookService.Update(id, bookIn);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public IActionResult Delete(string id)
    {
        var book = _bookService.Get(id);

        if (book == null)
        {
            return NotFound();
        }

        _bookService.Remove(book.Id);

        return NoContent();
    }
}
//non-pretty
{ "_id" : ObjectId("5df2b193405b7e9c1efa286f"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" }
{ "_id" : ObjectId("5df2b193405b7e9c1efa2870"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
{ "_id" : ObjectId("5df2b1c9fe91da06078d9fbb"), "Name" : "A New Test", "Price" : 43.15, "Category" : "Computers", "Author" : "Ricky", "Metadata" : { "Key" : "Value" } }

Mongo司机的详细结果:

[/0]:{api.models.book}作者[string]:“Ralph Johnson”类别[string]:“computers”Id[string]:“5df2b193405b7e9c1efa286f”元数据[BsonDocument]:null Name[string]:“design patterns”价格[decimal]:54.93

[/1]:{api.models.book}作者[string]:“Robert C.Martin”类别[string]:“computers”Id[string]:“5df2b193405b7e9c1efa2870”元数据[BsonDocument]:null Name[string]:“clean code”价格[decimal]:43.15

[/2]:{api.models.book}作者[string]:“ricky”类别[string]:“computers”Id[string]:“5df2b1c9fe91da06078d9fbb”元数据[BsonDocument]:{{“Metadata”:{“key”:“value”}}}AllowDuplicateNames[bool]:false AsBoolean[bool]:'(new items2).Metadata.AsBsonArray“引发类型为”System.InvalidCastException“AsBsonBinaryData[BsonBinaryData]:”(new System.Collections.generic.icollectionDebugView(test).items2).Metadata.AsBsonBinaryData“引发类型为”System.InvalidCastException“asbsonData[BsonBinaryData]:”asbsonData[BsonBinaryData]:“(new}}}AsBsonJavaScript[BSOnJavaScript]:“(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.asbsonJavaScript”引发类型为“System.InvalidCastException”AsbsonJavaScript“AsbsonJavaScript[bsonJavaScriptTwithScope[bsonJavaScriptScope]:”(new System.Collections.Generic.icollectionS.Generic.icollectionDebugView(test).Items2).“”引发“System.InvalidCastException”类型的异常AsBsonMinKey[BsonMinKey]:“(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.AsBsonMinKey”引发“System.InvalidCastException”类型的异常AsBsonNull]:“(new System.Collections.Generic.icollectionDebugView(test).Items2)。Metadata.AsBsonMinKey”引发“t).items2).metadata.asbsonRegulareXPression“引发类型为”System.InvalidCastException“AsBsonSymbol[BsonSymbol]:”(new System.Collections.generic.icollectionDebugView(test).Items2)“.metadata.AsBsonSymbol”引发类型为“System.InvalidCastException”AsBsonTimestamp[BsonTimestamp[BsonTimestamp]:“(new gview(test).items2).metadata.AsBsonUndefined”抛出类型为“system.invalidcastexception”AsBsonValue[BsonValue]:{{“metadata”:{“key”:“value”}}AsByteArray[byte[]]:“(new system.collections.generic.icollectiondebugview(test).items2).metadata.AsByteArray”抛出类型为“system.invalidcastexception”类型“System.InvalidCastException”AsDecimal[decimal]:“(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.AsDecimal”引发了类型“System.InvalidCastException”AsDecimal128[Decimal128]:“(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.AsDecimal128)引发了类型”System.InvalidCastException AsGuid[Guid]:“(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.AsGuid”引发类型为“System.InvalidCastException”AsInt32[int]:“(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.AsInt32”引发类型为“System.InvalidCastException”AsInt32[int]:“(newStException“AsLocalTime[DateTime]:”(new System.Collections.Generic.icollectionDebugView(test).Items2).Metadata.AsLocalTime“引发了类型为”System.InvalidCastException“[更多]名称[string]:”一个新测试“价格[decimal]:43.15

共有1个答案

乐正涵忍
2023-03-14

您应该使用BSONDocument在C#中与MongoDB一起处理非类型化数据。

private readonly IMongoCollection<BsonDocument> _books;

这并不理想,因为C#更喜欢强类型的字段名。我建议尝试为数据构建POCO模型,以简化查询/更新操作。如果不能做到这一点,就不能使用类似于

_books.DeleteOne(book => book.Id == id);

您将需要使用字典类型accesor语法,例如:

_books.DeleteOne(book => book["_id"] == id);
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]

虽然您提供的示例数据确实有些不同,但仍然可以创建一个POCO模型,允许您在查询中使用类型信息。我建议您调查一下这样做的可行性,以简化您的开发。正如我在上面解释的,这不是一个要求,但它肯定会改善查询体验。

BSONExtraElements属性用于驱动程序反序列化模型中没有的字段。例如,如果将metadata字段重命名为foo并重新运行它。数据库中的metadata字段现在实际上应该包含在foo字段中。

System.InvalidCastException:无法将类型为“mongodb.bson.bsonDocument”的对象强制转换为类型为“mongodb.bson.bsonBoolean”。

BSONDocument是一种惰性类型。直到你尝试访问它,它才“知道”它包含什么。这是通过为许多不同的字段提供getter来处理的,所有字段都由它可能包含的类型命名。你可以在这里看到他们。

ASP中的JSON序列化程序在每个字段(AsbooleanAsbsonArrayAsbsonBinaryData等)上尽职尽责地html" target="_blank">迭代,试图检索要序列化到JSON的值。不幸的是,由于metadata中的值不能强制转换为其中的大多数(或任何)值,因此大多数都将失败。

我认为您需要告诉JSON序列化器忽略metadata字段,或者为BSONDocument编写一个JSON序列化器。

 类似资料:
  • 我正在尝试从页面: 控制器: 但是我似乎无法在前端检索会话

  • 我已经创建了非核心webapi项目来与移动应用程序交互。例如,如果我创建了一个名为Data的控制器,它有一个名为Search的方法,如下图所示。该项目已配置为发送和接收json数据。 我可以通过使用以下url,使用postman向该方法发送post请求http://localhost/api/Data/search 类似地,我可以在控制器内创建其他函数,并使用路由“/api/[controller

  • 任何人都可以帮助我将MongoDB驱动程序配置为JBoss中连接池的核心模块。请参阅我在阅读几篇文章后尝试的以下步骤。 EAP_HOME/modules/com/mongodb/main/ 创建了一个目录,并复制了 mongodb-driver-3.4.0-rc1.jar(rc1 版本,因为稳定版 3.3.0 不包含 MongoClientFactory.class)并创建了模块.xml文件,如下

  • 我已经完成了一个应用程序使用反应在前端和. net核心在后端。现在我需要将此存储库发布给heruko。本地,当我做dotnet构建和运行它工作正常,但同时推动它heroku我得到一个错误 :/bin/sh:2:/tmp/tmp35fd435a650b4b94a93ab28064f9c447。执行官。cmd:npm:not found remote:/tmp/build_46ea6d26/API/A

  • 我试图使用servlet上的Java驱动程序连接到托管在mlab上的MongoDB数据库。 问题是我得到以下错误: 这样做对吗?我还应该做什么/代替吗?

  • 我正在为PoC点构建我的dotnet core webapi服务,我关心的是为其他ARCH/Devs提供适当的指导。 “相同”方法签名的变化很少 公共动态获取(字符串名称=_defaultName) 公共IActionResult Get(字符串名称=_DefaultName) 获取公共异步任务(字符串名称=_defaultName) 撇开我为什么使用动态类型而不是自定义类型的讨论不谈,我试图理解