Conditionally uploading Excel SpreadSheet using FileUpload - asp.net

Below Is my Vb Code which is getting the row count of the excel file. However, i want to throw an exception and give an error message if the row count is greater than 10k rows. How would i be able to do that? I have done my research on getting the row count but not sure how to throw an exception. The following is an ASP.Net Windows Form Application.
Dim xls As New Excel.Application
Dim sheet As Excel.Worksheet
Dim filePath As String = Path.Combine(GlobalVariable.savedPath, GlobalVariable.excelFileName)
xls.Workbooks.Open(filePath)
sheet = xls.ActiveWorkbook.Sheets(1)
Dim maxSize As Integer = 2
Dim row As Integer = 1
Do Until sheet.Cells(row, 1).value Is Nothing
row += 1
Loop
MsgBox("last Row is " & row - 1)
xls.Workbooks.Close()
xls.Quit()
releaseObject(sheet)
releaseObject(xls)

You are already counting the rows, so you can modify your loop to continue only while row is less then 10,000.
Dim row As Integer = 1
Do
row += 1
Loop while sheet.Cells(row, 1).value IsNot Nothing AndAlso row <= 10000
This will loop, incrementing row until there are no more rows, or if you hit 10,000. You can then check if row is 10,000 to decide if you want to show an error message.
If row >= 10000 then
MsgBox("Over 10000 rows")
'If you want to throw an actual exception you can do:
Throw new Exception("Over 10000 rows")
Else
MsgBox("last Row is " & row - 1)
End If
Updated to reflect OP Question Updates:
I don't know if I would recommend throwing an exception to handle if row reaches 10,000. Instead I would do like so:
Private Sub BtnUpload_OnClick(sender As Object, e As EventArgs) Handles BtnUplaod.Click
REM Save SpreadSheet
Dim filePath As String = Path.Combine(GlobalVariable.savedPath, GlobalVariable.excelFileName)
myfileUploader.saveAs(filePath)
REM Open SpreadSheet
Dim xls As New Excel.Application
Dim sheet As Excel.Worksheet
xls.Workbooks.Open(filePath)
sheet = xls.ActiveWorkbook.Sheets(1)
Dim maxSize As Integer = 2
REM Loop through spreadsheet and count rows
Dim row As Integer = 1
Do
row += 1
Loop While sheet.Cells(row, 1).value IsNot Nothing AndAlso row <= 10000 'Exit loop when end of SpreadSheet is reached or if rows exceeds 10,000
REM Release Resources
xls.Workbooks.Close()
xls.Quit()
releaseObject(sheet)
releaseObject(xls)
REM Decide whether to accept upload, or reject and show error
If row >= 10000 Then 'If row > 10000 delete file and show error
REM Delete the file
File.Delete(filePath)
REM Show some sort of error to user - Its up to you how you want to do so. That is a seperate question
MsgBox("Your Error")
REM Else SpreadSheet is valid
Else
'Your Code code doing what you want with spreadsheet goes here
MsgBox("last Row is " & row - 1)
End If
End Sub
This code will run when the users clicks a button called BtnUpload on the WebPage. You can put it anywhere you like though.
I think this is what you want. Is that correct?

Related

Excel column values being appended as rows instead of columns into datatable

I have an Excel file which I need to read through and extract particular values of a certain range into a datatable so I can then save that data into a table in a database.
Whilst debugging, on every loop I check the datatable visualizer to see what's going on and I find that I'm appending values of a different row, to the same row. Example in photo.
SamplePhoto
Here is the code responsible for that action.(Surrounded in a Try-Catch)
Using excel As New ExcelPackage (ulTarget.PostedFile.InputStream)
Dim _worksheet = excel.Workbook.Worksheets.First()
Dim _hasHeader = True
For Each cell In _worksheet.Cells(1,2,147,4)
_dataTable.Columns.Add(If(_hasHeader, cell.Value, String.Format("{0}", cell.Start.Column)))
If _worksheet.Cells.Value Is Nothing Then
Continue For
Next
Assume that the range 1,2,147,4 is correct as the data going into the datatable is correct, the row seperation is simply the problem. _dataTable is my DataTable (obvious I know but nothing bad in clarifying it) and _hasHeader is set to True because the Excel worksheet being uploaded has headers and I don't want them being put into the DataTable because the data will all end up in a table in SQL Server where appropriate column names exist.
Also ulTarget is my File uploader. I am using EPPlus most recent version for this.
Anybody have any suggestions as to how I can seperate the data into rows as per the example in the photo above? Happy to make any clarifications if needed.
Added the horizontal range of the columns without headers and read each cell row by row.
Using excel As New ExcelPackage(ulTargetFile.PostedFile.InputStream)
'Add the columns'
Dim _worksheet = excel.Workbook.Worksheets.First()
Dim _hasHeader As Boolean = False
For Each col In _worksheet.Cells("B1:D1")
_dataTable.Columns.Add(If(_hasHeader, Nothing, col.Value))
String.Format("{0}", col.Start.Column)
Next
'Add the rows'
For rowNumber As Integer = 1 To 147
Dim worksheetRow = _worksheet.Cells(rowNumber, 2, rowNumber, 4)
Dim row As DataRow = _dataTable.Rows.Add()
For Each cell In worksheetRow
row(cell.Start.Column - 2) = cell.Value
Next
Next

