Hi @ismcagdas - I found a solution using the existing library.
Basically - the NPOI library has a nuance with how you get cells.
The nuance manifests in .cell[num] vs .GetCell[num] after GetRow.
The Cells collection simply drops empty cells.
Thus if you have an empty phone number field in the fourth column, the 5th column becomes the 4th column, and the import fails because it tries to read the column at the end and it doesn't exist.
In your code, worksheet.GetRow(row).Cells[4] is used.
However, if one were to do worksheet.GetRow(row).GetCall(4), in the above example, it returns a null.
Thus, my solution was to use simple counters for the order of the cells, and handle thusly:
int colCheck = 0;
int cellIndex = 0;
if (worksheet.GetRow(row).GetCell(colCheck) ==null) throw new System.ArgumentException("User Name is required");
user.UserName = GetRequiredValueFromRowOrNull(worksheet, row, cellIndex, nameof(user.UserName), exceptionMessage);
cellIndex++;
colCheck++;
if (worksheet.GetRow(row).GetCell(colCheck) == null) throw new System.ArgumentException("First Name is required");
user.Name = GetRequiredValueFromRowOrNull(worksheet, row, cellIndex, nameof(user.Name), exceptionMessage);
cellIndex++;
colCheck++;
if (worksheet.GetRow(row).GetCell(colCheck) == null) throw new System.ArgumentException("Last Name is required");
user.Surname = GetRequiredValueFromRowOrNull(worksheet, row,cellIndex, nameof(user.Surname), exceptionMessage);
cellIndex++;
colCheck++;
if (worksheet.GetRow(row).GetCell(colCheck) == null) throw new System.ArgumentException("Email is required");
user.EmailAddress = GetRequiredValueFromRowOrNull(worksheet, row, cellIndex, nameof(user.EmailAddress), exceptionMessage);
cellIndex++;
colCheck++;
// TODO Handle no phone number
if (worksheet.GetRow(row).GetCell(colCheck) != null)
{
worksheet.GetRow(row).Cells[cellIndex].SetCellType(CellType.String);
user.PhoneNumber = worksheet.GetRow(row).Cells[cellIndex]?.StringCellValue;
cellIndex++;
}
colCheck++;
if (worksheet.GetRow(row).GetCell(colCheck) == null) throw new System.ArgumentException("A valid password is required");
user.Password = GetRequiredValueFromRowOrNull(worksheet, row, cellIndex, nameof(user.Password), exceptionMessage);
cellIndex++;
colCheck++;
if (worksheet.GetRow(row).GetCell(colCheck) != null)
{
user.AssignedRoleNames = GetAssignedRoleNamesFromRow(worksheet, row, cellIndex);
cellIndex++;
}
colCheck++;
I've not refactored the code to be more elegant - but what this does is assume the column values are retreived in order.
Using GetCell, I am able to determine if a column has a value (not null). If it does, I increment the cell being examined (cellIndex) and column I'm checking (colCheck) and continue.
If the column is NULL after getcell, I know the cell has no value. In this case, I increment the column (colCheck) being examined, but do NOT increment the cells index (cellIndex) , since the cells array collapses empty values.
Hope this helps.
A more elegant approach maybe reconstruct the Cells array with a linq statement into a "rowvalues" array, or use the GetCell method.
While not perfect, my current approach is simple, and allows me to tinker while I work up my solution.
Thank you, that did it.
I uninstalled and reinstalled the tool, no luck.
Is there a way to enable debug logging?
RAD Tool logs don't provide any information other than:
DEBUG 2020-09-17 23:03:20,263 [1 ] dioExtension.Dialogs.EntityGeneratorForm - Generate entity started. DEBUG 2020-09-17 23:03:20,460 [1 ] dioExtension.Dialogs.EntityGeneratorForm - Entity successfully generated. DEBUG 2020-09-17 23:06:46,921 [1 ] lVisualStudioExtension.AspNetZeroRadTool - Menu item clicked with params > loadFromJson: False, loadFromDatabase: False, showAboutForm: True
thank you, i'll investigate this.
Figured mine out. It's that int filter issue again with DTOs.
I had one that I didn't set to -1, so every time it did a GetAll on an important entity it was failing.
If you have a filter object, and in your GetAll, you have there WhereIf(input.filterName>-1....)
What happens is the object mapper or something sets these to 0, triggering the filter.
In my case, I have a condition with one filter where another is always true - but because I didn't set the default value to -1, it was passing 0..
In this instance the 0 was asking for a condition that would cause a tenants entire install to go down.
I have to remember these!
My project was working in production, just pushed an update and I'm getting this error now, too.
It's azure, so it's for sure production.
Any tips?
To re-itterate - you cannot change your namespace.
I'm not support.. but...
FWIW - the namespace you pick will propogate into the UI, and you'd have to go and find and replace it.
I made the same mistake, which sucks, as there's not really an easy way.
My suggestion would be to generate your app using a namespace that is very unique - so it's very easy to find in your project.
For example, let's say your app is going to be something common, like the word Filter.
Finding and replacing that would be a nightmare
So I'd suggest you make it something like FilterApp. Then, you can search your project for FilterApp.
It will, of course, come up with all the namespace rows, but you can go through your find in VS and quickly change them.
The name will be sprinkled everywhere. Email templates, work.xml.. etc..
I'm facing the same issue and considered regenerating my project to get a new name, but frankly it's just not worth the effort of moving the code over if you are down the road.
So again, my suggestion is to pick something that you wouldn't normally see in code (c3, css, html, or otherwise). The more unique in the universe, the easier your job will be.
AppFilterBackendNS, or BackendNSFilterApp, or even go with something crazy like AAABBBCCCDDDD, that will make it exceptionally easy to find.
At the end of the day, if you think you're going to need to change your namespace, your release is keyed to your namespace.
If you've already downloaded one, you can do one more. If you haven't, then I strongly recommend using something that would be ok in release or dev, and that follows the guidelines I suggested.
If you're concerned about how your namespace will appear externally, then I'd do something very descriptive. Lets say you work for ATI.. then make something ATIFilterAppNameSpace.
Yeah, a lot to type, but in reality I've not found myself typing my namespace a lot; but that will depend on where you drop your classes and what namespace you put them in.
HTH
BTW - in looking at ABP code - I'm wondering if this is related: