AspDotNet+VueCli3從零開始

0. Why笙各?

  • 前后端分離開發(fā),后端提供api前端獨(dú)立建工程邦鲫,相信大家都是這么干的灸叼。但這種方式有個(gè)弊端:在部署上線時(shí),需要為前端頁面新開一個(gè)端口庆捺,而且古今,開發(fā)期間兩個(gè)編輯器切來切去總感覺很煩。
  • 如果你和我一樣滔以,前后端同時(shí)開發(fā)捉腥,并且使用dotnet core + Vue技術(shù)棧。我覺得本文比較適合你你画,這里介紹了如何使用dotnet2x與最新的Vue Cli3無縫集成抵碟,進(jìn)行行云流水般的開發(fā)。
  • 如果你依然喜歡使用dotnet mvc + Razor撬即, 本文不適合你立磁。不過,看看下面的代碼剥槐,我真心覺得沒幾個(gè)人再會(huì)用這樣的語法寫工程了唱歧。
//.cshtml代碼片段截取
  <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Info" class="control-label"></label>
                <textarea class="form-control" rows="15" asp-for="Info"></textarea>
                <span asp-validation-for="Info" class="text-danger"></span>
            </div>
  • 如果你Typescript很熟練,本文既適合也不適合你粒竖,官方有現(xiàn)成的TS模板開箱即用颅崩,但是,VueCli3的Ts模板比官方的要好用很多蕊苗。這個(gè)你自己決定吧沿后。

下面正式開始,首先摘錄一段來自官方低沉的抱怨

As far as I’m aware, we don’t have plans to introduce Vue-specific features. This isn’t because we have anything against Vue, but rather just to limit the growth in the number of frameworks that we’re maintaining support for. The dev team only has a finite capacity for handling third-party concepts, and last year we made the strategic choice to focus on only Angular and React.

--我們暫時(shí)沒有針對(duì)Vue開發(fā)項(xiàng)目模板的計(jì)劃朽砰,這并不是說我們對(duì)Vue有什么偏見尖滚,而是我們...tm的實(shí)在是太忙了喉刘,顧不過來啊兄嘚...我們暫時(shí)只有 Angular 和React的,你們先將就著用吧...

本文所有內(nèi)容使用vs code編輯器+控制臺(tái)完成

1. 找個(gè)合適的地方漆弄,運(yùn)行dotnet new建項(xiàng)目

注意睦裳,官方并沒有現(xiàn)成的Vue模板(官方目前是TypeScript版本的),所以我們使用react模板撼唾,然后無偶們一步步修改成Vue:

dotnet new react

2. 開始修改

  • Startup.cs文件中,將目標(biāo)文件夾改為dist:
// configuration.RootPath = "ClientApp/build";
 configuration.RootPath = "ClientApp/dist";
  • 移去45行的https設(shè)置廉邑,否則還要設(shè)置證書
//app.UseHttpsRedirection();
  • 根據(jù)開頭那段話,官方?jīng)]有包倒谷,我們需要安裝一個(gè)第三方包:dotnet add package VueCliMiddleware
  • 繼續(xù)回到Startup文件蛛蒙,
    using VueCliMiddleware;
    將react替換為vue(64行附近):
  //spa.UseReactDevelopmentServer(npmScript: "start");
  spa.UseVueCli(npmScript: "serve", port: 8080);
  • 現(xiàn)在, 你的工程看起來是這個(gè)樣子渤愁,接下來牵祟,刪除ClienApp文件夾下的所有內(nèi)容(保留ClientApp文件夾)
    image.png

3. 建立客戶端項(xiàng)目

下一步自然是在ClientApp文件夾下使用好評(píng)如潮的VueCli3建立項(xiàng)目了。but wait猴伶, vue不允許使用首字母大寫的命名方式课舍,所以我們還是需要先建立一個(gè)client-app項(xiàng)目,然后把所有內(nèi)容移動(dòng)到到ClientApp文件夾下他挎。
經(jīng)過一番探索筝尾,可以改這個(gè)文件夾的,假定我們想把客戶端建立在admin文件夾下:

  1. 在項(xiàng)目根文件夾下办桨,使用vue ui或者vue create admin建立項(xiàng)目筹淫。
  2. 打開.net 項(xiàng)目配置文件csproj,將這里改一下:
<PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
    <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
    <IsPackable>false</IsPackable>
    <!--改這里-->
    <SpaRoot>admin\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
  </PropertyGroup>
  1. 打開Startup.cs, 將所有ClientApp替換為admin
 services.AddSpaStaticFiles (configuration =>
 {
   configuration.RootPath = "admin/dist";
});
  //...
 app.UseSpa (spa =>
{
   spa.Options.SourcePath = "admin";
   if (env.IsDevelopment ())
   {
      spa.UseVueCli (npmScript: "serve", port : 8080);
   }
});
  1. 檢查項(xiàng)目.csproj設(shè)置呢撞,已有條目覆蓋损姜,沒有條目添加(這一步必須要做,否則將來發(fā)布時(shí)會(huì)有問題)
 <PropertyGroup>
    <!-- Typescript/Javascript Client Configuration -->
    <SpaRoot>admin\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
  </PropertyGroup>
  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build">
    <!-- Build Target:  Ensure Node.js is installed -->
    <Exec Command="node --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    </Exec>
    <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
  </Target>

  <Target Name="DebugEnsureNpm" AfterTargets="DebugEnsureNodeEnv">
    <!-- Build Target:  Ensure Node.js is installed -->
    <Exec Command="npm --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    </Exec>
  </Target>

  <Target Name="EnsureNodeModulesInstalled" BeforeTargets="Build" Inputs="package.json" Outputs="packages-lock.json">
    <!-- Build Target: Restore NPM packages using npm -->
    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />

    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
  </Target>

  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- Build Target: Run webpack dist build -->
    <Message Importance="high" Text="Running npm build..." />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />

    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="$(SpaRoot)dist\**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>%(DistFiles.Identity)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

That's All...??

項(xiàng)目根目錄下運(yùn)行dotnet run, 打開localhost:8080, 熟悉的Vue啟動(dòng)界面出現(xiàn)了殊霞。這一切簡直不要太美好摧阅。感謝開源社區(qū)。

測試一下看看:

  • 首先hotload:沒問題绷蹲,編輯器修改瀏覽器自動(dòng)刷新
  • 然后測試axios:

額外bb一下:強(qiáng)推大家使用vue ui棒卷,真是好用的不得了????,插件祝钢、依賴比规、項(xiàng)目生成運(yùn)行全部用面板操作,再不用控制臺(tái)了

干貨時(shí)刻

1. 獨(dú)立前端拦英,加快開發(fā)速度

我們一般習(xí)慣使用dotnet watch run跑程序蜒什,上面的配置就有一個(gè)問題:每次變化,不管是前端還是后端疤估,都要全部重新編譯一遍灾常,很快你就會(huì)發(fā)現(xiàn)速度不能忍了...霎冯。如果能像前后端獨(dú)立開發(fā)那樣,前端變動(dòng)了只更新前端岗憋,后端只更新后端就好了肃晚,其實(shí)锚贱,只需要修改一個(gè)地方就能實(shí)現(xiàn):
在Startup.cs里仔戈,修改一處地方:

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "admin";
              
                if (env.IsDevelopment())
                {
                    spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
                    //spa.UseVueCli(npmScript: "serve", port: 8080);
                }
            });

8080端口就是你vue項(xiàng)目的前端端口
設(shè)置好了以后

  1. 用vscode打開前端文件夾admin,然后就跟以前一樣yarn serve;
  2. visual studio中拧廊,運(yùn)行控制臺(tái)命令dotnet watch run
  3. 瀏覽器中打開http://localhost:5000, 注意打開的是后端端口

然后你就會(huì)發(fā)現(xiàn)监徘,前端后端分離了,爽歪歪~~

2. 使用axios

我們首先進(jìn)入clientapp目錄吧碾,運(yùn)行vue ui,然后找到vue-cli-plugin-axios插件凰盔,并安裝


安裝完畢后vue cli會(huì)自動(dòng)配置插件,不用手動(dòng)引入倦春。
打開plugins/axios.js文件户敬,我們看到vue已經(jīng)自動(dòng)將axios注冊(cè)成了Vue全局組件:

Plugin.install = function(Vue, options) {
  Vue.axios = _axios;
  window.axios = _axios;
  Object.defineProperties(Vue.prototype, {
    axios: {
      get() {
        return _axios;
      }
    },
    $axios: {
      get() {
        return _axios;
      }
    },
  });
};

Vue.use(Plugin)

在后臺(tái)Controller文件夾下,我們新建一個(gè)HelloWorldController.cs, get時(shí)返回一個(gè)字符串列表:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
public class HelloWorldController : Controller
{
    [HttpGet]
    public IActionResult Index()
    {
        var data = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
        return Json(data);
    }
}

下面我們?cè)谇芭_(tái)的About.vue中測試一下:

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <ul>
      <li v-for="i in items" :key="i">{{i}}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: []
    };
  },
  created() {
    this.axios.get("api/helloworld").then(res => {
      this.items = res.data;
    });
  }
};
</script>

運(yùn)行報(bào)錯(cuò)睁本,我們還需要進(jìn)一步設(shè)置才能愉快玩耍:

  1. 修改Startup.cs文件尿庐,刪除默認(rèn)路由(沒什么用了),重新定義api路由呢堰。注意現(xiàn)在客戶端在同一個(gè)域下抄瑟,所以不需要啟用跨域。這也是這種模式的最大好處⊥魈郏現(xiàn)在chrome的跨域檢測越來越嚴(yán)格了皮假。
//Configure方法:
//不需要啟用跨域,不需要啟用跨域骂维,不需要啟用跨域
 //app.UseCors();
//定義api路由:
 app.UseMvc(routes =>
            { 
                routes.MapRoute(
                    name: "api",
                    template: "api/{controller}/{action=Index}/{id?}");
            });

頁面顯示正確惹资,axios配制成功!


3. 使用靜態(tài)文件服務(wù)器注意事項(xiàng)(20190702更新)

使用了spa后航闺,如果想同時(shí)使用靜態(tài)服務(wù)褪测,那么Startup中的聲明順序非常重要,應(yīng)該是這樣的順序:

//1
app.UseFileServer(new FileServerOptions
{
  FileProvider = new PhysicalFileProvider(
     Path.Combine(Directory.GetCurrentDirectory(), "Resources")),
     RequestPath = "/resources",
     EnableDirectoryBrowsing = true
});
//2
app.UseSpaStaticFiles();
//3
app.UseSpa(spa =>
{
  spa.Options.SourcePath = "admin";
  if (env.IsDevelopment())
  {
      //spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
     spa.UseVueCli(npmScript: "serve", port: 8080);
  }
});

否則靜態(tài)資源無法訪問

發(fā)布

  • 發(fā)布時(shí)按照正常的IIS流程来颤,右鍵項(xiàng)目publish發(fā)布就行汰扭,發(fā)布后出現(xiàn)問題,可以在項(xiàng)目目錄下運(yùn)行dotnet 你的項(xiàng)目名.dll查看福铅。
  • 若問題找不到萝毛,建議選擇“獨(dú)立”發(fā)布模式,這個(gè)模式其實(shí)就是把你現(xiàn)在用的.net core打包進(jìn)發(fā)布項(xiàng)目中滑黔,從而不用管目標(biāo)機(jī)器的環(huán)境依賴笆包。


    image.png
  • 發(fā)布完畢后你的客戶端項(xiàng)目將出現(xiàn)在最終文件中


    image.png

    這時(shí)直接訪問iis里設(shè)置的地址和端口就能訪問了
  • 注意环揽,前端項(xiàng)目axios的請(qǐng)求端口一定要和iis的端口保持一致,
VUE_APP_BACKEND_BASEURL=http://localhost
VUE_APP_BACKEND_PORT=8848

這里是我的.env文件設(shè)置庵佣。不同于別的項(xiàng)目歉胶,這個(gè)env在發(fā)布后是看不見的,所以這里一定要設(shè)置好巴粪。
下面是我的axios設(shè)置:

let config = {
    baseURL: configs.backendUrls.apiUrl,
    timeout: 60 * 1000 // Timeout 
}; 
const _axios = axios.create(config);

這樣每次axios都請(qǐng)求8848端口通今,就不存在跨域的問題了

寫在最后:

  1. 注意,安裝插件肛根、依賴時(shí)一定要確保在客戶端文件夾下進(jìn)行
  2. 在工程根目錄運(yùn)行dotnet watch run獲得前后端同時(shí)刷新無縫開發(fā)體驗(yàn)辫塌,??
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市派哲,隨后出現(xiàn)的幾起案子臼氨,更是在濱河造成了極大的恐慌,老刑警劉巖芭届,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件储矩,死亡現(xiàn)場離奇詭異,居然都是意外死亡褂乍,警方通過查閱死者的電腦和手機(jī)持隧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來树叽,“玉大人舆蝴,你說我怎么就攤上這事√馑校” “怎么了洁仗?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長性锭。 經(jīng)常有香客問我赠潦,道長,這世上最難降的妖魔是什么草冈? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任她奥,我火速辦了婚禮,結(jié)果婚禮上怎棱,老公的妹妹穿的比我還像新娘哩俭。我一直安慰自己,他們只是感情好拳恋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布凡资。 她就那樣靜靜地躺著,像睡著了一般谬运。 火紅的嫁衣襯著肌膚如雪隙赁。 梳的紋絲不亂的頭發(fā)上垦藏,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音伞访,去河邊找鬼掂骏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛厚掷,可吹牛的內(nèi)容都是我干的弟灼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蝗肪,長吁一口氣:“原來是場噩夢啊……” “哼袜爪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起薛闪,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俺陋,沒想到半個(gè)月后豁延,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腊状,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年诱咏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缴挖。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袋狞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出映屋,到底是詐尸還是另有隱情苟鸯,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布棚点,位于F島的核電站早处,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘫析。R本人自食惡果不足惜砌梆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贬循。 院中可真熱鬧咸包,春花似錦、人聲如沸杖虾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亏掀。三九已至忱反,卻和暖如春泛释,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背温算。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工怜校, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人注竿。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓茄茁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巩割。 傳聞我的和親對(duì)象是個(gè)殘疾皇子裙顽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容