ASP.NET Core MVC + Vue 3 集成指南

在vs2022中建立ASP.NET CORE MVC项目,项目结构如下

MyVueApp/
├── ClientApp/          # Vue 3 前端代码
│   ├── src/
│   │   ├── components/
│   │   ├── views/
│   │   ├── router/
│   │   ├── store/
│   │   └── App.vue
│   ├── package.json
│   └── vite.config.js
├── Controllers/
├── Views/
├── wwwroot/
└── Program.cs

步骤 1:创建项目并配置后端

1.1 创建 ASP.NET Core MVC 项目

dotnet new mvc -n MyVueApp -f net5.0
cd MyVueApp

1.2 安装必要的 NuGet 包

<!-- 编辑 MyVueApp.csproj 文件 -->
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <!-- 添加Spa服务支持 -->
    <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.*" />
  </ItemGroup>
</Project>

1.3 配置 Program.cs

// Program.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = WebApplication.CreateBuilder(args);

// 添加 MVC 服务
builder.Services.AddControllersWithViews();

var app = builder.Build();

// 配置中间件管道
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// 为静态文件提供服务
app.UseStaticFiles();

app.UseRouting();
app.UseAuthorization();

// MVC 路由
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

// 用于开发环境的 Vue 开发服务器代理
if (app.Environment.IsDevelopment())
{
    // 配置 Vue 开发服务器的代理
    app.UseSpa(spa =>
    {
        spa.Options.SourcePath = "ClientApp";
        
        // Vue 开发服务器运行在 3000 端口
        if (app.Environment.IsDevelopment())
        {
            spa.UseProxyToSpaDevelopmentServer("http://localhost:3000");
        }
    });
}
else
{
    // 生产环境:提供编译后的 Vue 文件
    app.Map(new PathString("/clientapp"), clientApp =>
    {
        clientApp.UseSpaStaticFiles();
        clientApp.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp/dist";
        });
    });
}

app.Run();

步骤 2:创建 Vue 3 前端应用

2.1 创建 Vue 3 项目

在项目根目录下:

# 使用 Vite 创建 Vue 3 项目(推荐)
npm create vue@latest ClientApp -- --template vue
# 或者使用 Vue CLI
# vue create ClientApp

cd ClientApp
npm install

2.2 安装 Vue Router 和 Vuex(可选)

npm install vue-router@4 vuex@next axios

2.3 配置 Vite

// ClientApp/vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'url'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:5000', // ASP.NET Core 后端地址
        changeOrigin: true
      }
    }
  },
  build: {
    outDir: 'dist',
    assetsDir: 'assets'
  }
})

步骤 3:创建 Vue 应用结构

3.1 主入口文件

// ClientApp/src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

// 创建 Vue 应用实例
const app = createApp(App)

// 使用路由和状态管理
app.use(router)
app.use(store)

// 挂载到 #app 元素
app.mount('#app')

3.2 Vue 路由配置

// ClientApp/src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
import ProductsView from '../views/ProductsView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: AboutView
  },
  {
    path: '/products',
    name: 'products',
    component: ProductsView
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

3.3 Vuex 状态管理(可选)

// ClientApp/src/store/index.js
import { createStore } from 'vuex'

export default createStore({
  state: {
    counter: 0,
    user: null,
    products: []
  },
  mutations: {
    increment(state) {
      state.counter++
    },
    setUser(state, user) {
      state.user = user
    },
    setProducts(state, products) {
      state.products = products
    }
  },
  actions: {
    async fetchProducts({ commit }) {
      // 调用 API 获取产品数据
      const response = await fetch('/api/products')
      const products = await response.json()
      commit('setProducts', products)
    }
  },
  getters: {
    getProductCount: state => state.products.length
  }
})

3.4 App.vue 根组件

<!-- ClientApp/src/App.vue -->
<template>
  <div id="app">
    <!-- 导航栏 -->
    <nav class="navbar">
      <router-link to="/">首页</router-link> |
      <router-link to="/about">关于</router-link> |
      <router-link to="/products">产品</router-link>
    </nav>
    
    <!-- 路由视图 -->
    <router-view />
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}

.navbar {
  padding: 20px;
  text-align: center;
  background-color: #f5f5f5;
}

.navbar a {
  font-weight: bold;
  color: #2c3e50;
  text-decoration: none;
  margin: 0 10px;
}

.navbar a.router-link-exact-active {
  color: #42b983;
}
</style>

3.5 创建示例组件

<!-- ClientApp/src/views/HomeView.vue -->
<template>
  <div class="home">
    <h1>欢迎使用 Vue 3 + ASP.NET Core MVC</h1>
    <p>这是一个集成示例</p>
    
    <!-- 使用 Vuex 状态 -->
    <div>
      <p>计数器: {{ counter }}</p>
      <button @click="incrementCounter">增加</button>
    </div>
    
    <!-- 调用 API 示例 -->
    <div v-if="products.length > 0">
      <h3>产品列表:</h3>
      <ul>
        <li v-for="product in products" :key="product.id">
          {{ product.name }} - ¥{{ product.price }}
        </li>
      </ul>
    </div>
    <button @click="fetchProducts">获取产品</button>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions } from 'vuex'

export default {
  name: 'HomeView',
  computed: {
    ...mapState(['counter', 'products'])
  },
  methods: {
    ...mapMutations(['increment']),
    ...mapActions(['fetchProducts']),
    incrementCounter() {
      this.increment()
    }
  }
}
</script>

步骤 4:创建 ASP.NET Core API 控制器

