首页 > 编程语言 >C#中的WebAPI

C#中的WebAPI

时间:2022-12-10 23:11:26浏览次数:74  
标签:WebAPI axios vue const C# api import id

前端用:vue3,后端:net6,的结合代码
vue3手动创建:勾选1、路由配置:router。2、vuex状态管理:store类似全局变量。3、在加上UI库:element-plus模板
大致UI库模板如下:安装ui库命令:npm install element-plus --save,UI库图标命令:npm install @element-plus/icons-vue
App.vue CategoryView.vue

import { createApp } from 'vue' //框架实例
import App from './App.vue' 
import router from './router' //路由
import store from './store' //状态管理vuex--类似全局变量

import ElementPlus from 'element-plus'//ui库
import 'element-plus/dist/index.css' //ui库的样式
import * as ElementPlusIconsVue from '@element-plus/icons-vue'//ui库图标

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)//注册icon图标,ui库图标
  }
app.use(store).use(router).use(ElementPlus).mount('#app')
main.js入口的挂载
{
    path:'/category',
    name:'category',
    component:()=>import('../views/CategoryView.vue')
}
index.js路由的配置

一、后台webAPI的搭建

创建asp.net core  web api项目:搭建数据库连接
1.创建【Models】文件夹保存实体类:Category.cs

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
}

2.创建【Data】文件夹保存数据库上下文类:ShopDbContext.cs

using Microsoft.EntityFrameworkCore;
using ShoopingWeb.Models;

namespace ShoopingWeb.Data
{
    public class ShopDbContext:DbContext
    {
        public ShopDbContext(DbContextOptions<ShopDbContext> options) : base(options)
        {
            //参数DbContext选项值创建的这个新的类型,包装后用base关键字传给父类
        }
        public DbSet<Category> Categories { get; set; }//添加表
    }
}

3.在【appsettings.json】文件中配置数据库连接字符串,这里用的vs自带数据库

"ConnectionStrings": {
    "ShopConn": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=OA;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
  }

4.把数据库添加到服务全局【Program.cs】

builder.Services.AddDbContext<ShopDbContext>(option => { //添加数据库上下文类
    option.UseSqlServer(builder.Configuration.GetConnectionString("ShopConn"));//拿到数据库连接字符串,在appsettings.json配置文件里
});

5.工具-》nuget包管理-》控制台:1.执行数据库迁移:add-migration initDb  2.保存到数据库:update-database 手打
6.在【Controllers】文件夹下创建控制器:CategoryController.cs ,用的是RESTfull开发风格:路由+http请求=方法体定义的api

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ShoopingWeb.Data;
using ShoopingWeb.Models;

namespace ShoopingWeb.Controllers
{
    [Route("api/[controller]")]//路由:api/控制器名,这里是Category别写错哟
    [ApiController]//控制器是webapi
    public class CategoryController : ControllerBase
    {
        private readonly ShopDbContext db;

        public CategoryController(ShopDbContext db)//鼠标右键快速生成字段并赋值
        {
            this.db = db;//绑定数据库ShopDbContext上下文类
        }
        [HttpGet]//在webapi中,是通过路由+http请求【特性】来找到方法的,和方法名无关,无调用只有注释的作用。
        public async Task<IEnumerable<Category>> GetList()//有async定义的异步编程,不过有没有返回值都必须Task
        {
            return await db.Categories.ToListAsync();//有async异步定义的方法,就必须有await来执行任务。
        }
        [HttpGet("{id}")]//路由模式:api/controller/{id}
        public async Task<ActionResult<Category>> Getid(int id)
        {
            var category = await db.Categories.FindAsync(id);//通过id查询
            if (category == null)
            {
                return NotFound();//返回404的状态码,多种返回类型用:ActionResult
            }
            return Ok(category);//返回数据
        }
        [HttpPost]//增
        public async Task<ActionResult<int>> Add(Category model)
        {
            await db.Categories.AddAsync(model);//添加数据
            await db.SaveChangesAsync();
            return Ok(model.Id);
        }
        [HttpDelete("{id}")]//删
        public async Task<IActionResult> Delete(int id)
        {
            var category = await db.Categories.FindAsync(id);
            if (category == null) { return NotFound(); }//返回404,都是返回状态码,用接口即可:IActionResult
            db.Categories.Remove(category);//删除数据不需要异步
            await db.SaveChangesAsync();//保存需要异步
            return NoContent();//返回204,成功删除
        }
        [HttpPut]//改
        public async Task<IActionResult> Update(Category model)
        {
            var category = await db.Categories.FindAsync(model.Id);
            if (category == null) { return NotFound(); }//返回404
            category.Name = model.Name;
            await db.SaveChangesAsync();//保存修改的数据
            return NoContent();//返回204,成功修改
        }
    }
}

测试:直接运行后台代码,可以看出后台其实返回的就是josn字符串和状态码而已

二、前后端CORS跨域配置

