c# - 使用 EPPlus 验证 Excel(电子表格)文件

标签 c# excel asp.net-mvc epplus

场景:有一个包含用户数据的 Excel 工作表。需要在插入(如果是新的)或更新(如果存在的话)数据库中的任何用户数据之前验证 Excel 工作表。如果任何单元格的数据不正确或数据为空,该单元格将以红色突出显示并带有解释错误的注释。
例如:电子邮件格式不正确

最佳答案

我想将此作为解决方案发布,这样可以帮助任何在使用 EPPlus 验证 Excel 工作表时遇到问题的人。
EPPlus版本:4.5.2.1

以下是excel表格结构。 excel sheet structure

以下是验证 excel 表的完整代码。

    [HttpPost]
    public ActionResult BulkUserUpload(HttpPostedFileBase uploadFile)
    {
        string          tempFileName            = string.Empty;
        string          errorMessage            = string.Empty;

        if (uploadFile != null && uploadFile.ContentLength > 0)
        {
            //ExcelExtension contains array of excel extension types
            if ( Config.ExcelExtension.Any(p => p.Trim() == Path.GetExtension(uploadFile.FileName)) )
            {
                //save the uploaded excel file to temp location
                SaveExcelTemp(uploadFile, out tempFileName);
                //validate the excel sheet
                if (ValidateExcel(tempFileName, out errorMessage))
                {
                    //save the data
                    SaveExcelDataToDatabase(tempFileName);
                    //spreadsheet is valid, show success message or any logic here
                }
                else
                {
                    //set error message to shown in front end
                    ViewBag.ErrorMessage        = errorMessage;
                }
            }
            else
            {
                //excel sheet is not uploaded, show error message
            }                                
        }
        else
        {
            //file is not uploaded, show error message
        }

        return View();
    }


    private bool ValidateExcel(string tempFileName, out string errorMessage)
    {
        bool                result              = true;
        string              error               = string.Empty;
        string              filePath            = GetTempFilePath(tempFileName);
        FileInfo            fileInfo            = new FileInfo(filePath);
        ExcelPackage        excelPackage        = new ExcelPackage(fileInfo);
        ExcelWorksheet      worksheet           = excelPackage.Workbook.Worksheets.First();
        int                 totalRows           = worksheet.Dimension == null ? -1 : worksheet.Dimension.End.Row; //worksheet total rows
        int                 totalCols           = worksheet.Dimension == null ? -1 : worksheet.Dimension.End.Column; // total columns

        //check spread sheet has rows (empty spreadsheet uploaded)
        if (totalRows == -1)
        {
            result                              = false;
            error                               = "Empty spread sheet uploaded.";
        }
        //check rows are more than or equal 2 (spread sheet has only header row)
        else if (totalRows < 2)
        {
            result                              = false;
            error                               = "Spread sheet does not contain any data";
        }
        //check total columns equal to headers defined (less columns)
        else if (totalCols > 0 && totalCols != GetColumnHeaders().Count)
        {
            result                              = false;
            error                               = "Spread sheet column header value mismatch.";
        }

        if (result)
        {
            //validate header columns
            result                              &= ValidateColumns(worksheet, totalCols);

            if (result)
            {
                //validate data rows, skip the header row (data rows start from 2)
                result                          &= ValidateRows(worksheet, totalRows, totalCols);
            }

            if (!result)
            {
                error                           = "There are some errors in the uploaded file. Please correct them and upload again.";
            }
        }

        errorMessage                            = error;
        worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
        excelPackage.Save();

        return result;
    }

验证方法如下

    private bool SetError(ExcelRange cell, string errorComment)
    {           
        var         fill        = cell.Style.Fill;
        fill.PatternType        = OfficeOpenXml.Style.ExcelFillStyle.Solid;
        fill.BackgroundColor.SetColor(System.Drawing.Color.Red);
        cell.AddComment(errorComment, "");

        return false;
    }

    private bool ValidateHeaderColumns(ExcelWorksheet worksheet, int totlaColumns)
    {
        bool                result                  = true;
        List<string>        listColumnHeaders       = GetColumnHeaders();

        for (int i = 1; i < totlaColumns; i++)
        {
            var             cell                    = worksheet.Cells[1, i]; //header columns are in first row

            if (cell.Value != null)
            {
                //column header has a value
                if (!listColumnHeaders.Contains(cell.Value.ToString()))
                {
                    result                          &= SetError(cell, "Invalid header. Please correct.");
                }
            }
            else
            {
                //empty header
                result                              &= SetError(cell, "Empty header. Remove the column.");
            }
        }

        return result;
    }

    private bool ValidateRows(ExcelWorksheet worksheet, int totalRows, int totalCols)
    {
        bool        result              = true;

        for (int i = 2; i <= totalRows; i++) //data rows start from 2`
        {
            for (int j = 1; j <= totalCols; j++)
            {
                var         cell        = worksheet.Cells[i, j];

                switch (j)
                {
                    //email address
                    case 1:
                        {
                            result      &= ValidateEmailAddress(cell, "Email address");
                            break;
                        }
                    //first name
                    case 2:
                        {
                            result      &= ValidateText(cell, "First name");
                            break;
                        }
                    //last name
                    case 3:
                        {
                            result      &= ValidateText(cell, "Last name");
                            break;
                        }
                    //address line 1
                    case 4:
                        {
                            result      &= ValidateText(cell, "Address line 1");
                            break;
                        }
                    //address line 2
                    case 5:
                        {
                            result      &= ValidateText(cell, "Address line 2");
                            break;
                        }
                    //city
                    case 6:
                        {
                            result      &= ValidateText(cell, "City");
                            break;
                        }
                    //telephone number
                    case 7:
                        {
                            result      &= ValidateText(cell, "Telephone number");
                            break;
                        }
                    //mobile number
                    case 8:
                        {
                            result      &= ValidateText(cell, "Mobile number");
                            break;
                        }
                    //job title
                    case 9:
                        {
                            result      &= ValidateJobTitle(cell, "Job title");
                            break;
                        }
                    //salary
                    case 10:
                        {
                            result      &= ValidateNumber(cell, "Salary");
                            break;
                        }
                    //role
                    case 11:
                        {
                            result      &= ValidateRole(cell, "Role");
                            break;
                        }
                    //branch
                    case 12:
                        {
                            result      &= ValidateBranch(cell, "Branch");
                            break;
                        }
                    //joined date
                    case 13:
                        {
                            result      &= ValidateDate(cell, "Joined date");
                            break;
                        }
                }                   
            }
        }

        return result;
    }

    private bool ValidateEmailAddress(ExcelRange cell, string columnName)
    {
        bool        result      = true;
        result                  = ValidateText(cell, columnName); //validate if empty or not

        if (result)
        {
            if (!ValidateEmail(cell.Value.ToString())) //ValidateEmail => true, if email format is correct
            {
                result          = SetError(cell, "Email address format is invalid.");
            }
            else if (cell.Value.ToString().Length > 150)
            {
                result          = SetError(cell, "Email address too long. Max characters 150.");
            }
        }

        return result;
    }

    private bool ValidateText(ExcelRange cell, string columnName)
    {
        bool        result      = true;
        string      error       = string.Format("{0} is empty", columnName);

        if (cell.Value != null)
        {
            //check if cell value has a value
            if (string.IsNullOrWhiteSpace(cell.Value.ToString()))
            {
                result          = SetError(cell, error);
            }
        }
        else
        {
            result              = SetError(cell, error);
        }

        return result;
    }


    private bool ValidateNumber(ExcelRange cell, string columnName)
    {
        bool        result      = true;
        double      value       = 0.0;
        string      error       = string.Format("{0} format is incorrect.", columnName);
        result                  = ValidateText(cell, columnName);

        if (result)
        {
            if (!double.TryParse(cell.Value.ToString(), out value))
            {
                result          = SetError(cell, error);
            }
        }

        return result;
    }

    private bool ValidateDate(ExcelRange cell, string columnName)
    {
        bool            result      = true;
        DateTime        date        = DateTime.MinValue;
        string          error       = string.Format("{0} format is incorrect.", columnName);
        result                      = ValidateText(cell, columnName);

        if (result)
        {
            if (!DateTime.TryParse(cell.Value.ToString(), out date))
            {
                result              = SetError(cell, error);
            }
        }

        return result;
    }

    private bool ValidateJobTitle(ExcelRange cell, string columnName)
    {
        bool                result              = true;
        string              error               = "Job title does not exist.";
        List<JobTitle>      listJobTitle        = JobTitle.GetJobTitles((int)JobTitle.JobTitleStatus.Active);
        result                                  = ValidateText(cell, columnName);

        if (result)
        {
            if (!listJobTitle.Any(x => x.Name.ToLowerInvariant() == cell.Value.ToString().ToLowerInvariant()))
            {
                result                          = SetError(cell, error);
            }
        }

        return result;
    }

方法 ValidateBranch() 和 ValidateRole() 的实现与 ValidateJobTitle() 方法相同。

以下是经过验证但有错误的 Excel 工作表。 Error excel sheet

希望对大家有所帮助。

关于c# - 使用 EPPlus 验证 Excel(电子表格)文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51664221/

相关文章:

c# - 在 C# 中遍历树的递归 lambda 表达式

c# - 阻止并发集合,例如 ConcurrentBag 或 BlockingCollection

c# - 为什么要创建一个引用派生类的基类对象

Excel CountIfs 与日期或条件

C# 多线程和套接字问题

excel - 通过键盘输入激活 SelectionChange 上的单元格范围

用于将日期时间转换为 excel 数字 DATEVALUE 转换的 PHP 函数

asp.net - ASP.NET 最大请求大小的临时覆盖

c# - 具有两个操作的 Razor 输入

c# - MVC4 和路由