4.1 创建 ProductsController

// Controllers/Api/ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace MyVueApp.Controllers.Api
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        // 模拟产品数据
        private static readonly List<Product> _products = new List<Product>
        {
            new Product { Id = 1, Name = "笔记本电脑", Price = 5999.99m, Description = "高性能笔记本电脑" },
            new Product { Id = 2, Name = "智能手机", Price = 3999.99m, Description = "最新款智能手机" },
            new Product { Id = 3, Name = "平板电脑", Price = 2999.99m, Description = "便携式平板电脑" }
        };

        // GET: api/products
        [HttpGet]
        public IActionResult GetProducts()
        {
            return Ok(_products);
        }

        // GET: api/products/1
        [HttpGet("{id}")]
        public IActionResult GetProduct(int id)
        {
            var product = _products.Find(p => p.Id == id);
            if (product == null)
                return NotFound();
            
            return Ok(product);
        }

        // POST: api/products
        [HttpPost]
        public IActionResult CreateProduct([FromBody] Product product)
        {
            if (product == null)
                return BadRequest();

            // 模拟生成ID
            product.Id = _products.Count + 1;
            _products.Add(product);
            
            return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);
        }
    }

    // 产品模型类
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Description { get; set; }
    }
}

4.2 修改 HomeController

// Controllers/HomeController.cs
using Microsoft.AspNetCore.Mvc;

namespace MyVueApp.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            // 返回主页面,Vue 应用将在此加载
            return View();
        }

        // 其他 MVC 视图(如果需要)
        public IActionResult Privacy()
        {
            return View();
        }

        // 用于服务端渲染的 API(如果需要)
        [HttpGet]
        public IActionResult GetServerData()
        {
            return Json(new { message = "来自服务器的数据", timestamp = DateTime.Now });
        }
    }
}

步骤 5:创建 MVC 视图

5.1 修改 Index.cshtml

<!-- Views/Home/Index.cshtml -->
@{
    ViewData["Title"] = "Vue 3 + ASP.NET Core";
    Layout = null; // 不使用布局页,完全由 Vue 控制
}

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
    
    @if (Context.Request.Host.Host == "localhost")
    {
        <!-- 开发环境:使用 Vite 开发服务器 -->
        <script type="module" src="http://localhost:3000/@vite/client"></script>
        <script type="module" src="http://localhost:3000/src/main.js"></script>
    }
    else
    {
        <!-- 生产环境:使用构建后的文件 -->
        <link rel="stylesheet" href="~/clientapp/assets/index.css" />
        <script type="module" src="~/clientapp/assets/index.js"></script>
    }
</head>
<body>
    <!-- Vue 应用挂载点 -->
    <div id="app"></div>
    
    <!-- 服务器端数据(可选) -->
    <script>
        // 将服务器端数据传递给 Vue 应用
        window.serverData = {
            baseUrl: '@Url.Content("~")',
            userInfo: @Html.Raw(Json.Serialize(ViewBag.UserInfo))
        };
    </script>
</body>
</html>

步骤 6:配置 package.json 脚本

{
  "name": "my-vue-app",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "dev:full": "concurrently \"npm run dev\" \"dotnet run\"",
    "build:full": "npm run build && dotnet build"
  },
  "dependencies": {
    "vue": "^3.2.0",
    "vue-router": "^4.0.0",
    "vuex": "^4.0.0",
    "axios": "^0.24.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.0.0",
    "vite": "^2.7.0",
    "concurrently": "^7.0.0"
  }
}

步骤 7:创建 API 服务示例

// ClientApp/src/services/api.js
import axios from 'axios'

// 创建 axios 实例
const apiClient = axios.create({
  baseURL: '/api',
  headers: {
    'Content-Type': 'application/json'
  }
})

// 产品 API
export default {
  // 获取所有产品
  getProducts() {
    return apiClient.get('/products')
  },
  
  // 获取单个产品
  getProduct(id) {
    return apiClient.get(`/products/${id}`)
  },
  
  // 创建产品
  createProduct(product) {
    return apiClient.post('/products', product)
  }
}

步骤 8:运行和构建

8.1 开发环境运行

# 终端1:启动 Vue 开发服务器
cd ClientApp
npm run dev

# 终端2:启动 ASP.NET Core
cd ..
dotnet run

访问 https://localhost:5001 查看应用

8.2 生产环境构建

# 构建 Vue 应用
cd ClientApp
npm run build

# 构建 ASP.NET Core 应用
cd ..
dotnet publish -c Release

集成方式总结

  1. 开发模式:Vue 运行在独立的开发服务器(端口 3000),通过代理连接到后端 API

  2. 生产模式:Vue 编译为静态文件,放置在 ClientApp/dist 目录,由 ASP.NET Core 静态文件中间件提供服务

  3. API 通信:Vue 组件通过 Axios 调用 ASP.NET Core Web API

  4. 路由处理:Vue Router 处理前端路由,MVC 路由处理后端 API 和页面服务

注意事项

  1. CORS 配置:如果前后端完全分离部署,需要配置 CORS

  2. 身份验证:可以使用 ASP.NET Core Identity 或 JWT 进行身份验证

  3. 服务器端渲染:如需 SSR,可以考虑使用 Vue 3 的 SSR 功能或第三方解决方案

  4. 热重载:开发时 Vue 组件支持热重载,提高开发效率

这种架构结合了 ASP.NET Core MVC 的强大后端能力和 Vue 3 的现代前端体验,适合需要 SEO 友好、渐进增强的应用场景。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

caifox菜狐狸

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值