在Ajax请求时遵循的是同源策略:协议相同,域名相同,端口相同。而在webapi中前后端分离的,端口肯定不一样。所以不能在使用Ajax来发送请求。
CORS(Cross-orgin-resource-sharing)跨域资源共享:打破同源策略的限制。Ajax为了安全考虑做的限制,打破限制的方案有很多,cors最常见。
后台:服务端的配置【Program.cs】,开放运行策略

builder.Services.AddCors(options => //添加跨域服务
{
    options.AddPolicy("cors", p =>//添加策略,可以添加多种
    { //如果是允许指定的域、方法、消息头需要使用WithOrigins、WithMethods、WithHeaders方法。
        p.AllowAnyOrigin()//允许可以,参数可以给ip,不给表示允许所有
        .AllowAnyMethod() //允许所有方法
        .AllowAnyHeader();//请求头
    });
});
app.UseCors("cors");//启用策略中间件管道,必须放跳转:app.UseHttpsRedirection();的后面

前台:客户端vue3的框架配置文件【vue.config.js】,每次修改此文件需要重启项目,Ctrl+c项目关闭,重启命令:npm run serve

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({//会覆盖webpack默认配置
  transpileDependencies: true,
  devServer:{//开发环境的服务器配置
    open:true,//是否自动打开浏览器
    host:"localhost",
    port:8080,//修改默认端口
    proxy:{//通过代理的方式访问,会重写路由
      "/api":{
        target:"https://localhost:7135/api/",//服务器请求地址,在后台Properties--》launchSettings.json中
        secure:false,//HTTPS需要配置这个参数
        changeOrigin:true,//请求头host属性,默认false发本机ip。true会把host设置为target的值。
        pathRewrite:{'^/api':''}//路径重写,(正则表达式)识别api路径替换为空字符串。
      }
    }
  }
})

三、获取后台数据【axios请求库】

安装命令:npm install axios ,请求库还有很多,axios只是vue3的一种
vue3前端src目录下创建【api】文件夹放配置文件:api_config.js

import axios from "axios" //请求库

axios.defaults.baseURL="http://localhost:8080/api" //基础路径,做请求前缀。
axios.defaults.headers['X-Requested-With']="XMLHttpRequest" //请求类型:异步请求
axios.defaults.headers.post['Content-Type']='application/json' //post以json格式提交到后台

export default axios;

获取后台所有数据:在【views】试图中【CategoryView.vue】组件下请求数据即可

<template>
    <el-card class="box-card">
      <template #header>
        <div class="card-header">
          <span>商品分类</span>
          <el-button type="primary" icon="CirclePlus" round>添加分类</el-button>
        </div>
      </template>
      <el-table :data="tableData.list" stripe style="width: 100%">
    <el-table-column prop="id" label="Id" width="180" />
    <el-table-column prop="name" label="名称" width="180" />
    <el-table-column fixed="right" label="操作" width="180">
      <template #default>
        <el-button type="success" size="small">修改</el-button>
        <el-button type="danger" size="small">删除</el-button>
      </template>
    </el-table-column>
  </el-table>
    </el-card>
  </template>
  
<script setup>
  import {reactive,onMounted} from 'vue' //vue里面要定义变量,需要导入reactive这个方法
  import axios from '@/api/api_config';//请求库,@符号表示src文件夹
  
  const tableData = reactive({list:[]})//reactive也可以定义一个对象list

  onMounted(()=>{ //类似于后台构造方法,初始化时调用
    getList() 
  })
  const getList=()=>{//获取数据信息
    return axios.get('/Category').then((res)=>{//get得的后台控制器的数据,返回结果用then方法获取。
      tableData.list=res.data
      console.log(res.data)//打印到控制台
    })
  }
</script>

增删改:在【components】创建弹窗组件:AddCategory.vue 做添加和修改

<template>
    <el-dialog
      v-model="state.dialogVisible"
      :title="dialogTitle"
      width="35%"
      :before-close="handleClose"
    >
    <el-form :model="ruleForm" label-width="120px">
        <el-form-item label="姓名">
            <el-input v-model="ruleForm.name" />
        </el-form-item>
    </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="add">
            保存
          </el-button>
        </span>
      </template>
    </el-dialog>
</template>
  
