DevExpress DxUpload实现大文件上传

该博客展示了前端文件上传的API控制器实现,使用了DevExpress相关组件。代码中定义了文件大小、类型、存储路径等参数,实现了临时文件清理、文件处理、文件追加等功能,包含UploadFile和Upload两个文件上传接口,并对文件大小和类型进行了检查。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前端实现在如下

@inherits ProductionOrderComponentBase

<ProcessingSpiner Visible="@IsComponentBusy"/>

@if (IsValidating)
{
    <LoadingProcess />
}
else
{
    if (ComponentMode == ComponentMode.List)
    {
        <div class="position-relative">
            <div class="@(IsDetailBusy ? "component-backdrop" : null)"></div>

            <WarningModal WarningMessage="@WarningMessage"
                          WarningResponse="@HandleWarningResponse"
                          @bind-IsShowWarning="@IsShowWarning"/>

            <DxDataGrid CustomData="@LoadProductionOrders"
                        KeyFieldName="@KeyFieldName"
                        CssClass="@CssClass"
                        PageSize="@PageSize"
                        PageIndex="@PageIndex"
                        SelectionMode="@SelectionMode"
                        SelectAllMode="@SelectAllMode"
                        ShowFilterRow="IsShowFilterRow"
                        RowClick="@OnRowClick"
                        LayoutRestoring="@OnLayoutRestoring"
                        PagerPageSizeSelectorVisible="true"
                        PagerAllDataRowsItemVisible="true"
                        PagerAllowedPageSizes="@AllowedPageSizes"
                        @bind-MultipleSelectedDataRows="@SelectedCollection"
                        @ref="@Grid"
                        T="@ProductionOrderWithDetail">

                <HeaderTemplate>
                    <DataGridToolbar IsBusy="@(IsBusy || IsMasterBusy || IsDetailBusy)"
                                     CssClass="@ToolbarCssClass"
                                     SelectedCount="@SelectedCount"
                                     RequiredClaimType="@RequiredClaimType"
                                     OnToolbarClick="@HandleToolbarResponse"
                                     CanRestore="@CanRestore"
                                     ReadOnly="@ReadOnly">
                        @if (ReadOnly == false)
                        {
                            <DxToolbarItem Text="Generate Delivery Sheet"
                                           Click="@GenerateInventoryRequest"
                                           IconCssClass="mdi mdi-18px mdi-file-move-outline"
                                           Enabled="@(IsBusy == false)"
                                           CssClass="font-bigger"
                                           Visible="@CanEdit"/>

                            <DxToolbarItem Text="上传"
                                           id="overviewDemoSelectButton1" 
                                           IconCssClass="mdi mdi-18px mdi-file-move-outline"
                                           Enabled="@(IsBusy == false)"
                                           CssClass="font-bigger"
                                           Visible="@CanEdit" /> 
                            <DxUpload Name="myFile"
                                      Visible=true
                                      ExternalSelectButtonCssSelector="#overviewDemoSelectButton1"
                                      ExternalDropZoneCssSelector="#overviewDemoDropZone"
                                      ExternalDropZoneDragOverCssClass="bg-light border-secondary text-dark" 
                                      ChunkSize="2000000"
                                      MaxFileSize=999999999
                                      UploadUrl="@GetUploadUrl("/api/Files/UploadFile/")"
                                      CssClass="w-100">
                            </DxUpload>
                        }
                    </DataGridToolbar>

                    
                </HeaderTemplate>

                <Columns>
                    @* <DxDataGridSelectionColumn Width="60px"/> *@
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.OrderNumber)"
                                      Caption="No."
                                      Width="100px">
                        <DisplayTemplate>
                            @{
                                var requestNumb = $"{((ProductionOrderWithDetail) context).OrderNumber:000000}";
                                <span>@requestNumb</span>
                            }
                        </DisplayTemplate>
                    </DxDataGridColumn>
                    <DxDataGridDateEditColumn Field="@nameof(ProductionOrderWithDetail.OrderDate)"
                                              DisplayFormat="dd/MM/yyyy"
                                              Width="100px"
                                              Caption="Date"
                                              Visible="false"/>
                    <DxDataGridDateEditColumn Field="@nameof(ProductionOrderWithDetail.DueDate)"
                                              DisplayFormat="dd/MM/yyyy"
                                              Width="100px"
                                              Caption="Due Date"/>
                    <DxDataGridDateEditColumn Field="@nameof(ProductionOrderWithDetail.CompletedDate)"
                                              DisplayFormat="dd/MM/yyyy"
                                              Width="100px"
                                              Caption="Completed Date"
                                              Visible="false"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.StatusName)"
                                      Caption="Status"
                                      Width="100px"/>
                    <DxDataGridDateEditColumn Field="@nameof(ProductionOrderWithDetail.StatusDate)"
                                              DisplayFormat="dd/MM/yyyy"
                                              Width="100px"
                                              Caption="Status Date"
                                              Visible="false"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.LotNumber)"
                                      Caption="Lot Number"
                                      Width="100px"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.ProductCode)"
                                      Caption="Product Code"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.ProductName)"
                                      Caption="Product Name"
                                      Visible="false"/>
                    <DxDataGridSpinEditColumn Field="@nameof(ProductionOrderWithDetail.Quantity)"
                                              DisplayFormat="N"
                                              Caption="Quantity"
                                              Width="100px"/>
                    <DxDataGridSpinEditColumn Field="@nameof(ProductionOrderWithDetail.ReadyQuantity)"
                                              DisplayFormat="N"
                                              Caption="Ready Qty."
                                              Width="100px"/>
                    <DxDataGridSpinEditColumn Field="@nameof(ProductionOrderWithDetail.DeliveredQuantity)"
                                              DisplayFormat="N"
                                              Caption="Delivered Qty."
                                              Width="100px"/>
                    <DxDataGridSpinEditColumn Field="@nameof(ProductionOrderWithDetail.RemainQuantity)"
                                              DisplayFormat="N"
                                              Caption="Remain Qty."
                                              Width="100px"/>
                    <DxDataGridSpinEditColumn Field="@nameof(ProductionOrderWithDetail.ProducingQuantity)"
                                              DisplayFormat="N"
                                              Caption="Producing Qty."
                                              Width="100px"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.UnitName)"
                                      Caption="Unit"
                                      Width="100px"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.Comment)"
                                      Caption="Remark"
                                      Visible="false"/>
                    <DxDataGridColumn Field="@nameof(ProductionOrderWithDetail.DeletedStatus)"
                                      TextAlignment="DataGridTextAlign.Center"
                                      Caption="Status"
                                      Width="80px"
                                      Visible="@IsAdmin"
                                      ShowInColumnChooser="false"/>
                </Columns>
            </DxDataGrid>
        </div>
    }
    else
    {
        <div class="card py-2">
            <EditForm Model="@DataEditContext" Context="editFormContext" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit">
                <FluentValidationValidator/>
                <DxFormLayout CaptionPosition="@CaptionPosition.Vertical" ItemSizeMode="SizeMode.Medium" Context="FormLayoutContext">
                    <DxFormLayoutItem Caption="Order No." ColSpanMd="3" CssClass="@(ComponentMode == ComponentMode.Add ? "with-tooltip" : null)">
                        <Template>
                            <DxTextBox ReadOnly="true"
                                       @bind-Text="@DataEditContext.OrderNumberDisplay"/>
                            <ValidationMessage For="() => DataEditContext.OrderNumber"/>
                        </Template>

                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="日期" ColSpanMd="3">
                        <Template>
                            <DxDateEdit DisplayFormat="dd/MM/yyyy"
                                        Format="dd/MM/yyyy"
                                        ReadOnly="true"
                                        @bind-Date="@DataEditContext.OrderDate"/>
                            <ValidationMessage For="() => DataEditContext.OrderDate"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="Due Date" ColSpanMd="3">
                        <Template>
                            <DxDateEdit DisplayFormat="dd/MM/yyyy"
                                        Format="dd/MM/yyyy"
                                        ReadOnly="@(IsFromProductionRequest || CanChange == false)"
                                        @bind-Date="@DataEditContext.DueDate"/>
                            <ValidationMessage For="() => DataEditContext.DueDate"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="订单 状态" ColSpanMd="3">
                        <Template>
                            <DxComboBox Data="@OrderStatusCollection"
                                        ValueFieldName="@nameof(TgOrderStatuses.Value)"
                                        TextFieldName="@nameof(TgOrderStatuses.DisplayName)"
                                        CssClass="normal-combobox"
                                        @bind-Value="@DataEditContext.Status"/>
                            <ValidationMessage For="() => DataEditContext.Status"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="Lot Number" ColSpanMd="3">
                        <Template>
                            <DxTextBox @bind-Text="@DataEditContext.LotNumber"/>
                            <ValidationMessage For="() => DataEditContext.LotNumber"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="Product" ColSpanMd="3">
                        <Template>
                            @if (CanChange)
                            {
                                <BlazoredTypeahead SearchMethod="SearchProducts"
                                                   EnableDropDown="true"
                                                   Context="productContext"
                                                   placeholder="Type to search..."
                                                   @bind-Value="SelectedProduct">
                                    <SelectedTemplate>
                                        @productContext.Code
                                    </SelectedTemplate>
                                    <ResultTemplate>
                                        @productContext.Code
                                    </ResultTemplate>
                                </BlazoredTypeahead>
                            }
                            else
                            {
                                <DxTextBox ReadOnly="true"
                                           @bind-Text="@DataEditContext.ProductCode"/>
                            }
                            <ValidationMessage For="() => DataEditContext.ProductId"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="Name" ColSpanMd="6">
                        <Template>
                            <DxTextBox ReadOnly="true"
                                       @bind-Text="@DataEditContext.ProductName"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="@($"Quantity{UnitName}")" ColSpanMd="3">
                        <Template>
                            <DxSpinEdit BindValueMode="BindValueMode.OnInput"
                                        MaxValue="999999.9999m"
                                        MinValue="0m"
                                        Increment="0.0001m"
                                        DisplayFormat="N"
                                        @bind-Value="@DataEditContext.Quantity"/>
                            <ValidationMessage For="() => DataEditContext.Quantity"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="@($"Ready Quantity{UnitName}")" ColSpanMd="3">
                        <Template>
                            <DxSpinEdit BindValueMode="BindValueMode.OnInput"
                                        MaxValue="999999.9999m"
                                        MinValue="0m"
                                        Increment="0.0001m"
                                        DisplayFormat="N"
                                        @bind-Value="@DataEditContext.ReadyQuantity"/>
                            <ValidationMessage For="() => DataEditContext.ReadyQuantity"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem Caption="Remark" ColSpanMd="6">
                        <Template>
                            <DxTextBox ReadOnly="@(IsFromProductionRequest || CanChange == false)"
                                       @bind-Text="@DataEditContext.Comment"/>
                            <ValidationMessage For="() => DataEditContext.Comment"/>
                        </Template>
                    </DxFormLayoutItem>
                    <DxFormLayoutItem ColSpanMd="12">
                        <Template>
                            <EditFormButtonGroup ComponentMode="@ComponentMode"
                                                 SaveAndCloseOnlyWhenAdd="true"
                                                 CancelUpdateClicked="@CancelUpdateClick"
                                                 @bind-SubmitClick="@SubmitClick"
                                                 @bind-SaveAndClose="@SaveAndClose">
                                <span class="mr-auto help-text @(ComponentMode == ComponentMode.Edit ? "d-none" : null)">* Auto-generate after saved.</span>
                            </EditFormButtonGroup>
                        </Template>
                    </DxFormLayoutItem>
                </DxFormLayout>
            </EditForm>
        </div>
    }
}
@code {
    
    protected string GetUploadUrl(string url)
    {
        return NavigationManager.ToAbsoluteUri(url).AbsoluteUri;
    }
}

