实现简单的ASP.NET核心Web API服务(PersonExample)的问题

时间:2016-09-15 14:52:45

标签: asp.net-mvc entity-framework rest asp.net-web-api asp.net-core-1.0

我是ASP.Net,ASP.NET MVC和EntityFrameWork(通常)以及.NET Core变体(特别是)的新手。目前我正在努力让我的第一个示例/测试项目运行(在Visuals Studio 2015中),但有一些问题我无法在Google上找到解决方案。

部分教程&我到目前为止所遵循的说明:

那些教程&说明仅描述了解决方案的片段,但这些片段不能组合在一起并导致问题。所以我试图将缺失的部分组合在一起。

我想要实现的是(尽可能简单)示例项目

  • ASP.NET核心WEB API演示/示例项目(在Visual Studio 2015中)
  • 使用EntityFramework Core将数据存储在(SQL)数据库(不是某个手写存储库)中(只有1个表包含3列:id作为主键标识,2列firstname和lastname作为nvarchar(30))
  • 哪里可以
    • 请求(GET)所有人(以下代码中的工作)
    • (GET)通过id或姓氏(在下面的代码中工作)的特定人员
    • 创建(POST)一个新人(在下面的代码中工作)
    • (删除)一个人通过id(在下面的代码中工作)
    • 完全替换(PUT)由id(如何做?)
    • 修改(PATCH)姓氏(人们仍然结婚)只发送id和新姓(怎么做?)
  • 在控制器和dbContext之间使用存储库(用于存储库函数的可重用性)
    • 让控制器符合标准(返回正确的错误代码/错误结果)
    • 有工作异常处理

我的问题实施

  1. IPersonRepository.cs
  2. 
    
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Threading.Tasks;
        using PersonExample.Models;
    
        namespace PersonExample.Repository
        {
            public interface IPersonRepositoy
            {
                IEnumerable GetAll();
                Person GetById(int id);
                IEnumerable GetByLastname(string lastname);
                IEnumerable SearchByLastname(string namePart);
    
                int Create(Person item);
                int Delete(int id);
                int Replace(int id, Person item);
                int Modify(int id, string newLastname);
    
            }
        }
    
    
    1. PersonRepository.cs
    2. 
      
          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading.Tasks;
          using Microsoft.Extensions.Logging;
          using PersonExample.Models;
      
          namespace PersonExample.Repository
          {
              public class PersonRepository : IPersonRepositoy
              {
      
                  private readonly PersonDbContext _dbContext;
                  private readonly ILogger _logger;
      
                  public PersonRepository(PersonDbContext dbContext, ILogger logger)
                  {
                      _dbContext = dbContext;
                      _logger = logger;
                  }
      
                  public IEnumerable GetAll()
                  {
                      //always returns an IEnumberable (even if it is empty)
                      _logger.LogDebug(string.Format("{0}.GetAll()", GetType().Name));
                      return _dbContext.Person;
                  }
      
                  public Person GetById(int id)
                  {
                      //SingleOrDefault() returns an instance of Person or null 
                      _logger.LogDebug(string.Format("{0}.GetById({1})", GetType().Name, id));
                      return _dbContext.Person.Where(i => i.Id == id).SingleOrDefault();
                  }
      
                  public IEnumerable GetByLastname(string lastname)
                  {
                      //always returns an IEnumberable (even if it is empty)
                      _logger.LogDebug(string.Format("{0}.GetByLastname({1})", GetType().Name, lastname));
                      return _dbContext.Person.Where(i => i.Lastname == lastname);
                  }
      
                  public IEnumerable SearchByLastname(string namePart)
                  {
                      //always returns an IEnumberable (even if it is empty)
                      _logger.LogDebug(string.Format("{0}.SearchByLastname({1})", GetType().Name, namePart));
                      return _dbContext.Person.Where(i => i.Lastname.Contains(namePart));
                  }
      
                  public int Create(Person item)
                  {
                      _logger.LogDebug(string.Format("{0}.Create({1}) (id: {2}, firstname: {3}, lastname: {4})", 
                              GetType().Name, item, item.Id, item.Firstname, item.Lastname));
                      //Add seems to be atomic > Attach would save linked objects too but seems to fail on simple objects
                      //what exceptions could occure to catch somewhere else (e.g. if lastname would have a unique contraint)?
                      _dbContext.Person.Add(item);
                      int res;
                      try {
                          res = _dbContext.SaveChanges();
                      } catch (Microsoft.EntityFrameworkCore.DbUpdateException e)
                      {
                          _logger.LogError(string.Format("", GetType().Name));
                          res = -1;
                      }
      
                      if (res == 0)
                      {
                          _logger.LogError(string.Format("{0}.Create({1}) -> no items were created/changed", GetType().Name, item));
                      }
                      else
                      {
                          _logger.LogDebug(string.Format("{0}.Create({1}) -> {2} item(s) were created/changed", GetType().Name, item, res));
                      }
      
                      return res;
                  }
      
                  public int Delete(int id)
                  {
                      _logger.LogDebug(string.Format("{0}.Delete({1}", GetType().Name, id));
                      Person item = _dbContext.Person.Where(i => i.Id == id).SingleOrDefault();
                      if (item != null)
                      {
                          _dbContext.Person.Remove(item);
                          int res = _dbContext.SaveChanges();
      
                          if (res == 0)
                          {
                              _logger.LogError(string.Format("{0}.Delete({1} -> no items deleted", GetType().Name, id));
                          } else
                          {
                              _logger.LogDebug(string.Format("{0}.Delete({1} -> {2} item(s) deleted", GetType().Name, id, res));
                          }
      
                          return res;
                      }
                      else
                      {
                          _logger.LogError(string.Format("{0}.Delete({1} -> not item found by id", GetType().Name, id));
                          return -1; // better way to indicate not found?
                      }
      
                  }
      
                  public int Replace(int id, Person item)
                  {
                      //how to implement replace
                      throw new NotImplementedException();
                  }
      
                  public int Modify(int id, string newLastname)
                  {
                      //how to implement modify
                      throw new NotImplementedException();
                  }
      
              }
      
          }
      
      
      1. PersonController.cs
      2. 
        
            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Threading.Tasks;
            using Microsoft.AspNetCore.Mvc;
            using Microsoft.Extensions.Logging;
            using PersonExample.Repository;
            using PersonExample.Models;
        
            namespace PersonExample.Controllers
            {
                [Route("api/[controller]")]
                public class PersonController : Controller
                {
        
                    private readonly IPersonRepositoy _repo;
                    private readonly ILogger _logger;
        
                    public PersonController(IPersonRepositoy repo, ILogger logger)
                    {
                        _repo = repo;
                        _logger = logger;
                    }
        
                    // GET: api/values
                    [HttpGet]
                    public IEnumerable Get()
                    {
                        _logger.LogDebug(string.Format("{0}.GetAll()", GetType().Name));
                        IEnumerable data = _repo.GetAll();
                        _logger.LogDebug(string.Format("{0}.GetAll() -> returned {1} result(s)", GetType().Name, "?"));
                        return data;
                    }
        
                    // GET api/values/5
                    [HttpGet("{id:int}", Name = "GetPerson")]
                    public IActionResult Get(int id)
                    {
                        _logger.LogDebug(string.Format("{0}.GetById({1})", GetType().Name, id));
                        Person item = _repo.GetById(id);
                        if (item == null)
                        {
                            _logger.LogError(string.Format("{0}.GetById({1}) -> no item found by id", GetType().Name, id));
                            return NotFound(id);
                        }
                        return new ObjectResult(item);
                    }
        
                    [HttpGet("{lastname}")]
                    public IEnumerable Get(string lastname)
                    {
                        //example to demonstrate overloading of types (int for id, string for lastname)
                        _logger.LogDebug(string.Format("{0}.GetByLastname()", GetType().Name));
                        IEnumerable data = _repo.GetByLastname(lastname);
                        _logger.LogDebug(string.Format("{0}.GetByLastname() -> returned {1} result(s)", GetType().Name, "?"));
                        return data;
                    }
        
                    [HttpGet("search/{namepart}")]
                    public IEnumerable Search(string namepart)
                    {
                        //example to demonstrate url modification (how would I do multiple name parts?)
                        _logger.LogDebug(string.Format("{0}.Search({1})", GetType().Name, namepart));
                        IEnumerable data = _repo.SearchByLastname(namepart);
                        _logger.LogDebug(string.Format("{0}.Search({1}) -> returned {2} result(s)", GetType().Name, namepart, "?"));
                        return data;
                    }
        
                    // POST api/values
                    [HttpPost]
                    public IActionResult Post([FromBody]Person value)
                    {
                        //how to validate data and what to return in error cases?
                        _logger.LogDebug(string.Format("{0}.Post({1})", GetType().Name, value));
                        if (value == null)
                        {
                            _logger.LogDebug(string.Format("{0}.Post({1}) -> bad request: item is null", GetType().Name, value));
                            return BadRequest();
                        }
        
                        //return 409 Conflict if resource exists -> where and how to check?
        
                        int res = _repo.Create(value);
                        if (res == 0) //no items changed
                        {
                            _logger.LogError(string.Format("{0}.Post({1}) -> zero items changed", GetType().Name, value));
                            return NotFound(); //what to return? not found isn't the problem
                        }
                        else if (res == -1) //DbUpdateException
                        {
                            _logger.LogError(string.Format("{0}.Post({1}) -> DbUpdateException", GetType().Name, value));
                            return NotFound(); //what to return? not found isn't the problem
                        }
        
                        _logger.LogDebug(string.Format("{0}.Post({1}) -> {2} items changed", GetType().Name, value, res));
                        return CreatedAtRoute("GetPerson", new { id = value.Id }, value);
                    }
        
                    // DELETE api/values/5
                    [HttpDelete("{id}")]
                    public IActionResult Delete(int id)
                    {
                        _logger.LogDebug(string.Format("{0}.Delete(id: {1})", GetType().Name, id));
                        int res = _repo.Delete(id);
        
                        if (res == 0) // zero entries changed
                        {
                            _logger.LogError(string.Format("{0}.Delete({1}) -> zero items changed", GetType().Name, id));
                            //what to return in that case, its a different error than not found???
                            return NotFound();
                        }
                        else if (res == -1) // id not found
                        {
                            _logger.LogError(string.Format("{0}.Delete({1}) -> not found item by id", GetType().Name, id));
                            return NotFound(id);
                        }
        
                        return Ok();
                    }
        
                    // PUT api/values/5
                    [HttpPut("{id}")]
                    public void Put(int id, [FromBody]Person value)
                    {
                        //example for full update / complete replace with logging and error handling
                        // how to implement, what to return?
                       // _repo.Replace(id, value);
                    }
        
                    // PATCH api/values/5
                    [HttpPatch("{id}")]
                    public void Patch(int id, [FromBody]Person value)
                    {
                        //example for partial update  with logging and error handling
                        // how to implement, what to return?
                        //_repo.Modify(id, lastname);
                    }
        
        
                }
            }
        
        

        我的问题

        一般来说:

        控制器和存储库的正确(以及REST标准符合)实现是什么,包括异常处理,数据验证(必要?)和错误记录(发生时)

0 个答案:

没有答案