博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在ASP.NET Core 2.2 中创建 Web API并结合Swagger
阅读量:4701 次
发布时间:2019-06-09

本文共 25501 字,大约阅读时间需要 85 分钟。

一、创建 ASP.NET Core WebApi项目

二、添加

三、

 

-----------------------------------------------------------

一、创建项目,WideWorldImporters.API,选项按照下列图操作

二、引用需要的Nuget包

  • Microsoft.EntityFrameworkCore.SqlServer
  • Swashbuckle.AspNetCore

Swashbuckle.AspNetCore包允许为Web API启用帮助页。

试运行一下项目

OK, 没任何错误。?

添加一个文件夹Models,在里面添加4个.cs文件,

Entities.cs  //实体,为了简单些把多个实体放在这一个文件里,实际项目里可以一个文件一个类

Extensions.cs //扩展类,
Requests.cs //请求类,
Responses.cs //响应类,

4个文件的完整代码如下:

Entities.cs

1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Threading.Tasks;  5 using Microsoft.EntityFrameworkCore;  6 using Microsoft.EntityFrameworkCore.Metadata.Builders;  7   8 namespace WideWorldImporters.API.Models  9 { 10     public partial class StockItem 11     { 12         public StockItem() 13         { 14         } 15  16         public StockItem(int? stockItemID) 17         { 18             StockItemID = stockItemID; 19         } 20  21         public int? StockItemID { get; set; } 22  23         public string StockItemName { get; set; } 24  25         public int? SupplierID { get; set; } 26  27         public int? ColorID { get; set; } 28  29         public int? UnitPackageID { get; set; } 30  31         public int? OuterPackageID { get; set; } 32  33         public string Brand { get; set; } 34  35         public string Size { get; set; } 36  37         public int? LeadTimeDays { get; set; } 38  39         public int? QuantityPerOuter { get; set; } 40  41         public bool? IsChillerStock { get; set; } 42  43         public string Barcode { get; set; } 44  45         public decimal? TaxRate { get; set; } 46  47         public decimal? UnitPrice { get; set; } 48  49         public decimal? RecommendedRetailPrice { get; set; } 50  51         public decimal? TypicalWeightPerUnit { get; set; } 52  53         public string MarketingComments { get; set; } 54  55         public string InternalComments { get; set; } 56  57         public string CustomFields { get; set; } 58  59         public string Tags { get; set; } 60  61         public string SearchDetails { get; set; } 62  63         public int? LastEditedBy { get; set; } 64  65         public DateTime? ValidFrom { get; set; } 66  67         public DateTime? ValidTo { get; set; } 68     } 69  70     public class StockItemsConfiguration : IEntityTypeConfiguration
71 { 72 public void Configure(EntityTypeBuilder
builder) 73 { 74 // Set configuration for entity 75 builder.ToTable("StockItems", "Warehouse"); 76 77 // Set key for entity 78 builder.HasKey(p => p.StockItemID); 79 80 // Set configuration for columns 81 82 builder.Property(p => p.StockItemName).HasColumnType("nvarchar(200)").IsRequired(); 83 builder.Property(p => p.SupplierID).HasColumnType("int").IsRequired(); 84 builder.Property(p => p.ColorID).HasColumnType("int"); 85 builder.Property(p => p.UnitPackageID).HasColumnType("int").IsRequired(); 86 builder.Property(p => p.OuterPackageID).HasColumnType("int").IsRequired(); 87 builder.Property(p => p.Brand).HasColumnType("nvarchar(100)"); 88 builder.Property(p => p.Size).HasColumnType("nvarchar(40)"); 89 builder.Property(p => p.LeadTimeDays).HasColumnType("int").IsRequired(); 90 builder.Property(p => p.QuantityPerOuter).HasColumnType("int").IsRequired(); 91 builder.Property(p => p.IsChillerStock).HasColumnType("bit").IsRequired(); 92 builder.Property(p => p.Barcode).HasColumnType("nvarchar(100)"); 93 builder.Property(p => p.TaxRate).HasColumnType("decimal(18, 3)").IsRequired(); 94 builder.Property(p => p.UnitPrice).HasColumnType("decimal(18, 2)").IsRequired(); 95 builder.Property(p => p.RecommendedRetailPrice).HasColumnType("decimal(18, 2)"); 96 builder.Property(p => p.TypicalWeightPerUnit).HasColumnType("decimal(18, 3)").IsRequired(); 97 builder.Property(p => p.MarketingComments).HasColumnType("nvarchar(max)"); 98 builder.Property(p => p.InternalComments).HasColumnType("nvarchar(max)"); 99 builder.Property(p => p.CustomFields).HasColumnType("nvarchar(max)");100 builder.Property(p => p.LastEditedBy).HasColumnType("int").IsRequired();101 102 // Computed columns103 104 builder105 .Property(p => p.StockItemID)106 .HasColumnType("int")107 .IsRequired()108 .HasComputedColumnSql("NEXT VALUE FOR [Sequences].[StockItemID]");109 110 builder111 .Property(p => p.Tags)112 .HasColumnType("nvarchar(max)")113 .HasComputedColumnSql("json_query([CustomFields],N'$.Tags')");114 115 builder116 .Property(p => p.SearchDetails)117 .HasColumnType("nvarchar(max)")118 .IsRequired()119 .HasComputedColumnSql("concat([StockItemName],N' ',[MarketingComments])");120 121 // Columns with generated value on add or update122 123 builder124 .Property(p => p.ValidFrom)125 .HasColumnType("datetime2")126 .IsRequired()127 .ValueGeneratedOnAddOrUpdate();128 129 builder130 .Property(p => p.ValidTo)131 .HasColumnType("datetime2")132 .IsRequired()133 .ValueGeneratedOnAddOrUpdate();134 }135 }136 137 public class WideWorldImportersDbContext : DbContext138 {139 public WideWorldImportersDbContext(DbContextOptions
options)140 : base(options)141 {142 }143 144 protected override void OnModelCreating(ModelBuilder modelBuilder)145 {146 // Apply configurations for entity147 148 modelBuilder149 .ApplyConfiguration(new StockItemsConfiguration());150 151 base.OnModelCreating(modelBuilder);152 }153 154 public DbSet
StockItems { get; set; }155 }156 }
View Code

Extensions.cs 

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.EntityFrameworkCore;namespace WideWorldImporters.API.Models{    public static class WideWorldImportersDbContextExtensions    {        public static IQueryable
GetStockItems(this WideWorldImportersDbContext dbContext, int pageSize = 10, int pageNumber = 1, int? lastEditedBy = null, int? colorID = null, int? outerPackageID = null, int? supplierID = null, int? unitPackageID = null) { // Get query from DbSet var query = dbContext.StockItems.AsQueryable(); // Filter by: 'LastEditedBy' if (lastEditedBy.HasValue) query = query.Where(item => item.LastEditedBy == lastEditedBy); // Filter by: 'ColorID' if (colorID.HasValue) query = query.Where(item => item.ColorID == colorID); // Filter by: 'OuterPackageID' if (outerPackageID.HasValue) query = query.Where(item => item.OuterPackageID == outerPackageID); // Filter by: 'SupplierID' if (supplierID.HasValue) query = query.Where(item => item.SupplierID == supplierID); // Filter by: 'UnitPackageID' if (unitPackageID.HasValue) query = query.Where(item => item.UnitPackageID == unitPackageID); return query; } public static async Task
GetStockItemsAsync(this WideWorldImportersDbContext dbContext, StockItem entity) => await dbContext.StockItems.FirstOrDefaultAsync(item => item.StockItemID == entity.StockItemID); public static async Task
GetStockItemsByStockItemNameAsync(this WideWorldImportersDbContext dbContext, StockItem entity) => await dbContext.StockItems.FirstOrDefaultAsync(item => item.StockItemName == entity.StockItemName); } public static class IQueryableExtensions { public static IQueryable
Paging
(this IQueryable
query, int pageSize = 0, int pageNumber = 0) where TModel : class => pageSize > 0 && pageNumber > 0 ? query.Skip((pageNumber - 1) * pageSize).Take(pageSize) : query; }}
View Code

Requests.cs

using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.Linq;using System.Threading.Tasks;namespace WideWorldImporters.API.Models{    public class PostStockItemsRequest    {        [Key]        public int? StockItemID { get; set; }        [Required]        [StringLength(200)]        public string StockItemName { get; set; }        [Required]        public int? SupplierID { get; set; }        public int? ColorID { get; set; }        [Required]        public int? UnitPackageID { get; set; }        [Required]        public int? OuterPackageID { get; set; }        [StringLength(100)]        public string Brand { get; set; }        [StringLength(40)]        public string Size { get; set; }        [Required]        public int? LeadTimeDays { get; set; }        [Required]        public int? QuantityPerOuter { get; set; }        [Required]        public bool? IsChillerStock { get; set; }        [StringLength(100)]        public string Barcode { get; set; }        [Required]        public decimal? TaxRate { get; set; }        [Required]        public decimal? UnitPrice { get; set; }        public decimal? RecommendedRetailPrice { get; set; }        [Required]        public decimal? TypicalWeightPerUnit { get; set; }        public string MarketingComments { get; set; }        public string InternalComments { get; set; }        public string CustomFields { get; set; }        public string Tags { get; set; }        [Required]        public string SearchDetails { get; set; }        [Required]        public int? LastEditedBy { get; set; }        public DateTime? ValidFrom { get; set; }        public DateTime? ValidTo { get; set; }    }    public class PutStockItemsRequest    {        [Required]        [StringLength(200)]        public string StockItemName { get; set; }        [Required]        public int? SupplierID { get; set; }        public int? ColorID { get; set; }        [Required]        public decimal? UnitPrice { get; set; }    }    public static class Extensions    {        public static StockItem ToEntity(this PostStockItemsRequest request)            => new StockItem            {                StockItemID = request.StockItemID,                StockItemName = request.StockItemName,                SupplierID = request.SupplierID,                ColorID = request.ColorID,                UnitPackageID = request.UnitPackageID,                OuterPackageID = request.OuterPackageID,                Brand = request.Brand,                Size = request.Size,                LeadTimeDays = request.LeadTimeDays,                QuantityPerOuter = request.QuantityPerOuter,                IsChillerStock = request.IsChillerStock,                Barcode = request.Barcode,                TaxRate = request.TaxRate,                UnitPrice = request.UnitPrice,                RecommendedRetailPrice = request.RecommendedRetailPrice,                TypicalWeightPerUnit = request.TypicalWeightPerUnit,                MarketingComments = request.MarketingComments,                InternalComments = request.InternalComments,                CustomFields = request.CustomFields,                Tags = request.Tags,                SearchDetails = request.SearchDetails,                LastEditedBy = request.LastEditedBy,                ValidFrom = request.ValidFrom,                ValidTo = request.ValidTo            };    }}
View Code

Responses.cs

1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Net;  5 using System.Threading.Tasks;  6 using Microsoft.AspNetCore.Mvc;  7   8 namespace WideWorldImporters.API.Models  9 { 10     public interface IResponse 11     { 12         string Message { get; set; } 13  14         bool DidError { get; set; } 15  16         string ErrorMessage { get; set; } 17     } 18  19     public interface ISingleResponse
: IResponse 20 { 21 TModel Model { get; set; } 22 } 23 24 public interface IListResponse
: IResponse 25 { 26 IEnumerable
Model { get; set; } 27 } 28 29 public interface IPagedResponse
: IListResponse
30 { 31 int ItemsCount { get; set; } 32 33 double PageCount { get; } 34 } 35 36 public class Response : IResponse 37 { 38 public string Message { get; set; } 39 40 public bool DidError { get; set; } 41 42 public string ErrorMessage { get; set; } 43 } 44 45 public class SingleResponse
: ISingleResponse
46 { 47 public string Message { get; set; } 48 49 public bool DidError { get; set; } 50 51 public string ErrorMessage { get; set; } 52 53 public TModel Model { get; set; } 54 } 55 56 public class ListResponse
: IListResponse
57 { 58 public string Message { get; set; } 59 60 public bool DidError { get; set; } 61 62 public string ErrorMessage { get; set; } 63 64 public IEnumerable
Model { get; set; } 65 } 66 67 public class PagedResponse
: IPagedResponse
68 { 69 public string Message { get; set; } 70 71 public bool DidError { get; set; } 72 73 public string ErrorMessage { get; set; } 74 75 public IEnumerable
Model { get; set; } 76 77 public int PageSize { get; set; } 78 79 public int PageNumber { get; set; } 80 81 public int ItemsCount { get; set; } 82 83 public double PageCount 84 => ItemsCount < PageSize ? 1 : (int)(((double)ItemsCount / PageSize) + 1); 85 } 86 87 public static class ResponseExtensions 88 { 89 public static IActionResult ToHttpResponse(this IResponse response) 90 { 91 var status = response.DidError ? HttpStatusCode.InternalServerError : HttpStatusCode.OK; 92 93 return new ObjectResult(response) 94 { 95 StatusCode = (int)status 96 }; 97 } 98 99 public static IActionResult ToHttpResponse
(this ISingleResponse
response)100 {101 var status = HttpStatusCode.OK;102 103 if (response.DidError)104 status = HttpStatusCode.InternalServerError;105 else if (response.Model == null)106 status = HttpStatusCode.NotFound;107 108 return new ObjectResult(response)109 {110 StatusCode = (int)status111 };112 }113 114 public static IActionResult ToHttpResponse
(this IListResponse
response)115 {116 var status = HttpStatusCode.OK;117 118 if (response.DidError)119 status = HttpStatusCode.InternalServerError;120 else if (response.Model == null)121 status = HttpStatusCode.NoContent;122 123 return new ObjectResult(response)124 {125 StatusCode = (int)status126 };127 }128 }129 }
View Code

接下来开始添加Api控制器 WarehouseController

右击项目文件夹Controllers

WarehouseController.cs 

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Logging;using WideWorldImporters.API.Models;namespace WideWorldImporters.API.Controllers{    [Route("api/v1/[controller]")]    [ApiController]    public class WarehouseController : ControllerBase    {        protected readonly ILogger _logger;        protected readonly WideWorldImportersDbContext _dbContext;        public WarehouseController(ILogger
logger, WideWorldImportersDbContext dbContext) { _logger = logger; _dbContext = dbContext; } ///
/// 获取库存项列表 /// ///
页大小 ///
页号 ///
最后编辑者 ///
颜色ID ///
外包装ID ///
供应商ID ///
///
public async Task
GetStockItemsAsync(int pageSize = 10, int pageNumber = 1, int? lastEditedBy = null, int? colorId = null, int? outerPackageId = null, int? supplierId = null, int? unitPackageId = null ) { _logger?.LogDebug($"'{nameof(GetStockItemsAsync)}' 被调用了"); var response = new PagedResponse
();//创建分页对象 try { var query = _dbContext.GetStockItems(); response.PageSize = pageSize; response.PageNumber = pageNumber; response.ItemsCount = await query.CountAsync();//获取总记录数 response.Model = await query.Paging(pageSize, pageNumber).ToListAsync(); response.Message = $"第 {pageNumber} 共 {response.PageCount}, 产品总数量: {response.ItemsCount}"; _logger?.LogInformation("已成功检索库存项!"); } catch (Exception e) { response.DidError = true; response.ErrorMessage = "有一个内部错误,请联系技术支持!"; _logger?.LogCritical($"There was an error on '{nameof(GetStockItemsAsync)}' invocation: {e}"); } return response.ToHttpResponse(); } ///
/// 获取单记录 /// ///
///
[HttpGet("StockItem/{id}")] [ProducesResponseType(200)] [ProducesResponseType(404)] [ProducesResponseType(500)] public async Task
GetStockItemAsync(int id) { _logger?.LogDebug($"'{nameof(GetStockItemAsync)}' 被执行了!"); var response = new SingleResponse
(); try { response.Model = await _dbContext.GetStockItemsAsync(new StockItem(id)); } catch (Exception e) { response.DidError = true; response.ErrorMessage = "有错误,请联系技术支持!"; _logger?.LogCritical($"There was an error on '{nameof(GetStockItemAsync)}' invocation: {e}"); } return response.ToHttpResponse(); } // POST // api/v1/Warehouse/StockItem/ ///
/// Creates a new stock item /// ///
Request model ///
A response with new stock item
///
Returns the stock items list
///
A response as creation of stock item
///
For bad request
///
If there was an internal server error
[HttpPost("StockItem")] [ProducesResponseType(200)] [ProducesResponseType(201)] [ProducesResponseType(400)] [ProducesResponseType(500)] public async Task
PostStockItemAsync([FromBody]PostStockItemsRequest request) { _logger?.LogDebug("'{0}' has been invoked", nameof(PostStockItemAsync)); var response = new SingleResponse
(); try { var existingEntity = await _dbContext.GetStockItemsByStockItemNameAsync(new StockItem { StockItemName = request.StockItemName }); if (existingEntity != null) ModelState.AddModelError("StockItemName", "Stock item name already exists"); if (!ModelState.IsValid) return BadRequest(); // Create entity from request model var entity = request.ToEntity(); // Add entity to repository _dbContext.Add(entity); // Save entity in database await _dbContext.SaveChangesAsync(); // Set the entity to response model response.Model = entity; } catch (Exception ex) { response.DidError = true; response.ErrorMessage = "There was an internal error, please contact to technical support."; _logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(PostStockItemAsync), ex); } return response.ToHttpResponse(); } // PUT // api/v1/Warehouse/StockItem/5 ///
/// Updates an existing stock item /// ///
Stock item ID ///
Request model ///
A response as update stock item result
///
If stock item was updated successfully
///
For bad request
///
If stock item is not exists
///
If there was an internal server error
[HttpPut("StockItem/{id}")] [ProducesResponseType(200)] [ProducesResponseType(400)] [ProducesResponseType(404)] [ProducesResponseType(500)] public async Task
PutStockItemAsync(int id, [FromBody]PutStockItemsRequest request) { _logger?.LogDebug("'{0}' has been invoked", nameof(PutStockItemAsync)); var response = new Response(); try { // Get stock item by id var entity = await _dbContext.GetStockItemsAsync(new StockItem(id)); // Validate if entity exists if (entity == null) return NotFound(); // Set changes to entity entity.StockItemName = request.StockItemName; entity.SupplierId = request.SupplierID; entity.ColorId = request.ColorID; entity.UnitPrice = request.UnitPrice; // Update entity in repository _dbContext.Update(entity); // Save entity in database await _dbContext.SaveChangesAsync(); } catch (Exception ex) { response.DidError = true; response.ErrorMessage = "There was an internal error, please contact to technical support."; _logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(PutStockItemAsync), ex); } return response.ToHttpResponse(); } // DELETE // api/v1/Warehouse/StockItem/5 ///
/// Deletes an existing stock item /// ///
Stock item ID ///
A response as delete stock item result
///
If stock item was deleted successfully
///
If stock item is not exists
///
If there was an internal server error
[HttpDelete("StockItem/{id}")] [ProducesResponseType(200)] [ProducesResponseType(404)] [ProducesResponseType(500)] public async Task
DeleteStockItemAsync(int id) { _logger?.LogDebug("'{0}' has been invoked", nameof(DeleteStockItemAsync)); var response = new Response(); try { // Get stock item by id var entity = await _dbContext.GetStockItemsAsync(new StockItem(id)); // Validate if entity exists if (entity == null) return NotFound(); // Remove entity from repository _dbContext.Remove(entity); // Delete entity in database await _dbContext.SaveChangesAsync(); } catch (Exception ex) { response.DidError = true; response.ErrorMessage = "There was an internal error, please contact to technical support."; _logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(DeleteStockItemAsync), ex); } return response.ToHttpResponse(); } }}
View Code

接下来设置依赖注入,ASP.NET Core自带依赖注入,不需要第三方框架

修改根目录下Startup 类,

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Reflection;using System.Threading.Tasks;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Mvc;using Microsoft.EntityFrameworkCore;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;using Microsoft.Extensions.Options;using Swashbuckle.AspNetCore.Swagger;using WideWorldImporters.API.Controllers;using WideWorldImporters.API.Models;namespace WideWorldImporters.API{    public class Startup    {        public Startup(IConfiguration configuration)        {            Configuration = configuration;        }        public IConfiguration Configuration { get; }        // This method gets called by the runtime. Use this method to add services to the container.        public void ConfigureServices(IServiceCollection services)        {            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);            //注入数据库上下文对象            services.AddDbContext
(options => { options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));//从配置文件中获取数据库连接字符串 }); //--------------上面是框架系统的访问,下面是应用程序的注入-------------------- services.AddScoped
>();//只用这里写了这一句,apiController里的注入才有效 //注入丝袜哥Swagger services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Info {Title = "WideWorldImporters API", Version = "v1"}); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); options.IncludeXmlComments(xmlPath); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "WideWorldImporters API V1"); }); app.UseMvc(); } }}
View Code

在appsettings.json文件中添加数据库连接字符串

{  "ConnectionStrings": {    "DefaultConnection": "Server=(localdb);Database=WideWorldImportersDb;Trusted_Connection=True;MultipleActiveResultSets=true"  },  "Logging": {    "LogLevel": {      "Default": "Warning"    }  },  "AllowedHosts": "*"}

设置项目属性的swagger生成的文件,丝袜哥就是靠这个文件来生成UI的。

设置完,记得保存!

代码写完了,数据库还没有,需要利用EF Core迁移并生成数据库

在命令行输入迁移命令: add-migration AddEntity

生成了迁移文件

然后更新到数据库,输入:update-database

数据库创建完毕。

 

运行项目试试!!!!

访问地址:

http://localhost:49956/api/v1/Warehouse/StockItem 

 

 

 

 

好像有问题,明天继续吧.................................郁闷了

 

转载于:https://www.cnblogs.com/wanghaibin/p/10296774.html

你可能感兴趣的文章
MySQL批量SQL插入性能优化
查看>>
定义列属性:null,default,PK,auto_increment
查看>>
用户画像展示
查看>>
C#中StreamReader读取中文出现乱码
查看>>
使用BufferedReader的时候出现的问题
查看>>
批处理文件中的路径问题
查看>>
hibernate出现No row with the given identifier exists问题
查看>>
为什么wait()和notify()属于Object类
查看>>
配置NRPE的通讯
查看>>
匹配两个空格之间的字符。。。
查看>>
CSS 文字溢出 变成省略号 ...
查看>>
Spring事务
查看>>
java编程基础(三)流程控制语句
查看>>
让数据库跑的更快的7个MySQL优化建议
查看>>
jquery 取id模糊查询
查看>>
解决在vue中,自用mask模态框出来后,下层的元素依旧可以滑动的问题
查看>>
修改node节点名称
查看>>
PAT(B) 1014 福尔摩斯的约会(Java)
查看>>
PAT甲级题解-1123. Is It a Complete AVL Tree (30)-AVL树+满二叉树
查看>>
项目开发总结报告(GB8567——88)
查看>>