ASP.NET WebAPI 中的无限方法执行(Mongodb 反序列化)

Infinitely method execution (Mongodb Deserialization) in ASP.NET WebAPI

简而言之:默认Console Application 项目中的方法工作正常,但在另一个项目(asp.net WebAPI) 中相同的方法不起作用。我有两个 mongoDB 集合,如下所示。 subjects 集合(JSON)的示例文档:

{
        "_id" : ObjectId("5b9a2637635d16b2a2c5c562"),
        "userId" : ObjectId("5b9a23d1a54d26b98f6acf34"),
        "name" : "someName",
        "notes" : [
                {
                        "date" : ISODate("2012-11-20T05:05:15.229Z"),
                        "title" : "someTitle",
                        "body" : "Note body - long teeeeeeext",
                        "files" : [ ]
                }
        ]
}

用户集合的示例文档:

{
        "_id" : ObjectId("5b9a23d1a54d26b98f6acf34"),
        "loginName" : "someName",
        "pass" : "hashedpassword"
}

我写了几个类(POCO Representation):

public class Subject
{
    [BsonElement("_id")]
    public ObjectId Id { get; set; }

    [BsonElement("name")]
    public string Name { get; set; }

    [BsonElement("notes")]
    public List<Notes> Notes { get; set; }

    [BsonElement("userId")]
    public ObjectId UserId { get; set; }
}

public class Notes
{
    [BsonElement("date")]
    [BsonRepresentation(BsonType.DateTime)]
    public DateTime Date { get; set; }

    [BsonElement("title")]
    public string Title { get; set; }

    [BsonElement("body")]
    public string Body { get; set; }

    [BsonElement("files")]
    public List<ObjectId> Files { get; set; }
}

public class User
{
    [BsonElement("_id")]
    public ObjectId Id { get; set; }

    [BsonElement("loginName")]
    public string LoginName  { get; set; }

    [BsonElement("pass")]
    public string HashedPass { get; set; }
}

和 类 用于数据库操作:

public class MongoDataModel
{
   /// <summary>
   /// Singleton
   /// </summary>
    public static MongoDataModel Instance { get; set; }

   public IMongoClient MongoClient { get; set; }

   public IMongoDatabase CurrentMongoDB { get; set; }

   public string CurrentDB { get; set; }

   public async Task<List<User>> GetUsers(IMongoDatabase db)
   {
       List<User> users = await db.GetCollection<User>(MongoSettings.Instanse.UsersCollection)
           .Find(new BsonDocument())
           .ToListAsync();

       return users;
   }

   public async Task<List<Subject>> GetSubjects(IMongoDatabase db)
   {
       List<Subject> subjects = await db.GetCollection<Subject>(MongoSettings.Instanse.SubjectCollection)
           .Find(new BsonDocument())
           .ToListAsync();

       return subjects;
   }

   public MongoDataModel()
   {
       CurrentDB = "reminder1";
       MongoClient = new MongoClient(MongoSettings.Instanse.ClientSettings);
       CurrentMongoDB = MongoClient.GetDatabase(CurrentDB);
   }

   static MongoDataModel()
   {
       Instance = new MongoDataModel();
   }
}

public class MongoSettings
{
    public MongoClientSettings ClientSettings { get; set; }

    /// <summary>
    /// Singleton
    /// </summary>
    public static MongoSettings Instanse { get; set; }

    public string UsersCollection { get; set; }

    public string SubjectCollection { get; set; }

    private string Host { get; set; }

    private int Port { get; set; }

    static MongoSettings()
    {
        Instanse = new MongoSettings()
        {
            Host = "localhost",
            Port = 27017,

            UsersCollection = "users",
            SubjectCollection = "subjects",
        };

        Instanse.ClientSettings = new MongoClientSettings
        {
            Server = new MongoServerAddress(Instanse.Host, Instanse.Port)
        };
    }
}

控制台应用程序代码,工作正常:

class Program
{
    static void Main(string[] args)
    {
        MongoDataModel.Instance
            .GetUsers(MongoDataModel.Instance.CurrentMongoDB)
            .GetAwaiter()
            .GetResult().ForEach(usr => {
                Console.WriteLine("Test user values\nUser id: {0}\nlogin:{1}\nHashed pass:{2}\n",
                    usr.Id, usr.LoginName, usr.HashedPass);
        });

        MongoDataModel.Instance
            .GetSubjects(MongoDataModel.Instance.CurrentMongoDB)
            .GetAwaiter()
            .GetResult()
            .ForEach(subj => {
                Console.WriteLine("Test subject values\nid:{0}\nName:{1}\nNumber of notes:{2}\nNotes:",
                    subj.Id, subj.Name, subj.Notes.Count);

                    subj.Notes.ForEach(note => {
                        Console.WriteLine(" Note Title:{0}\n Note Body:{1}\n NoteDate:{2}",
                            note.Title, note.Body, note.Date.ToString());
                    });
        });

        Console.ReadLine();
    }
}

控制台输出(上面的代码工作正常):

Test user values
User id: 5b9a23d1a54d26b98f6acf34
login:someName
Hashed pass:hashedpassword

Test subject values
id:5b9a2637635d16b2a2c5c562
Name:someName
Number of notes:1
Notes:
 Note Title:someTitle
 Note Body:Note body - long teeeeeeext
 NoteDate:11/20/2012 5:05:15 AM

我将 JSON 格式化程序设置为默认格式化程序。 ASP.NET WebAPI 代码:

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<User> Get()
    {
        List<User> users = MongoDataModel.Instance
            .GetUsers(MongoDataModel.Instance.CurrentMongoDB)
            .GetAwaiter()
            .GetResult();

        TestMethod();

        return users;
    }

    private void TestMethod() { }
}

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Formatters.JsonFormatter.SupportedMediaTypes
              .Add(new MediaTypeHeaderValue("text/html"));

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

在 Chrome(IIS) 中没有得到那个值,因为方法没有 return 这个值。 第一个断点有效,因此方法执行,但第二个断点从不执行:Chrome debug window Breakpoints

我不知道发生了什么。我对这种奇怪的代码行为感到很困惑。我的代码有什么问题?请帮忙。提前致谢!

是死锁了吗?如果是这样,那是因为您混合了异步和非异步代码,并且在尝试重新捕获同步上下文时发生了死锁。让代码一路异步。

public async Task<IEnumerable<User>> Get()
{
    List<User> users = await MongoDataModel.Instance.GetUsers(MongoDataModel.Instance.CurrentMongoDB);

    TestMethod();

    return users;
}

  • 有关详细信息,请参阅标记的副本
  • 您应该使用与 Microsoft 相同的命名约定,即任何 returns TaskTask<T> 都应以 Async 为后缀,因此重命名 GetUsersGetUsersAsync.
  • 如果要使用异步,请在整个调用堆栈中使用它。