Cross domain trace listeners VB.NET - cross-domain

I have an application where I use TraceListener to collect data/debugging information while application executes. There are more than one listeners at the same time, one of them will write trace information to disk file, other may collect in string (for a short period of execution) and then it will be displayed to user or might saved to another file as per needs.
All went well, unless we decided something else.
We had lot of plugins which were loaded at runtime and executed. However, the issue with that was it was hard to replace the plugin DLL since it was used by application, so we had to stop and replace DLL and then start it again. We decided to use appDomain to load plugin into so that we can easily replace DLL without restarting the application(s).
That was also went well, but one major issue came in. the trace listerns were blind. Since the plugins are loaded into different app domain, so the traces never reached to the parent app domain which was listening to it (the traces made by plugin, which is loaded into new appdomain).
Our trace listener looks like this.
Public Class StringTraceListener
Inherits TextWriterTraceListener
Dim sw As System.Text.StringBuilder = Nothing
Public Overrides Sub WriteLine(ByVal message As String)
Try
MyBase.WriteLine(message)
sw.AppendLine(Now.ToString & " : " & message)
Catch ex As Exception
'Do not write anything here... or it might go into recursive loop
End Try
End Sub
I wonder, if there is a way that we don’t have to make much changes and the trace listener might receive traces from plugins (child appDomain) as well?
Any idea will be appreciated
Thanks

The config is read in when the application is loaded. So for a plug in where the assembly isn't loaded in the usual way, it is plausible that the config isn't being read. You can configure the trace listeners in code, although it is obviously less flexible.
To configure a trace listener in source code, add a listener to the TraceSource's Listener collection. Make sure this happens once for the life of that trace listener, else you will get duplicate Listeners.

Related

ServiceStack RedisPubSubServer will enter in OnStop, OnInit, and OnStart frequently

Here is my situation:
I instantiate a RedisPubSubServer and configure it with OnInit, OnStart, and OnStop callbacks.
I keep this reference as long as the application lives and, in the end, I dispose it.
Somehow, during the application life cycle, I noticed that the OnStart/OnStop callbacks are called without any explicit disposing of the RedisPubSubServer, and I suspect that something goes wrong with the connection, but I cannot figure why.
Is there any way of identifying the problem? Or am I am not understanding it right how it works?
If there's a connection error or failover the RedisPubSubServer will auto-reconnect, you can get notified when this happens by overriding the OnError and OnFailover callbacks.

Excel add-in with logging class: How to react to VBA state loss?

The setup
I'm developing and maintaining an Excel add-in that comes with its own tab of controls within Excel's Ribbon UI. I've come across the problem of state loss before (meaning loss of all variables with global scope, static variables, etc, which of course includes my reference to the RibbonUI). With regards to the ribbon reference I've "solved" the problem by including a "Reset Ribbon" button that restores the reference from a persistently stored pointer and then invalidates the ribbon. Although certainly not the most elegant, this part works just fine.
However, after the introduction of a logging class, the state loss issue haunts me once again. The logger is instantiated in ThisWorkbook's module:
Private Sub Workbook_Open()
Set LogToFile = SingletonFactory.getToFileLogger
End Sub
and is then put to work, for example, as follows:
Private Sub buttonReloadObjects_onAction(ByVal control As IRibbonControl)
LogToFile.trace "Event firing: buttonReloadObjects_onAction"
' more stuff happening...
invalidateRibbon ' restores ribbon object and invalidates it
End Sub
The logger is instantiated when the add-in is loaded so that I have the freedom to log whatever I want within the confines of my add-in's code. It has several logging levels like trace/debug/error/... and a couple of other methods. Usually it works just fine - until the state loss hits (usually caused by an unrelated error, followed by clicking "End").
State loss
At this point the VBA environment forgets about the very existence of my LogToFile object and nothing works any more, because every click on the ribbon controls will trigger a runtime error 91: Object variable or with block variable not set pointing to whatever line is the first to contain a reference to LogToFile.
A solution?
Now, short of doing crazy workarounds like placing
if not isObject(LogToFile) then
Set LogToFile = SingletonFactory.getToFileLogger
end if
LogToFile.trace "Message"
before any occurrence of LogToFile, the only real "solution" I was able to come up with is to wrap all my logger calls in functions (residing in a standard module) and call these functions any time I want to send something to the log. This way I could catch the missing object reference right before the object is needed and I avoid calling methods of uninstantiated objects.
However, after having everything neatly encapsulated in class modules, it strikes me as odd, maybe even wrong(?), going down this route.
So, is there a "proper" solution to the problem of a lost logger instance? Or is my suggested approach already as proper as it can get?
Note: This problem is of course not specific to logging classes. It affects all global variables, most notably my ApplicationEventClass. The issue just happens to be the most glaring with the logger due to its frequent usage around all entry points to the code.
You only need one function that either returns the original variable or resets it. If you call that function LogToFile you don't need to change any of the other code other than removing the Workbook_Open code which is then superfluous. So:
Function LogToFile() As WhateverVariableType
Static temp as WhateverVariableType
If temp is Nothing then Set temp = SingletonFactory.getToFileLogger
Set LogToFile = temp
End Function
This way you will also still benefit from Intellisense when writing the code.
Note: you may not actually need the temp variable - it depends on whether there are settings that you want persisted. If there are, you may want to reset them in the function too.