<script  setup>
  import {inject, reactive,toRefs,watch} from "vue" //reactive可以定义变量也可以定义对象。
    import {ElMessage} from "element-plus" //弹窗
    import axios from '@/api/api_config';//请求库

  const state =reactive({
    dialogVisible:false,//表示不显示对话框,ui库包对话框当做属性来判断了
    ruleForm:{id:"",name:""}//对话框的数据,也是修改和添加用
  });//如果没有toRef转换,那么必须通过state.dialogVisible这样一层一层的取值
  const {dialogVisible,ruleForm} =toRefs(state)//将reactive转为ref对象,也不需要点value取值
  const dialogCategory=()=>{//定义一个打开对话框的方法
    state.dialogVisible = true;//调用方法就显示对话框
  };
  //主动暴露子组件方法,这是编译器的宏命令,不需要引入,其他组件就可以使用
  defineExpose({dialogCategory})//需要配置文件.eslintrc.js将宏命令打开:"vue/setup-compiler-macros":true在env选项中添加。
  const title = defineProps({//自动暴露这个变量
    dialogTitle:{type:String},//标题
    tableRow:{type:Object}//id
    })
  watch(//监听器,是vue的一个选项,监听数据的变化而变化
    ()=>title.tableRow,//需要监听的数据,
    ()=>{state.ruleForm=title.tableRow},//如果有变化就改变数据。
    {//配置
        deep:true,//是否深度检测,数据又多层,可以深度查找
        immediate:true //立即执行
    }
  )
  const getList=inject("getList")//依赖注入刷新页面,传过来的用provide,接收的用inject
  const add =()=>{
    if(title.dialogTitle==="添加数据"){
        let param={name:ruleForm.value.name} //let定义的变量在作用于大括号中,出了大括号无用
        axios.post('/Category',param).then(()=>{
            ElMessage.success("添加成功")
            getList()//刷新页面数据
            state.dialogVisible = false//关闭窗口
        })
    }else{
        let param={
            id:title.tableRow.id, //id
            name:ruleForm.value.name //姓名
        }
        axios.put('/Category',param).then(()=>{
            ElMessage.success("修改成功")
            getList()//刷新页面数据
            state.dialogVisible = false//关闭窗口
        })
    }
  }

</script>
<style scoped>
  .dialog-footer button:first-child {
    margin-right: 10px;
  }
</style>
  

数据页代码如下

<template>
    <el-card class="box-card">
      <template #header>
        <div class="card-header">
          <span>商品分类</span>
          <el-button type="primary" icon="CirclePlus" round @click="handleDialog()">添加分类</el-button>
        </div>
      </template>
      <el-table :data="tableData.list" stripe style="width: 100%">
    <el-table-column prop="id" label="Id" width="180" />
    <el-table-column prop="name" label="名称" width="180" />
    <el-table-column fixed="right" label="操作" width="180">
      <template #default="scop">
        <el-button type="success" size="small" @click="handleDialog(scop.row)">修改</el-button>
        <el-button type="danger" size="small" @click="open(scop.row.id)">删除</el-button>
      </template>
    </el-table-column>
  </el-table>
    </el-card>
    <AddCategoryVue ref="AddCategory" :dialogTitle="dialogTitle" :tableRow="tableRow"></AddCategoryVue>
  </template>
  
<script setup>
  import {reactive,onMounted,ref, provide} from 'vue' //vue里面要定义变量,需要导入reactive这个方法
  import axios from '@/api/api_config';//请求库,@符号表示src文件夹
  import AddCategoryVue from '@/components/AddCategory.vue'; //子组件,对话框的标签
  import { isNull } from '@/utils/filter';//自定义的做数据筛选处理
  import { ElMessage, ElMessageBox } from 'element-plus'//删除的消息弹窗
  
  const tableData = reactive({list:[]})//reactive也可以定义一个对象list
  
  onMounted(()=>{ //类似于后台构造方法,初始化时调用,自动运行
    getList() 
  })
  const getList=()=>{//获取数据信息的方法
    return axios.get('/Category').then((res)=>{//返回结果用then方法获取。
      tableData.list=res.data
      console.log(res.data)//打印到控制台,测试数据用
    })
  }
  provide("getList",getList);//依赖注入:跨组件,把这个方法提供给子组件执行,传过去的用provide,接收的用inject他们两个是一对依赖注入

  const AddCategory = ref(null)//定义在标签里的ref属性,当做一个实例,名字就代表了这个对话框组件,就可以用变量去调用他里面的方法了
  const dialogTitle =ref("")//弹窗标题
  const tableRow =ref({})//修改和删除的id,绑定到标签,传给子组件
  const handleDialog=(row)=>{ //打开弹窗的事件
    if(isNull(row)){
      dialogTitle.value="添加数据"
    }else{
      dialogTitle.value="修改数据"
      tableRow.value = row //把id传入子组件的弹窗
    }
    AddCategory.value.dialogCategory()//调用子组件的弹窗方法
  }
  const open =(id)=>{
      ElMessageBox.confirm('你确定要删除吗?','温馨提示',{
        confirmButtonText:'确定',
        cancelButtonText:'取消',
        type:'warning',
      }).then(()=>{
        axios.delete(`/Category/${id}`).then(()=>{//这里的符号是反引号波浪线下面
          ElMessage({
            type:'success',
            message:'删除成功!',
          });
          getList() //加载数据的方法,刷新数据
        })
    }).catch(()=>{//捕捉到错误
        ElMessage({
          type:'info',
          message:'取消删除!',
        })
      })
  }
  

</script>
  

这里自定义了一个数据过滤器:src项目创建【utils】文件夹:filter.js怎么配置一些数据过滤

export const isNull=(data)=>{ //定义个数据过滤器
    if(!data)return true //普通值
    if(JSON.stringify(data)==='{}')return true //对象
    if(JSON.stringify(data)==='{}')return true //数组
}

 







 

标签:WebAPI,axios,vue,const,C#,api,import,id
From: https://www.cnblogs.com/longxinyv/p/16969952.html

相关文章