Currently, we have this VB script in SSIS on a ForEach Loop:
Public Sub Main()
Dim url, destination As String
destination = Dts.Variables("DestinationPath").Value.ToString + Dts.Variables("NomFichier").Value.ToString
url = "http://XXXXXX/ReportServer_RS/Pages/ReportViewer.aspx?XXXXXX&rs:Command=Render&P_CodeAffilie=" + Dts.Variables("CodeAffilie").Value.ToString + "&P_NumeroMouvement=" + Dts.Variables("NumeroMouvement").Value.ToString + "&rs:Format=EXCEL"
SaveFile(url, destination)
Dts.TaskResult = ScriptResults.Success
End Sub
But when it bugs, we can't find the reason of the error.
So, I thought of adding a code that generate a log file.
Into this log file it will store the script before the execution.
Like that, when it will bug, I can open the log file and see at which step it has bugged.
How can I do that please?
Thanks.
I would encourage you to use the native logging mechanics of SSIS which is raising events. The runner/invoker of packages can then decide what, how, and where it logs the data. By default an Information event is perfect for this task.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.dts.runtime.idtsinfoevents.fireinformation?view=sqlserver-2019
Apologies on probably incorrect VB.NET It has been a while and I am freehanding this code.
Public Sub Main()
Dim url, destination As String
Dim errTemplate As String = "{0} -> {1}"
Dim fireAgain As Boolean = False
' Not sure on the syntax here, too lazy to google
' Enumerate through the Variables collection
' Raise information event for each variable found
For Each item As Variable in Dts.Variables
Dts.Events.FireInformation(0, "SCR SSRS thing", String.Format(errTemplate, item.QualifiedName, item.Value), "", 0, ByRef fireAgain)
Next
destination = Dts.Variables("DestinationPath").Value.ToString + Dts.Variables("NomFichier").Value.ToString
url = "http://XXXXXX/ReportServer_RS/Pages/ReportViewer.aspx?XXXXXX&rs:Command=Render&P_CodeAffilie=" + Dts.Variables("CodeAffilie").Value.ToString + "&P_NumeroMouvement=" + Dts.Variables("NumeroMouvement").Value.ToString + "&rs:Format=EXCEL"
' Log the destination
Dts.Events.FireInformation(0, "SCR SSRS thing", String.Format(errTemplate, "destination", destination), "", 0, ByRef fireAgain)
' Log the url
Dts.Events.FireInformation(0, "SCR SSRS thing", String.Format(errTemplate, "url", url), "", 0, ByRef fireAgain)
' We know this might blow up, so put some error handling
try
SaveFile(url, destination)
catch ex As Exception
' TODO better error handling
Dts.Events.FireInformation(0, "SCR SSRS thing", String.Format(errTemplate, "Exception thrown", ex), "", 0, ByRef fireAgain)
Dts.Events.FireInformation(0, "SCR SSRS thing", String.Format(errTemplate, "Exception thrown", ex.InnerException), "", 0, ByRef fireAgain)
end try
Dts.TaskResult = ScriptResults.Success
End Sub
Assuming that all worked, every time the Script Task runs, it's going to dump the values of all the SSIS Variables that have been passed in as read or write values as well as dumps the local variables url and destination.
Personally, I like that level of information being generated on successful and non-successful runs as I can compare what the previous loop looked like and compare it to the failing one.
But, if you find that's too much diagnostic noise, move all the FireInformation events into the error handler (Catch block) and when it goes boom, you'll get a lovely set of recorded values to debug against.
Related
first of all: I'm a newbie in this forum and not a professional programmer, just hobby.
This is what I have: One solution in VisualStudio with 3 Projects in VB.net.
First project contains common functions etc.
Second project is a windows service.
Third project is a Windows Forms UI.
Second an third project imports the first project.
My problem: When the service from second project is running and UI from third project is started I want to set a variable (e.g. by pressing a button) that will be set in the service, too. So the service is informed to do some special things.
I've tried to declare this variable in the common project, but this doesn't work. After searching a bit I know now this can't work, because the service and the UI are seperate processes.
There are several solutions to communicate between processes, e.g. IPC, shared memory, named pipes....
But isn't there a simple way to solve my problem ?
Thanks a lot and with best regards,
Matthias
OK, thanks for your answers!! :-)
I decided to try it with memory mapped file.
This is my making function:
Public Function MakeMemoryMappedFile(ByVal pValue As String) As String
Dim Buffer As Byte() = ASCIIEncoding.ASCII.GetBytes(pValue)
Try
Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateOrOpen("test", 10000)
Dim accessor As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
accessor.Write(54, CType(Buffer.Length, UShort))
accessor.WriteArray(54 + 2, Buffer, 0, Buffer.Length)
Return "ok"
Catch ex As Exception
Return "Error = " & ex.Message
End Try
End Function
And this is my reading function:
Public Function ReadMemoryMappedFile() As String
Try
Dim mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("test")
Dim accessor As MemoryMappedViewAccessor = mmf.CreateViewAccessor()
Dim Size As UShort = accessor.ReadUInt16(54)
Dim Buffer As Byte() = New Byte(Size - 1) {}
accessor.ReadArray(54 + 2, Buffer, 0, Buffer.Length)
Return ASCIIEncoding.ASCII.GetString(Buffer)
Catch noFile As FileNotFoundException
Return "No File found ..."
Catch ex As Exception
Return "Error = " & ex.Message
End Try
End Function
I have on my application a button for setting the value and one button for reading the value -> works fine.
If I start this application twice and set the value in the first instance and then read the value from the second instance -> it works fine.
But: If I set the value in the application my windows service can't read ist. Always got a "FileNotFoundException".
Could you please tell me whats wrong ?!?
Thanks !!!
I really can not understand why the exception is triggered.
I created this code that performs some checks for the correctness of the license.
The function isittrial occurs if the trial software is creating a hidden file, this file is then checked with File.exist.
The problem is the following:
the file is created by isittrial but for some strange reason you enable the exception of file.exist, what can I do to fix it?
I really can not understand why it does not work.
isittrial() 'this function make the file to check
Dim percorsoCompleto As String = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\Software\cc.txt"
Try
If My.Computer.FileSystem.FileExists(directory) Then
Dim fileReader As String
Dim dire As String = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\Software\cc.txt"
fileReader = My.Computer.FileSystem.ReadAllText(directory,
System.Text.Encoding.UTF32)
Dim check = DeCryptIt(fileReader, "aspanet")
Dim datadecripted As String = DeCryptIt(Registry.GetValue("HKEY_CURRENT_USER\Software\cc", "end", ""), "aspanet")
If Date.Now < check And check <> datadecripted Then
MsgBox("License not valid", MsgBoxStyle.Critical, "Attention!")
DeActivate()
ForceActivation()
Else
End If
Else
MsgBox("License not valid", MsgBoxStyle.Critical, "Attention!")
DeActivate()
ForceActivation()
End If
Catch ex As Exception
MsgBox("License not valid", MsgBoxStyle.Critical, "Attention!")
'DeActivate()
'ForceActivation()
End Try
This line
If My.Computer.FileSystem.FileExists(directory) Then
seems to test for the existence of a file passing the name of a directory (or an empty string or whatever, we can see how this variable is initialized). In every case the result will be false.
Then your code jumps to an else block with the same error message of the exception fooling your perception of the error.
Try instead
Dim percorsoCompleto As String = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
percorsoCompleto = Path.Combine(percorsoCompleto, "Software", "cc.txt")
Try
If My.Computer.FileSystem.FileExists(percorsoCompleto) Then
Dim fileReader As String
fileReader = My.Computer.FileSystem.ReadAllText(percorsoCompleto,
System.Text.Encoding.UTF32)
.....
Notice that I have removed the path concatenation with a more fail safe call to Path.Combine
I have been staring at this problem all day and I'm completely baffled by what I'm seeing.
There are two issues occurring, and unfortunately, one of them only happens in Production so I can't test it the way I'd like.
I will give all the background and relevant information up front with the code at the end. Some of what I say in these next couple sections won't make much sense until you review the code.
Background info:
(I have triple verified all this information)
This class is being called from a TFS 2010 WWF build template. It relies on a library I've created in another tool to deploy files to our Universe environment using UniDK
The deployment itself is working fine, the problem is with the logging and return codes.
The build is marked as "Success" if the class below returns a code of 0, "Partial Success" with a return code of 1, and "Failed" if there is any other return code.
The files are only being deployed one time (objDeploy.DeployFiles() is only called once)
serverInfo.ServerCount = 2
serverInfo.ServerActive for the second environment (counter = 1) is False
To help track down the issues, I have added additional logging in ProcessResults() to output the values of the different collections to a separate file, but I haven't had an opportunity to run it with the additional code
Symptoms:
In Production, it is exiting with a return code of 1 (exitCode = 1)
This is what is returned by the results string:
Results for server name Deployment successful!
*********************** Results for server name Deployment successful!
*********************** Results for server name Deployment errors, please review the log
*********************** Results for server name Deployment successful!
*********************** Results for server name Deployment successful!
***********************
3. In QA, we have the "results for server name" message 6 times, but each time says the deployment is successful
4. Everything in the deployment log file shows that all files deployed returned with a code of 0 (This means that Result40Collection, BackupErrorCollection, and BadErrorCollection should be empty. I will explain in a moment why this is especially significant)
What I expect to happen:
exitCode = 0
Build = succeeded
results:
Results for server name Deployment successful!
***********************
What I expect to happen based on the results in the TFS build log:
In this section, I'm ignoring the fact that there are multiple entries being returned and only focusing on the one that says there were errors
exitCode = 2
Build = Failed
results:
Results for server name Deployment errors, please review the log
***********************
Code:
Imports System
Imports Microsoft.TeamFoundation.Build.Client
Imports System.Activities
Imports RMUtilities
<BuildActivity(HostEnvironmentOption.All)>
Public NotInheritable Class DeployU2Files
Inherits CodeActivity
#Region "Arguments"
' In Arguments
Property inServerDataSet As InArgument(Of DataSet) ' Dataset containing the server information
Property inSourcesDirectory As InArgument(Of String) ' Full path to the Source directory being deployed
Property inBuildName As InArgument(Of String) ' Name of the build, to be used for backups
Property inLogDirectory As InArgument(Of String) ' Path to the log folder
' Out Arguments
Property outExitCode As OutArgument(Of Integer) ' Resulting error code, 0 is good
Property outResult As OutArgument(Of String) ' Result string
#End Region ' "Arguments"
#Region "Variables"
' Variables passed in from the build
Dim dsServerDataSet As DataSet
Dim strSourcesDirectory As String
Dim strBuildName As String
Dim strLogDirectory As String
' Variables used by the build
Dim serverInfo As XMLReader
Dim fileList As U2FileListParser
' Result variables
Dim exitCode As Integer = 0
Dim results As String = ""
#End Region '"Variables"
Protected Overrides Sub Execute(context As System.Activities.CodeActivityContext)
' Sets the working variables
dsServerDataSet = context.GetValue(Me.inServerDataSet)
strSourcesDirectory = context.GetValue(Me.inSourcesDirectory)
strBuildName = context.GetValue(Me.inBuildName)
strLogDirectory = context.GetValue(Me.inLogDirectory)
' Creates the base objects needed for the deployment
Try
serverInfo = New XMLReader(dsServerDataSet)
fileList = New U2FileListParser(strSourcesDirectory)
Catch ex As NullReferenceException
Throw New NullReferenceException("Invalid XML Dataset", ex)
Exit Sub
Catch ex As Exception
Throw New Exception("Error processing file list: " & ex.Message, ex)
End Try
' First, determine if there are files to deploy
Dim fileCount As Integer
Try
With fileList
fileCount = .DeployList.Count + .PreDeployList.Count + .PostDeployList.Count
End With
Catch ex As Exception
Throw New ArgumentException("No files to deploy")
End Try
If fileCount = 0 Then Throw New ArgumentException("No files to deploy")
' Then, check to make sure there are servers to deploy to
If serverInfo.ServerCount = 0 Then
Throw New ArgumentException("No servers listed in XML file to deploy to")
End If
' Iterates through each server in the XML file
For counter = 0 To serverInfo.ServerCount - 1
' Sets the current environment
serverInfo.ChosenEnvironment = counter
' Checks to make sure the server is active. If it isn't, it's skipped
If serverInfo.ServerActive Then
' Creates new logging object to log all output to a file with the name of the server being deployed to
Dim logger = New RMLogging(strLogDirectory & "\" & serverInfo.ServerHostName & ".log")
logger.Header = "Automated deploy" & vbCrLf & _
"Build Number: " & strBuildName & vbCrLf & _
"Date: " & DateTime.Now.ToString("MMM ddd d yyyy hh:mm:ss tt")
' Creates the deployment object
Dim objDeploy As New U2Deploy(serverInfo, fileList, logger, strBuildName)
' Deploys the files to the environment, then checks the results to make sure they
objDeploy.DeployFiles()
' This will determine the success level of the deployment, and also parses the message for the log
ProcessResults(objDeploy, serverInfo.ServerHostName)
' If there was a problem writing the log, then add the full text of the log to the results
If objDeploy.FullLog.Length > 0 Then
results &= objDeploy.FullLog & vbCrLf
results &= "**********************************" & vbCrLf
End If ' objDeploy.FullLog.Length > 0
' Disposes the objects
logger = Nothing
objDeploy.Clear()
objDeploy = Nothing
End If ' serverInfo.ServerActive
Next ' counter = 0 To serverInfo.ServerCount - 1
SetResults(exitCode, results, context)
End Sub
''' <summary>
''' Will change the exite code based on the results of the deployment
''' </summary>
''' <param name="objDeploy">U2Deploy object that contains the collections</param>
''' <remarks></remarks>
Private Sub ProcessResults(objDeploy As U2Deploy, serverName As String)
Dim currentErrorCode As Integer = 0
results &= "Results for " & serverName & vbCrLf
If objDeploy.Result40Collection.Count() > 0 Then
currentErrorCode = 1
results &= "Type 40 errors, please review the log" & vbCrLf
End If ' objDeploy.Result40Collection.Count() > 0
If objDeploy.BackupErrorCollection.Count > 0 Then
currentErrorCode = 1
results &= "File backup errors, please review the log" & vbCrLf
End If ' objDeploy.BackupErrorCollection.Count > 0
If objDeploy.BadErrorCollection.Count > 0 Then
currentErrorCode = 2
results &= "Deployment errors, please review the log" & vbCrLf
End If
If currentErrorCode = 0 Then results &= "Deployment successful!" & vbCrLf
results &= "***********************" & vbCrLf
If currentErrorCode > exitCode Then exitCode = currentErrorCode
End Sub
' Sets the outgoing message and exit code. This is used by the workflow to add messages to the buld itself
Private Sub SetResults(ByVal exitCode As Int32, message As String, ByRef context As CodeActivityContext)
context.SetValue(Me.outExitCode, exitCode)
context.SetValue(Me.outResult, message)
End Sub
End Class
UPDATE:
I've been able to run this in QA twice with verbose logging turned on, and here are the results (Again, totally inconsistent). I am using VS2013 only to view and run the builds, any code changes to the classes used by the build are done within VS2010.
Run 1:
Run 2:
I actually just had a resolution to this last night. The problem was actually with the documentation I had read on the WWF process. This code was actually executing properly, and returned the proper values, but because of the incorrect instructions, it was taking the wrong path in the workflow, which made it appear that this code was wrong.
It took me a while for this error to occur again with the diagnostic logging turned on, and once I saw it, I knew immediately what the problem was.
The root cause was that I was under the impression that WriteBuildError would mark the build as Failed, instead it marked it as Partially Succeeded, which put me on the wrong troubleshooting path.
Is there a method to verify that a file is open? The only thing I can think of is the Try/Catch to see if i can catch the file-open exception but I figured that a method be available to return true/false if file is open.
Currently using System.IO and the following code under class named Wallet.
Private holdPath As String = "defaultLog.txt"
Private _file As New FileStream(holdPath, FileMode.OpenOrCreate, FileAccess.ReadWrite)
Private file As New StreamWriter(_file)
Public Function Check(ByVal CheckNumber As Integer, ByVal CheckAmount As Decimal) As Decimal
Try
file.WriteLine("testing")
file.Close()
Catch e As IOException
'Note sure if this is the proper way.
End Try
Return 0D
End Function
Any pointers will be appreciated! Thank you!!
Private Sub IsFileOpen(ByVal file As FileInfo)
Dim stream As FileStream = Nothing
Try
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)
stream.Close()
Catch ex As Exception
If TypeOf ex Is IOException AndAlso IsFileLocked(ex) Then
' do something here, either close the file if you have a handle, show a msgbox, retry or as a last resort terminate the process - which could cause corruption and lose data
End If
End Try
End Sub
Private Shared Function IsFileLocked(exception As Exception) As Boolean
Dim errorCode As Integer = Marshal.GetHRForException(exception) And ((1 << 16) - 1)
Return errorCode = 32 OrElse errorCode = 33
End Function
Call it like this:
Call IsFileOpen(new FileInfo(filePath))
There is really no point using a 'is file in use check' function since you will still need to have try catch to handle the case that the file fails to open. The file open can fail for many more reasons than it just being already open.
Also using a function to do a check is no guarantee of success. The 'is file in use check' might return false only for the file open to fail with a file already open error, because in time between the check and trying to open the file it was opened by someone else.
It looks like the two suggestions from this MSDN forum posting both involve trying to open the file.
The first one is similar to what you are doing now, and the second involves using a Windows API function (CreateFile) and checking for a invalid handle signifying the file is in use. In both cases they are relying on an error condition to determine if the file is open or not. In short, in my opinion the method you are using is correct since there is not a System.IO.File.IsOpen property.
I am trying to redirect command line output to a list box in a vba macro, and I've found some code that I think might point me in the right direction, but I keep on getting the same error. When I use this code
Function ReadCmdOutput(ByVal applicationName As String,
Optional ByVal applicationArgs As String = "", Optional ByVal
workingDirectory As String = "", Optional ByVal showWindow As Boolean
= False) As String
Try
Dim processObj As New Process
processObj.StartInfo.UseShellExecute = False
processObj.StartInfo.RedirectStandardOutput = True
processObj.StartInfo.FileName = applicationName
processObj.StartInfo.Arguments = applicationArgs
processObj.StartInfo.WorkingDirectory = workingDirectory
If showWindow = True Then
processObj.StartInfo.CreateNoWindow = False
Else
processObj.StartInfo.CreateNoWindow = True
End If
processObj.Start()
processObj.WaitForExit()
Return processObj.StandardOutput.ReadToEnd
Catch ex As Exception
Return ""
End Try
End Function
It gives me the error in the title and highlights the first declaration line.
Question: What does it take to define a new "process".
Bonus points: Helping me with command line output redirect!
This can't be VBA since there is no Try/Catch in VBA or return statements. This looks like VB.NET. Either way, the compiler is telling you that there is currently no reference to any dll that contains the process object.
If this is VB.NET, you need to add Imports System.Diagnostics