Saya membahas cara memuat gambar di Reactjs dengan Asp.Net Core WebAPI. Kami membuat API web Asp.Net Core dan membuat DB server SQL dengan inti kerangka entitas. dan kemudian saya membuat pengontrol API Inti asp.net untuk memuat gambar.
Kami membuat aplikasi sisi klien di Reactjs. Formulir dengan pengunggah gambar telah dirancang untuk ini. Pratinjau gambar yang dipilih ditampilkan secara terpisah. Di dalam acara pengiriman formulir, saya memuat gambar yang dipilih ke Asp.Net Web API.
Alat: VS Code, Visual Studio, SSMS, Tukang Pos
Klien: Reactjs
API: API Web Inti Asp.Net
Pengontrol ini terhubung ke koneksi database dan menyediakan metode untuk membuat daftar, menyisipkan, memperbarui, dan menghapus catatan karyawan dengan menangani permintaan HTTP GET, POST, PUT, dan DELETE.
Pengontrol ini bekerja dengan berinteraksi dengan formulir karyawan di mana karyawan dapat mengunggah gambarnya. Formulir ini dirancang di sisi React dan dibuat menggunakan perintah npx create-react-app di direktori root proyek.
Metode yang relevan disediakan untuk operasi GET, POST, PUT dan DELETE. Dengan permintaan GET, semua catatan karyawan yang ada akan dicantumkan. Permintaan PUT memperbarui catatan karyawan tertentu dan juga digunakan untuk mengubah gambar profil karyawan. Permintaan POST menambahkan catatan karyawan baru dan mengunggah gambar profil karyawan. Permintaan DELETE menghapus catatan karyawan tertentu.
Selain itu, dua metode khusus, SaveImage() dan DeleteImage(), disediakan untuk memuat dan menghapus gambar dalam catatan karyawan. Metode ini menangani pengunggahan dan penghapusan gambar profil karyawan.
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 ) ; } } }
Formulir ini memungkinkan pengguna untuk menambah atau mengedit karyawan. Komponen ini menyediakan formulir di mana Anda dapat mengunggah gambar dan memasukkan informasi tentang nama karyawan dan pekerjaan. Formulir terdiri dari area unggah gambar dan dua kolom input teks.
Banyak variabel yang digunakan. Variabel defaultImageSrc menyimpan jalur gambar default. Variabel InitialFieldValues berisi nilai awal yang akan digunakan dalam keadaan awal komponen. Menggunakan useState, status nilai dilacak dalam komponen.
Fungsi useEffect digunakan selama pemuatan komponen dan ketika variabel recordForEdit berubah, ini memicu komponen untuk dimuat ulang dan variabel nilai diperbarui dengan fungsi setValues.
Fungsi handleInputChange dipanggil ketika kolom input teks diubah. Fungsi ini menangkap nama dan nilai bidang yang diubah menggunakan e.target.name dan e.target.value dan memperbarui variabel nilai menggunakan fungsi setValues.
Fungsi showPreview dipanggil jika area upload gambar diubah. Fungsi ini menyimpan jalur file yang dipilih dalam variabel imageFile dan membuat pratinjau file menggunakan objek FileReader dan memperbarui variabel imageSrc.
Fungsi validasi memverifikasi kebenaran formulir. Fungsi ini digunakan untuk memastikan bahwa variabel nilai terisi dengan benar. Fungsi setErrors memperbarui variabel kesalahan dan fungsi resetForm mengatur ulang formulir dan menghapus variabel kesalahan.
Fungsi handleFormSubmit dipanggil saat formulir dikirimkan. Fungsi ini mengambil data formulir menggunakan objek FormData dan mengirimkan data ke server dengan memanggil fungsi addOrEdit.
Fungsi applyErrorClass menerapkan kelas bidang yang tidak valid ke bidang yang salah, sehingga menyebabkan bidang ini ditampilkan dengan kesalahan.
Komponen ini menyediakan formulir di mana Anda dapat mengunggah gambar dan memasukkan informasi tentang nama karyawan dan pekerjaan. Formulir terdiri dari area unggah gambar dan dua kolom input teks.
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 >
>
)
}
Komponen React ini menangani pembuatan, pengeditan, penghapusan, dan tampilan catatan karyawan.
Ia menggunakan kait useState dan useEffect React. useState mendefinisikan variabel status untuk status komponen dan mengembalikan setState. useEffect menjalankan fungsi sebagai respons terhadap peristiwa seperti memuat atau menggambar ulang komponen.
Axios digunakan untuk melakukan panggilan layanan web RESTful. Fungsi pembantu yang disebut EmployeeAPI membuat instance panggilan RESTful dan dapat mengubah URL sumber daya menggunakan fitur Axios.
Fungsi refreshEmployeeList mengambil catatan karyawan dari server dan menetapkannya sebagai status komponen dengan setEmployeeList.
Fungsi addOrEdit menangani pembuatan atau pembaruan catatan karyawan. Objek FormData berisi entri pengguna untuk catatan karyawan.
Fungsi onDelete meminta pengguna untuk mengonfirmasi apakah mereka ingin menghapus catatan dan kemudian mengirimkan permintaan DELETE ke server.
Fungsi imageCard digunakan untuk menampilkan kartu karyawan. Kartu tersebut berisi foto karyawan, nama, deskripsi pekerjaan, dan tombol hapus.
Terakhir, komponen tersebut mencakup header jumbotron, formulir karyawan, dan tabel kartu karyawan. Tabel tersebut menampilkan kartu pegawai dengan tiga kolom dan baris tambahan dimana kolom ketiga tidak terisi.
{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 >
)
}
Saya menggunakan .Net Core 6.0 di proyek saya. Paket Nuget yang perlu diunduh dalam proyek tercantum di bawah ini.
Microsoft.VisualStudio.Web.CodeGeneration.Desain
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.Alat
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
Pertama-tama, mari tambahkan kelas ke folder Models kita. Saya menamakannya 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 ; }
}
Mari buat kelas Context di folder Models kita.
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 ; }
}
}
Mari masuk ke folder Startup.cs dan buat string koneksi untuk metode 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" ) ) ) ;
}
Mari kita masuk ke appsettings.json. Di sini kita menulis informasi koneksi ke file json seperti ini
"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;"
}
}
Setelah itu, kami membangun proyek kami, pergi ke manajer paket dan melakukan operasi migrasi.
PM > Add-Migration " InitialCreate "
Mari buat Migrasi dengan perintah dan bangun proyek kita. Kemudian berikan perintah ini
PM > update-database
Lalu mari kita cek apakah database sudah dibuat atau belum dari MSSQL.
Dan kemudian mari kita buat pengontrol untuk model kita. Saya akan menggunakan Pengontrol API dengan tindakan menggunakan pengontrol EF.
Gambar akan muncul di sini, 2 di antaranya
Kami membuat kontrol kami, menentukan model dan file Konteks kami, dan menentukan nama Pengontrol kami.
5 Layanan ini disebut AddDb.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DevConnection"))); Fungsi ini akan membuat permintaan untuk pengontrol karyawan ini setiap kali kita membuat permintaan ke EmployeeController ini. Konstruktor EmployeeController adalah EmployeeController publik (konteks EmployeeDbContext) Nilai EmployeeDbContext dalam kode ini adalah metode injeksi ketergantungan asp.net, yang secara otomatis dikelola oleh kerangka kerja itu sendiri, sehingga permintaan di pengontrol ini akan berkomunikasi dengan db untuk saat ini.
Sekarang, mari kita desain sisi Klien sehingga bereaksi dengan formulir karyawan untuk mengunggah gambar profil karyawan. Mari kita buat aplikasi reaksi di direktori proyek. Kita perlu membuka command prompt dari direktori proyek ini.
npx create-react-app employee-register-client
Perintah Oxios yang akan digunakan untuk sisi klien
$ npm install react-axios
Kami telah membuat struktur proyek kami. Mulai sekarang, saya ingin Anda meninjau kode saya di repo saya. Semoga beruntung :)
GET /api/Employee
Parameter | Obat | Penjelasan |
---|---|---|
api_key | string | Diperlukan . Kunci API Anda. |
GET /api/Employee/${id}
Parameter | Obat | Penjelasan |
---|---|---|
id | string | Diperlukan . Nilai kunci dari item yang akan dipanggil |
{ "employeeID" : 3 , "employeeName" : " piedhorse " , "occupation" : " C# " , "imageName" : " capture_20231646962.jpeg " , "imageFile" : null , "imageSrc" : " https://localhost:44334/Images/capture_20231646962.jpeg " }