Generic Import/Export Library
Magicodes.ExporterAndImporter is a generic import/export library developed by the Xinlai team, which is continuously being refined and improved.
GitHub Repository: https://github.com/xin-lai/Magicodes.ExporterAndImporter
Features
- Provides encapsulation for import/export operations, currently supporting Excel only (CSV, PDF, and other formats could be added)
- Uses configuration attributes to control logic and display results without modifying core code
- Recommended to be used with Import/Export DTOs
- Export supports custom header handling for scenarios like multilingual support
- Export supports custom text filtering or processing
- Import supports automatic generation of import templates based on DTOs with template validation
- Import supports data validation logic
- Import supports data dropdown selections
- Import supports adding comments
Export Demos
Basic Export
public class ProductData
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
var exportResult = await ExcelExporter.Export(filePath, new List<productdata>()
{
new ProductData()
{
ProductId = "P001",
ProductName = "Laptop",
Price = 999.99m,
Quantity = 10
},
new ProductData()
{
ProductId = "P002",
ProductName = "Mouse",
Price = 19.99m,
Quantity = 50
}
});
</productdata>
Attribute-Based Export
[ExcelExporter(Name = "Product Report", TableStyle = "Medium10")]
public class ProductReportData
{
[ExporterHeader(DisplayName = "Product ID", IsBold = true)]
public string Id { get; set; }
[ExporterHeader(DisplayName = "Product Name")]
public string Name { get; set; }
[ExporterHeader(DisplayName = "Unit Price", Format = "$#,##0.00")]
public decimal Price { get; set; }
[ExporterHeader(DisplayName = "Stock", IsAutoFit = true)]
public int StockQuantity { get; set; }
}
var exportResult = await ExcelExporter.Export(filePath, new List<productreportdata>()
{
new ProductReportData()
{
Id = "P001",
Name = "Laptop Computer",
Price = 999.99m,
StockQuantity = 15
},
new ProductReportData()
{
Id = "P002",
Name = "Wireless Mouse",
Price = 29.99m,
StockQuantity = 45
}
});
</productreportdata>
Custom Header Handling and Multilingual Support
[ExcelExporter(Name = "Sales Report", TableStyle = "Light10")]
public class SalesData
{
[ExporterHeader(DisplayName = "Sale Date")]
public DateTime Date { get; set; }
[ExporterHeader(DisplayName = "Customer Name")]
public string Customer { get; set; }
[ExporterHeader(DisplayName = "Amount", Format = "#,##0.00")]
public decimal TotalAmount { get; set; }
[ExporterHeader(DisplayName = "Status")]
public string Status { get; set; }
}
ExcelBuilder.Create()
.WithLocalStringFunc((key) =>
{
if (key.Contains("Date")) return "Fecha";
if (key.Contains("Customer")) return "Cliente";
if (key.Contains("Amount")) return "Monto";
if (key.Contains("Status")) return "Estado";
return key;
})
.Build();
var exportResult = await ExcelExporter.Export(filePath, new List<salesdata>()
{
new SalesData()
{
Date = DateTime.Now,
Customer = "John Doe",
TotalAmount = 1250.75m,
Status = "Completed"
},
new SalesData()
{
Date = DateTime.Now.AddDays(-1),
Customer = "Jane Smith",
TotalAmount = 890.50m,
Status = "Pending"
}
});
</salesdata>
Import Demos
The import functionality uses several key components:
- ImporterHeader attributes:
- Name (string): Display name for the column header (required)
- Description (string): Comment to add to the header
- Author (string): Comment author, default is "X.M"
- ImportModel<T>: Contains:
- Data: IList<T> of imported data
- ValidationResults: IList<ValidationResultModel> for validasion results
- HasValidTemplate: bool indicating if template validation passed
- ValidationResultModel: Contains:
- Index: int for the row with errors
- Errors: IDictionary<string, string> for Excel-wide errors
- FieldErrors: IDictionary<string, string> for field-specific validation errors
Basic Template
Template Generation
public class CustomerImportDto
{
/// <summary>
/// Customer full name
/// </summary>
[ImporterHeader(Name = "Full Name")]
public string FullName { get; set; }
/// <summary>
/// Customer email address
/// </summary>
[ImporterHeader(Name = "Email Address")]
public string Email { get; set; }
/// <summary>
/// Customer phone number
/// </summary>
[ImporterHeader(Name = "Phone Number")]
public string Phone { get; set; }
/// <summary>
/// Customer registration date
/// </summary>
[ImporterHeader(Name = "Registration Date")]
public DateTime RegistrationDate { get; set; }
}
Multiple Data Types
Template Generation
public class ProductImportDto
{
/// <summary>
/// Product name
/// </summary>
[ImporterHeader(Name = "Product Name")]
public string Name { get; set; }
/// <summary>
/// Product SKU
/// </summary>
[ImporterHeader(Name = "Product SKU")]
public string Sku { get; set; }
/// <summary>
/// Product barcode
/// </summary>
[ImporterHeader(Name = "Barcode")]
public string Barcode { get; set; }
/// <summary>
/// Category ID
/// </summary>
[ImporterHeader(Name = "Category ID")]
public int CategoryId { get; set; }
/// <summary>
/// Product model
/// </summary>
[ImporterHeader(Name = "Model")]
public string Model { get; set; }
/// <summary>
/// Unit price
/// </summary>
[ImporterHeader(Name = "Unit Price")]
public decimal UnitPrice { get; set; }
/// <summary>
/// Currency
/// </summary>
[ImporterHeader(Name = "Currency")]
public string Currency { get; set; }
/// <summary>
/// Brand name
/// </summary>
[ImporterHeader(Name = "Brand")]
public string Brand { get; set; }
/// <summary>
/// Dimensions
/// </summary>
[ImporterHeader(Name = "Dimensions (LxWxH)")]
public string Dimensions { get; set; }
/// <summary>
/// Weight in kilograms
/// </summary>
[ImporterHeader(Name = "Weight (KG)")]
public double Weight { get; set; }
/// <summary>
/// Product category
/// </summary>
[ImporterHeader(Name = "Category")]
public ProductCategory Category { get; set; }
/// <summary>
/// Is active
/// </summary>
[ImporterHeader(Name = "Active")]
public bool IsActive { get; set; }
}
public enum ProductCategory
{
[Display(Name = "Electronics")]
Electronics,
[Display(Name = "Clothing")]
Clothing,
[Display(Name = "Home & Garden")]
HomeAndGarden,
[Display(Name = "Sports")]
Sports
}
Data Validation
Template Generation
Required fields are marked in red in the header
public class ValidatedOrderImportDto
{
/// <summary>
/// Order number
/// </summary>
[ImporterHeader(Name = "Order Number", Description = "Required")]
[Required(ErrorMessage = "Order number is required")]
public string OrderNumber { get; set; }
/// <summary>
/// Customer ID
/// </summary>
[ImporterHeader(Name = "Customer ID", Description = "Maximum 10 characters")]
[MaxLength(10, ErrorMessage = "Customer ID cannot exceed 10 characters")]
public string CustomerId { get; set; }
/// <summary>
/// Product code
/// </summary>
[ImporterHeader(Name = "Product Code", Description = "Required, alphanumeric only")]
[Required(ErrorMessage = "Product code is required")]
[RegularExpression(@"^[a-zA-Z0-9]*$", ErrorMessage = "Product code must be alphanumeric")]
public string ProductCode { get; set; }
/// <summary>
/// Quantity
/// </summary>
[ImporterHeader(Name = "Quantity", Description = "Required, minimum 1")]
[Range(1, int.MaxValue, ErrorMessage = "Quantity must be at least 1")]
public int Quantity { get; set; }
/// <summary>
/// Unit price
/// </summary>
[ImporterHeader(Name = "Unit Price", Description = "Required, must be positive")]
[Range(0.01, double.MaxValue, ErrorMessage = "Unit price must be positive")]
public decimal UnitPrice { get; set; }
/// <summary>
/// Order date
/// </summary>
[ImporterHeader(Name = "Order Date", Description = "Required")]
[Required(ErrorMessage = "Order date is required")]
public DateTime OrderDate { get; set; }
/// <summary>
/// Delivery method
/// </summary>
[ImporterHeader(Name = "Delivery Method")]
public DeliveryMethod DeliveryMethod { get; set; }
/// <summary>
/// Is urgent
/// </summary>
[ImporterHeader(Name = "Urgent Order")]
public bool IsUrgent { get; set; }
}
public enum DeliveryMethod
{
[Display(Name = "Standard")]
Standard,
[Display(Name = "Express")]
Express,
[Display(Name = "Overnight")]
Overnight
}
Using in Docker
Required Libraries
To use Excel export functionality in Docker, you need to install the libgdiplus library:
# Install libgdiplus library for Excel export
RUN apt-get update && apt-get install -y libgdiplus libc6-dev
RUN ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
Dockerfile Example
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
# Install libgdiplus library for Excel export
RUN apt-get update && apt-get install -y libgdiplus libc6-dev
RUN ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["src/web/Admin.Host/Admin.Host.csproj", "src/web/Admin.Host/"]
COPY ["src/web/Admin.Web.Core/Admin.Web.Core.csproj", "src/web/Admin.Web.Core/"]
COPY ["src/application/Admin.Application/Admin.Application.csproj", "src/application/Admin.Application/"]
COPY ["src/core/Magicodes.Admin.Core/Magicodes.Admin.Core.csproj", "src/core/Magicodes.Admin.Core/"]
COPY ["src/data/Magicodes.Admin.EntityFrameworkCore/Magicodes.Admin.EntityFrameworkCore.csproj", "src/data/Magicodes.Admin.EntityFrameworkCore/"]
COPY ["src/core/Magicodes.Admin.Core.Custom/Magicodes.Admin.Core.Custom.csproj", "src/core/Magicodes.Admin.Core.Custom/"]
COPY ["src/application/Admin.Application.Custom/Admin.Application.Custom.csproj", "src/application/Admin.Application.Custom/"]
RUN dotnet restore "src/web/Admin.Host/Admin.Host.csproj"
COPY . .
WORKDIR "/src/src/web/Admin.Host"
RUN dotnet build "Admin.Host.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "Admin.Host.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Magicodes.Admin.Web.Host.dll"]