Website won't release file generated with openxml - asp.net

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. :|

Related

Upload large file to Microsoft Access

I am quite new to setup a MS Access data base. Just wondering whether there is a way to upload a coma delimited file with more than 1.5 million rows and ignore the first 3 lines (file header) and the last row (footer).
The header for the content of this file is at the 4th row.
Finally i worked it out myself.
the header and the footer are having different number of columns.
I used line input statement to check each line of the my text file.
Here is my code:
Sub FileUpload_CMP_Funding()
Dim sFile, sText As String
Dim dText As Variant
Dim db As Database
Dim rst As Recordset2
Dim i As Long
sFile = "C:\NotBackedUp\testfile\CMPFUNding.out"
Open sFile For Input As #1
Do While Not EOF(1)
Line Input #1, sText
dText = Empty
dText = Split(vText(i), ",")
'My main content has 24 columns
If UBound(dText) - LBound(dText) + 1 = 24 Then
If dText(0) <> "Product ID" Then 'skip the header row at the 4th rows
Set db = CurrentDb
Set rst = db.OpenRecordset("tblCMP_Funding", dbOpenDynaset)
rst.AddNew
rst!ProductID = Trim(Replace(dText(0), """", ""))
rst!FundID = Trim(Replace(dText(1), """", ""))
""
'Update whatever field is required to be updated
rst.Update
Set db = Nothing
Set rst = Nothing
End If
End If
Loop
Close #1
End Sub
Hope it helps anyone who have same requirement

Open XML SDK Open and Save not working

I am having trouble with the Open XML SDK opening and saving word documents.
I am using the following code (VB.Net):
Try
'Set Path
Dim openPath As String = "../Documents/" & worddoc
Dim savePath As String = "\\web-dev-1\HR_Documents\" & worddoc
Using doc As WordprocessingDocument = WordprocessingDocument.Open("/Documents/" & worddoc, 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 = ddlEmployeeList.SelectedItem.Text
'Save File
'Supervisor Name Insert
'Find second table in document
Dim tbl2 As Table = doc.MainDocumentPart.Document.Body.Elements(Of Table).First()
'First Row in tbl
Dim row2 As TableRow = tbl2.Elements(Of TableRow)().ElementAt(0)
'Find first cell in row
Dim cell2 As TableCell = row2.Elements(Of TableCell)().ElementAt(0)
'Insert selected Employee Name
Dim p2 As Paragraph = cell2.Elements(Of Paragraph)().First()
Dim r2 As Run = p2.Elements(Of Run)().First()
Dim txt2 As Text = r2.Elements(Of Text)().First()
txt2.Text = ddlSupervisorList.SelectedItem.Text
End Using
Return 1
Catch ex As Exception
Return Nothing
End Try
The trouble starts on the first using statement. It throws the following error:
Could not find a part of the path 'C:\Documents\Hourly_Employee_Performance_Review .docx
I have placed the word documents in a folder of the ASP.NET site called Documents. I also have created a public share on the dev server to see if maybe that would help.
The problem is that it doesn't use the supplied path variable. I have gone through the documentation for OPEN XMl SDK but all it talks about is the Using Statement and its need and use for it.
Can anyone tell me, show me, or point to a site that has examples of how to set both the open path and save path?
You need a path to the file which is based on the filesytem, not a URL. You can do that with
Dim openPath As String = Path.Combine(Server.MapPath("~/Documents"), worddoc)
And then to open the file:
Using doc As WordprocessingDocument = WordprocessingDocument.Open(openPath, True)
It appears that you will need to do the same for the location to save to, but you didn't say if "\\web-dev-1" is a different server; if it were that would need other considerations.
(Not tested, some typos may exist. You will need an Imports System.IO.)

Export Crystal Report to PDF in a Loop only works with first

i'm trying to generate a report and export it to pdf in a loop, the report will receive a new parameter in each loop and prompt the client to download a PDF, in other words, the client may need to download 2 or 3 (or more) PDFs at the same time, the problem is that the prompt to accept the download only appears for the first pdf, dont know why. I can export to disk (server side) without any problems.
Code:
Sub PrintReport(ByVal Cod As Integer)
Dim CTableLogInfo As TableLogOnInfo
Dim ConnInfo As CrystalDecisions.Shared.ConnectionInfo = New ConnectionInfo()
ConnInfo.Type = ConnectionInfoType.SQL
ConnInfo.ServerName = ConfigurationManager.AppSettings("SQLSERVERNAME")
ConnInfo.DatabaseName = ConfigurationManager.AppSettings("SQLDBNAME")
ConnInfo.UserID = ConfigurationManager.AppSettings("SQLSERVERUSER")
ConnInfo.Password = ConfigurationManager.AppSettings("SQLSERVERPASSWORD")
ConnInfo.AllowCustomConnection = False
ConnInfo.IntegratedSecurity = False
For Each CTable As Table In CrystalReportSource1.ReportDocument.Database.Tables
CTable.LogOnInfo.ConnectionInfo = ConnInfo
CTableLogInfo = CTable.LogOnInfo
CTableLogInfo.ReportName = CrystalReportSource1.ReportDocument.Name
CTableLogInfo.TableName = CTable.Name
CTable.ApplyLogOnInfo(CTableLogInfo)
Next
Dim pField As ParameterField = CrystalReportSource1.ReportDocument.ParameterFields(0)
Dim val1 As ParameterDiscreteValue = New ParameterDiscreteValue
val1.Value = Cod
pField.CurrentValues.Clear()
pField.CurrentValues.Add(val1)
Dim PDFName As String = "PDF Nº " & Cod
CrystalReportSource1.ReportDocument.ExportToHttpResponse(ExportFormatType.PortableDocFormat, Page.Response, True, PDFName)
End Sub
EDIT:
Tried to zip the reports with DotNetZip but i get an broken zip.
Can you tell me whats wrong? (Solved: code bellow is corrected now)
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/zip"
Response.AppendHeader("content-disposition", "attachment; filename=AllPDFs.zip")
Using zipFile As New ZipFile()
For i = 0 To Cod.Length - 1
If Cod(i) > 0 Then
val1.Value = Cod(i)
pField.CurrentValues.Clear()
pField.CurrentValues.Add(val1)
val2.Value = Cod(i)
pField2.CurrentValues.Clear()
pField2.CurrentValues.Add(val2)
Dim PDFNameAs String = "PDF Nº " & Cod(i) & ".pdf"
Dim s As New System.IO.MemoryStream
s =CrystalReportSource1.ReportDocument.ExportToStream(ExportFormatType.PortableDocFormat)
zipFile.AddEntry(PDFName, s)
End If
Next
zipFile.Save(Response.OutputStream)
End Using
Response.Clear()
Probably the response ends after the first one, therefore there's no response to write to for the 2nd and 3rd attempts.
Instead, you can have the client download the reports via AJAX Request (move your report generation into an .ashx generic handler), or have the user click the button 3 times to initiate new requests.
Or zip the PDF's up until a single file and allow the client to download that.

combining two textbox values

i called a field from mysql into a readonly textarea and i made another textbox to allow users to add fields into the textarea. how do I combine the values from the textbox into the textarea?
an example of what i want to do is:
textarea
15/12: Nothing special today
16/12: another day
17/12: and so on
textbox
this is a new input
Result
15/12: Nothing special today
16/12: another day
17/12: and so on
18/12: this is a new input
The textarea is "log1" and the textbox is "txb1". I'm currently using
log = trim(request.form("log1"))
how do I do something like
log = trim(request.form("log1")) <br> date ": " trim(request.form("txb1"))
assuming date is a string variable, You would want to do the following:
log = trim(request.form("log1")) & "<br>" & [date] & ": " & trim(request.form("txb1"))
also, if date is a DateTime variable, you would want to use date.ToShortDateString() and instead of <br/> i would recommend using Environment.NewLine
and even better, you should use StringBuilder:
Dim SB As New StringBuilder()
SB.AppendLine(trim(request.form("log1")))
SB.AppendLine([date] & ": " & trim(request.form("txb1")))
log = SB.ToString()
UPDATE:
if you want to store the entire log in one record rather than a separate table, you better off saving it as a list of logs into a varbinary(MAX) column.
here is a full example of how to do it:
1. we start by creating a <div> element that will hold our pretty logs and will be handled by the server, and a text box for new logs:
<asp:TextBox ID="txb1" runat="server"></asp:TextBox>
<div id="Text_Div1" runat="server"></div>
2. now in the code behind, we create a class to hold 1 single line of log:
'create a log class and state that it serializable
<Serializable> _
Public Class MyLogRecord
Public Sub New(_msg As String)
[Date] = DateTime.Now
Message = _msg
End Sub
Public Property [Date]() As DateTime
Get
Return m_Date
End Get
Set
m_Date = Value
End Set
End Property
Private m_Date As DateTime
Public Property Message() As [String]
Get
Return m_Message
End Get
Set
m_Message = Value
End Set
End Property
Private m_Message As [String]
Public Function ToText() As String
Return [Date].ToShortDateString() & ": " & Convert.ToString(Message)
End Function
End Class
3. wherever you update the logs, whether its button_click or textbox_keydown, you do the following:
' create a list of logs
Dim MyLogs As List(Of MyLogRecord)
'check if we stored the logs already in the session,
'if yes, retrieve it from the session var,
'if not then create a new one.
If Session("MyLogs") IsNot Nothing Then
MyLogs = DirectCast(Session("MyLogs"), List(Of MyLogRecord))
Else
MyLogs = New List(Of MyLogRecord)()
End If
' create a new log record from the new textbox value
Dim _tempLog As New MyLogRecord(txb1.Text)
'add the new log to the list
MyLogs.Add(_tempLog)
'save it back in a session var:
Session("MyLogs") = MyLogs
4. in the part where you save the logs to the mysql db, you do it this way: first convert the list to a byte array and store it in a varbinary(MAX) column
'create a new binary formatter, include System.Runtime.Serialization.Formatters.Binary;
Dim formatter As New BinaryFormatter()
'create a byte array to store our logs list
Dim _logsBinary As Byte()
'create a memory stream to write the logs list into
Using _logStream As New MemoryStream()
'use the formatter to serialize the list in to an array of bytes
'directly into the memory stream
formatter.Serialize(_logStream, MyLogs)
'dump the memory stream into the byte array
_logsBinary = _logStream.ToArray()
End Using
' ... save the _logsBinary into mysql as a 'varbinary(max)' ...
5. in the place where you retrieve the logs from the mysql db, you de-serialize the byte array back to a logs list:
Dim MyLogs As New List(Of MyLogRecord)()
Dim formatter As New BinaryFormatter()
Using _logStream As New MemoryStream()
_logStream.Write(_logsBinary, 0, _logsBinary.Length)
_logStream.Position = 0
' de-serialize the byte array back into a logs list
MyLogs = DirectCast(formatter.Deserialize(_logStream), List(Of MyLogRecord))
End Using
6. in the place where you write the logs in your page, you do it this way:
Dim SB As New StringBuilder()
' create a temp date to compare against all the records,
' and initialize it with the first value or else you will have
' a orizontal line before the first row
Dim _prevDate As DateTime = MyLogs.First().[Date]
For Each _logRec As MyLogRecord In MyLogs
'take the date of the currently iterrated item and
'compare against the temp date, note that comparing months is not enough,
'month might be same/earlier but year can be higher
Dim _currentDate As DateTime = _logRec.[Date]
If _currentDate.Month > _prevDate.Month OrElse _currentDate.Year > _prevDate.Year Then
'append horizontal line
SB.AppendLine("<hr/>")
'update temp value
_prevDate = _currentDate
End If
'finally append the log: ToText() is the class custom
'function that we created above
SB.AppendLine(_logRec.ToText())
Next
'dump the logs into the server managed div:
Text_Div1.InnerHtml = SB.ToString()

extract attachments from DB to separate folders for each document

Have an assignment to do - it's to extract data from Lotus Notes DB including documents and their attachments. The purpose of this is to put it and store on the Sharepoint as a library.
So far I have managed to create a view and export the data for it to structure in Excel.
Also, I have looked up some Agents examples for extracting the attachments. With implementation of the below script, I managed to export the attachments:
Dim sDir As String
Dim s As NotesSession
Dim w As NotesUIWorkspace
Dim db As NotesDatabase
Dim dc As NotesDocumentCollection
Dim doc As NotesDocument
Sub Initialize
Set s = New NotesSession
Set w = New NotesUIWorkspace
Set db = s.CurrentDatabase
Set dc = db.UnprocessedDocuments
Set doc = dc.GetFirstDocument
Dim rtItem As NotesRichTextItem
Dim RTNames List As String
Dim DOCNames List As String
Dim itemCount As Integer
Dim sDefaultFolder As String
Dim x As Integer
Dim vtDir As Variant
Dim iCount As Integer
Dim j As Integer
Dim lngExportedCount As Long
Dim attachmentObject As Variant
x = MsgBox("This action will extract all attachments From the " & CStr(dc.Count) & _
" document(s) you have selected, And place them into the folder of your choice." & _
Chr(10) & Chr(10) & "Would you like To continue?", 32 + 4, "Export Attachments")
If x <> 6 Then Exit Sub
sDefaultFolder = s.GetEnvironmentString("LPP_ExportAttachments_DefaultFolder")
If sDefaultFolder = "" Then sDefaultFolder = "F:"
vtDir = w.SaveFileDialog( False, "Export attachments To which folder?", "All files|*.*", sDefaultFolder, "Choose Folder and Click Save")
If IsEmpty(vtDir) Then Exit Sub
sDir = StrLeftBack(vtDir(0), "\")
Call s.SetEnvironmentVar("LPP_ExportAttachments_DefaultFolder", sDir)
While Not (doc Is Nothing)
iCount = 0
itemCount = 0
lngExportedCount = 0
Erase RTNames
Erase DocNames
'Scan all items in document
ForAll i In doc.Items
If i.Type = RICHTEXT Then
Set rtItem = doc.GetfirstItem(i.Name)
If Not IsEmpty(rtItem.EmbeddedObjects) Then
RTNames(itemCount) = CStr(i.Name)
itemCount = itemCount +1
End If
End If
End ForAll
For j = 0 To itemCount-1
Set rtItem = Nothing
Set rtItem = doc.GetfirstItem(RTNames(j))
ForAll Obj In rtItem.EmbeddedObjects
If ( Obj.Type = EMBED_ATTACHMENT ) Then
Call ExportAttachment(Obj)
Call doc.Save( False, True )
'creates conflict doc if conflict exists
End If
End ForAll
Next
'Scan all items in document
ForAll i In doc.Items
If i.Type = ATTACHMENT Then
DOCNames(lngExportedCount) = i.Values(0)
lngExportedCount = lngExportedCount + 1
End If
End ForAll
For j% = 0 To lngExportedCount-1
Set attachmentObject = Nothing
Set attachmentObject = doc.GetAttachment(DOCNames(j%))
Call ExportAttachment(attachmentObject)
Call doc.Save( False, True )
'creates conflict doc if conflict exists
Next
Set doc = dc.GetNextDocument(doc)
Wend
MsgBox "Export Complete.", 16, "Finished"
End Sub
Sub ExportAttachment(o As Variant)
Dim sAttachmentName As String
Dim sNum As String
Dim sTemp As String
sAttachmentName = sDir & "\" & o.Source
While Not (Dir$(sAttachmentName, 0) = "")
sNum = Right(StrLeftBack(sAttachmentName, "."), 2)
If IsNumeric(sNum) Then
sTemp = StrLeftBack(sAttachmentName, ".")
sTemp = Left(sTemp, Len(sTemp) - 2)
sAttachmentName = sTemp & Format$(CInt(sNum) + 1, "##00") & _
"." & StrRightBack(sAttachmentName, ".")
Else
sAttachmentName = StrLeftBack(sAttachmentName, ".") & _
"01." & StrRightBack(sAttachmentName, ".")
End If
Wend
Print "Exporting " & sAttachmentName
'Save the file
Call o.ExtractFile( sAttachmentName )
End Sub
So the issue I do have right now is that these attachments are being saved to the same folder, which means that I would manually have to put them into right folders of library (several thousands). Could anyone help on how should I change the above code to have the attachments saved to separate folder for each document from DB?
Also for some reason that I cant find out below line is causing error pop up with "Object Variable not set":
sAttachmentName = sDir & "\" & o.Source
Would anyone know why it causes failure and stops the whole process?
You need to use the MkDir statement to create directory and extract attachments in the folder. Probably write something like:
MkDir sDir
You need to write code that create a new directory for each document (make sure you check if the directory exists, and preferably you make sure each directory has a unique name).
I wrote a tool like that, that exports all the fields of a document into XML, as well as attachments and embedded images. It can be set to separate each document into it's own directory.
You can read more about it ate the link below, perhaps you can get some ideas from the description. I use the UniversalID of teh document to get a unique folder name.
http://www.texasswede.com/websites/texasswede.nsf/Page/Notes%20XML%20Exporter

Resources