API控制器实现
using DevExpress.Blazor.Upload.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
 
namespace Client.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class FilesController : ControllerBase
    {
        private static readonly long FileSize = 10485760;
        private static readonly string FilesType = ".gif,.jpg,.jpeg,.png,.bmp,.GIF,.JPG,.JPEG,.PNG,.doc,.docx,.xls,.xlsx,.csv,.pdf,.ppt,.dwg,.DXF,.zip,.rar,.txt";
        private static readonly string FilesBasePath = "c:\\wms_file";
        //在IIS新建图片服务器网站,路径指向 FilesBasePath
        private static readonly string Ip = "10.111.11.123";
        private static readonly string Port = "8899";


        void RemoveTempFilesAfterDelay(string path, TimeSpan delay)
        {
            var dir = new DirectoryInfo(path);
            if (dir.Exists)
                foreach (var file in dir.GetFiles("*.tmp").Where(f => f.LastWriteTimeUtc.Add(delay) < DateTime.UtcNow))
                    file.Delete();
        }
        void ProcessUploadedFile(string tempFilePath, string fileName)
        {
            var path = Path.Combine(FilesBasePath, "Images");
            var imagePath = Path.Combine(path, fileName);
            if (System.IO.File.Exists(imagePath))
                System.IO.File.Delete(imagePath);
            System.IO.File.Copy(tempFilePath, imagePath);
        }
        void AppendContentToFile(string path, IFormFile content)
        {
            using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write))
            {
                content.CopyTo(stream);
            }
        }

        public class ChunkMetadata
        {
            public int Index { get; set; }
            public int TotalCount { get; set; }
            public int FileSize { get; set; }
            public string FileName { get; set; }
            public string FileType { get; set; }
            public Guid FileGuid { get; set; }
        }
        [HttpPost]
        [Route("UploadFile")]
        [DisableRequestSizeLimit]
        public ActionResult UploadFile(IFormFile myFile)
        {
            string chunkMetadata = Request.Form["chunkMetadata"];
            var tempPath = Path.Combine(FilesBasePath, "Images");
            // Removes temporary files
            RemoveTempFilesAfterDelay(tempPath, new TimeSpan(0, 5, 0));

            try
            {
                if (!string.IsNullOrEmpty(chunkMetadata))
                {
                    var metaDataObject = JsonConvert.DeserializeObject<ChunkMetadata>(chunkMetadata);
                    var tempFilePath = Path.Combine(tempPath, metaDataObject.FileGuid + ".tmp");
                    if (!Directory.Exists(tempPath))
                        Directory.CreateDirectory(tempPath);

                    AppendContentToFile(tempFilePath, myFile);

                    if (metaDataObject.Index == (metaDataObject.TotalCount - 1))
                    {
                        ProcessUploadedFile(tempFilePath, metaDataObject.FileName); 
                    }
                }
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
            return Ok();
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        [HttpPost("Upload")]
        public ActionResult Upload(IFormFile myFile)
        {
            try
            {
                var id = "WMS";//我自己的combine id生成器
                string newFileName = string.Empty;
                if (myFile == null)
                {
                    throw new Exception("传入文件为空");//类型
                }
                if (myFile.Length <= FileSize)//检查文件大小
                {
                    var suffix = Path.GetExtension(myFile.FileName);//提取上传的文件文件后缀
                    if (FilesType.IndexOf(suffix) != -1)//检查文件格式
                    {
                        newFileName = myFile.FileName + suffix;
                        //创建每日存储文件夹
                        if (Directory.Exists($@"{FilesBasePath}\{id}"))
                        {
                            //删除原有文件防止文件名重复
                            DirectoryInfo subdir = new DirectoryInfo($@"{FilesBasePath}\{id}");
                            subdir.Delete(true);

                        }
                        Directory.CreateDirectory($@"{FilesBasePath}\{id}");

                        using (FileStream fs = System.IO.File.Create($@"{FilesBasePath}\{id}\{newFileName}"))//注意路径里面最好不要有中文
                        {
                            myFile.CopyTo(fs);//将上传的文件文件流,复制到fs中
                            fs.Flush();//清空文件流
                        }
                    }
                    else
                        throw new Exception("不支持此文件类型");//类型不正确
                }
                else
                {
                    throw new Exception($"文件大小不得超过{FileSize / (1024f * 1024f)}M");  //请求体过大,文件大小超标
                }
                return Ok(new { code = 0 });
            }
            catch (Exception ex)
            {
                return Ok(new { code = ex.Message });
            }
        } 
          
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

meslog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值