本教程仅作为asp.net core web api 入门教程
参考网址:web api
前言
-
这篇教程包含下面几个api:
-
应用的结构
-
项目结构预览:
正文
下面开始演示操作流程及代码
1.创建项目
(1)文件->新建->项目
(2)web->ASP.NET Core Web应用程序
(3)API
如图:
2. 代码实现
2.1 增加一个Model类
先增加一个Models文件夹,然后右键增加一个TodoItem类
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
}
2.2 创建 database context
这个类继承自 Microsoft.EntityFrameworkCore.DbContext
在Models文件夹下右键新建类TodoContext
using Microsoft.EntityFrameworkCore;namespace TodoApi.Models
{
public class TodoContext : DbContext
{
public TodoContext(DbContextOptions<TodoContext> options)
: base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; }
}
}
2.3 注册 database context
在Startup类中进行注册
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using TodoApi.Models;namespace TodoApi
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
}
注意:
这里用的并不是数据库的数据,而是采用内存模仿的数据库来简单实现
services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList"));
如果要使用数据库,可以这样
var connection = @"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.AspNetCore.NewDb;Trusted_Connection=True;ConnectRetryCount=0";
services.AddDbContext<TodoContext>
(options => options.UseSqlServer(connection));
这里使用内存模仿的数据简单实现
2.4 增加一个controller
在controller文件夹下,右键添加controller,命名为TodoController
下面定义的controller类,还没有方法
使用了[ApiController]属性进行修饰,表示这个controller会对api请求进行响应
使用DI在controller中注入了context(ToDoContext)
如果数据库是空,会增加一个名字为iItem1的实体
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TodoApi.Models;
namespace TodoApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
private readonly TodoContext _context;
public TodoController(TodoContext context)
{
_context = context;
if (_context.TodoItems.Count() == 0)
{
// Create a new TodoItem if collection is empty,
// which means you can't delete all TodoItems.
_context.TodoItems.Add(new TodoItem { Name = "Item1" });
_context.SaveChanges();
}
}
}
}
2.5 在controller 中 增加方法
// GET: api/Todo
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
return await _context.TodoItems.ToListAsync();
}
// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
上面方法提供了两个接口
- GET /api/todo
- GET /api/todo/{id}
访问方式,如下:
- https://localhost:<port>/api/todo
- https://localhost:<port>/api/todo/1
路由和url路径
- 这里会以api/[controller]作为路由
例如,上面两个接口的访问都是以api/todo作为前缀的
- 如果[HttpGet]的属性有路由模板(例如:[HttpGet("/products")]),则直接加到路径后面。这里没有用路由模板。
可以在Action方法用注解的方式定义路由,例如上面两个接口
2.5.1 增加一个新建方法
// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
}
路由访问如下图:
2.5.2 增加一个PutTodoItem方法
// PUT: api/Todo/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
await _context.SaveChangesAsync();
return NoContent();
}
PutTodoItem类似于PostTodoItem,区别在与它用的Http Put方式。返回的是204(No Content)。
路由如下图:
2.5.3 增加一个DeleteTodoItem方法
// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return todoItem;
}
返回的204(No Content)
用postman调用删除:
把方法设置成DELETE.
设置路径,例如:https://localhost:5001/api/todo/1
2.6 用Jquery调用api
配置静态文件和允许默认文件映射
如下图:
在wwwroot下增加一个index.html和site.js
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>To-do CRUD</title>
<style>
input[type='submit'], button, [aria-label] {
cursor: pointer;
}
#spoiler {
display: none;
}
table {
font-family: Arial, sans-serif;
border: 1px solid;
border-collapse: collapse;
}
th {
background-color: #0066CC;
color: white;
}
td {
border: 1px solid;
padding: 5px;
}
</style>
</head>
<body>
<h1>To-do CRUD</h1>
<h3>Add</h3>
<form action="javascript:void(0);" method="POST" onsubmit="addItem()">
<input type="text" id="add-name" placeholder="New to-do">
<input type="submit" value="Add">
</form>
<div id="spoiler">
<h3>Edit</h3>
<form class="my-form">
<input type="hidden" id="edit-id">
<input type="checkbox" id="edit-isComplete">
<input type="text" id="edit-name">
<input type="submit" value="Save">
<a onclick="closeInput()" aria-label="Close">✖</a>
</form>
</div>
<p id="counter"></p>
<table>
<tr>
<th>Is Complete</th>
<th>Name</th>
<th></th>
<th></th>
</tr>
<tbody id="todos"></tbody>
</table>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="site.js"></script>
</body>
</html>
site.js
const uri = "api/todo";
let todos = null;
function getCount(data) {
const el = $("#counter");
let name = "to-do";
if (data) {
if (data > 1) {
name = "to-dos";
}
el.text(data + " " + name);
} else {
el.text("No " + name);
}
}
$(document).ready(function() {
getData();
});
function getData() {
$.ajax({
type: "GET",
url: uri,
cache: false,
success: function(data) {
const tBody = $("#todos");
$(tBody).empty();
getCount(data.length);
$.each(data, function(key, item) {
const tr = $("<tr></tr>")
.append(
$("<td></td>").append(
$("<input/>", {
type: "checkbox",
disabled: true,
checked: item.isComplete
})
)
)
.append($("<td></td>").text(item.name))
.append(
$("<td></td>").append(
$("<button>Edit</button>").on("click", function() {
editItem(item.id);
})
)
)
.append(
$("<td></td>").append(
$("<button>Delete</button>").on("click", function() {
deleteItem(item.id);
})
)
);
tr.appendTo(tBody);
});
todos = data;
}
});
}
function addItem() {
const item = {
name: $("#add-name").val(),
isComplete: false
};
$.ajax({
type: "POST",
accepts: "application/json",
url: uri,
contentType: "application/json",
data: JSON.stringify(item),
error: function(jqXHR, textStatus, errorThrown) {
alert("Something went wrong!");
},
success: function(result) {
getData();
$("#add-name").val("");
}
});
}
function deleteItem(id) {
$.ajax({
url: uri + "/" + id,
type: "DELETE",
success: function(result) {
getData();
}
});
}
function editItem(id) {
$.each(todos, function(key, item) {
if (item.id === id) {
$("#edit-name").val(item.name);
$("#edit-id").val(item.id);
$("#edit-isComplete")[0].checked = item.isComplete;
}
});
$("#spoiler").css({ display: "block" });
}
$(".my-form").on("submit", function() {
const item = {
name: $("#edit-name").val(),
isComplete: $("#edit-isComplete").is(":checked"),
id: $("#edit-id").val()
};
$.ajax({
url: uri + "/" + $("#edit-id").val(),
type: "PUT",
accepts: "application/json",
contentType: "application/json",
data: JSON.stringify(item),
success: function(result) {
getData();
}
});
closeInput();
return false;
});
function closeInput() {
$("#spoiler").css({ display: "none" });
}
2.7 改变这个项目的launch setting(运行时的配置)
打开launchSetting.json文件
删除launchUrl属性,强制应用index.html(项目的默认文件)
这样运行后,默认展示页面为index.html页面