Here is the brief explanation for my script task in SSIS.
Read/Write variable LOGERROR, and it does exist in the Variables panel with string type.
Inside the script, C# code:
try
{
... //what here does is to iterate a folder and move all of them to another folder, codes here are working correctly
Dts.TaskResult = (int)ScriptResults.Success;
}
catch(Exception e)
{
Variables lockedVariables = null;
Dts.VariableDispenser.LockOneForWrite("User::LOGERROR", ref lockedVariables);
lockedVariables["User::LOGERROR"].Value = e.ToString();
lockedVariables.Unlock();
Dts.TaskResult = (int)ScriptResults.Failure;
}
The reason that I manually control the writes of the variable is that the same variable LOGERROR was added to the Event Handler for the same purpose of Point 4.
I direct the Failure to another Execute SQL task, which is trying to insert LOGERROR (Should contain the exception details) into an underlying table.
My questions:
Sometimes the SSISPackage failed at above task (not always, but at almost the same time every day, may have conflicts with the other jobs?) for not any apparent reasons (at least for now). That's why I would like to track what exactly the issue is, but if I query the target logging table. The details does not show anything, just empty.
And, I have a general logging task in Event Handler that logged all the message when task ran with errors. And that message shows nothing but Exception has been thrown by the target of an invocation.
Did I miss something when trying to log LOGERROR? Because it seems for me that the script did not go into the Try & Catch, just failed directly, otherwise it should store the Exception details. (Please correct me if I am wrong). Or, how could I track the error details?
After some investigations, I think the issue was caused by SQL Server Agent failed to access the shared folder during certain time frame.
Possible solution to my questions:
https://social.technet.microsoft.com/Forums/azure/en-US/988207fe-5a25-4da7-a8df-a38fada703da/ssis-script-task-exception-has-been-thrown-by-target-of-invocation?forum=sqlintegrationservices
Related
I'm doing some testing which outputs the full result set into script task (display messagebox) from Execute SQL Task using Foreach loop Container. but running into DTS Script task: runtime error.
Error Message box
Am I missing some sort of DLL file?
Script
Control flow
Error message
exception has been thrown by the target of an invocation
Is a general error message that is shown when an exception is thrown by the script code. To read the main error message you can add a try catch clause into your code and use Dts.FireError() method to throw the real exception.
public void Main()
{
try
{
string strMessage = Dts.Variables["User::FinalTieOut"].Value.ToString();
Messagebox.Show(strMessage);
Dts.TaskResult = (int)ScriptResults.Success;
}
catch(Exception ex)
{
Dts.Events.FireError(0,"An error occured", ex.Message,String.Empty, 0);
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
Variables names
Based on Using Variables in the Script Task - official documentation:
You add existing variables to the ReadOnlyVariables and ReadWriteVariables lists in the Script Task Editor to make them available to the custom script. Keep in mind that variable names are case-sensitive. Within the script, you access variables of both types through the Variables property of the Dts object. Use the Value property to read from and write to individual variables. The Script task transparently manages locking as the script reads and modifies the values of variables.
Just change USER::FinalTieOut to User::FinalTieOut and it will solves the issue.
In .NET, the default exception handler will let the user continue running the program. However, I'd like to have a global exception handler that saves the stack trace to an "errorlog.txt" file so the user can send it to me and doesn't have to remember to click "Details" and copy it out of the dialog (and remove all the useless crap about loaded assemblies and such). But when I do this, the code doesn't know how to continue, so all I can do is exit the app. Is there any way to have the best of both worlds? (Yes, I know what I'm asking for is essentially "On Error Resume Next" with logging, but I really think it would be useful!)
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
If you bind yourself to this event when the application starts, you should be able to catch any Unhandled Exception your application throws, and save it to a file. (Use the Exception object part of the UnhandledExceptionEventArgs. I do not believe it is possible to resume from where the error Occurred.
You can write a global exception handler method that you call in every catch block, which writes the stack trace where ever you want to save it. But you'd need to write try . . . catch blocks for every operation that needs them and call the exception handler in each.
You can also call that global exception handler method in the MyApplication.UnhandledException handler for all unhandled events. But when control gets to that method in that case, the program is not going to continue running.
In a Winform app you can attach an handler to the Application.ThreadException event (make sure you do before calling Application.Run()). This will get rid of the standard exception dialog (the one with the "details" button) and give you the power to display / log anything you want.
However, remember that this will work ONLY for exceptions thrown within the UI thread. Exceptions raised from a background thread won't be reachable from your handler. These can still be caught by AppDomain.UnhandledException handler, though.
in main constructor, put this and will do it globally:
AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
MessageBox.Show(eventArgs.Exception.ToString());
};
(Note: as said in comments, this might not be thread-safe).
No that does not exist, exceptions are a flow control construct, so On Error Resume Next is not possible.
You could do your operation in a loop and on an exception, retry your logic.
KandallFrey is right however, you shouldn't use exceptions as flow control, use them only in exceptional cases.
I use My.Application.UnhandledException to open a dialog form where the user can save every information about the exception.
When the form is closed I call e.ExitApplication = False.
At my firm, I've built an exception handling framework which has served me well for 7 years now. Every assembly references the DLL, and every method in each assembly has a try-catch block. In the catch, I basically have to make one decision based on the question "where do I want my exception handling framework to intervene, i.e. to log the exception data externally and inform the user of the problem?". In most cases, the answer to this question is that I want it to intervene in cases where the method is called externally, e.g. if it's inside an event handler or other delegate. So here is some example code:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Try
Method1()
Catch ex As Exception
BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName))
End Try
End Sub
Private Sub Method1()
Try
method2()
Catch ex As Exception
Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
End Try
End Sub
Private Sub method2()
Try
Dim x As Integer = CInt("x") 'exception thrown here.
Catch ex As Exception
Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
End Try
End Sub
When Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName) is called for the first time in Method2(), the original exception is wrapped inside a BSException, and the original method name is stored as well (more on that later). Any subsequent calls to BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName), e.g. in Method1(), will recognize that the exception is already of type BSException and just throw that instead of re-wrapping it. Ultimately, it reaches the "top" of the call stack (not really the top, just the point at which I've decided I want to process the exception through my framework -- i.e. log it, inform the user, etc.) -- in this case, in Button1_Click -- and then BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)) is called.
What my framework does in ProcessException is to determine the type of reporting configured on the system. This is defaulted to "simple", which means the user gets a very general and minimally-intrusive dialog box indicating a problem has occurred and instructing them to contact the IT department. However, there is an optional registry setting which will set the reporting type to either "verbose" or to "email". I use "verbose" on my development machine, because it includes all the exception info in the dialog box so I don't have to go look at the log. The "email" option is used on servers where I have applications running when there is no user logged on; in that case, the error information is emailed to the IT department to alert them of the issue.
The other thing that happens from here, regardless of the reporting type, is that the error information is recorded to the Windows event log. Here is an example:
SILENT: No
ROOT ASSEMBLY: C:\Users\roryap\AppData\Local\Temporary Projects\WindowsApplication1\bin\Debug\WindowsApplication1.exe
DESCRIPTION: BromsunExceptionHandling.BSException: Calling Method 'WindowsApplication1.Form1.method2()' produced 'System.FormatException' exception with message 'Conversion from string "x" to type 'Integer' is not valid.'.
CALLING METHOD: WindowsApplication1.Form1.method2()
STACK TRACE: at Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(String Value)
at WindowsApplication1.Form1.method2() in C:\Users\roryap\AppData\Local\Temporary Projects\WindowsApplication1\Form1.vb:line 32
CALL STACK: WindowsApplication1.Form1.method2()
WindowsApplication1.Form1.Method1()
WindowsApplication1.Form1.Button1_Click(sender As System.Object, e As System.EventArgs)
SOURCE: Microsoft.VisualBasic
TARGET SITE: Int32 ToInteger(System.String)
EXTRA INFO:
When the user reports the issue to IT, all IT has to do is check their event log to get the error info. Furthermore, the application does not exit; it continues running because it never allows the exception to bubble up outside of the point where you've chosen to process the exception with the handling framework. Once it's handled by the framework, it's done.
While there are a few downsides to this approach, I have found it to be an extremely robust system and it has saved me many many hours of blind troubleshooting over the years. I have created snippets so that all I have to do is create a try-catch block then type the snippet shortcut -- e.g. "pbs" or "tbs" -- into the catch-block and hit the tab key to populate the appropriate exception handling method. Therefore, it's quite painless to use this framework in every method. I've even modified my VS project templates to always reference and include the framework so I don't have to do that for every new project.
So, regarding the GetThisMethodName() function: this method uses System.Diagnostics.StackTrace, System.Diagnostics.StackFrame, and System.Reflection.MethodBase to figure out the name of the method where the original exception was wrapped inside the BSException.
For me works this solution:
In WebApiConfig.cs add:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());
...
}
Create new file UnhandledExceptionLogger.cs:
public class UnhandledExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
File.AppendAllText("log.txt", context.Exception.ToString());
}
}
I'm working on an existing C# program that queries and makes changes to various resources outside of the program and computer that the program is run on. The program works on most computers but randomly fails on random computers every so often. When this happens we have no feedback as to why other than what the user tells us about the exception that was thrown up on the screen that they may or may not have already cleared. Even if they leave it up on the screen for us it provides little to no useful information to us. I have since modified the program to log particular events and gathered information to a text file that I can use to approximate where the program stopped. This is at least a start but from reading many threads on stackoverflow.com as well as other forums I know that the program needs to at least make an attempt to handle the specific exceptions that could come up when querying and modifying LDAP, DS, DNS, SQL and so on.
Currently there is just big try blocks surrounding all of the to do code with just one catch block at the end of each.
private void method_name()
{
try
{
//many lines of to do code calling many other methods
}
catch (exception ex)
{
MessageBox.Show("An Error has occurred in method_name() :" + ex.Message);
}
My first thought was to nest more specific try/catch blocks within the larger try blocks but I keep running into problems with variables becoming unreachable in different contexts. for example
try
{
LdapConnection ldapConn = new LdapConnection();
ldapConn.Connect(details of connection);
ldapConn.Bind(details of bind statement);
LdapSearchQueue queue = ldapConn.Search(search criteria and such);
LdapMessage message;
}
catch (somesortofexception ex)
{
//do something sensible about it
}
while ((message = queue.getResponse()) != null)
{
//do things with message
}
ldapConn.Disconnect();
the problem being that message and queue are unreachable outside of the try block. This is just one example of something done withing the "//many lines of to do code calling many other methods" that I'm trying to work with.
So here are my questions:
Would it be better to try and make the try block bigger in the above example to include the while loop and ldap disconnect or to just leave the big try loop, make a list of things that happen during that and create many catch blocks at the end to catch specific exceptions? I feel like putting in the smaller try blocks around specific code is the way to go based on what I've read on this site.
Should I use the smaller try blocks like I've been trying to implement, would be be okay to just use a catch block that catches any exception raised within that small snippet of code and log it to my log file or should I try and catch specific exceptions? I don't really have anything different I can do with those exceptions other than log them to the file anyways.
Do I need to throw the exceptions? I don't really want anything bubbling up to the user other than a message in plain english saying that something went wrong and to contact IT. Currently none of the catch blocks throw anything.
About breaking down exceptions, I would always separate the connection code from the query one.
So this would become:
LdapConnection ldapConn = new LdapConnection();
try
{
ldapConn.Connect(details of connection);
ldapConn.Bind(details of bind statement);
}
catch (somesortofexception ex)
{
//Log, send error message..
ldapConn = null;
}
if (ldapConn != null)
{
try
{
//Do what you need with your connection
}
catch (Exception ex)
{
//Log, Error....
}
finally
{
//Disconnect your ldap here
}
}
Ideally i would put all the connection code and search code in separate methods as well,
so you'll have some nicer stack trace.
About error message I would also just use some generic message and log exception specifics into some kind of file ( http://logging.apache.org/log4net/ ) is quite nice for having nicely formatted log files.
A local catch block that swallows a specific exception is fine as long as you're expecting that exception and it can be handled locally. In this case you can provide information to the user based only on what the exception contains, or you can move the variable definitions above the try block if you want to include their state in the logging and/or message.
For exceptions that you're not expecting, you should let them bubble upwards to the top of the call stack where they can be logged by a global handler before exiting the program gracefully. You don't want to potentially nail the corpse in an upright position by swallowing these exceptions.
Assuming this is a WinForms app, the setup of global handlers looks something like this:
public static void Main(string[] args)
{
// Switch-off the Windows Forms default handler for unhandled exceptions.
// NB From .NET 4 upwards, this won't work if the process state is corrupted.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Setup event handler to intercept an unhandled exception on a UI thread.
// NB The exception will still terminate the application.
// But you can show a MessageBox and/or log the exception.
Application.ThreadException +=
new ThreadExceptionEventHandler(App_UiThreadException);
// Setup event handler to intercept unhandled exception on a non-UI thread.
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(App_NonUiThreadException);
// Run the application (open main form etc).
}
I have this code:
catch (Exception e)
{
try
{
transmitModel.AddAck(transmitBatchId,
"<error><message>" + e.Message + "</message><stack>" + e.StackTrace +
"</stack><Location>FromLisAtOMServer<Location>" +
"<TransmitBatchId>" + message.TransmitBatchId +
"</TransmitBatchId></error>", false, true);
}
// If we fail to log, we don't want that to bubble up...
// We want the real error to do that.
catch (Exception){}
// Re-throw the exception so that the service bus will
// move this off to the error queue.);
throw;
}
The AddAck method will save that string to the database (Using Entity Framework).
When I run this without the last statement throw, it saves my error message to database fine.
When I have the throw; in there, it says it saves but when I query the database it is not in there. I can even run a entity query via my data context right after saving (in the code) and it returns the value as if it is saved (though that may be using a cached version). But if I go and query afterwards the data is not there....
I have checked to be sure that no other logic is causing the value to be removed on an exception.
Any ideas what could be causing this?
OK, post as an answer here, it comes in my mind very easily as I used to met the same issue, and figured out it was just caused I didn't commit the DB transaction.
Thanks, :)
This call is as a result of an NServiceBus message.
I forgot that my NServiceBus stuff runs in a distributed transaction. So when I threw the exception it roll back all my pending changes.
I need to find out how to get this log file to post outside the transaction...
It is possible that NServiceBus provides hooks for this kind of thing.
Your problem is quite possibly what you have stated: the message handling has to happen in a transaction. You cannot commit that else you are also committing errors. So you definitely have to find out where you can hook into the post message handling exception processing.
With Shuttle ESB (http://shuttle.codeplex.com/) we use pipelines for handling different use cases and you can hook into the PipelineException event that is raised by the various pipelines. Shuttle has a the ability for developers to add modules that hook into the various events. There is already a SystemExceptionModule that does more-or-less what you want to do.
I've been starting at this code for the best part of 2 hours (literally) but I can not seem to grasp why this would fail. This method below does not report any exceptions, yet it seems to return false:
public bool SaveFile(string filename, object source)
{
bool result = true;
StringBuilder exportText = new StringBuilder(source.ToString());
try {
File.WriteAllText(filename, exportText.ToString());
}
catch (Exception e)
{
OnPluginError(new ErrorEventArgs(e));
result = false;
}
return result;
}
The problem is: the file is properly written at the requested path, is complete, and readable. No exceptions are thrown, because the OnPluginError() handler invocation method isn't called - any message would be logged in that case, but there is nothing logged. It can't be a permission problem because the file does exist after the call.
And still, the method result is false.
The problem only appears in a Release build. In Debug builds, all seems to work OK. Hence, I can't use the debugger to step through.
This is called from a web application. Any ideas appreciated.
As a temporary troubleshooting step, add another try catch to block any exceptions and then see if the function is still returning false.
public bool SaveFile(string filename, object source)
{
bool result = true;
StringBuilder exportText = new StringBuilder(source.ToString());
try {
try {
File.WriteAllText(filename, exportText.ToString());
} catch(Exception e) { }
}
catch (Exception e)
{
OnPluginError(new ErrorEventArgs(e));
result = false;
}
return result;
}
If it is returning true, then you have isolated the problem and determined that an exception is being thrown, causing the block with result = false to be run.
If it is still returning false, then you can be certain the problem is outside of this function, as the rules of control flow would dictate that the result variable would never be changed.
One possibility is you have an issue with either the code you think is being run is not really being run. For example some issue with the build process not picking up your most recent code changes or redirection. Checking the versions of the website project DLLs, doing clean/rebuild, adding additoinal code to write out trace messages, are all things you should try to cross check to verify your most recent code is being run.
Another possibility is a problem in the code that is checking the return value.
Well...I do feel a bit silly here. I finally found the problem, and it is (as some posters questioned) not related to the WriteAllText() method at all.
FYI: this code ran deep inside an extensive plugin library. Not all that code was designed and written by me, and has been around for almost 2 years without running into problems.
As I mentioned, the WriteAllText() ran fine. It did. Problem was that the location of the file saved, was stored in a Dictionary, which in turn was requested from the plugin currently running. That Dictionary (containing plugin settings) turned out to be created from scratch with each call to that property! So I could add to it as much as I wanted....at the next call to that property, the newly added items would 'disappear' magically since the Dictionary was created anew.
Since it never surfaced before, and that code ran in a lot of other plugins with no problems, I didn't check that property. My bad.
Apologies to everyone that responded for wasting their time. Rest assured it won't happen any time soon! Lesson learned...