I Have Excel import feature with ClosedXM and meet the errror with ctivator.CreateInstance(typeof(T)). It throws:

System.MissingMethodException: 'Cannot dynamically create an instance of type 'FSH.WebApi.Domain.Catalog.Brand'. Reason: No parameterless constructor defined.

Please help !!!

// Controller

[HttpPost("import")]
    
    public async Task<ActionResult<int>> ImportAsync(ImportBrandsRequest request)
    {
        IList<Brand> result = new List<Brand>();
        result = await _excelReader.ImportAsync<Brand>(request.ExcelFile, FileType.Excel);
        return Ok(result.Count);
     }

// Interface

public interface IExcelReader : ITransientService
{
    Task<IList<T>> ImportAsync<T>(
        FileUploadRequest request,
        FileType supportedFileType,
        string sheetName = "Sheet1");
}

// Service:

public class ExcelReader : IExcelReader
{
public async Task<IList<T>> ImportAsync<T>(FileUploadRequest request, FileType supportedFileType, string sheetName = "Sheet1")
    {

        var streamData = new MemoryStream(Convert.FromBase64String(base64Data));
        List<T> list = new List<T>();
        Type typeOfObject = typeof(T);
        using (IXLWorkbook workbook = new XLWorkbook(streamData))
        {
            var worksheet = workbook.Worksheets.First(w => w.Name == sheetName);

            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));

            // header column texts
            var columns = worksheet.FirstRow().Cells().Select((v, i) => new { v.Value, Index = i + 1 });

            // indexing in closedxml starts with 1 not from 0
            // Skip first row which is used for column header texts
            foreach (IXLRow row in worksheet.RowsUsed().Skip(1))
            {
                T item = (T)Activator.CreateInstance(typeof(T));

                // T item = (T)Activator.CreateInstance(typeof(T));

                foreach (PropertyDescriptor prop in properties)
                {
                    int colIndex = columns.Single(
                                            c => c.Value.ToString() == prop.Name).Index;
                    if (colIndex == 0) continue;
                    object? val = row.Cell(colIndex).Value;
                    var type = prop.PropertyType;
                    prop.SetValue(item, Convert.ChangeType(val, type));
                }

                if (item != null) list.Add(item);
            }
        }

        return await Task.FromResult(list);
}


1

There are 1 best solutions below

0
Stephen Cleary On

Presumably, Brand doesn't have a constructor without parameters. So, either add a parameterless constructor to Brand or pass parameter arguments to Activator.CreateInstance.