Exit loop and continue to next line when first empty cell is found

I need to be able to loop through an Excel worksheet and at the first null or empty value I'd like the loop to exit and to continue to the next line.
'Add the rows'
For Each cell In worksheetRow
If cell.Value Is Nothing Then
For index = _dataTable.Rows.Count - 1 To 0
Dim deleteRow = _dataTable.Rows(index)
If _dataTable.Rows.Contains("NULL") Then
deleteRow.Delete()
End If
Next
GoTo executeInsert
Else
row(cell.Start.Column - 2) = cell.Value.ToString.Trim()
End If
Next cell
Next
executeInsert: Try
Company.Applications.ProductionEngine.BusinessAccess.BankTargetsConfigurationBusinessAccess.ExecuteLoadFileData(_dataTable, _year)
The problem is that the For Each loops through each cell. So on the first empty cell it finds, it proceeds onto the next empty cell and so on.
This is the result that is inserted into the table.
New Table
Up until row 13, at the first null occurence, I want to exit the loop and go to my next line of code which is responsible for saving what the loop gathered so far which is up until the far right cell with value '2018' on row 12.
For the sake of completeness, this is the next block of code that connects to the database and saves the data. This is where I need to go after I find the first null occurence.
Try
Company.Applications.ProductionEngine.BusinessAccess.BankTargetsConfigurationBusinessAccess.ExecuteLoadFileData(_dataTable, _year)
Catch ex As Exception
'The data insert failed'
InformationBox1.ShowErrorMessage("An internal error occured. Please refresh the page and try again.")
End Try
InformationBox1.ShowSuccessMessage("Data Uploaded")
I have tried this and it works. Problem is if something is added to the worksheet later and the rows become 148, this won't help.
For rowNumber As Integer = 1 To 147
Dim worksheetRow = _worksheet.Cells(rowNumber, 2, rowNumber, 4)
Dim row As DataRow = _dataTable.Rows.Add()
For Each cell In worksheetRow
row(cell.Start.Column - 2) = cell.Value.ToString.Trim()
Next
Next
I have also tried this but the rows don't increment. Each row from the worksheet is read and added to the first row, each record overwrites the previous one, so here there is always one row.
Dim rowCounter As Integer = 0
While rowCounter < _worksheet.Dimension.End.Row
Dim worksheetRow = _worksheet.Cells(1, 2, _worksheet.Dimension.End.Row, 4)
Dim row As DataRow = _dataTable.Rows.Add()
For Each cell In worksheetRow
If cell.Value IsNot Nothing Then
row(cell.Start.Column - 2) = cell.Value.ToString.Trim()
End If
rowCounter += 1
Next
End While
And finally, I've tried a Do Loop. I get the same result as the While Loop above.
Do
Dim worksheetRow = _worksheet.Cells(1, 2, _worksheet.Dimension.End.Row, 4)
Dim row As DataRow = _dataTable.Rows.Add()
For Each cell In worksheetRow
row(cell.Start.Column - 2) = cell.Value.ToString.Trim()
Next
Loop Until _worksheet.Cells.Value = ""
For any clarifications please let me know.
It's kind of difficult to understand what exactly you're trying to achieveso I'm having to go with the presumption your variables such as worksheet row are correctly defined...
Also, you have an error in your code. .Start is not a property of a
range object (cell.Start.Column - 2) in your code. This will result
in an error I can't correct given you haven't provided your input data
nor expected result.
I presumed you're trying to offset the column by 2 to the right, but change it accordingly to what you're trying to achieve
Same goes for .ToString which is not a Range object method in VBA. Unless you have them somewhere defined in your own class properties and have not included it in your code here. Just like with offset, sounds like you're trying to utilize the CStr() function here, but once again, with no expected output I can only be guessing here.
Either way, those are small potential errors you should be able to take care of yourself. In general, your loop should look something like this:
For each cell in worksheetRow
If IsEmpty(Cell) Then
Exit For ' this will exit the entire for loop after reachign an empty cell
End If
row.Offset(0, -2) = CStr(Trim(cell.Value))
Next cell
In case you want to skip empty cell, instead of exiting the entire for loop, use a secondrary dowhile loop in your cell that would act as an continue - example found in this stack question: Continue For loop
Did it guys. Just needed to delete the particular row if it contained Nothing.
Here's the final code.
For rowNumber As Integer = 1 To _worksheet.Dimension.End.Row
Dim worksheetRow = _worksheet.Cells(rowNumber, 2, rowNumber, 4)
Dim row As DataRow = _dataTable.Rows.Add()
For Each cell In worksheetRow
If cell.Value Is Nothing Then
row.Delete()
GoTo executeInsert
Else
row(cell.Start.Column - 2) = cell.Value.ToString.Trim()
End If
Next cell
Next
//executeInsert is the connection/insert data method
Thanks all for your help.
I am not sure, but maybe you could just do something like:
For Each cell In rng
' do some stuff
If myCondition Then GoTo exitFor
Next cell
exitFor:

