<file_sep>﻿using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ToDoList.Models;

namespace ToDoList.Services
{
    public class MongoDBTrainingRepository : IRepository
    {
        MongoClient _client;
        private readonly IMongoCollection<ToDoItem> _collection;
       
        public MongoDBTrainingRepository()
        {
            _client = new MongoClient("mongodb://localhost:27017");
            _collection = _client.GetDatabase("test").GetCollection<ToDoItem>("ItemList");
        }

        public async Task DeleteAsync(string id)
        {
            await _collection.DeleteOneAsync(itemlist => itemlist.Id == id);
        }

        public async Task<ToDoItem> GetAsync(string id)
        {
            return await _collection.FindSync(itemlist => itemlist.Id == id).FirstAsync();
        }

        public async Task<List<ToDoItem>> QueryAsync(string description, bool? done)
        {
            IEnumerable<ToDoItem> models = await _collection.Find(itemlist => true).ToListAsync();

            if (!string.IsNullOrEmpty(description))
                models = models.Where(v => v.Description?.IndexOf(description, StringComparison.OrdinalIgnoreCase) >= 0);

            if (done != null)
                models = models.Where(v => v.Done == done.Value);

            return models.ToList();
            // return null;
            // return await _collection.Find(i => true).ToListAsync();
            // throw new NotImplementedException();
        }

        public async Task<ToDoItem> UpdateAsync(string id, ToDoItemUpdateModel updateModel)
        {
            //IEnumerable<ToDoItem> models = await _collection.Find(itemlist => true).ToListAsync();
            //models = await _collection.Find(itemlist => true).ToList();
            //if (_dic.TryGetValue(id, out var item))
            //{
            //    if (!string.IsNullOrEmpty(updateModel.Description))
            //        item.Description = updateModel.Description;

            //    if (updateModel.Favorite != null)
            //        item.Favorite = updateModel.Favorite.Value;

            //    if (updateModel.Done != null)
            //        item.Done = updateModel.Done.Value;

            //    return item;
            //}
            // return null;
             return null;
            // throw new NotImplementedException();
        }

        public async Task UpsertAsync(ToDoItem model)
        {
            await _collection.ReplaceOneAsync(itemlist => itemlist.Id == model.Id, model);          
        }
    }
}
<file_sep>import { UserService } from './../services/user.service';
import { ToDoItem } from './../app.todoitem ';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { identifierModuleUrl } from '@angular/compiler';

@Component({
  selector: 'app-todo-detail',
  templateUrl: './todo-detail.component.html',
  styleUrls: ['./todo-detail.component.css']
})
export class TodoDetailComponent implements OnInit {
  items$: ToDoItem[];
  id: string;
  constructor(private usersService: UserService, private router: Router, private route: ActivatedRoute) { }

  ngOnInit() {
    this.getService();
  }

  getService(): void {
    this.usersService.getUsers().subscribe((items) => {this.items$ = items});
  }

  switch(): void {
    if(confirm("Sure to discard changes")) {
        this.router.navigate(['/todo']);
    }
  }
}
<file_sep>﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using ToDoList.Models;
using ToDoList.Services;

namespace ToDoList.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ToDoItemController : ControllerBase
    {
        // private MemoryRepository _repository = MemoryRepository.Instance;
        private IRepository _repository;

        // public ToDoItemController(IRepository repository)
         public ToDoItemController()
         {
             _repository = new MongoDBTrainingRepository();
         }

        /// <summary>
        /// Query ToDoItem by specific description and done
        /// </summary>
        /// <remarks>
        /// In remarks, we can document some detail information
        /// </remarks>
        /// <param name="description">ToDoItem description</param>
        /// <param name="done">ToDoItem status</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ActionResult<List<ToDoItem>>> QueryAsync(
            string description, bool? done)
        {
            var list = await _repository.QueryAsync(description, done);
            return Ok(list);
        }

        [HttpPatch("{id}")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<ToDoItem>> UpdateAsync(
            [Required] string id,
            [Required] ToDoItemUpdateModel updateModel)
        {
            var modelInDb = await _repository.GetAsync(id);
            if (modelInDb == null)
                return NotFound(new Dictionary<string, string>() { { "message", $"Can't find {id}" } });

            //update
            var updated = await _repository.UpdateAsync(id, updateModel);
            return Ok(updated);
        }

        [HttpPut]
        public async Task<ActionResult<ToDoItem>> UpsertAsync(ToDoItem item)
        {
            //check id
            if (string.IsNullOrEmpty(item.Id))
                return BadRequest(new Dictionary<string, string>() { { "message", "Id is required" } });

            await _repository.UpsertAsync(item);

            var model = await _repository.GetAsync(item.Id);
            if (model == null)
                return new ObjectResult(500) { };

            return Ok(model);
        }

        [HttpDelete("{id}")]
        public async Task<ActionResult> DeleteAsync(
            [Required] string id)
        {
            var modelInDb = await _repository.GetAsync(id);
            if (modelInDb == null)
                return NotFound(new Dictionary<string, string>() { { "message", $"Can't find {id}" } });

            await _repository.DeleteAsync(id);

            return NoContent();
        }
    }
}
<file_sep>import { ToDoItem } from './../app.todoitem ';
import { Component, OnInit } from '@angular/core';
import { UserService } from '../services/user.service';
import { ActivatedRoute, Router} from '@angular/router';
import { ObjectUnsubscribedError } from 'rxjs';


