I have a SQL Sever 2008 R2/64-bit database server for which I'm writing some fairly basic scripting utilities with the Sql Server Management Objects (SMO). My project is a 32-bit VS2010 executable written in C#.
Most of the effort has been fairly simple and successful. The only problem I'm having is in the firing of my custom event handler that should be called in response to a Scripting Error.
The Scripter object exposes a ScriptingError event, which I have attempted to leverage thusly:
//srv contains a valid server name
Scripter scrp = new Scripter(srv);
//scrp_ScriptingError is my handler
scrp.ScriptingError += new ScriptingErrorEventHandler(scrp_ScriptingError);
My handler is declared thusly:
static void scrp_ScriptingError(object sender, ScriptingErrorEventArgs e)
{
// my handler goes here, just printing e.Current.Urn to the console
// This is merely representative, have had other things here, but
// the handler never fires
Console.WriteLine(e.Current.Value);
}
All this compiles cleanly.
My code is invoked via simple scrp.Script(urns); where urns is just an array of the database objects being scripted out. Nothing fancy:
try
{
sc = scripter.Script(urns);
}
catch (Exception e)
{
WriteLog(String.Format("Failure during scripting: {0}: Inner exception message (if any): {1}",e.Message,((e.InnerException==null)?"[None]":e.InnerException.Message)));
}
using (System.IO.StreamWriter file = new System.IO.StreamWriter(fileName,true))
{
foreach(String currentLine in sc)
{
file.WriteLine(currentLine);
file.WriteLine("GO");
}
}
The problem is that, no matter what I've tried so far, when errors occur during scripting, my ScriptingError handler never fires.
Even in debug mode within VS2010, when I set a breakpoint within the handler, and fire my scripting code, and know an error will occur, only an exception will be thrown, but the breakpoint in my ScriptingError handler never trips.
I'm in trees-for-forest mode now, not sure what I've done wrong. Am I expecting the wrong things for the ScriptingError handler?
I have searched the MSDN docs on the SMO objects and found virtually nothing on ScriptingError handlers other than the basic API calls themselves, and precious few examples on the Internet. It seems incredibly simple and straightforward to me - just assigning an event handler to the event - but there's some battery-not-included notice I've failed to note.
Pointers to my error are greatly appreciated, with a polite request for minimal brickbats if the error is exceptionally stupid on my part :)
I am not at a pc right know, but I think you should try to set the ContinueScriptingOnError option. Otherwise there would be no reason for SMO to invoke the event, but rather through an exception instead.
Related
I have a simple wpf application that continues to run even after I explicitly call it to shut down.
It integrates with a third party application and needs to check that a few documents of a certain type and with specific content are open as it initializes.
Here is a portion of the initialization code:
try
{
ActiveProductDoc = Automation.CATIA.ActiveDocument as ProductDocument;
}
catch
{
InvalidAssemblyShutdown("You must have an assembly open before you run the app");
}
if(ActiveProduct == null)
InvalidAssemblyShutdown("You must have one assembly open (not a part)");
ActiveProduct = ActiveProductDoc.Product;
And here is the InvalidAssemblyShutdown method:
private void InvalidAssemblyShutdown(string message)
{
MessageBox.Show(message);
Close();
Application.Current.Shutdown();
}
I have set the application's ShutdownMode property to OnMainWindowClose.
I am currently doing a use case test where the user has the wrong type of document open and so the ActiveProduct field is null. The InvalidAssemblyShutdown method is called as expected but despite this the line in the initialization method following the shutdown call still runs and throws an exception.
Any ideas what's going on?
Should I throw exceptions instead and use a global exception handler?
If you have a look at the source code for Application.Current.Shutdown (link to source), you'll see that it uses Dispatcher.BeginInvoke() to initiate the shutdown. In other words, the shutdown gets queued on the UI thread. It doesn't take effect during that precise method call, so the following code keeps executing.
You'll need to exit the code right after the call to Application.Current.Shutdown if you don't want some code to run while the shutdown request gets processed. Something like:
if(ActiveProduct == null)
{
InvalidAssemblyShutdown("You must have one assembly open (not a part)");
return; // prevent further code execution.
}
For what it's worth, this.Close() works in a similar way. So if you have proper flow control, you won't need to invoke Application.Current.Shutdown at all. Your call to this.Close() should be enough.
I want to circunscribe this question to the specific context of WPF aplications.
The accepted answer says
"You should only to catch exceptions that you can actually do something about"
and also
"Note that if you're simply trying to catch any unhandled exceptions that might occur for the purposes of logging or error reporting, you should be using the AppDomain.UnhandledException event"
Well, all would be good and well EXCEPT (pun intended) that I had a very serious problem while deploying a WPF application which would crash right at application startup, with the dreaded IOException error in PresentationFramework.
I tried the Application.Current.DispatcherUnhandledException, but the crash apparently happended outside its grasp. I tried Windbg but the error messages were still elusive.
Then I followed advice from this post (changing app.xaml Build Action property from "Application Definition" to "Page" and putting Main() function inside App.xaml.cs itself), putting a try/catch with a MessageBox (it could be a logging call, whatever), and the message displayed immediately led me to the solution.
So the question is:
Considering WPF has its own esoterical bugs, is there any actual problem in putting Main() function body inside a try/catch?
Here is my current code:
public partial class App : System.Windows.Application {
/// <summary>
/// Application Entry Point.
/// </summary>
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main() {
try {
var v3d = new App();
v3d.InitializeComponent();
var shellview = new ShellView();
v3d.Run(shellview);
} catch (Exception e) {
MessageBox.Show(e.ToString());
}
}
And for the record, I was getting "Cannot locate resource 'app.xaml'" caused by some culture mismatch, the problem happened in only one of two similar machines apparently because one OS (Win7) is English and other is Portuguese. I solved it with this answer.
I have an existing Silverlight 5 application. I'm adding a page to it to allow users to process mass updates to data in a 3rd party database system. The application currently uses WCF RIA services to communicate to the 3rd party system via SOAP. The functionality of the update is contained in a Workflow 4 application I created and is referenced as an assembly on the server-side of the SL application. Lastly, the application is hosted right now in my local instance of IIS 7.5 running on Windows 7; I'm also debugging with IIS, not the VS dev server.
At the basic level, the application functions as follows:
Select text file
Click "Start" button
Event handler creates an instance of a user-defined Type that keeps track of the batch
Event handler creates a new BackgroundWorker instance and wires up handlers for the DoWork, ProgressChanged, and RunWorkerCompleted events
Event handler calls RunWorkerAsync()
Here's the shortened code for the DoWork event handler, since that's where the majority of the work is done.
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs, BatchContainerControl batchProcess)
{
var worker = sender as BackgroundWorker;
// Iterate through each record of data file and call the 'UpdateAddress' function
// of the AddressDomainService which, in turn, executes the Workflow
foreach (var item in batchProcess.FileData)
{
// Check if operation has been cancelled
if (worker.CancellationPending)
{
doWorkEventArgs.Cancel = true;
break;
}
. . .
// Invoke THINKComm.CustomerAddressUpdate Workflow via AddressContext
var invokeOp = _addressDomainContext.UpdateAddress(activityData);
// 'activityData' is an instance of Dictionary<string, string>
invokeOp.Completed += (o, args) => InvokeOpOnCompleted(o, args, batchProcess);
}
}
The handlers for the ProgressChanged and RunWorkerCompleted events, as well as the Completed event of the InvokeOperation instance all, for the most part, update a part of the UI. If you think posting any of that code would be helpful, I'd be happy to update the post.
Speaking of UI, the parts that are updated by the event handlers are two ProgressBar controls - one that tracks the records as they're read from the file and a second one that tracks the records as the update has taken place on the 3rd party database.
Getting to the actual problem...
I've processed files of 10, 100, and 1,000 records with no problem. I then attempted to process a complete file containing ~15,000 records (or 1,907KB of data). The process starts and I can see in the debugger output that the Workflow is being executed. About a quarter of the way through or so, I get an OutOfMemoryException. Here's the stack trace:
at System.ServiceModel.DomainServices.Client.WebDomainClient`1.BeginInvokeCore(InvokeArgs invokeArgs, AsyncCallback callback, Object userState)
at System.ServiceModel.DomainServices.Client.DomainClient.BeginInvoke(InvokeArgs invokeArgs, AsyncCallback callback, Object userState)
at System.ServiceModel.DomainServices.Client.DomainContext.InvokeOperation(String operationName, Type returnType, IDictionary`2 parameters, Boolean hasSideEffects, Action`1 callback, Object userState)
at THINKImportSystem.Web.Address.AddressDomainContext.UpdateAddress(Dictionary`2 activityData)
at THINKImportSystem.BatchProcessPage.BwOnDoWork(Object sender, DoWorkEventArgs doWorkEventArgs, BatchContainerControl batchProcess)
at THINKImportSystem.BatchProcessPage.<>c__DisplayClass10.<StartButtonClick>b__6(Object s, DoWorkEventArgs args)
at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
at System.ComponentModel.BackgroundWorker.OnRun(Object argument)
Then, the JIT debugger pops up with an error of Unhandled Error in Silverlight Application Code:4004 with a message of System.ServiceModel.DomainServices.Client.DomainOperationException: Invoke operation 'UpdateAddress' failed. Error HRESULT E_FAIL has been returned from a call to a COM component.
I should mention that, sometimes, I get the JIT debugger first. I see in the Debug output that threads are still exiting, and then about 10 or 20 seconds later, the VS debugger pops up with the out of memory exception.
My best guess is that, objects somewhere (maybe related to the DomainService?) aren't being released and therefore, memory usage is building. From what I understand, IIS places restrictions on the amount of memory an application can use, but I can't tell if that's the case here or not.
I was thinking that, each time a record in the file is processed, the objects related to it's processing would be released and therefore overall memory usage would be pretty low. But obviously I'm not understanding how everything is being executed!
I was also wondering if using the TPL as opposed to BackgroundWorker would make a difference?
I have a Windows Service that monitors a COM port connected to a vendors hardware. This is a very busy piece of hardware that is constantly polling other devices on the wire (this is a twisted-pair RS485 "network"). My software needs to emulate X number of hardware devices on this wire, so I've got a multi-threaded thing going on with a multi-tiered state machine to keep track of where the communications protocol is at any moment.
Problem is with a Windows Service (this is my first one, BTW) is that you need some debugging to let you know if stuff is working properly. When I was first developing this state machine/multi-thread code I had a windows form with a RichTextBox that displayed the ASCII chars going back-n-forth on the line. Seems like I can't really have that GUI niceness with a service. I tried opening a form in the service via another program that sent the service messages that are received via the OnCustomCommand() handler but it didn't seem to work. I had "Allow service to interact with desktop" checked and everything. I was using the Show() and Hide() methods of my debug form.
I guess I don't need to see all of the individual characters going on the line but man that sure would be nice (I think I really need to see them :-) ). So does anyone have any crazy ideas that could help me out? I don't want to bog down the system with some IPC that isn't meant for the voluminous amount of data that is sure to come through. It will only be very short-term debugging though, just confirmation that the program, the RS485-to-USB dongle, and hardware is all working.
Use OutputDebugString to write to the debugging buffer and then use DebugView to watch it. If you're running on Windows XP or earlier, then you can use PortMon to see the raw bytes going through the serial port. The advantage over a log file is that there's very little overhead, particularly when you're not watching it. You can even run DebugView from another machine and monitor your service remotely.
I dunno if it will work for you, but I always build my services with a extra Main that build them as console app to get debug output.
Edit:
Some example:
class Worker : ServiceBase
{
#if(RELEASE)
/// <summary>
/// The Main Thread where the Service is Run.
/// </summary>
static void Main()
{
ServiceBase.Run(new Worker());
}
#endif
#if(DEBUG)
public static void Main(String[] args)
{
Worker worker = new Worker();
worker.OnStart(null);
Console.ReadLine();
worker.OnStop();
}
#endif
// Other Service code
}
You could write the output to a log file and then use another application to watch that file. This question about "tail" outlines several options for watching log files with windows.
What I usually do when working on a Windows Service is to create it so that it can be run either as a service, or as a plain old command-line application. You can easily check whether you are running as a service by checking Environment.UserInteractive. If this property is true, then you are running from the command line. If the property is false, then you are running as a service. Add this code to Program.cs, and use it where you would normally call ServiceBase.Run(servicesToRun)
/// <summary>Runs the provided service classes.</summary>
/// <param name="servicesToRun">The service classes to run.</param>
/// <param name="args">The command-line arguments to pass to the service classes.</param>
private static void RunServices(IEnumerable<ServiceBase> servicesToRun, IEnumerable args)
{
var serviceBaseType = typeof(ServiceBase);
var onStartMethod = serviceBaseType.GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var service in servicesToRun)
{
onStartMethod.Invoke(service, new object[] { args });
Console.WriteLine(service.ServiceName + " started.");
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
var onStopMethod = serviceBaseType.GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var service in servicesToRun)
{
onStopMethod.Invoke(service, null);
Console.WriteLine(service.ServiceName + " stopped.");
}
}
Now you can debug your service, set breakpoints, anything you want. When you run your application, you'll get a console window, appropriate for displaying console messages, and it will stay open until you hit a key.
I'm answering my own question here. I tried a couple of suggestions here but here's what I ended up doing...
I created a Windows Form application with a single Button and RichTextBox. This application constructed a NamedPipeServerStream on it's end. The Button's job was to send either "debug on" (command 128) or "debug off" (129) to the Windows Service. The initial value was "debug off". When the button was clicked, a command of 128 was sent to the Windows Service to turn debugging on. In the Windows Service this triggered an internal variable to be true, plus it connected to the Form application with a NamedPipeClientStream and started sending characters with a BinaryWriter as they were received or sent on the COM port. On the Form side, a BackgroundWorker was created to WaitForConnection() on the pipe. When it got a connection, a BinaryReader.ReadString() was used to read the data off of the pipe and shoot it to the RichTextBox.
I'm almost there. I'm breaking my pipe when I click the debug button again and a subsequent click doesn't correctly redo the pipe. All in all I'm happy with it. I can post any code if anyone is interested. Thanks for the responses!
I am porting TCPClient into Silverlight and I see that the BeginConnect can throw a SocketException somehow from the asynchronous process.
In silverlight there is a Completed event for the ConnectAsync function which supplies a SocketError in it's SocketAsyncEventArgs parameter.
I am throwing a new SocketException whenever the socket fails to connect from the method my implementation of TCPClient hooked into the Completed event.
The problem lays here:
try
{
var ar = client.BeginConnect(...);
// Do stuff
client.EndConnect(ar);
}
catch(SocketException e)
{
// Handle exception here
}
The exception won't be catched here due to the fact that it is thrown from an event? Or maybe it's because the event is executed on another thread? I'm not sure. In any case the exception is not caught.
Well, this doesn't answer your question directly, but if no one has a better solution, you can create your own thread and do a Connect instead of a BeginConnect. Then, you should be able to catch the exception.
You should do a lambda to capture the errors as shown here:
http://social.msdn.microsoft.com/Forums/hu-HU/csharpgeneral/thread/0fbe2ebd-a576-4ac5-a1ed-a5d13d0cd9c8