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.AddDbContext<unified_usersContext>(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?}"
                    );
            });

        }
    }
}
Statup.cs
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.UseStartup<Startup>();
            //    });
            Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder => {
                webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
            webBuilder.UseStartup<Startup>();
             //webBuilder.UseUrls("http://localhost:8088");
                });
    }
}
Program.cs

 第二步:編寫接口與數據庫訪問

添加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 
    {
       Task<NtUsers> GetUsers(int UserId);
       Task<IEnumerable<NtUsers>> GetUsersList(UsersDtoParameter usersDtoParameter);
        Task<int> UpdateUser(AddUserDto addUser);
    }
}
IRepository.cs
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  Task<NtUsers> GetUsers(int UserId)
        {
            return await _Context.NtUsers.Where(n => n.Id== UserId).FirstOrDefaultAsync();
        }

        public async Task<IEnumerable<NtUsers>> GetUsersList(UsersDtoParameter usersDtoParameter)
        {
            var query_user = _Context.NtUsers as IQueryable<NtUsers>;//創建篩選條件,
            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;
        }
    }
}
Repository.cs
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
    {

        Task<UsersDto> GetUsers(int UserId);
        Task<IEnumerable<UsersDto>> GetUsersList(UsersDtoParameter usersDtoParameter);
        Task<int> UpdateUser(AddUserDto addUser);
    }
}
IServices
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  Task<UsersDto> GetUsers(int UserId)
        {
          NtUsers ntusers= await _userpepository.GetUsers(UserId);
            return _mapper.Map<UsersDto>(ntusers);//表結構model轉換為Dtomodel,Dto用於暴露在外部
        }

        public async Task<IEnumerable<UsersDto>> GetUsersList(UsersDtoParameter usersDtoParameter)
        {
          return  _mapper.Map<IEnumerable<UsersDto>>(await _userpepository.GetUsersList(usersDtoParameter));
        }

        public async Task<int> UpdateUser(AddUserDto addUser)
        {
            return await _userpepository.UpdateUser(addUser);
        }
    }
}
UserService

第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.RegisterType<twoUserService>().As<IUserService>();
        }
    }
}
AutofacMoule.cs

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()
        {
            CreateMap<NtUsers, UsersDto>()
                .ForMember(
                u => u.name,
                opt => opt.MapFrom(
                    dto => dto.Name+dto.NickName
                    )
                );
        }
    }
}
UserProfile.cs

添加后需要在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 Task<UsersDto> GetDtoAsync(int uid)
        {
            return  await _userservice.GetUsers(uid);
        }
        [HttpPost("getuserlist")]
        [HttpOptions]
        public async Task<IEnumerable<UsersDto>> GetUserDtoAsync(UsersDtoParameter dtoParameter)
        {
            return await _userservice.GetUsersList(dtoParameter);
        }
    }
}
AdminUserController.cs

 這時使用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
<template>
    <div id="app">
        
        <el-container>
            <el-header><Header /></el-header>
            <el-container>
                <el-aside width="200px"><Left_menu /></el-aside>
                <el-main><Home /></el-main>
            </el-container>
        </el-container>

    </div>
</template>

<script>
    import Home from './components/Home.vue';
    import Header from './components/Header.vue';
    import Left_menu from './components/Left_menu.vue';
    export default {
        name: 'app',
        components: {
            
            Header,
            Left_menu,
            Home
        }
    };
</script>

<style>
    @import url("//unpkg.com/element-ui@2.14.0/lib/theme-chalk/index.css");

    .el-header, .el-footer {
        background-color: #B3C0D1;
        color: #333;
        text-align: center;
        line-height: 60px;
    }

    .el-aside {
        background-color: #D3DCE6;
        color: #333;
        text-align: center;
        line-height: 200px;
    }

    .el-main {
        background-color: #E9EEF3;
        color: #333;
        text-align: center;
        line-height: 160px;
    }

    body > .el-container {
        margin-bottom: 40px;
    }

    .el-container:nth-child(5) .el-aside,
    .el-container:nth-child(6) .el-aside {
        line-height: 260px;
    }

    .el-container:nth-child(7) .el-aside {
        line-height: 320px;
    }
</style>
App.vue

Left_menu、Header內容只是Element-ui的樣式,不貼代碼了

<template>
    <div class="home">
        <template>
            <el-table :data="tableData2"
                      style="width: 100%" :key="Math.random()">
                <el-table-column prop="login_name"
                                 label="登錄名"
                                 width="180">
                </el-table-column>
                <el-table-column prop="name"
                                 label="姓名"
                                 width="180">
                </el-table-column>
                <el-table-column prop="cellphone"
                                 label="地址">
                </el-table-column>
                
            </el-table>
        </template>

    </div>
</template>

<script>
   // var tabelData;
    
    export default {
        //data() 為函數,mounted methods 均為vue生命周期內的不同內容,寫法與順序 暫時沒搞清
        data() {
            return {
                tableData2: []//定義以及初始化數據
            }
        },
        mounted() {// 或者 mounted: function() {
            this.getData();
        },
        methods: {
             getData() {
                let params = new URLSearchParams()
                params.append("name", "學員");
                //$axios 是引用 的axios 的組件,定義的變量
                //后台接受參數是application/json 格式,需要指定content-type,不指定Content-type 或者不對應會報415 媒體類型不正確錯誤
                //參數需要 JSON.stringify 對象轉成字符串,不然會報400錯誤,
                this.$axios.post("http://127.0.0.1:5000/api/adminuser/getuserlist",//vue和后端webapi 會出現跨域情況,需要webapi內的startup 增加允許跨域配置,詳見后端
                    JSON.stringify(params), {
                    headers: {
                        'Content-Type': 'application/json;charset=UTF-8'
                    }
                }).then(msg=> {
                    this.tableData2 = msg.data;//為定義的數據賦值

                    //this.tabelData2 需要加this ,這里的this 是生命周期內的(要使用then(msg=>{})方式)
                    //如果使用then(function(msg){}) 方式 this表示window內,會報錯 tableData2未定義,解決方案:
                    // 在vue生命周期內定義常量 const that=this; function 內 改為that.tableData2=msg.data;
                });
            }
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
Home.vue

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錯誤
2、類型不正確會報415錯誤:API接口接受的 'Content-Type'類型是 'application/json;charset=UTF-8',所以需要加headers{ 'Content-Type': 'application/json;charset=UTF-8'},默認是
application/x-www-form-urlencoded
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM