.NET Core與React組合開發技_第01天_前言_專案建立與大致介紹

 

2022鐵人賽第一天文章,讀者朋友們好
來稍微探究一下於asp.net core中搭配React前端框架的開發
在這30天成蝶的過程

我想React本身很重ES6和Javascript一些基本語法
算還滿適合拿來當三框架中先拿來進行掌握的一門
(但也是最難掌握也很多人不太推先學的XD)

勉勵自己也將知識專業進行傳播
如文章對於你(可能是個小白)也可能是
只會React但不曉得如何結合.NET Core後端的
又或者只會.NET Core後端但不曉得怎麼和React進行結合的

我希望這系列文章
是個對上述這些開發者戰友們或者以往家教學員
有幫助讀起來不會吃力也很容易吸收的技術篇章


此系列會使用
NodeJs 16以上
visual studio 2022 
(.Net6長期支援版本)

會在Windows作業系統上做筆記文章
當然若是Mac愛好者的朋友.Net Core (.Net6)也以克服跨作業系統的限制
並不侷限於Windows OS
但Mac環境有關visual studio相關操作可能就都要用cli和vscode來搭配了
因為Mac上的Visual Studio for Mac我較沒接觸


請各位先準備好上述這些IDE和開發環境
有任何誤植或者觀點不認同皆可進行一些開發經驗分享
和批評指教一同成長

開啟vs2022創建第一個React.js配asp.net core的新專案


在此去命名專案名稱默認會配有一個.csproj(C#的專案檔)和.sln(方案)
方案中可包含一或多個專案



選.NET6.0


預設新專案建立好後就可看到如下專案結構


有默認範本的asp.net core web api(相關先備知識可參閱過去技術部落格貼文)
於此系列可能就會稍微帶過

可以觀察到專案目錄下有一份前端的專案檔
裡面有熟悉的NodeJs package.json






於後端C#專案中的範疇
主程式進入點會在Program.cs當中
~\MyReact1\Program.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();


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

app.MapFallbackToFile("index.html"); ;

app.Run();


到了.net6以後採用Minimal API
也跟過去.net3.1和.net5架構又有所不同了省略Startup.cs
和namespace外層包覆


一個後端Get請求抓取一個string List資料
~\MyReact1\Controllers\WeatherForecastController.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using Microsoft.AspNetCore.Mvc;

namespace MyReact1.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}




於前端React Js中的範疇
我們前端程式進入點位於Index.js這支程式檔中
~\MyReact1\ClientApp\src\index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import 'bootstrap/dist/css/bootstrap.css';
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import reportWebVitals from './reportWebVitals';

const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
const rootElement = document.getElementById('root');

ReactDOM.render(
  <BrowserRouter basename={baseUrl}>
    <App />
  </BrowserRouter>,
  rootElement);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://cra.link/PWA
serviceWorkerRegistration.unregister();

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();


而當中間接進行App Component的Render
~\MyReact1\ClientApp\src\App.js
在App.js中又間接去存取專for web api存取的Component 也就是FetchData.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from 'react';
import { Route } from 'react-router';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';

import './custom.css'

export default class App extends Component {
  static displayName = App.name;

  render () {
    return (
      <Layout>
        <Route exact path='/' component={Home} />
        <Route path='/counter' component={Counter} />
        <Route path='/fetch-data' component={FetchData} />
      </Layout>
    );
  }
}


~\MyReact1\ClientApp\src\components\FetchData.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import React, { Component } from 'react';

export class FetchData extends Component {
  static displayName = FetchData.name;

  constructor(props) {
    super(props);
    this.state = { forecasts: [], loading: true };
  }

  componentDidMount() {
    this.populateWeatherData();
  }

  static renderForecastsTable(forecasts) {
    return (
      <table className='table table-striped' aria-labelledby="tabelLabel">
        <thead>
          <tr>
            <th>Date</th>
            <th>Temp. (C)</th>
            <th>Temp. (F)</th>
            <th>Summary</th>
          </tr>
        </thead>
        <tbody>
          {forecasts.map(forecast =>
            <tr key={forecast.date}>
              <td>{forecast.date}</td>
              <td>{forecast.temperatureC}</td>
              <td>{forecast.temperatureF}</td>
              <td>{forecast.summary}</td>
            </tr>
          )}
        </tbody>
      </table>
    );
  }

  render() {
    let contents = this.state.loading
      ? <p><em>Loading...</em></p>
      : FetchData.renderForecastsTable(this.state.forecasts);

    return (
      <div>
        <h1 id="tabelLabel" >Weather forecast</h1>
        <p>This component demonstrates fetching data from the server.</p>
        {contents}
      </div>
    );
  }

  async populateWeatherData() {
    const response = await fetch('weatherforecast');
    const data = await response.json();
    this.setState({ forecasts: data, loading: false });
  }
}


以上是一個大致前後端如何互動的程式碼導讀

我們可將專案運行起來
默認啟動起來(按綠色撥放按鈕)
預設由於還要做前置build因此等他一段時間會自動跳轉到真正的主頁 URL
這邊是兩個站台應用(因此會有各自不同的port)
後端7248,前端44481





可看到React呼叫web api後呈現到頁面的結果





留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header