J'ai expliqué comment charger des images dans Reactjs avec Asp.Net Core WebAPI. Nous créons l'API Web Asp.Net Core et créons une base de données de serveur SQL avec un noyau de structure d'entité. puis j'ai créé un contrôleur API asp.net Core pour le chargement des images.
Nous avons créé l'application côté client dans Reactjs. Un formulaire avec téléchargeur d'images a été conçu à cet effet. L'aperçu de l'image sélectionnée est affiché séparément. Dans l'événement de soumission du formulaire, j'ai chargé l'image sélectionnée dans l'API Web Asp.Net.
Outils : VS Code, Visual Studio, SSMS, Postman
Client : Reactjs
API : API Web Asp.Net Core
Ce contrôleur est connecté à une connexion à une base de données et fournit des méthodes pour répertorier, insérer, mettre à jour et supprimer les enregistrements des employés en gérant les requêtes HTTP GET, POST, PUT et DELETE.
Ce contrôleur fonctionne en interagissant avec un formulaire d'employé où les employés peuvent télécharger leurs images. Ce formulaire est conçu côté React et est créé à l'aide de la commande npx create-react-app dans le répertoire racine du projet.
Des méthodes pertinentes sont fournies pour les opérations GET, POST, PUT et DELETE. Avec une requête GET, tous les enregistrements d'employés existants sont répertoriés. Une requête PUT met à jour le dossier d'un employé spécifié et est également utilisée pour modifier la photo de profil d'un employé. La requête POST ajoute un nouvel enregistrement d'employé et télécharge la photo de profil de l'employé. Une demande DELETE supprime un enregistrement d'employé spécifié.
De plus, deux méthodes spéciales, SaveImage() et DeleteImage(), sont fournies pour charger et supprimer des images dans les dossiers des employés. Ces méthodes gèrent le téléchargement et la suppression des images de profil des employés.
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 ) ; } } }
Le formulaire permet à l'utilisateur d'ajouter ou de modifier un employé. Le composant fournit un formulaire dans lequel vous pouvez télécharger une image et saisir des informations sur le nom et le poste de l'employé. Le formulaire se compose d'une zone de téléchargement d'images et de deux champs de saisie de texte.
De nombreuses variables sont utilisées. La variable defaultImageSrc contient le chemin de l'image par défaut. La variable initialFieldValues contient les valeurs initiales à utiliser dans l'état initial du composant. En utilisant useState, les états des valeurs sont suivis au sein du composant.
La fonction useEffect est utilisée lors du chargement du composant et lorsque la variable recordForEdit change, elle déclenche le rechargement du composant et la variable valeurs est mise à jour avec la fonction setValues.
La fonction handleInputChange est appelée lorsque les champs de saisie de texte sont modifiés. Cette fonction capture le nom et la valeur du champ modifié à l'aide de e.target.name et e.target.value et met à jour la variable de valeurs à l'aide de la fonction setValues.
La fonction showPreview est appelée si la zone de téléchargement d'image est modifiée. Cette fonction enregistre le chemin du fichier sélectionné dans la variable imageFile et crée un aperçu du fichier à l'aide de l'objet FileReader et met à jour la variable imageSrc.
La fonction validate vérifie l'exactitude du formulaire. Cette fonction est utilisée pour garantir que la variable de valeurs est correctement renseignée. La fonction setErrors met à jour la variable d'erreurs et la fonction resetForm réinitialise le formulaire et efface la variable d'erreurs.
La fonction handleFormSubmit est appelée lorsque le formulaire est soumis. Cette fonction récupère les données du formulaire à l'aide de l'objet FormData et envoie les données au serveur en appelant la fonction addOrEdit.
La fonction applyErrorClass applique la classe invalid-field aux champs erronés, provoquant ainsi l'affichage de ces champs avec des erreurs.
Le composant fournit un formulaire dans lequel vous pouvez télécharger une image et saisir des informations sur le nom et le poste de l'employé. Le formulaire se compose d'une zone de téléchargement d'images et de deux champs de saisie de texte.
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 >
>
)
}
Ce composant React gère la création, la modification, la suppression et l'affichage d'un dossier d'employé.
Il utilise les hooks useState et useEffect React. useState définit une variable d'état pour l'état du composant et renvoie setState. useEffect exécute une fonction en réponse à des événements tels que le chargement ou le redessin du composant.
Axios est utilisé pour effectuer des appels de services Web RESTful. Une fonction d'assistance appelée EmployeeAPI instancie les appels RESTful et peut modifier l'URL de la ressource à l'aide des fonctionnalités d'Axios.
La fonction rafraîchirEmployeeList récupère les enregistrements des employés du serveur et les définit comme état du composant avec setEmployeeList.
La fonction addOrEdit gère la création ou la mise à jour du dossier de l'employé. L'objet FormData contient les entrées utilisateur pour l'enregistrement de l'employé.
La fonction onDelete demande à l'utilisateur de confirmer s'il souhaite supprimer un enregistrement, puis envoie une requête DELETE au serveur.
La fonction imageCard permet d'afficher les cartes des salariés. La carte comprend la photo de l'employé, son nom, sa description de poste et un bouton de suppression.
Enfin, le composant comprend un en-tête Jumbotron, un formulaire d'employé et un tableau des cartes d'employé. Le tableau affiche les fiches des employés avec trois colonnes et des lignes supplémentaires où la troisième colonne n'est pas occupée.
{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 >
)
}
J'utilise .Net Core 6.0 dans mon projet. Les packages Nuget qui doivent être téléchargés dans le projet sont répertoriés ci-dessous.
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
Tout d’abord, ajoutons une classe à notre dossier Models. Je l'ai nommé 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 ; }
}
Créons une classe Context dans notre dossier Models.
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 ; }
}
}
Allons dans le dossier Startup.cs et créons une chaîne de connexion pour la méthode 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" ) ) ) ;
}
Venons-en à appsettings.json. Ici, nous écrivons les informations de connexion dans le fichier json comme ceci.
"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;"
}
}
Ensuite, nous construisons notre projet, allons dans le gestionnaire de packages et effectuons nos opérations de migration.
PM > Add-Migration " InitialCreate "
Créons Migration avec la commande et construisons notre projet. Ensuite, donnons cette commande.
PM > update-database
Vérifions ensuite si la base de données a été créée ou non à partir de MSSQL.
Et puis créons un contrôleur pour notre modèle. J'utiliserai le contrôleur API avec des actions utilisant le contrôleur EF.
Les photos viendront ici, 2 d'entre elles
Nous avons créé nos contrôles, spécifié notre modèle et notre fichier de contexte, ainsi que le nom de notre contrôleur.
5 Ces services appelés AddDb.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DevConnection"))); La fonction créera une demande pour ce contrôleur d'employé chaque fois que nous ferons une demande à ce EmployeeController. Le constructeur de EmployeeController est public EmployeeController (contexte EmployeeDbContext) La valeur EmployeeDbContext dans ce code est cette méthode d'injection de dépendance asp.net, qui est automatiquement gérée par le framework lui-même, donc la requête dans ce contrôleur communiquera avec la base de données pour l'instant.
Maintenant, concevons le côté client pour qu'il réagisse avec un formulaire d'employé pour télécharger les photos de profil des employés. Créons une application de réaction dans le répertoire du projet. Nous devons ouvrir l'invite de commande à partir du répertoire de ce projet.
npx create-react-app employee-register-client
Commande Oxios à utiliser côté client
$ npm install react-axios
Nous avons créé la structure de nos projets. À partir de maintenant, je souhaite que vous révisiez mes codes dans mon dépôt. Bonne chance :)
GET /api/Employee
Paramètre | Médecine | Explication |
---|---|---|
api_key | string | Nécessaire . Votre clé API. |
GET /api/Employee/${id}
Paramètre | Médecine | Explication |
---|---|---|
id | string | Nécessaire . Valeur clé de l'élément à appeler |
{ "employeeID" : 3 , "employeeName" : " piedhorse " , "occupation" : " C# " , "imageName" : " capture_20231646962.jpeg " , "imageFile" : null , "imageSrc" : " https://localhost:44334/Images/capture_20231646962.jpeg " }