Website won't release file generated with openxml

Here is the situation:
Asp.Net Web Forms site using Open XML to read in a (via a stream) word document (docx). I then insert some text into the document and then write the file back out to a different location. It is then emailed to an end user. All of this works great.
The problem i am running into is that I can't the new file written by the site. I receive the following error:
"The process cannot access the file (file name here) because it is being used nt another process"
I have confirmed that it is the site (or IIS) that is holding on to the file.
Here is the code that reads the original file and generates the new file:
Private Function GetDocument(worddoc As String) As Integer
Dim byteArray As Byte() = File.ReadAllBytes("\\WEB-DEV-1\HR_Documents\" & worddoc)
Using Stream As New MemoryStream()
Stream.Write(byteArray, 0, CInt(byteArray.Length))
Try
'Set Row & Cell variables
Dim rowNum As Integer = 0
Dim cellNum As Integer = 0
'Set File Stream
Using doc As WordprocessingDocument = WordprocessingDocument.Open(Stream, True)
'Employee Name Insert
'Find first table in document
Dim tbl1 As Table = doc.MainDocumentPart.Document.Body.Elements(Of Table).First()
'First Row in tbl
Dim row As TableRow = tbl1.Elements(Of TableRow)().ElementAt(0)
'Find first cell in row
Dim cell As TableCell = row.Elements(Of TableCell)().ElementAt(0)
'Insert selected Employee Name
Dim p As Paragraph = cell.Elements(Of Paragraph)().First()
Dim r As Run = p.Elements(Of Run)().First()
Dim txt As Text = r.Elements(Of Text)().First()
txt.Text = "Employee Name: " & ddlEmployeeList.SelectedItem.Text
'Supervisor Name Insert
'Check for form
If ddlFormChoice.SelectedIndex <> 2 Then
'Reset row to supervisors row in table
row = tbl1.Elements(Of TableRow)().ElementAt(1)
ElseIf ddlFormChoice.SelectedIndex = 2 Then
'Reset row to supervisors row in table
row = tbl1.Elements(Of TableRow)().ElementAt(2)
End If
If ddlFormChoice.SelectedIndex <> 2 Then
'Reset cell to supervisor cell in row
cell = row.Elements(Of TableCell)().ElementAt(1)
ElseIf ddlFormChoice.SelectedIndex = 2 Then
'Reset cell to supervisor cell in row
cell = row.Elements(Of TableCell)().ElementAt(0)
End If
'Insert selected Employee Name
p = cell.Elements(Of Paragraph)().First()
r = p.Elements(Of Run)().First()
txt = r.Elements(Of Text)().First()
If ddlFormChoice.SelectedIndex <> 2 Then
txt.Text = "Supervisor: " & ddlSupervisorList.SelectedItem.Text
ElseIf ddlFormChoice.SelectedIndex = 2 Then
txt.Text = "Manager/Supervisor: " & ddlSupervisorList.SelectedItem.Text
End If
doc.Close()
End Using
'Save File to temp location
File.WriteAllBytes("\\WEB-DEV-1\HR_Documents\TempDocs\" & worddoc, Stream.ToArray())
Stream.Close()
Stream.Dispose()
Return 1
Catch ex As Exception
Return Nothing
End Try
End Using
End Function
I close the OpenXML doc and the stream as well dispose of the stream but when I try to delete the file from the main sub that called the function I get the error listed above.
What am I missing?? I closed the doc, the stream and disposed of the stream. Why is the site still holding the file?
Note here the line of code that trys to delete the file;
File.Delete("\\Web-Dev-1\HR_Documents\TempDocs\" & fileAttach)
So after most of the day i finally found out what the problem was. After the document was created, saved , and emailed it was being held by the email method. For some reason i thought that when the method finishes that it disposed of the Mail Message but this not the case.
Once I added the dispose line it all worked fine.
Only been Googling for almost two days. :|

How to compare row values of two gridviews with dropdownlist column in asp.net?

I have two gridviews. The first one has a dropdownlist. When a user clicks a button named 'Show' data will be displayed on both gridviews where data comes from database. The row data on column with dropdownlist must be compared to the rows on the first column of the second gridview. If they are equal a messagebox will prompt saying that there's no changes and data will not be saved, else if they are not equal modal pop-up will be displayed asking if data are correct.
Below is my code for comparing but it only reads the value of the 1st row in gridview1.
For i = 0 To GridView1.Rows.Count - 1
Dim ddl As DropDownList = DirectCast(GridView1.Rows(i).Cells(6).FindControl("dropdowncriteria"), DropDownList)
Dim txt As TextBox = DirectCast(GridView1.Rows(i).Cells(7).FindControl("txtreason"), TextBox)
If ddl.SelectedValue = GridView2.Rows(i).Cells(0).Text And txt.Text = GridView2.Rows(i).Cells(1).Text Then
MessageBox("No Changes Made! Nothing will be Saved.")
Return
Else
lblmsg.Text = "Are you sure that all the Data you've Selected/Entered are Correct?"
mdlpopupmsg.Show()
Return
End If
Next
What must be the problem on this?
Thanks in advance.
It only reads the first value (i=0) because the return statements cause the for loop to exit after the first comparison. If you want to compare all the rows you will need a variable to keep track of the result of the if test for each row. Something like this:
Dim hasChanges As Boolean = False
For i = 0 To GridView1.Rows.Count - 1
...
If ddl.SelectedValue = GridView2.Rows(i).Cells(0).Text And txt.Text = GridView2.Rows(i).Cells(1).Text Then
'do nothing
Else
hasChanges = True
End If
Next
If hasChanges Then
MessageBox("Has changes.")
Else
MessageBox("No changes.")
End If
Dim itemt As Double
If (DataGridCart.RowCount() > 0) Then
For i = 0 To DataGridCart.Rows.Count - 1
'if itemt as double
itemt = Val(Trim(txtItem.Text))
If ((DataGridCart.Rows(i).Cells("Item").Value).Equals(itemt)) Then
MsgBox("existing entry")
End If
Next
End If

webform multi column single row SQL Server result to vb variables

Ive looked through a few questions on here today and think I'm going round in circles.
My webform has a number of elements including username which is a drop down list (populated by a SQL statement)
On submit of the form i would like the code behind aspx.vb file run a select top 1 query and return a single row of data with 4 columns.
The returned SQL query result 4 columns would only be used later in the aspx.vb file so i want to assign each of the columns to a variable. I'm struggling with this task and assigning the variable the column result from the query.
Protected Sub submitbtn_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles submitbtn.Click
Dim connString1 As String = System.Configuration.ConfigurationManager.ConnectionStrings("ConnectionString").ToString
Dim conn As New SqlConnection(connString1)
Dim sql1 As String = ""
Dim col1h As String = ""
Dim col2r As String = ""
Dim col3title As String = ""
Dim col4UQN As String = ""
sql1 = "SELECT TOP 1 col1h,col2r,col3title, col4UNQ from tblDistinctUserOHR where colID_Username= '" + username + "' "
Dim cmd1 As New SqlCommand(sql1, conn)
'open the connection
'run the sql
'the result will always be found but in case its not some form of safety catch (the variables stay as empty strings
'assign the results to the variables
'close connections
'lots of other code
End Sub
could someone point me in the right direction to run the SQL and assign the result to the the variables. I've been reading about ExecuteScalar() and SqlDataReader but that doesn't seem to be the correct option as the only examples I've found handle a single result or lots of rows with a single column
Thanks for any samples and pointers.
Try this:
Dim da As New OleDb.OleDbDataAdapter(sql1, conn)
Dim dt As New DataTable
da.Fill(dt)
If dt.Rows.Count < 0 Then
col1h = dt.Rows(0).Item("col1h")
col2r = dt.Rows(0).Item("col2r")
col3title = dt.Rows(0).Item("col3title")
col4UQN = dt.Rows(0).Item("col4UQN")
Else
'No rows found
End If

Resources