@Component({
  selector: 'app-todo',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {

  // item: ToDoItem;
  constructor(private usersService: UserService, private router: Router, private route: ActivatedRoute) { }
  title = 'TO-DO List';
  items$: ToDoItem[];
  item: ToDoItem;

  selectAll: boolean = true;

  getService(): void {
    this.usersService.getUsers().subscribe((items) => {this.items$ = items});
  }

  getMongoId(): string{

    return String(Math.random());
  }

  add(): void {
    let item = {id: this.getMongoId(), description: '', createdTime: new Date(), done: false, favorite: false, children: []};
    // this.usersService.addUser(item).subscribe();

    this.items$.push(item);
  }
  // getServiceId(): void {
  //   this.usersService.getUser(this.item.id).subscribe(i => this.item = i);
  // }
  ngOnInit() {
   // const id = this.route.snapshot.params['id'];
    this.getService();
    //this.getServiceId();
  }

  delete(ids) {
    if(confirm("Sure to delete?")) {
      this.items$ = this.items$.filter(item => ids.indexOf(item.id) === -1);
    }
  }

  search() {
    this.items$[0];
    //return this.items$[0];
    //return this.items$.find(item => item.id = ids);
  }

  switch(id: string): void {
     this.router.navigate(['todo/detail/' + id]);
  }

}

<file_sep>﻿using MongoDB.Bson.Serialization.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MongoDB.Bson;
namespace ToDoList.Models
{
    public class ToDoItem
    {
        // 存放数据类型
        [BsonRepresentation(BsonType.ObjectId)]
        public string Id { get; set; }
        [BsonElement("description")]
        public string Description { get; set; }
        [BsonElement("createdTime")]
        public DateTime CreatedTime { get; set; } 
        [BsonElement("done")]
        public bool Done { get; set; }
        [BsonElement("favorite")]
        public bool Favorite { get; set; }
        [BsonElement("children")]
        public ToDoItem[] Children { get; set; }
    }
}
<file_sep>import { ToDoItem } from './../app.todoitem ';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { Observable, of } from 'rxjs';

@Injectable({
    providedIn: `root`,
})

export class UserService {

  constructor(private httpClient: HttpClient) { }

  getUsers(): Observable<ToDoItem[]> {
      return this.httpClient.get<ToDoItem[]>(`https://localhost:5001/api/ToDoItem`);
  }

  getUser(id: string): Observable<ToDoItem> {
    return this.httpClient.get<ToDoItem>(`https://localhost:5001/api/ToDoItem/${id}`)
      .pipe(catchError(this.handleError<ToDoItem>('getUsers id=${id}')));
  }

  addUser(item: ToDoItem): Observable<ToDoItem> {
    return this.httpClient.post<ToDoItem>(`https://localhost:5001/api/ToDoItem`, item)
      .pipe(catchError(this.handleError<ToDoItem>('add item')));
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error); // log to console instead
      console.log(`${operation} failed: ${error.message}`);
      return of(result as T);
    };
  }

 }
<file_sep>export interface ToDoItem {
      id: string;
      description: string;
      createdTime: Date;
      favorite: boolean;
      done: boolean;
      children: ToDoItem[];

  }



