VS2019创建WebApi+Vue+Element-UI(入门)
初步思路:创建WebApi编写接口,创建Vue,引用Element-UI,抽取WebApi数据展示
需要添加的包:
Autofac.Extensions.DependencyInjection
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
AutoMapper.Extensions.Microsoft.DependencyInjection
Microsoft.EntityFrameworkCore.Tools(DbFirst依据数据库生成实体需要使用)
Pomelo.EntityFrameworkCore.MySql
第一步:创建WebApi,VS2019创建项目不再描述。
Statup.cs
添加api 控制器、添加DbContext、添加AutoMapper、配置跨域访问(用于Vue调用)、添加AutoFac容器。
AutoMapper 用于api返回数据与数据库表机构之间转换,AutoFac配置Service和Repository的注入关系
using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Autofac; using AdminWebApi.Autofac; using Autofac.Extensions.DependencyInjection; using DataDAO; using Microsoft.EntityFrameworkCore; using AutoMapper; namespace AdminWebApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public ILifetimeScope AutofacContainer { get; private set; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); //services.AddMvc(); services.AddDbContextStatup.cs(options => options.UseMySql(Configuration.GetConnectionString("unified_users"), x => x.ServerVersion("5.6.21-mysql"))); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //必须appsettings.json中配置 string corsUrls = Configuration["CorsUrls"]; if (string.IsNullOrEmpty(corsUrls)) { throw new Exception("请配置跨请求的前端Url"); } //增加允许跨域配置 //services.AddCors(m => m.AddPolicy(name:"Any", a => a.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));//开放全部 //开放指定域名的访问 services.AddCors(options => { options.AddDefaultPolicy( builder => { builder.WithOrigins(corsUrls.Split(",")) //添加预检请求过期时间 .SetPreflightMaxAge(TimeSpan.FromSeconds(2520)) .AllowCredentials() .AllowAnyHeader() .AllowAnyMethod(); }); }); } public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterModule(new AutofacMoule()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } this.AutofacContainer = app.ApplicationServices.GetAutofacRoot(); //app.UseHttpsRedirection(); // app.UseCors(bulider => bulider.AllowAnyOrigin()); app.UseRouting(); //增加允许跨域配置,放在routing 之后 验证之前,顺序很重要 app.UseCors();//加载默认跨域配置 //app.UseCors("Any");//加载有命名的策略 app.UseAuthorization(); app.UseEndpoints(endpoints => { //endpoints.MapControllers(); endpoints.MapControllerRoute( name: "default", pattern: "api/{controller=Users}/{action=index}/{id?}" ); }); } } }
using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Autofac.Extensions.DependencyInjection; using System.IO; namespace AdminWebApi { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => //Host.CreateDefaultBuilder(args) // .ConfigureWebHostDefaults(webBuilder => // { // webBuilder.UseStartupProgram.cs(); // }); Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseContentRoot(Directory.GetCurrentDirectory()); webBuilder.UseStartup(); //webBuilder.UseUrls("http://localhost:8088"); }); } }
第二步:编写接口与数据库访问
添加IRepository和Repository,用于访问数据库,添加IService和Service用于接受处理请求。
EF Core 参考:https://www.cnblogs.com/zeran/p/11125309.html
using ModelDto; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ModelDto.DtoParameters; using ModelDto.RUDDto; using ModelDto.ViewDto; using DataDAO; namespace AdminWebApi.IRepository { public interface IUsersRepository { TaskIRepository.csGetUsers(int UserId); Task > GetUsersList(UsersDtoParameter usersDtoParameter); Task<int> UpdateUser(AddUserDto addUser); } }
using AdminWebApi.IRepository; using DataDAO; using Microsoft.EntityFrameworkCore; using ModelDto; using ModelDto.DtoParameters; using ModelDto.RUDDto; using ModelDto.ViewDto; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace AdminWebApi.Repository { public class UsersRepository : IUsersRepository { public UsersRepository() { } readonly unified_usersContext _Context; public UsersRepository(unified_usersContext unifiedUserDbContext) { _Context = unifiedUserDbContext; } public async TaskRepository.csGetUsers(int UserId) { return await _Context.NtUsers.Where(n => n.Id== UserId).FirstOrDefaultAsync(); } public async Task > GetUsersList(UsersDtoParameter usersDtoParameter) { var query_user = _Context.NtUsers as IQueryable ;//创建筛选条件, if (!string.IsNullOrWhiteSpace(usersDtoParameter.name))//筛选姓名 { usersDtoParameter.name = usersDtoParameter.name.Trim(); query_user=query_user.Where(n => n.Name.StartsWith(usersDtoParameter.name)); } return await query_user.Take(usersDtoParameter.pageCount).ToListAsync();//取数据 } public async Task<int> UpdateUser(AddUserDto addUser) { return 1; } } }
using DataDAO; using ModelDto; using ModelDto.DtoParameters; using ModelDto.RUDDto; using ModelDto.ViewDto; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace AdminWebApi.IServices { public interface IUserService { TaskIServicesGetUsers(int UserId); Task > GetUsersList(UsersDtoParameter usersDtoParameter); Task<int> UpdateUser(AddUserDto addUser); } }
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using AdminWebApi.IRepository; using AdminWebApi.IServices; using AutoMapper; using DataDAO; using ModelDto; using ModelDto.DtoParameters; using ModelDto.RUDDto; using ModelDto.ViewDto; namespace AdminWebApi.Service { public class UserService : IUserService { readonly IUsersRepository _userpepository; private readonly IMapper _mapper; public UserService(IUsersRepository usersRepository,IMapper mapper) { _userpepository = usersRepository; this._mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } public async TaskUserServiceGetUsers(int UserId) { NtUsers ntusers= await _userpepository.GetUsers(UserId); return _mapper.Map (ntusers);//表结构model转换为Dtomodel,Dto用于暴露在外部 } public async Task > GetUsersList(UsersDtoParameter usersDtoParameter) { return _mapper.Map >(await _userpepository.GetUsersList(usersDtoParameter)); } public async Task<int> UpdateUser(AddUserDto addUser) { return await _userpepository.UpdateUser(addUser); } } }
第2.1步:在编写这些代码期间,需要创建DbContext、AutoMapper、AutoFac等
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using AdminWebApi.IServices; using AdminWebApi.Service; using Autofac; namespace AdminWebApi.Autofac { public class AutofacMoule:Module { protected override void Load(ContainerBuilder builder) { builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly())//注册整个程序集 .Where(n => n.Name.EndsWith("Service")).AsImplementedInterfaces()//注册程序集内以Service结尾的文件 .SingleInstance();//单例模式 //.InstancePerLifetimeScope(); builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()) .Where(n => n.Name.EndsWith("Repository")).AsImplementedInterfaces()//注册程序集内以Repository结尾的文件 .SingleInstance(); //builder.RegisterTypeAutofacMoule.cs().As } } }();
Statup.cs中引用AutoFac,添加函数
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new AutofacMoule());
}
Program.cs需要按照上面的Program.cs代码段修改
第2.2步:引用AutoMapper,并编写Dto类,并编写映射关系的UserProfile,AutoMapper 是按照名称进行映射,名称不同不能映射成功,可以在映射是对某个字段进行处理
using System; using System.Collections.Generic; using System.Text; using ModelDto.ViewDto; using ModelDto.RUDDto; using AutoMapper; namespace DataDAO.profiles { class UserProfile : Profile { public UserProfile() { CreateMapUserProfile.cs() .ForMember( u => u.name, opt => opt.MapFrom( dto => dto.Name+dto.NickName ) ); } } }
添加后需要在Sturtup中的ConfigureService 添加
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
第三步:编写api接口,RESTful Web API是按照http动词(get/post/put/delete/options等)请求接口的,比如接口上增加[HttpPost]无论接口命名是什么只要是post请求都调用这个接口,
指定接口名称使用[HttpPost("getuserlist")]或者[HttpPost(nameof(接口名))]
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using ModelDto; using Autofac; using AdminWebApi.IServices; using ModelDto.ViewDto; using ModelDto.DtoParameters; using System.Net.Mime; using Microsoft.AspNetCore.Cors; namespace AdminWebApi.Controllers { [EnableCors]//加载默认跨域配置 //[EnableCors("Any")]//加载有命名的跨域策略 [ApiController] [Route("api/[controller]")] //[Produces(MediaTypeNames.Application.Json)] public class AdminUserController : ControllerBase { readonly IUserService _userservice; public AdminUserController(IUserService userService) { _userservice = userService; } [HttpGet("getuserByid")] public async TaskAdminUserController.csGetDtoAsync(int uid) { return await _userservice.GetUsers(uid); } [HttpPost("getuserlist")] [HttpOptions] public async Task > GetUserDtoAsync(UsersDtoParameter dtoParameter) { return await _userservice.GetUsersList(dtoParameter); } } }
这时使用postman 请求接口能够正常返回数据。postman不涉及跨域问题。
第四步:创建Vue项目并饮用Element-ui,VS2019可以创建Vue项目,没有的话先安装VS2019的Node.JS支持
Vue的启动文件是Main.js引用第三方js 可以在indexhtml的body之前
需要先在项目路径下安装 Element-ui,axios(用于请求后端数据)
npm i element-ui -S
npm install axios -S
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; import axios from 'axios';//引用axios 用于请求数据 import qs from 'qs'; Vue.config.productionTip = true; Vue.use(ElementUI);//注册组件 Vue.component(ElementUI); //Vue.use(axios);// Vue.prototype.$axios = axios;//相当于定义变量,没太搞清 Vue.prototype.$qs = qs; //跨域问题处理开始,实际没效果,后端开放跨域就可以 Vue.prototype.HOST = '/api'; var http = axios.create({ baseURL: 'http://127.0.0.1:5000/', timeout: 10000 }); axios.defaults.headers.post['Content-Type'] = 'application/json'; //axios.defaults.baseUrl = "/api"; Vue.http = http; //跨域问题处理 结束 new Vue({ el: '#app', render: h => h(App) }).$mount('#app');Main.js
App.vue"app">"200px">
Left_menu、Header内容只是Element-ui的样式,不贴代码了
Home.vueclass="home">"tableData2" style="width: 100%" :key="Math.random()"> "login_name" label="登录名" width="180"> "name" label="姓名" width="180"> "cellphone" label="地址">
Home.vue的逻辑只是动态给table赋值,请求了api接口,遇到的问题比较多。特地记录一下
1、vue生命周期问题,暂时没搞懂,exprot default{data(){return ……},mounted(){},methods:{}} 其中data和mounted是函数,menthods是属性,这些执行是有先后顺序的。首先需要在data中定义并初始化数据,在mounted内计算。
其中getData()函数内的$axios.post()错了很多次才调整好语法(还是语法不了解呀T_T)
this表示window,代表整个页面,使用msg=>{this.XXX} 这里边的this代表局部 | function(msg){this.XXX}这里的this表示window |
400错误和415错误
application/x-www-form-urlencoded
2、类型不正确会报415错误:API接口接受的 'Content-Type'类型是 'application/json;charset=UTF-8',所以需要加headers{ 'Content-Type': 'application/json;charset=UTF-8'},默认是
3、参数不被识别会报400错误:参数需要JSON.stringify转为字符串,我个人理解是传递的是对象,但是后端需要的是json字符串,需要转换,不然会报400错误。
重要的一点:跨域
一般Vue都是和后端分离的,所以涉及到跨域问题,所以需要后端设置
首先需要在appsettings.json中添加允许访问的域
"CorsUrls": "http://localhost:1337,http://127.0.0.1:1337,http://127.0.0.1:8081,http://127.0.0.1:8080,http://172.21.210.1:1337"
Startup.cs中的ConfigureServices增加跨域设置,可以设置全部,也可以设置指定的域
//必须appsettings.json中配置 string corsUrls = Configuration["CorsUrls"]; if (string.IsNullOrEmpty(corsUrls)) { throw new Exception("请配置跨请求的前端Url"); } //增加允许跨域配置 //services.AddCors(m => m.AddPolicy(name:"Any", a => a.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().AllowCredentials()));//开放全部 //开放指定域名的访问 services.AddCors(options => { options.AddDefaultPolicy( builder => { builder.WithOrigins(corsUrls.Split(",")) //添加预检请求过期时间 .SetPreflightMaxAge(TimeSpan.FromSeconds(2520)) .AllowCredentials() .AllowAnyHeader() .AllowAnyMethod(); }); });Cors配置
在Configure中需要在app.UseRoting()和app.UseAuthorization()之间添加:app.UseCors();
在Api的Controller上添加[EnableCors]
简单记录一下 配置带名称的Cors规则和default的默认规则,有些资源可以公开访问,有些资源只允许某些用户或域名访问,比如新闻是允许公开访问的,用户信息是限定的,就可以定义不同名称的Cors规则,Controller上使用[EnableCors("名称")]
代码位置:https://gitee.com/zeran/NetCore3.X-WebApi-Vue-AutoFac