Asp.Net Core WebAPI を使用して Reactjs に画像を読み込む方法について説明しました。 Asp.Net Core Web API を作成し、エンティティ フレームワーク コアを使用して SQL サーバー DB を作成しました。次に、画像を読み込むための asp.net Core API コントローラーを作成しました。
Reactjsでクライアント側アプリケーションを作成しました。画像アップローダーを備えたフォームがこのために設計されました。選択した画像のプレビューが個別に表示されます。フォーム送信イベント内で、選択した画像を Asp.Net Web API に読み込みました。
ツール: VS コード、Visual Studio、SSMS、Postman
クライアント: Reactjs
API: Asp.Net Core WebAPI
このコントローラーはデータベース接続に接続されており、HTTP GET、POST、PUT、および DELETE リクエストを処理することにより、従業員レコードの一覧表示、挿入、更新、および削除を行うメソッドを提供します。
このコントローラーは、従業員が画像をアップロードできる従業員フォームと対話することで機能します。このフォームは React 側で設計されており、プロジェクトのルート ディレクトリで npx create-react-app コマンドを使用して作成されます。
GET、POST、PUT、および DELETE 操作に関連するメソッドが提供されます。 GET リクエストを使用すると、既存の従業員レコードがすべてリストされます。 PUT リクエストは、指定された従業員レコードを更新し、従業員のプロフィール写真を変更するためにも使用されます。 POST リクエストは、新しい従業員レコードを追加し、従業員のプロフィール写真をアップロードします。 DELETE リクエストは、指定された従業員レコードを削除します。
さらに、従業員レコード内の画像のロードと削除のために、SaveImage() と DeleteImage() という 2 つの特別なメソッドが提供されています。これらのメソッドは、従業員プロフィール画像のアップロードと削除を処理します。
using System ; using System . Collections . Generic ; using System . Linq ; using System . Threading . Tasks ; using Microsoft . AspNetCore . Http ; using Microsoft . AspNetCore . Mvc ; using Microsoft . EntityFrameworkCore ; using EmployeeRegisterAPI . Models ; using System . IO ; using Microsoft . AspNetCore . Hosting ; namespace EmployeeRegisterAPI . Controllers { [ Route ( "api/[controller]" ) ] [ ApiController ] public class EmployeeController : ControllerBase { private readonly EmployeeDbContext _context ; private readonly IWebHostEnvironment _hostEnvironment ; public EmployeeController ( EmployeeDbContext context , IWebHostEnvironment hostEnvironment ) { _context = context ; this . _hostEnvironment = hostEnvironment ; } // GET: api/EmployeeModels [ HttpGet ] public async Task < ActionResult < IEnumerable < EmployeeModel > > > GetEmployees ( ) { return await _context . Employees . Select ( x => new EmployeeModel ( ) { EmployeeID = x . EmployeeID , EmployeeName = x . EmployeeName , Occupation = x . Occupation , ImageName = x . ImageName , ImageSrc = String . Format ( "{0}://{1}{2}/Images/{3}" , Request . Scheme , Request . Host , Request . PathBase , x . ImageName ) } ) . ToListAsync ( ) ; } // GET: api/Employee/5 [ HttpGet ( "{id}" ) ] public async Task < ActionResult < EmployeeModel > > GetEmployeeModel ( int id ) { var employeeModel = await _context . Employees . FindAsync ( id ) ; if ( employeeModel == null ) { return NotFound ( ) ; } return employeeModel ; } // PUT: api/Employee/5 // To protect from overposting attacks, enable the specific properties you want to bind to, for // more details, see https://go.microsoft.com/fwlink/?linkid=2123754. [ HttpPut ( "{id}" ) ] public async Task < IActionResult > PutEmployeeModel ( int id , [ FromForm ] EmployeeModel employeeModel ) { if ( id != employeeModel . EmployeeID ) { return BadRequest ( ) ; } if ( employeeModel . ImageFile != null ) { DeleteImage ( employeeModel . ImageName ) ; employeeModel . ImageName = await SaveImage ( employeeModel . ImageFile ) ; } _context . Entry ( employeeModel ) . State = EntityState . Modified ; try { await _context . SaveChangesAsync ( ) ; } catch ( DbUpdateConcurrencyException ) { if ( ! EmployeeModelExists ( id ) ) { return NotFound ( ) ; } else { throw ; } } return NoContent ( ) ; } // POST: api/Employee // To protect from overposting attacks, enable the specific properties you want to bind to, for // more details, see https://go.microsoft.com/fwlink/?linkid=2123754. [ HttpPost ] public async Task < ActionResult < EmployeeModel > > PostEmployeeModel ( [ FromForm ] EmployeeModel employeeModel ) { employeeModel . ImageName = await SaveImage ( employeeModel . ImageFile ) ; _context . Employees . Add ( employeeModel ) ; await _context . SaveChangesAsync ( ) ; return StatusCode ( 201 ) ; } // DELETE: api/Employee/5 [ HttpDelete ( "{id}" ) ] public async Task < ActionResult < EmployeeModel > > DeleteEmployeeModel ( int id ) { var employeeModel = await _context . Employees . FindAsync ( id ) ; if ( employeeModel == null ) { return NotFound ( ) ; } DeleteImage ( employeeModel . ImageName ) ; _context . Employees . Remove ( employeeModel ) ; await _context . SaveChangesAsync ( ) ; return employeeModel ; } private bool EmployeeModelExists ( int id ) { return _context . Employees . Any ( e => e . EmployeeID == id ) ; } [ NonAction ] public async Task < string > SaveImage ( IFormFile imageFile ) { string imageName = new String ( Path . GetFileNameWithoutExtension ( imageFile . FileName ) . Take ( 10 ) . ToArray ( ) ) . Replace ( ' ' , '-' ) ; imageName = imageName + DateTime . Now . ToString ( "yymmssfff" ) + Path . GetExtension ( imageFile . FileName ) ; var imagePath = Path . Combine ( _hostEnvironment . ContentRootPath , "Images" , imageName ) ; using ( var fileStream = new FileStream ( imagePath , FileMode . Create ) ) { await imageFile . CopyToAsync ( fileStream ) ; } return imageName ; } [ NonAction ] public void DeleteImage ( string imageName ) { var imagePath = Path . Combine ( _hostEnvironment . ContentRootPath , "Images" , imageName ) ; if ( System . IO . File . Exists ( imagePath ) ) System . IO . File . Delete ( imagePath ) ; } } }
このフォームを使用すると、ユーザーは従業員を追加または編集できます。このコンポーネントは、画像をアップロードして従業員の名前と職務に関する情報を入力できるフォームを提供します。フォームは、画像アップロード領域と 2 つのテキスト入力フィールドで構成されます。
多くの変数が使用されます。 defaultImageSrc 変数は、デフォルトの画像パスを保持します。 initialFieldValues 変数には、コンポーネントの初期状態で使用される初期値が含まれています。 useState を使用すると、値の状態がコンポーネント内で追跡されます。
useEffect 関数はコンポーネントの読み込み中に使用され、recordForEdit 変数が変更されると、コンポーネントの再読み込みがトリガーされ、values 変数が setValues 関数で更新されます。
handleInputChange 関数は、テキスト入力フィールドが変更されたときに呼び出されます。この関数は、e.target.name と e.target.value を使用して変更されたフィールドの名前と値をキャプチャし、setValues 関数を使用して値変数を更新します。
画像アップロード領域が変更されると、showPreview 関数が呼び出されます。この関数は、選択したファイルのパスを imageFile 変数に保存し、FileReader オブジェクトを使用してファイルのプレビューを作成し、imageSrc 変数を更新します。
validate 関数はフォームが正しいかどうかを検証します。この関数は、値変数が適切に設定されていることを確認するために使用されます。 setErrors 関数はエラー変数を更新し、resetForm 関数はフォームをリセットしてエラー変数をクリアします。
handleFormSubmit 関数は、フォームが送信されるときに呼び出されます。この関数は、FormData オブジェクトを使用してフォーム データを取得し、addOrEdit 関数を呼び出してデータをサーバーに送信します。
applyErrorClass 関数は、無効なフィールド クラスをエラーのあるフィールドに適用するため、これらのフィールドはエラーとともに表示されます。
このコンポーネントは、画像をアップロードして従業員の名前と職務に関する情報を入力できるフォームを提供します。フォームは、画像アップロード領域と 2 つのテキスト入力フィールドで構成されます。
import React , { useState , useEffect } from 'react'
const defaultImageSrc = '/img/3135715.png'
const initialFieldValues = {
employeeID : 0 ,
employeeName : '' ,
occupation : '' ,
imageName : '' ,
imageSrc : defaultImageSrc ,
imageFile : null
}
export default function Employee ( props ) {
const { addOrEdit , recordForEdit } = props
const [ values , setValues ] = useState ( initialFieldValues )
const [ errors , setErrors ] = useState ( { } )
useEffect ( ( ) => {
if ( recordForEdit != null )
setValues ( recordForEdit ) ;
} , [ recordForEdit ] )
const handleInputChange = e => {
const { name , value } = e . target ;
setValues ( {
... values ,
[ name ] : value
} )
}
const showPreview = e => {
if ( e . target . files && e . target . files [ 0 ] ) {
let imageFile = e . target . files [ 0 ] ;
const reader = new FileReader ( ) ;
reader . onload = x => {
setValues ( {
... values ,
imageFile ,
imageSrc : x . target . result
} )
}
reader . readAsDataURL ( imageFile )
}
else {
setValues ( {
... values ,
imageFile : null ,
imageSrc : defaultImageSrc
} )
}
}
const validate = ( ) => {
let temp = { }
temp . employeeName = values . employeeName == "" ? false : true ;
temp . imageSrc = values . imageSrc == defaultImageSrc ? false : true ;
setErrors ( temp )
return Object . values ( temp ) . every ( x => x == true )
}
const resetForm = ( ) => {
setValues ( initialFieldValues )
document . getElementById ( 'image-uploader' ) . value = null ;
setErrors ( { } )
}
const handleFormSubmit = e => {
e . preventDefault ( )
if ( validate ( ) ) {
const formData = new FormData ( )
formData . append ( 'employeeID' , values . employeeID )
formData . append ( 'employeeName' , values . employeeName )
formData . append ( 'occupation' , values . occupation )
formData . append ( 'imageName' , values . imageName )
formData . append ( 'imageFile' , values . imageFile )
addOrEdit ( formData , resetForm )
}
}
const applyErrorClass = field => ( ( field in errors && errors [ field ] == false ) ? ' invalid-field' : '' )
return (
< >
< div className = "container text-center" >
< p className = "lead" > p >
div >
< form autoComplete = "off" noValidate onSubmit = { handleFormSubmit } >
< div className = "card" style = { { backgroundColor : '#ced114' } } >
< img src = { values . imageSrc } className = "card-img-top" />
< div className = "card-body" >
< div className = "form-group" >
< input type = "file" accept = "image/*" className = { "form-control-file" + applyErrorClass ( 'imageSrc' ) }
onChange = { showPreview } id = "image-uploader" />
div >
< div className = "form-group" style = { { backgroundColor : '#ced114' } } >
< input className = { "form-control" + applyErrorClass ( 'employeeName' ) } placeholder = "Employee Name" name = "employeeName"
value = { values . employeeName }
onChange = { handleInputChange } />
div >
< div className = "form-group" >
< input className = "form-control" placeholder = "Occupation" name = "occupation"
value = { values . occupation }
onChange = { handleInputChange } />
div >
< div className = "form-group text-center" >
< button type = "submit" className = "btn btn-light" style = { { color : '#ced114' } } > Submit button >
div >
div >
div >
form >
>
)
}
この React コンポーネントは、従業員レコードの作成、編集、削除、表示を処理します。
useState および useEffect React フックを使用します。 useState はコンポーネントの状態の状態変数を定義し、setState を返します。 useEffect は、コンポーネントのロードや再描画などのイベントに応答して関数を実行します。
Axios は、RESTful Web サービス呼び出しを行うために使用されます。 employeeAPI と呼ばれるヘルパー関数は RESTful 呼び出しをインスタンス化し、Axios の機能を使用してリソース URL を変更できます。
freshEmployeeList 関数は、サーバーから従業員レコードを取得し、setEmployeeList を使用してそれをコンポーネントの状態として設定します。
addOrEdit 関数は、従業員レコードの作成または更新を処理します。 FormData オブジェクトには、従業員レコードのユーザー エントリが含まれています。
onDelete 関数は、レコードを削除するかどうかをユーザーに確認し、サーバーに DELETE リクエストを送信します。
imageCard 関数は、従業員カードを表示するために使用されます。カードには従業員の写真、名前、職務内容、および削除ボタンが含まれています。
最後に、このコンポーネントには、ジャンボトロン ヘッダー、従業員フォーム、および従業員カードのテーブルが含まれています。この表には、3 つの列と、3 番目の列が占有されていない追加の行からなる従業員カードが表示されます。
{imageCard(employeeList[3 * i])} | {employeeList[3 * i + 1] ? imageCard(employeeList[3 * i + 1]) : null} | {employeeList[3 * i + 2] ? imageCard(employeeList[3 * i + 2]) : null} |
import React , { useState , useEffect } from 'react'
import Employee from './Employee'
import axios from "axios" ;
export default function EmployeeList ( ) {
const [ employeeList , setEmployeeList ] = useState ( [ ] )
const [ recordForEdit , setRecordForEdit ] = useState ( null )
useEffect ( ( ) => {
refreshEmployeeList ( ) ;
} , [ ] )
const employeeAPI = ( url = 'https://localhost:44334/api/Employee/' ) => {
return {
fetchAll : ( ) => axios . get ( url ) ,
create : newRecord => axios . post ( url , newRecord ) ,
update : ( id , updatedRecord ) => axios . put ( url + id , updatedRecord ) ,
delete : id => axios . delete ( url + id )
}
}
function refreshEmployeeList ( ) {
employeeAPI ( ) . fetchAll ( )
. then ( res => {
setEmployeeList ( res . data )
} )
. catch ( err => console . log ( err ) )
}
const addOrEdit = ( formData , onSuccess ) => {
if ( formData . get ( 'employeeID' ) == "0" )
employeeAPI ( ) . create ( formData )
. then ( res => {
onSuccess ( ) ;
refreshEmployeeList ( ) ;
} )
. catch ( err => console . log ( err ) )
else
employeeAPI ( ) . update ( formData . get ( 'employeeID' ) , formData )
. then ( res => {
onSuccess ( ) ;
refreshEmployeeList ( ) ;
} )
. catch ( err => console . log ( err ) )
}
const showRecordDetails = data => {
setRecordForEdit ( data )
}
const onDelete = ( e , id ) => {
e . stopPropagation ( ) ;
if ( window . confirm ( 'Are you sure to delete this record?' ) )
employeeAPI ( ) . delete ( id )
. then ( res => refreshEmployeeList ( ) )
. catch ( err => console . log ( err ) )
}
const imageCard = data => (
< div className = "card" onClick = { ( ) => { showRecordDetails ( data ) } } >
< img src = { data . imageSrc } className = "card-img-top rounded-circle" />
< div className = "card-body" >
< h5 > { data . employeeName } h5 >
< span > { data . occupation } span > < br />
< button className = "btn btn-light delete-button" onClick = { e => onDelete ( e , parseInt ( data . employeeID ) ) } >
< i className = "far fa-trash-alt" > i >
button >
div >
div >
)
return (
< div className = "row" >
< div className = "col-md-12" style = { { backgroundColor : '#ced114' } } >
< div className = "jumbotron jumbotron-fluid py-4" style = { { backgroundColor : '#ced114' } } >
< div className = "container text-center" style = { { backgroundColor : '#ced114' } } >
< h1 className = "display-4" style = { { backgroundColor : '#ced114' , color : 'yellow' } } > Employee Register h1 >
div >
div >
div >
< div className = "container text-center" >
< p className = "lead" > p >
div >
< div className = "col-md-4" >
< Employee
addOrEdit = { addOrEdit }
recordForEdit = { recordForEdit }
/>
div >
< div className = "col-md-8" >
< table >
< tbody >
{
//tr > 3 td
[ ... Array ( Math . ceil ( employeeList . length / 3 ) ) ] . map ( ( e , i ) =>
< tr key = { i } >
< td > { imageCard ( employeeList [ 3 * i ] ) } td >
< td > { employeeList [ 3 * i + 1 ] ? imageCard ( employeeList [ 3 * i + 1 ] ) : null } td >
< td > { employeeList [ 3 * i + 2 ] ? imageCard ( employeeList [ 3 * i + 2 ] ) : null } td >
tr >
)
}
tbody >
table >
div >
div >
)
}
私のプロジェクトでは .Net Core 6.0 を使用しています。プロジェクトでダウンロードする必要がある Nuget パッケージを以下に示します。
Microsoft.VisualStudio.Web.CodeGeneration.Design
PM > NuGet I nstall-Package Microsoft.VisualStudio.Web.CodeGeneration.Design -Version 6.0.13
Microsoft.EntityFrameworkCore
PM > NuGet I nstall-Package Microsoft.EntityFrameworkCore -Version 7.0.4
Microsoft.EntityFrameworkCore.SqlServer
PM > NuGet I nstall-Package Microsoft.EntityFrameworkCore.SqlServer -Version 7.0.4
Microsoft.EntityFrameworkCore.Tools
PM > NuGet I nstall-Package Microsoft.EntityFrameworkCore.Tools -Version 7.0.4
Microsoft.AspNetCore.Cors
PM > NuGet I nstall-Package Microsoft.AspNetCore.Cors -Version 2.2.0
まず最初に、Models フォルダーにクラスを追加しましょう。これを「EmployeeModel」と名付けました。
public class EmployeeModel
{
[ Key ]
public int EmployeeID { get ; set ; }
[ Column ( TypeName = "nvarchar(50)" ) ]
public string EmployeeName { get ; set ; }
[ Column ( TypeName = "nvarchar(50)" ) ]
public string Occupation { get ; set ; }
[ Column ( TypeName = "nvarchar(100)" ) ]
public string ImageName { get ; set ; }
}
Models フォルダーに Context クラスを作成しましょう。
using Microsoft . EntityFrameworkCore ;
namespace EmployeeRegisterAPI . Models
{
public class EmployeeDbContext : DbContext //burada ef Dbcontext den kalitim aldirdik
{
public EmployeeDbContext ( DbContextOptions < EmployeeDbContext > options ) : base ( options )
{
}
public DbSet < EmployeeModel > Employees { get ; set ; }
}
}
Startup.cs フォルダーに移動し、ConfigureServices メソッドの接続文字列を作成しましょう。
public void ConfigureServices ( IServiceCollection services )
{
services . AddControllers ( ) ;
//Baglanti dizesini olusturduk ve bu kodda sql server icin bir ConnectionString olusturduk "DevConnection" diye bunula baglanti bilgilerimizi appsettings de belirtecegiz
services . AddDbContext < EmployeeDbContext > ( options => options . UseSqlServer ( Configuration . GetConnectionString ( "DevConnection" ) ) ) ;
}
appsettings.json に進みます。ここでは、次のように接続情報を json ファイルに記述します。
"Logging" : {
"LogLevel" : {
"Default" : "Information" ,
"Microsoft" : "Warning" ,
"Microsoft.Hosting.Lifetime" : "Information"
}
} ,
"AllowedHosts" : "*" ,
//buradan sonraki kod satirlaridir
"ConnectionStrings" : {
"DevConnection" : "Server=LAPTOP-6OAEM3JA; Database=EmployeeDB; Trusted_Connection=True; MultipleActiveResultSets=True;"
}
}
その後、プロジェクトをビルドし、パッケージ マネージャーに移動して、移行操作を実行します。
PM > Add-Migration " InitialCreate "
コマンドで Migration を作成し、プロジェクトをビルドしましょう。次に、このコマンドを実行します。
PM > update-database
次に、MSSQLからデータベースが作成されているかどうかを確認してみましょう。
次に、モデルのコントローラーを作成しましょう。EF コントローラーを使用したアクションを持つ API コントローラーを使用します。
写真はここに来ます、そのうちの 2 枚
コントロールを作成し、モデルとコンテキスト ファイルを指定し、コントローラー名を指定しました。
5 これらのサービスは、AddDb.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DevConnection"))); と呼ばれます。この関数は、この EmployeeController にリクエストを行うたびに、この従業員コントローラに対するリクエストを作成します。 EmployeeController のコンストラクターは public EmployeeController(EmployeeDbContext context) です。このコードの EmployeeDbContext 値は、この asp.net 依存関係注入メソッドであり、フレームワーク自体によって自動的に管理されるため、このコントローラーのリクエストは今のところデータベースと通信します。
次に、従業員のプロフィール写真をアップロードするためにクライアント側を設計しましょう。このプロジェクトのディレクトリからコマンド プロンプトを開く必要があります。
npx create-react-app employee-register-client
クライアント側で使用するOxiosコマンド
$ npm install react-axios
プロジェクトの構造を作成しました。ここからは、私のリポジトリでコードを確認してください。幸運を :)
GET /api/Employee
パラメータ | 薬 | 説明 |
---|---|---|
api_key | string | 必要。 API キー。 |
GET /api/Employee/${id}
パラメータ | 薬 | 説明 |
---|---|---|
id | string | 必要。呼び出す項目のキー値 |
{ "employeeID" : 3 , "employeeName" : " piedhorse " , "occupation" : " C# " , "imageName" : " capture_20231646962.jpeg " , "imageFile" : null , "imageSrc" : " https://localhost:44334/Images/capture_20231646962.jpeg " }