"mscorlib.pdb not loaded" yet the mscorlib.dll is NOT missing

I am running my application in VS2012 and I am getting a runtime error;
When I look in the "Original Location" I see mscorlib.dll, but not mscorlib.pdb.
Why is this happening and how do I fix it?
Goto Tools, Options, Debugging, General, Enable Just My Code
This will prevent the debugger from trying to launch on a Internal .NET Framework Assembly.
Goto Tools, Options, Debugging, Symbols and set a cache location. Then hit load in the above and it will fetch the necesary symbols for you and store them in the cache location you provide.
Microsoft's compiler tools create symbols in separate files with a .pdb extension (program database). This allows them to create detached symbols for release binaries. With a symbol server, your IDE can fetch the symbol file matching the specific version of the DLL during debugging. You can configure this system for your own product binaries as well which can be very useful for post-mortem debugging any crashes on end-user machines.
See Microsoft's documentation for more details about using their public symbols.
I had this issue when I was using a static variable, whose value is assigned off a static method.
So, whenever I ran the application, this line of code threw exception. If you place a debug point on this (like I did), you will notice the exception being thrown.
The best Solution to solve this error is:
1: Open App.config file.
2: Paste this useLegacyV2RuntimeActivationPolicy="true" code in the startup tag.
3: Save it.
Now the error would disappear.
Moreover see Image. I have done this for you.
This happened to me for a different reason: I had referenced an old version of NLog (2.0) and needed to reference version 4.0, instead.
In a VB console app, in my case it was none of the above.
Just doing a string calculation in the Dim declarations before my subs.
The offending code:
Dim FylPrefix$ = Fyl.Substring(0, Fyl.LastIndexOf("."))
Moving this calculation into the sub it was needed in fixed it! GERONIMO!!
This can happen when you initialize a variable in your class declarations and that initialization throws an exception:
class Program
{
static OracleConnection ora = getOracleConnection();
}
static void main(string[] args)
{
ora.Open();
}
static OracleConnection getOracleConnection()
{
OracleConnection orax = new OracleConnection(description=(host=myHost)
(port=1521)(protocol=tcp))(connect_data=(sid=mySid)));user id=user;password=pw;
}
If an exception is thrown by getOracleConnection() you can get this error. Move your assignment (but not necessarily your declaration) inside of main (where it belongs anyway), and you will get the actual exception that is causing the error instead of the mscorlib error.
In my case the exception began to appear after I changed the "Assembly name" in the "Application" tab of the properties window. If that's the case with you try reverting to the original name and see if the exception disappears.
Perhaps the reason for this was that the new name did not match the AssemblyTitle in AssemblyInfo.cs.
if you have this type of project runtime error in visualstudio
Answer:Cntr+Alt+E open Exception window Uncheck All chechboxes
Must and shoud its working written by B sriram Mca Giet College
rajahmundry, east godavary ,2014 batch

GCHandle, AppDomains managed code and 3rd party dll

I have looking at many threads about the exception "cannot pass a GCHandle across AppDomains" but I still don't get it....
I'm working with an RFID Reader which is driven by a DLL. I don't have source code for this DLL but only a sample to show how to use it.
The sample works great but I have to copy some code in another project to add the reader to the middleware Microsoft Biztalk.
The problem is that the process of Microsoft Biztalk works in another AppDomain. The reader handle events when a tag is read. But when I run it under Microsoft Biztalk I got this annoying exception.
I can't see any solution on how to make it work...
Here is some code that may be interesting :
// Let's connecting the result handlers.
// The reader calls a command-specific result handler if a command is done and the answer is ready to send.
// So let's tell the reader which functions should be called if a result is ready to send.
// result handler for reading EPCs synchronous
Reader.KSRWSetResultHandlerSyncGetEPCs(ResultHandlerSyncGetEPCs);
[...]
var readerErrorCode = Reader.KSRWSyncGetEPCs();
if (readerErrorCode == tKSRWReaderErrorCode.KSRW_REC_NoError)
{
// No error occurs while sending the command to the reader. Let's wait until the result handler was called.
if (ResultHandlerEvent.WaitOne(TimeSpan.FromSeconds(10)))
{
// The reader's work is done and the result handler was called. Let's check the result flag to make sure everything is ok.
if (_readerResultFlag == tKSRWResultFlag.KSRW_RF_NoError)
{
// The command was successfully processed by the reader.
// We'll display the result in the result handler.
}
else
{
// The command can't be proccessed by the reader. To know why check the result flag.
logger.error("Command \"KSRWSyncGetEPCs\" returns with error {0}", _readerResultFlag);
}
}
else
{
// We're getting no answer from the reader within 10 seconds.
logger.error("Command \"KSRWSyncGetEPCs\" timed out");
}
}
[...]
private static void ResultHandlerSyncGetEPCs(object sender, tKSRWResultFlag resultFlag, tKSRWExtendedResultFlag extendedResultFlag, tKSRWEPCListEntry[] epcList)
{
if (Reader == sender)
{
// Let's store the result flag in a global variable to get access from everywhere.
_readerResultFlag = resultFlag;
// Display all available epcs in the antenna field.
Console.ForegroundColor = ConsoleColor.White;
foreach (var resultListEntry in epcList)
{
handleTagEvent(resultListEntry);
}
// Let's set the event so that the calling process knows the command was processed by reader and the result is ready to get processed.
ResultHandlerEvent.Set();
}
}
You are having a problem with the gcroot<> helper class. It is used in the code that nobody can see, inside that DLL. It is frequently used by C++ code that was designed to interop with managed code, gcroot<> stores a reference to a managed object. The class uses the GCHandle type to add the reference. The GCHandle.ToIntPtr() method returns a pointer that the C++ code can store. The operation that fails is GCHandle.FromIntPtr(), used by the C++ code to recover the reference to the object.
There are two basic explanations for getting this exception:
It can be accurate. Which will happen when you initialized the code in the DLL from one AppDomain and use it in another. It isn't clear from the snippet where the Reader class object gets initialized so there are non-zero odds that this is the explanation. Be sure to keep it close to the code that uses the Reader class.
It can be caused by another bug, present in the C++ code inside the DLL. Unmanaged code often suffers from pointer bugs, the kind of bug that can accidentally overwrite memory. If that happens with the field that stores the gcroot<> object then nothing goes wrong for a while. Until the code tries to recover the object reference again. At that point the CLR notices that the corrupted pointer value no longer matches an actual object handle and generates this exception. This is certainly the hard kind of bug to solve since this happens in code you cannot fix and showing the programmer that worked on it a repro for the bug is very difficult, such memory corruption problems never repro well.
Chase bullet #1 first. There are decent odds that Biztalk runs your C# code in a separate AppDomain. And that the DLL gets loaded too soon, before or while the AppDomain is created. Something you can see with SysInternals' ProcMon. Create a repro of this by writing a little test program that creates an AppDomain and runs the test code. If that reproduces the crash then you'll have a very good way to demonstrate the issue to the RFID vendor and some hope that they'll use it and work on a fix.
Having a good working relationship with the RFID reader vendor to get to a resolution is going to be very important. That's never not a problem, always a good reason to go shopping elsewhere.

How can I make Visual Studio 2012 break on Debug.Assert for a Windows Store application? [duplicate]

I notice Debug.Assert does not trigger in Metro apps, however, if the project is a traditional one like Console or WinForm, it does trigger. And yes, I am in Debug mode.
Is it a setting not properly set in Visual Studio (11 Beta)? Or Debug.Assert is intended to be disabled in metro apps?
I know many exceptions are swallowed during the execution of Metro apps, but Debug.Assert is so handy that I can't think of a reason why it should be disabled.
Seems like a bug. I would roll out my own assert method. Something like:
[Conditional("DEBUG")]
public static void Assert(bool condition)
{
if (!condition)
System.Diagnostics.Debugger.Break();
}
It does trigger, look in the Output window. It just doesn't automatically prompt you to ask if you want a debugger break and thus just keeps motoring.
The DefaultTraceListener.AssertUIEnabled property is false. That's an implementation problem, can't display a message box on top of Metro UI. Which does actually work but the monitor switches to the desktop, pretty undesirable when you would have liked to click No. Hard to solve and no doubt on the todo list. You can't easily get to the property to set it to true, it is inaccessible from the metadata. Filip's workaround sounds half-decent.
There is the same problem with F# in WinRT, in VS2013. The assert statement, which is an alias for System.Diagnostics.Debug.Assert, does not raise an exception, so unless you are watching the Output window then your assertions can fail without being noticed. Even if you are watching, it is hard to find the spot where the assertion was raised.
I followed Filip's suggestion and wrote a short utility, as follows:
namespace MyProj.Infrastructure
module Diagnostics =
let Assert condition = if not condition then
System.Diagnostics.Debugger.Break()
I chose Debugger.Break over raising an exception because it stops the debugger at the place the assertion fails. However, raising an exception is an acceptable alternative.
I didn't have any suitable global projects or modules already in my solution, so I had to create them just for this, which was quite annoying.

Resources