2018年5月14日 星期一

React & ASP.NET Core 2.0 Upload File

一個新增檔案的Form含有上傳圖片的功能並可預覽圖片,圖片與表單內容一起傳送到後端,資料新增後再存檔圖片

建立一個選取圖片的子Component
import React from 'react';
 
class ImageUpload extends React.Component {
    constructor(props) {
        super(props);
        this.state = { file: '', imagePreviewUrl: '' };
    }
 
    handleImageChange(e) {
        e.preventDefault();
 
        let reader = new FileReader();
        let file = e.target.files[0];
 
        reader.onloadend = () => {
            this.setState({
                file: file,
                imagePreviewUrl: reader.result
            });
        };
 
        reader.readAsDataURL(file);
        this.props.onImageChange(file);
    }
 
    render() {
        let { imagePreviewUrl } = this.state;
        let $imagePreview = null;
        if (imagePreviewUrl) {
            $imagePreview = <img src={imagePreviewUrl} />;
        } else {
            $imagePreview = (
                <div className="previewText">
                    Please select an Image for Preview
                </div>
            );
        }
 
        return (
            <div className="previewComponent form-group">
                <label htmlFor="file">{this.props.label}</label>
                <input
                    id="file"
                    type="file"
                    className="fileInput form-control"
                    accept="image/*"
                    onChange={e => this.handleImageChange(e)}
                />
                <div className="imgPreview">
                    {$imagePreview}
                </div>
            </div>
        );
    }
}
 
ImageUpload.defaultProps = {
    label: '上傳圖片',
    onImageChange: (file) => {
        console.log('default onImageChange() has been called', file);
    }
};
 
export default ImageUpload;

建立新增資料的Form的父Component,兩個輸入欄位的type分別為text和file
import React from 'react';
import axios from 'axios';
 
import ImageUpload from './ImageUpload';
 
class CreateProduct extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            product: '',
            file: '',
        }
        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.handleImageChange = this.handleImageChange.bind(this);
    }
    handleSubmit(e) {
        e.preventDefault();
        const formData = new FormData();
        const keys = Object.keys(this.state);
        keys.forEach(key => {
            formData.append(key, this.state[key]);
        });
        const headers = { 'Content-Type''multipart/form-data' };
        axios.post('api/product', formData, { headers: headers }).then(response => {
            console.log('create success', response);
        });
    }
    handleChange(e) {
        this.setState({
            [e.target.id]: e.target.value
        });
    }
    handleImageChange(file) {
        this.setState({ file });
    }
    render() {
        const { product } = this.state;
        return (
            <div>
                <form onSubmit={this.handleSubmit}>
                    <div>
                        <label htmlFor="url">Product</label>
                        <input
                            type="text"
                            id="product"
                            value={product}
                            onChange={this.handleChange}
                        />
                    </div>
                    <ImageUpload onImageChange={this.handleImageChange} />
                    <button type="submit">Submit</button>
                </form>
            </div>
        );
    }
}
 
export default CreateProduct;

後端接收資料資料的參數類型
public class ProductCreationModel
{
    public string Product{ getset; }
    public IFormFile File { getset; }
}

處理上傳的後端程式
public class AppService
{
    private readonly IHostingEnvironment _environment;
 
    public AppService(IHostingEnvironment environment)
    {
        _environment = 
            environment ?? throw new ArgumentNullException(nameof(environment));
    }
    public async Task<string> Upload(IFormFile file, string name = null)
    {
        if (string.IsNullOrWhiteSpace(_environment.WebRootPath))
        {
            _environment.WebRootPath = Path.Combine(
                Directory.GetCurrentDirectory(), "wwwroot"
                );
        }
        var dir = Path.Combine(_environment.WebRootPath, "uploads");
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
        var fileName = file.FileName;
        var path = Path.Combine(dir, fileName);
        if (!string.IsNullOrEmpty(name)) // 使用自訂的檔案名稱
        {
            var extension = Path.GetExtension(path);
            fileName = $"{name}{extension}";
            path = path.Replace(file.FileName, fileName);
        }
        if (file.Length > 0)
        {
            using (var fileStream = new FileStream(path, FileMode.Create))
            {
                try
                {
                    await file.CopyToAsync(fileStream);
                    return fileName;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
        else
        {
            throw new Exception("file is empty");
        }
    }
}




沒有留言: