I am randomly getting this exception. From the below stack trace i can understand that it is originating from the log4net functionality.
LogExceptionValue -
System.ArgumentOutOfRangeException: capacity was less than the current size.
Parameter name: value
at System.Collections.ArrayList.set_Capacity(Int32 value)
at System.Collections.ArrayList.Add(Object value)
at log4net.Util.LogReceivedEventHandler.Invoke(Object source, LogReceivedEventArgs e)
at log4net.Util.LogLog.OnLogReceived(Type source, String prefix, String message, Exception exception)
at log4net.Config.XmlConfigurator.InternalConfigure(ILoggerRepository repository)
at log4net.Config.XmlConfigurator.Configure(ILoggerRepository repository)
at log4net.Config.XmlConfigurator.Configure()
at Loggers.LoggerBase.LogMessage(LogInformation logInformation)
at LookupByReasonCode(String reasonCode)
Code for Log4Net
/// <summary>
/// Logs message based on logger.
/// </summary>
/// <param name="logInformation">Log Information </param>
protected void LogMessage(LogInformation logInformation)
{
this.log = LogManager.GetLogger(logInformation.Logger);
log4net.Config.XmlConfigurator.Configure();
if (!string.IsNullOrEmpty(logInformation.Request))
{
ThreadContext.Properties["request"] = logInformation.Request;
}
if (!string.IsNullOrEmpty(logInformation.Response))
{
ThreadContext.Properties["response"] = logInformation.Response;
}
if (!string.IsNullOrEmpty(logInformation.ResponseCode))
{
ThreadContext.Properties["responsecode"] = logInformation.ResponseCode;
}
if (!string.IsNullOrEmpty(logInformation.Keys))
{
ThreadContext.Properties["keys"] = logInformation.Keys;
}
//// Logs exception
this.Log(logInformation.Message, logInformation.LogLevel, logInformation.Exception);
}
Any help would be much appreciated.
If you're getting this intermittently it's most likely because you are loading the log4net configuration on every single logging call and two threads are trying and load it at the same time.
Move XmlConfigurator.Configure(); to your startup program and only call it once.
Related
I want to validate if my understanding is correct.. having read the documentation about ICacheEntryProcessor, it says that if we want to update a field in cache entry, we implement this class and use Invoke on cache to update the field in cache record atomically..
when I implement the above approach, the record does not seem to be updated..there are no exceptions thrown in the process method.
here's my implementation
public class UserConnectionUpdateProcessor : ICacheEntryProcessor<string, User, UserConnection, bool>
{
/// <summary>
/// Processes the update
/// </summary>
/// <param name="entry"></param>
/// <param name="arg"></param>
/// <returns></returns>
public bool Process(IMutableCacheEntry<string, User> entry, UserConnection arg)
{
var connection = (from conn in entry.Value.Connections
where conn.ConnectionId == arg.ConnectionId
select conn).FirstOrDefault();
if(connection == null)
{
//this is a new connection
entry.Value.Connections.Add(arg);
return true;
}
if(arg.Disconnected)
{
entry.Value.Connections.Remove(connection);
}
else
{
connection.LastActivity = DateTime.Now;
}
return true;
}
}
I enabled Ignite Trace logs and this got printed
2020-06-21 21:09:54.1732|DEBUG|org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache|<usersCache> Entry did not pass the filter or conflict resolution (will skip write) [entry=GridDhtCacheEntry [rdrs=ReaderId[] [], part=358, super=GridDistributedCacheEntry [super=GridCacheMapEntry [key=KeyCacheObjectImpl [part=358,
also I was going through Ignite source to understand what operations are performed..no luck yet
https://github.com/apache/ignite/blob/master/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
Your code is fine, but since you only change the data inside the entry.Value object, Ignite does not detect those changes and does not update the entry.
Add entry.Value = entry.Value right before return true.
Ignite uses the Value property setter to mark the entry as updated.
I already developed one application with the EF6 and MS-SQL Server.
Everywhere in my application I wrote the code like below where I needed to Insert, Update or delete the data from the table:
Code:
using (DemoEntities objContext = GetDemoEntities())
{
using (TransactionScope objTransaction = new TransactionScope())
{
Demo1(objContext);
Demo2(objContext);
// Commit the changes in the database.
objTransaction.Complete();
}
}
public void Demo1(DemoEntities objContext)
{
Demo1 objDemo1 = new Demo1();
objDemo1.Title = "ABC";
objContext.Demo1.Add(objDemo1);
objContext.SaveChanges();
}
public void Demo2(DemoEntities objContext)
{
Demo2 objDemo2 = new Demo2();
objDemo2.Title = "ABC";
objContext.Demo2.Add(objDemo2);
objContext.SaveChanges();
}
My Application is running on the one server and database is running on the another server in the AWS.
My application is working smoothly, But 2-3 times weakly I got the error like the below.
System.Data.Entity.Core.EntityException: The underlying provider
failed on Open. ---> System.Data.SqlClient.SqlException: A
network-related or instance-specific error occurred while establishing
a connection to SQL Server. The server was not found or was not
accessible. Verify that the instance name is correct and that SQL
Server is configured to allow remote connections. (provider: Named
Pipes Provider, error: 40 - Could not open a connection to SQL Server)
---> System.ComponentModel.Win32Exception: Access is denied
In first request I got the above error and after the immediate another request I does not get any error and request is successful.
After doing some Google I got the concept like the Connection Resiliency I implemented in my application and it works and retry the query for some specific times after some specific period.
But it fails in the case of the where I used my Custom Transactions like in the above code. It throws the error like this.
System.InvalidOperationException: The configured execution strategy
'MYExecutionStrategy' does not support user initiated transactions.
See http://go.microsoft.com/fwlink/?LinkId=309381 for additional
information.
I configured the Execution Strategy like this:
public class MYExecutionStrategy : DbExecutionStrategy
{
/// <summary>
/// The default retry limit is 5, which means that the total amount of time spent
/// between retries is 26 seconds plus the random factor.
/// </summary>
public MYExecutionStrategy()
{
}
/// <summary>
///
/// </summary>
/// <param name="maxRetryCount"></param>
/// <param name="maxDelay"></param>
public MYExecutionStrategy(int maxRetryCount, TimeSpan maxDelay)
: base(maxRetryCount, maxDelay)
{
}
/// <summary>
///
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
protected override bool ShouldRetryOn(Exception exception)
{
bool bRetry = false;
SqlException objSqlException = exception as SqlException;
if (objSqlException != null)
{
List<int> lstErrorNumbersToRetry = new List<int>()
{
5 // SQL Server is down or not reachable
};
if (objSqlException.Errors.Cast<SqlError>().Any(A => lstErrorNumbersToRetry.Contains(A.Number)))
{
bRetry = true;
}
}
return bRetry;
}
}
And DBConfiguration like this:
/// <summary>
///
/// </summary>
public class MYConfiguration : DbConfiguration
{
/// <summary>
///
/// </summary>
public MYConfiguration()
{
SetExecutionStrategy("System.Data.SqlClient", () => new MYExecutionStrategy(3, TimeSpan.FromSeconds(1)));
}
}
Questions:
How can I use the Connection Resiliency in the Entity Framework 6 With the Custom Transaction.
I was unable to find the DatabaseFacade class or namespace.
So after doing some RnD and reading around the WEB I found the Solution like this:
var str = MYExecutionStrategy(3, TimeSpan.FromSeconds(1));
str.Execute(() =>
{
using (DemoEntities objContext = GetWDemoEntities ())
{
using (TransactionScope obj = new TransactionScope())
{
Demo1 objDemo1 = new Demo1();
objDemo1.Title = "ABC";
objContext.Demo1.Add(objDemo1);
objContext.SaveChanges(); // First SaveChanges() method called.
Demo2 objDemo2 = new Demo2();
objDemo2.Title = "ABC";
objContext.Demo2.Add(objDemo2);
objContext.SaveChanges();// Second SaveChanges() method called.
obj.Complete();
}
}
}
With a custom transaction if you get a connection failure on the second SaveChanges(), the first SaveChanges() will also be rolled back. How do you propose to retry that? You can't. That's why EF retry only supports a single SaveChanges() per transaction.
One way forward is to remove the SaveChanges() from Demo1() and Demo2(), and have a single SaveChanges() in the calling method instead of a transaction.
Another way is for you to catch the exception in the calling method and orchestrate the retry there.
PREFACE: I know the code excerpt is lengthy but I did't want to leave out a detail that someone else might spot as the cause of the issue. The reason for the somewhat verbose nature of the code and the many Exception traps is due to the hunt for the NullReferenceException that I describe below. You can wade through the code quickly to the salient parts by jumping to the await keywords found amongst the async methods that call each other.
UPDATE: The InvalidOperationException is occurring because I am altering the IsEnabled status of certain buttons. I am on the Main thread so I am not sure why this is happening. Does anyone know why?
I have a Windows Phone 7 application written C# that is getting a System.InvalidOperationException when GetResponseAsync() is called in a particular code context. The application uses the PetFinder API to create a Cat Breed Guessing game with the intention of helping cats in animal shelters get adopted. Here is the exact Exception message in its entirety:
Message: An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.ni.dll
Before the Exception occurs, there are several successful calls to GetResponseAsync(). I have included the code for the methods involved in the Exception in the order that they are called below. Can someone tell me why I am getting this Exception and how to fix it?
The Exception is occurring completely out of the current code context that calls it, so it's some interaction between the code below and the library that contains GetResponseAsync() that is creating the conditions for the problem. The thread code context just before the call to GetResponseAsync() is the Main thread.
BACKGROUND NOTE:
This all began while I was chasing down a NullReferenceException that was occuring during the call to getRandomPetExt() within doLoadRandomPet(). From the reading I did on SO, my guess is that a NULL Task was being returned from getRandomPetExt(). But if you look at that code you'll see I'm doing everything in my power to trap a spurious Exception and to avoid returning a NULL Task. My current belief still at this time is that the NULL Task is occurring because some other code is generating a spurious Exception outside of my code. Perhaps something in Microsoft.Bcl.Async? Is this some strange synchronization context problem or hidden cross-thread access issue?
The strange part is that before I made a particular change I did not get the InvalidOperationException at all, only the intermittent NullReferenceException every 1 out of 20 to 30 calls to the method chain shown below. The InvalidOperationException on the other hand happens every time with the new code structure. The change I made was to me a minor one meant to help my debugging efforts. The only thing I did was create a method wrapper that moved the guts of loadRandomPet() into doLoadRandomPet(). I did this so I could disable some buttons that triggered method calls that might interfere with the operation to get a random pet. I wrapped the call to doLoadRandomPet() in a try/finally block, to make sure the buttons were re-enabled when the operation exited. Why would this cause such a major change in code execution?
async private void loadRandomPet(int maxRetries = 3)
{
// Do not allow the Guess My Breed or Adopt Me buttons to be
// clicked while we are getting the next pet.
btnAdoptMe.IsEnabled = false;
btnGuessMyBreed.IsEnabled = false;
try
{
await doLoadRandomPet(maxRetries);
}
finally
{
// >>>>> THIS CODE IS NEVER REACHED.
// Make sure the buttons are re-enabled.
btnAdoptMe.IsEnabled = true;
btnGuessMyBreed.IsEnabled = true;
}
}
// -------------------- CALLED NEXT
/// <summary>
/// (awaitable) Loads a random pet with a limit on the number of retries in case of failure.
/// </summary>
/// <param name="maxRetries">The number of retries permitted.</param>
async private Task doLoadRandomPet(int maxRetries = 3)
{
// Show the busy indicator.
radbusyMain.Visibility = Visibility.Visible;
try
{
// Get a random pet.
List<KeyValuePair<string, string>> listUrlArgs = new List<KeyValuePair<string, string>>();
// Only cats.
listUrlArgs.addKVP("animal", PetFinderUtils.EnumAnimalType.cat.ToString());
if (!String.IsNullOrWhiteSpace(MainMenu.ZipCode))
{
listUrlArgs.addKVP(PetFinderUtils.URL_FIELD_LOCATION, MainMenu.ZipCode);
}
if (maxRetries < 0)
throw new ArgumentOutOfRangeException("The maximum retries value is negative.");
Debug.WriteLine("------------------ START: LOADING Random Pet ----------------");
// Loop until a random pet is found.
int numRetries = 0;
// Select the breed, otherwise we will get a ton of "Domestic Short Hair" responses,
// which are not good for the game. Breeds that are returning empty search
// results this session are filtered too.
string strBreedName = MainMenu.GetRandomBreedName();
listUrlArgs.addKVP("breed", strBreedName);
while (numRetries <= maxRetries)
{
try
{
// Save the last successful retrieval.
if (this._pbi != null)
_pbiLast = this._pbi;
this._pbi = await getRandomPetExt(listUrlArgs);
}
catch (EmptySearchResultsException esr)
{
// getRandomPetExt() could not find a suitable cat given the current parameters.
// Swallow the Exception without notifying the user. Just allow the code
// further down to re-use the last cat retrieved in the hopes the next
// quiz won't have the problem.
Debug.WriteLine(">>>>>>>>>> doLoadRandomPet() - getRandomPet() failed to find a cat.");
}
catch (PetFinderApiException pfExc)
{
if (pfExc.ResponseCode == PetFinderUtils.EnumResponseCodes.PFAPI_ERR_LIMIT)
// Swallow the Exception, but let the user know to stop playing for the awhile
// since we have exceeded our rate limit.
CatQuizAux.EasyToast("The PetFinder server is busy.\nPlease try playing the game\nlater.");
else
// Swallow the Exception, but let the user know to stop playing for the awhile
// since we have exceeded our rate limit.
CatQuizAux.EasyToast("The PetFinder may be down.\nPlease try playing the game\nlater.");
// Just exit.
return;
} // try
catch (Exception exc)
{
// This is really bad practice but we're out of time. Just swallow the Exception
// to avoid crashing the program.
Debug.WriteLine(">>>>>>>>>> doLoadRandomPet() - getRandomPet() Other Exception occurrred. Exception Message: " + exc.Message);
}
// If the returned pet is NULL then no pets using the current search criteria
// could be found.
if (this._pbi != null)
{
// Got a random pet, stop looping. Save it to the backup cat field too.
break;
}
else
{
// Are we using a location?
if (listUrlArgs.hasKey(PetFinderUtils.URL_FIELD_LOCATION))
// Retry without the location to open the search to the entire PetFinder API
// inventory.
listUrlArgs.deleteKVP(PetFinderUtils.URL_FIELD_LOCATION);
else
{
// Use a differet breed. Add the current breed to the list of breeds returning
// empty search results so we don't bother with that breed again this session.
MainMenu.ListEmptyBreeds.Add(strBreedName);
// Remove the current breed.
listUrlArgs.deleteKVP("breed");
// Choose a new breed.
strBreedName = MainMenu.GetRandomBreedName();
listUrlArgs.addKVP("breed", strBreedName);
} // else - if (listUrlArgs.hasKey(PetFinderUtils.URL_FIELD_LOCATION))
} // if (this._pbi == null)
// Sleep a bit.
await TaskEx.Delay(1000);
numRetries++;
} // while (numRetries <= maxRetries)
// If we still have a null _pbi reference, use the back-up one.
if (this._pbi == null)
this._pbi = this._pbiLast;
if (this._pbi == null)
throw new ArgumentNullException("(ViewPetRecord::doLoadRandomPet) Failed completely to find a new cat for the quiz. Please try again later.");
// Add the pet to the already quizzed list.
MainMenu.AddCatQuizzed(this._pbi.Id.T.ToString());
// Show the cat's details.
lblPetName.Text = this._pbi.Name.T;
imgPet.Source = new BitmapImage(new Uri(this._pbi.Media.Photos.Photo[0].T, UriKind.Absolute));
// Dump the cat's breed list to the Debug window for inspection.
dumpBreedsForPet(this._pbi);
}
finally
{
// Make sure the busy indicator is hidden.
radbusyMain.Visibility = Visibility.Collapsed;
}
} // async private void doLoadRandomPet(int maxRetries = 3)
// -------------------- CALLED NEXT
/// <summary>
/// Gets a Random Pet. Retries up to maxRetries times to find a pet not in the already <br />
/// quizzed list before giving up and returning the last one found. Also skips pets without <br />
/// photos.
/// </summary>
/// <param name="listUrlArgs">A list of URL arguments to pass add to the API call.</param>
/// <param name="maxRetries">The number of retries to make.</param>
/// <returns>The basic info for the retrieved pet or NULL if a pet could not be found <br />
/// using the current URL arguments (search criteria).</returns>
async private Task<PetBasicInfo> getRandomPetExt(List<KeyValuePair<string, string>> listUrlArgs, int maxRetries = 3)
{
PetBasicInfo newPbi = null;
try
{
newPbi = await doGetRandomPetExt(listUrlArgs, maxRetries);
}
catch (Exception exc)
{
Debug.WriteLine(">>>>>> (ViewPetRecord::getRandomPetExt) EXCEPTION: " + exc.Message);
throw;
} // try/catch
return newPbi;
} // async private void getRandomPetExt()
// -------------------- CALLED NEXT
// This was done just to help debug the NullReferenceException error we are currently fighting.
// see getRandomPetExt() below.
async private Task<PetBasicInfo> doGetRandomPetExt(List<KeyValuePair<string, string>> listUrlArgs, int maxRetries = 3)
{
if (maxRetries < 0)
throw new ArgumentOutOfRangeException("The maximum retries value is negative.");
Debug.WriteLine("------------------ START: Getting Random Pet ----------------");
// Loop until a random pet is found that has not already been used in the quiz or until
// we hit the maxRetries limit.
int numRetries = 0;
PetBasicInfo pbi = null;
while (numRetries <= maxRetries)
{
try
{
pbi = await MainMenu.PetFinderAPI.GetRandomPet_basic(listUrlArgs);
}
catch (PetFinderApiException pfExcept)
{
// pfExcept.ResponseCode = PetFinderUtils.EnumResponseCodes.PFAPI_ERR_LIMIT;
switch (pfExcept.ResponseCode)
{
case PetFinderUtils.EnumResponseCodes.PFAPI_ERR_NOENT:
Debug.WriteLine("The PetFinder API returned an empty result set with the current URL arguments.");
// No results found. Swallow the Exception and return
// NULL to let the caller know this.
return null;
case PetFinderUtils.EnumResponseCodes.PFAPI_ERR_LIMIT:
Debug.WriteLine("The PetFinder API returned a rate limit error.");
// Throw the Exception. Let the caller handler it.
throw;
default:
// Rethrow the Exception so we know about it from the crash reports.
// Other Exception. Stop retrying and show the user the error message.
Debug.WriteLine("Exception during getRandomPetExt()\n" + pfExcept.ErrorMessage);
throw;
} // switch()
}
// Does the pet have a photo?
if (pbi.Media.Photos.Photo.Length > 0)
{
// Yes. Has the pet already been used in a quiz?
if (!MainMenu.IsCatQuizzed(pbi.Id.T.ToString()))
// No. Success.
return pbi;
} // if (pbi.Media.Photos.Photo.Length > 0)
// Retry required.
Debug.WriteLine(String.Format("Retrying, retry count: {0}", numRetries));
// No photo or already used in a quiz. Wait a little before retrying.
await TaskEx.Delay(1000);
// Count retires.
numRetries++;
} // while (numRetries <= maxRetries)
// Unable to find a cat not already quizzed. Just return the last retrieved.
Debug.WriteLine("Retry count exceeded. Returning last retreived pet.");
// Returning NULL results in a await throwing a non-specific NullReferenceException.
// Better to throw our own Exception.
throw new EmptySearchResultsException("(ViewPetRecord::getRandomPetExt) Unable to retrieve a new random cat from the PetFinder API server.");
// return pbi;
} // async private PetBasicInfo doGetRandomPetExt()
// ------------------ CALLED NEXT
/// <summary>
/// Returns the basic information for a randomly chosen pet of the given animal type.
/// </summary>
/// <param name="enAnimalType">The desired animal type to restrict the search to.</param>
/// <returns></returns>
async public Task<JSON.JsonPetRecordTypes.PetBasicInfo> GetRandomPet_basic(List<KeyValuePair<string, string>> urlArgumentPairs = null)
{
Debug.WriteLine("(GetRandomPet_basic) Top of call.");
// If the URL Argument Pairs parameter is null, then create one.
if (urlArgumentPairs == null)
urlArgumentPairs = new List<KeyValuePair<string, string>>();
// Add the "output" parameter that tells PetFinder we want the Basic information for the pet,
// not the ID or full record.
urlArgumentPairs.addKVP("output", "basic");
// Add a unique URL argument to defeat URL caching that may be taking
// place in the Windows Phone library or at the PetFinder API server.
// This defeats the problem so that a new random pet is returned
// each call, instead of the same one.
long n = DateTime.Now.Ticks;
urlArgumentPairs.addKVP("nocache", n.ToString());
// Build the API call.
string strApiCall =
buildPetFinderApiUrl(METHOD_RANDOM_PET,
urlArgumentPairs);
Debug.WriteLine("(GetRandomPet_basic) URL for call: \n" + strApiCall);
// Make the call.
string strJsonReturn = await Misc.URLToStringAsyncEZ(strApiCall);
bool bIsJsonReturnValid = false;
try
{
JSON.JsonPetRecordTypes.PetRecordBasicInfo jsonPetBasic = JsonConvert.DeserializeObject<JSON.JsonPetRecordTypes.PetRecordBasicInfo>(strJsonReturn);
// Deserialization succeeded.
bIsJsonReturnValid = true;
// Success code?
// For some strange reason T is cast to an "int" here where in GetBreedList it's equivalent is cast to a string.
int iResponseCode = jsonPetBasic.Petfinder.Header.Status.Code.T;
if (iResponseCode != 100)
throw new PetFinderApiException("PetFinder::GetRandomPet_basic", iResponseCode);
// throw new Exception("(PetFinder::GetRandomPet_basic) The response document contains a failure response code: " + iResponseCode.ToString() + ":" + jsonPetBasic.Petfinder.Header.Status.Message);
// Return the pet record basic info.
return jsonPetBasic.Petfinder.Pet;
}
finally
{
if (!bIsJsonReturnValid)
// Setting debug trap to inspect JSON return.
Debug.WriteLine("JSON Deserialization failure.");
Debug.WriteLine("(GetRandomPet_basic) BOTTOM of call.");
} // try/finally
}
// -------------------- CALLED NEXT, never returns
/// <summary>
/// (awaitable) Simpler version of above call. Same warnings about getting byte stream <br />
/// objects apply here as they do to URLtoStringAsync()
/// </summary>
/// <param name="stUrl"></param>
/// <param name="reqMethod"></param>
/// <returns></returns>
async public static Task<string> URLToStringAsyncEZ(string strUrl, HttpRequestMethod reqMethod = HttpRequestMethod.HTTP_get)
{
strUrl = strUrl.Trim();
if (String.IsNullOrWhiteSpace(strUrl))
throw new ArgumentException("(Misc::URLToStringAsyncEZ) The URL is empty.");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);
// Get the string value for the request method.
request.Method = reqMethod.GetDescription();
// >>>>> THIS CALL to GetResponseAsync() TRIGGERS THE EXCEPTION (see stack trace below)
// Async wait for the respone.
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
// Use a stream reader to return the string.
using (var sr = new StreamReader(response.GetResponseStream()))
{
return sr.ReadToEnd();
}
}
// -------------------- STACK TRACE JUST BEFORE URLToStringAsync(), the call the triggers the exception.
> Common_WP7.DLL!Common_WP7.Misc.URLToStringAsyncEZ(string strUrl, Common_WP7.Misc.HttpRequestMethod reqMethod) Line 1079 C#
CatQuiz.DLL!CatQuiz.PetFinderUtils.GetRandomPet_basic(System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string,string>> urlArgumentPairs) Line 441 C#
CatQuiz.DLL!CatQuiz.ViewPetRecord.doGetRandomPetExt(System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string,string>> listUrlArgs, int maxRetries) Line 55 C#
CatQuiz.DLL!CatQuiz.ViewPetRecord.getRandomPetExt(System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string,string>> listUrlArgs, int maxRetries) Line 123 C#
CatQuiz.DLL!CatQuiz.ViewPetRecord.doLoadRandomPet(int maxRetries) Line 243 C#
CatQuiz.DLL!CatQuiz.ViewPetRecord.loadRandomPet(int maxRetries) Line 343 C#
CatQuiz.DLL!CatQuiz.ViewPetRecord.PageViewPetRecord_Loaded(object sender, System.Windows.RoutedEventArgs e) Line 355 C#
System.Windows.ni.dll!MS.Internal.CoreInvokeHandler.InvokeEventHandler(int typeIndex, System.Delegate handlerDelegate, object sender, object args) Unknown
System.Windows.ni.dll!MS.Internal.JoltHelper.FireEvent(System.IntPtr unmanagedObj, System.IntPtr unmanagedObjArgs, int argsTypeIndex, int actualArgsTypeIndex, string eventName) Unknown
======================= EXCEPTION
// -------------------- STACK TRACE when EXCEPTION occurs
> CatQuiz.DLL!CatQuiz.App.Application_UnhandledException(object sender, System.Windows.ApplicationUnhandledExceptionEventArgs e) Line 101 C#
System.Windows.ni.dll!MS.Internal.Error.CallApplicationUEHandler(System.Exception e) Unknown
System.Windows.ni.dll!MS.Internal.Error.IsNonRecoverableUserException(System.Exception ex, out uint xresultValue) Unknown
System.Windows.ni.dll!MS.Internal.JoltHelper.FireEvent(System.IntPtr unmanagedObj, System.IntPtr unmanagedObjArgs, int argsTypeIndex, int actualArgsTypeIndex, string eventName) Unknown
// -------------------- CODE CONTEXT when EXCEPTION occurs
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
The usual advice when rethrowing an exception is to use a throw; statement so the original stack trace is preserved. (Example)
However, when I try this simple example, the Visual Studio debugger does not show the original stack trace.
namespace ExceptionTest
{
class Program
{
static void ThrowException()
{
throw new System.Exception(); // The line that I WANT the debugger to show.
}
static void Main(string[] args)
{
try
{
ThrowException();
}
catch (System.Exception)
{
System.Console.WriteLine("An exception was thrown.");
throw; // The line that the debugger ACTUALLY shows.
}
}
}
}
How can I use the debugger to find the original source of the exception?
Your best option is to ask Visual Studio to break on the original exception rather than navigate back to it from the stack trace. To do this:
1) Click on the 'Debug' menu item
2) Click 'Exceptions...'
3) Select 'Common Language Runtime Exceptions' - 'Thrown'
With this approach you may get more than you really wanted if there are many exceptions being thrown. You can filter which exceptions it breaks on by expanding the tree list.
See image:
If you're running Visual Studio 2010 Ultimate, use IntelliTrace.
It keeps a record of all exceptions thrown and allows you to "debug back in time" to see parameters, threads, and variables at the time of each throw.
(Taken from Chris Schmich's answer to a similar question.)
The best solution that I've found is write the Exception callstack to the Debug.Console and then let the built-in code line parser in Visual Studio to provide the navigation.
I found it really useful when dealing with unhandled exceptions on the AppDomain and WPF Dispatcher as Visual Studio always breaks too late.
Based from an article on Code Project, I have modified it that it outputs to the Console as a single block of text - rather than line-by-line - which was necessary I have logging also writing to the Console.
Usage
public void ReportException(Exception exception)
{
if (Debugger.IsAttached)
{
DebugHelper.PrintExceptionToConsole(exception);
Debugger.Break();
}
// ...
}
Source
public static class DebugHelper
{
// Original idea taken from the CodeProject article
// http://www.codeproject.com/Articles/21400/Navigating-Exception-Backtraces-in-Visual-Studio
private static readonly string StarSeparator = new String('*', 80);
private static readonly string DashSeparator = new String('-', 80);
private const string TabString = " ";
/// <summary>
/// Prints the exception using a format recognized by the Visual Studio console parser.
/// Allows for quick navigation of exception call stack.
/// </summary>
/// <param name="exception">The exception.</param>
public static void PrintExceptionToConsole(Exception exception)
{
using (var indentedTextWriter = new IndentedTextWriter(Console.Out, TabString))
{
var indentLevel = 0;
while (exception != null)
{
indentedTextWriter.Indent = indentLevel;
indentedTextWriter.Write(FormatExceptionForDebugLineParser(exception));
exception = exception.InnerException;
indentLevel++;
}
}
}
private static string FormatExceptionForDebugLineParser(Exception exception)
{
StringBuilder result = new StringBuilder();
result.AppendLine(StarSeparator);
result.AppendLineFormat(" {0}: \"{1}\"", exception.GetType().Name, exception.Message);
result.AppendLine(DashSeparator);
// Split lines into method info and filename / line number
string[] lines = exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.Where(x => !String.IsNullOrEmpty(x))
.ToArray();
foreach (var line in lines)
{
string[] parts = line.Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries);
string methodInfo = parts[0];
if (parts.Length == 2)
{
string[] subparts = parts[1].Split(new string[] { ":line " }, StringSplitOptions.RemoveEmptyEntries);
result.AppendLineFormat(" {0}({1},1): {2}", subparts[0], Int32.Parse(subparts[1]), methodInfo);
}
else
result.AppendLineFormat(" {0}", methodInfo);
}
result.AppendLine(StarSeparator);
return result.ToString();
}
}
To use the above, as is, you will also need the Extension Method below and add the System.CodeDom.Compiler namespace for IndentedTextWriter.
Extension Method
/// <summary>
/// Appends the string returned by processing a composite format string followed by the default line terminator.
/// </summary>
/// <param name="sb">The StringBuilder.</param>
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
public static void AppendLineFormat(this StringBuilder sb, string format, params object[] args)
{
sb.AppendFormat(format, args);
sb.AppendLine();
}
You can use the DebuggerNonUserCode Attribute.
See http://blogs.msdn.com/b/jmstall/archive/2007/02/12/making-catch-rethrow-more-debuggable.aspx
The example becomes like this:
namespace ExceptionTest
{
class Program
{
static void ThrowException()
{
throw new System.Exception(); // The line that I WANT the debugger to show.
}
[DebuggerNonUserCode()]
static void Main(string[] args)
{
try
{
ThrowException();
}
catch (System.Exception)
{
System.Console.WriteLine("An exception was thrown.");
throw; // The line that the debugger ACTUALLY shows.
}
}
}
}
Incidentally, in vb.net, one can use exception filters in some situations like this where one knows one isn't really interested in catching an exception--just finding out that it happened. If the code were written in vb.net and used a filter to capture the exception (probably doing the output itself within the 'finally' block) there wouldn't be a "catch and rethrow"--the cursor would jump to the source of the original exception (as a bonus, vs would interrupt the program flow before any stack unwinding took place). Note that one can opt to have vs trap every time a particular exception is thrown, whether or not it will be caught, but sometimes one is only interested in some of the places an exception is thrown, rather than all of them.
I recently came across this code:
public static class ClientBaseExtender
{
/// <summary>
/// Tries to execute async service call. If <see cref="TimeoutException"/> occured retries again.
/// </summary>
/// <typeparam name="TChannel">ServiceClient class.</typeparam>
/// <typeparam name="TArgs">Type of service client method return argument.</typeparam>
/// <param name="client">ServiceClient instance.</param>
/// <param name="tryExecute">Delegate that execute starting of service call.</param>
/// <param name="onCompletedSubcribe">Delegate that subcribes an event handler to the OnCompleted event of the service client method.</param>
/// <param name="onCompleted">Delegate that executes when service call is succeeded.</param>
/// <param name="onError">Delegate that executes when service call fails.</param>
/// <param name="maxAttempts">Maximum attempts to execute service call before error if <see cref="TimeoutException"/> occured (by default 5).</param>
public static void ExecuteAsyncRepeatedly<TChannel, TArgs>(this ClientBase<TChannel> client, Action tryExecute,
Action<EventHandler<TArgs>> onCompletedSubcribe, EventHandler<TArgs> onCompleted,
EventHandler<TArgs> onError, int maxAttempts)
where TChannel : class
where TArgs : AsyncCompletedEventArgs
{
int attempts = 0;
var serviceName = client.GetType().Name;
onCompletedSubcribe((s, e) =>
{
if (e.Error == null) // Everything is OK
{
if (onCompleted != null)
onCompleted(s, e);
((ICommunicationObject)client).Close();
Debug.WriteLine("[{1}] Service '{0}' closed.", serviceName, DateTime.Now);
}
else if (e.Error is TimeoutException)
{
attempts++;
if (attempts >= maxAttempts) // Final timeout after n attempts
{
Debug.WriteLine("[{2}], Final Timeout occured in '{0}' service after {1} attempts.", serviceName, attempts, DateTime.Now);
if (onError != null)
onError(s, e);
client.Abort();
Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now);
return;
}
// Local timeout
Debug.WriteLine("[{2}] Timeout occured in '{0}' service (attempt #{1}).", serviceName, attempts, DateTime.Now);
Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now);
tryExecute(); // Try again.
}
else
{
if (onError != null)
onError(s, e);
client.Abort();
Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now);
}
});
Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now);
tryExecute(); // First attempt to execute
}
}
public void GetData()
{
var client = new MyServiceClient();
client.ExecuteAsyncRepeatedly(() => client.MyOperationAsync(...),
(EventHandler<MyOperationCompletedEventArgs> handler) =>client.MyOperationCompleted += handler,
(s, e) => // OnCompleted
{
Do(e.Result);
},
(s, e) => // OnError
{
HandleError(e.Error);
}
);
}
The problem is, I have a button that fires this code off. When the button is pushed more than once the handler gets added again and again. This is a problem because the code will fire as many times as the user has pushed the button. How can I remove the handler created with the lambda expression in this code so it will only run once?
Thanks!
EDIT:
I'm calling the code like this from my button click command:
_dataService.GetData(GetDataCompleted);
private void GetDataComplete(Data data)
{
//do something with data }
I think that you can solve it by implementing a push-pull strategy in your code-behind. I propose something similar to this:
bool _requestPending;
readonly object _lock = new object();
void OnClick (...)
{
lock(_lock)
{
if (_requestPending == false)
{
_dataService.GetData(GetDataCompleted);
_requestPending = true;
}
}
}
private void GetDataComplete(Data data)
{
lock(_lock)
{
try
{
//do something with data
}
finally
{
_requestPending = false;
}
}
}
Even better, disable the UI button when you have a pending request. You wouldn't have any concurrency issues with accessing and modifying the _requestPending from different threads, but still you could suffer a race condition if the service response is fast enough, so still better to synchronize the two blocks of code.
Anyway, personally I don't like this implementation for what you're trying to achieve. The code is quite confusing, and makes it hard to foresee problems that may arise. Make sure that:
you provide a way to abort a request
and reenable the button again
the code that updates the screen is
executed by the UI thread