I have recently come across an issue in C#.Net app. The unmodified stack trace looks like below :
2018-09-12 21:08:31,596 [] [112] ERROR PLoggerFactory::RunLogic - Exception : System.Exception: Serialisation errorSystem.ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Block`2.GetConfigFromDB()
at Block`2.GetConfigFromDB()
at Block`2.Begin(IParcelGettable`1 P, Action`1 f)
at Run.<>c__DisplayClass45_0.<RunInNewThread>b__1()
In the above, GetConfigFromDB is called in a stack.
But I have verified the code, there is nothing recursive GetConfigFromDB in that. Is this possible?
Please let me know if the code of GetConfigFromDB is required, I will modify it and share.
-----EDIT ------- Code added
private Dictionary<string, object> GetConfigFromDB()
{
blockConfigJson = controller.BlockConfig.GetConfig(this.BlockInstanceId);
if (String.IsNullOrEmpty(blockConfigJson))
{
return new Dictionary<string, object>();
}
Dictionary<string, object> configDictionary = new Dictionary<string, object>();
try
{
configDictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(blockConfigJson);
foreach (var v in configDictionary)
{
var key = "__" + this.BlockInstanceId + "." + v.Key;
if (SharedConfig.ContainsKey(key))
{
SharedConfig[key] = v.Value;
}
else
{
SharedConfig.Add(key, v.Value);
}
if (v.Key.Trim() == "_extraInfo_")
{
dynamic extraInfo = JsonConvert.DeserializeObject(configDictionary["_extraInfo_"].ToString());
JsonConvert.DeserializeObject<List<Variable>>(extraInfo["Variables"].ToString());
Dictionary<string, string> _variablesTemp = new Dictionary<string, string>();
try
{
_variablesTemp = JsonConvert.DeserializeObject<Dictionary<string, string>>(extraInfo["Variables"].ToString());
}
catch (Exception ex)
{
mLogger.Debug("Variable parsing error " + ex);
}
List<Variable> _variables = new List<Variable>();
foreach (KeyValuePair<string, string> kyp in _variablesTemp)
{
_variables.Add(new Variable()
{
variableName = kyp.Key,
variableValue = kyp.Value
});
}
foreach (Variable _variable in _variables)
{
if (!SharedVariables.ContainsKey(_variable.variableName))
{
SharedVariables.Add(_variable.variableName, _variable.variableValue);
new Caching().Send(_variable.variableName, _EvaluateConfigValue(_variable.variableValue, this.blockConfig, this.SharedConfig, this.SharedVariables, this.propagatedConfig, this.propagatedVariables, this.ControlId));
}
}
}
}
}
catch (Exception ex)
{
configDictionary = new Dictionary<string, object>();
throw;
}
return configDictionary;
}
That stack trace shows your method calling Dictionary<,>.Insert(TKey, TValue, bool), but of course you never do. You can't, because that is a private method called by Dictionary<,>.Add, which you do call.
When optimisations are enabled, stack traces are not always 100% accurate. Especially when trivial methods are called, which almost certainly get inlined. Dictionary<,>.Add is such a trivial method: it literally does nothing else but call Dictionary<,>.Insert. It looks like enough information was recovered to determine that there was something between Dictionary<,>.Insert and GetConfigFromDB, but not what that something might be. Because nothing better is available, the name GetConfigFromDB is used a second time.
Related
I was perusing our large code base I came across this function which is used to format an exception:
private static string FormatException(Exception ex)
{
var errorMessage = new StringBuilder();
errorMessage.AppendLine($"ErrorMessage : {ex.Message}");
if (ex.Data.Count > 0)
{
var additionalMessage = new StringBuilder();
foreach (var key in ex.Data.Keys)
{
additionalMessage.Append($" {key} : {ex.Data[key]}");
}
errorMessage.AppendLine($"AdditionalMessage : 【 {additionalMessage} 】");
}
if (!string.IsNullOrWhiteSpace(ex.StackTrace))
{
errorMessage.AppendLine($"StackTrace : {ex.StackTrace}");
}
if (ex.InnerException != null)
{
errorMessage.AppendLine($"InnerException : {ex.InnerException.ToJson(false, true)}");
}
return errorMessage.ToString();
}
At first sight it appears, to me, to offer no real value over the built in ToString() method, given that the information is just going to be run written to a log file.
Am I missing something subtle in the ToString() method that would require something like to ensure the Exception's information is fully collected.
I am calling WEB API call using the following code in web service(.asmx).
Server.ScriptTimeout = 3600;
return util.util.Settle(ids, userName, userPwd, userBelongCountry);
Settle method invokes MakeRequest() as given below:
public Dictionary<string, string> MakeRequest(string addressAPI)
{
HttpWebRequest r=null;
try
{
r = (HttpWebRequest)WebRequest.Create(addressAPI);
r.Method = "Get";
HttpWebResponse res = (HttpWebResponse)r.GetResponse();
Stream sr = res.GetResponseStream();
StreamReader sre = new StreamReader(sr);
var s = sre.ReadToEnd();
sre.Close();
XDocument doc = XDocument.Parse(s);
foreach (XElement element in doc.Descendants().Where(p => p.HasElements == false))
{
int keyInt = 0;
string keyName = element.Name.LocalName;
while (!this.dataDictionary.ContainsKey(keyName))
{
keyName = element.Name.LocalName + "_" + keyInt++;
this.dataDictionary.Add(keyName, element.Value);
}
}
return this.dataDictionary;
}
catch (Exception ex)
{
SystemLogWebCom.Error("Error in WEBAPI call" + ex.ToString());
return null;
throw ex;
}
}
Problem:If any exception occurred the WEB API is getting called enormous times approx.15000+ times continuously. It supposed to execute once and return back.
Error logged in Logger:
"Error in WEBAPI callSystem.ArgumentException: An item with the same key has already been added.at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at WebAPICommunicator.Utility.MakeRequest(String addressAPI)".
I am wondering how come these many number of times it is invoking and the same number of errors i could see in Logger.
Now I have included
finally
{
r.Abort();
}
Can it solve the problem?
First is that you don't dispose streams in a finally block.
And second that your exception will never be re thrown because nothing will be executed after "return null" in catch, "throw ex;" is dead code.
Your exception is been thrown because of you using while instead of if:
while (!this.dataDictionary.ContainsKey(keyName))
if (!this.dataDictionary.ContainsKey(keyName))
Dictionaries can not contain duplicate keys, and that's what is happening here the second time you read the same key from xml.
So I encountered a strange issue today - I had a simple creation of an instance inside the critical section of a lock, and it would throw a null reference exception when I manually dragged the next line to execute. To illustrate:
public class SearchEngineOptimizationParser
{
protected static ConcurrentDictionary<string, SearchEngineOptimizationInfo> _referralInformation = null;
protected static DateTime _lastRecordingDate;
protected static object _lockRecordingObject = new object();
protected static Dictionary<string, string> _searchProviderLookups = null;
static SearchEngineOptimizationParser()
{
_referralInformation = new ConcurrentDictionary<string, SearchEngineOptimizationInfo>();
_lastRecordingDate = DateTime.Now;
_searchProviderLookups = new Dictionary<string, string>();
_searchProviderLookups.Add("google.com", "q");
_searchProviderLookups.Add("yahoo.com", "p");
_searchProviderLookups.Add("bing.com", "q");
}
public SearchEngineOptimizationParser()
{
}
public virtual void ParseReferrer(Uri requestUrl, NameValueCollection serverVariables, ISession session)
{
string corePath = requestUrl.PathAndQuery.SmartSplit('?')[0].ToLower();
string referrer = serverVariables["HTTP_REFERER"];
if (!string.IsNullOrWhiteSpace(referrer))
{
NameValueCollection queryString = HttpUtility.ParseQueryString(referrer);
string dictionaryKey = session.AffiliateID + "|" + corePath;
foreach (var searchProvider in _searchProviderLookups)
{
if (referrer.Contains(searchProvider.Key))
{
if (queryString[searchProvider.Value] != null)
{
string keywords = queryString[searchProvider.Value];
SearchEngineOptimizationInfo info = new SearchEngineOptimizationInfo
{
Count = 1,
CorePath = corePath,
AffiliateId = session.AffiliateID,
Keywords = keywords
};
_referralInformation.AddOrUpdate(dictionaryKey, info, (key, oldValue) =>
{
oldValue.Count++;
return oldValue;
});
break;
}
}
}
}
if (DateTime.Now > _lastRecordingDate.AddHours(1))
{
lock (_lockRecordingObject)
{
if (DateTime.Now > _lastRecordingDate.AddHours(1))
{
SearchEngineKeywordRepository repository = new SearchEngineKeywordRepository();
List<KeyValuePair<string, SearchEngineOptimizationInfo>> currentInfo = _referralInformation.ToList();
Action logData = () =>
{
foreach (var item in currentInfo)
repository.LogKeyword(item.Value);
};
Thread logThread = new Thread(new ThreadStart(logData));
logThread.Start();
_lastRecordingDate = DateTime.Now;
_referralInformation.Clear();
}
}
}
}
EDIT: Updated Real Object
public class SearchEngineKeywordRepository
{
public virtual void LogKeyword(SearchEngineOptimizationInfo keywordInfo)
{
LogSearchEngineKeywords procedure = new LogSearchEngineKeywords();
procedure.Execute(keywordInfo.CorePath, keywordInfo.AffiliateId, keywordInfo.Keywords, keywordInfo.Count);
}
}
The general pattern being that I want to do this 'something' only every hour (in the context of a website application that gets a lot of traffic). I would breakpoint my first if statement, and then step the next line to execute inside the second if statement. When doing so, the act of initializing the SomeObject instance would cause a null reference exception. It had a completely 100% default constructor - I didn't even specify one.
However, when I let the code go through naturally, it would execute without problem. For some reason, it seems that when I skipped over the lock call into the critical section to just test run that code, it caused all kinds of errors.
I'm curious to know why that is; I understand the lock keyword is just syntactic sugar for a Monitor.Enter(o) try / finally block, but that seems to be that when invoking the constructor, something else was happening.
Anyone have any ideas?
EDIT: I've added the actual code to this. I'm able to reproduce this at will, but I still don't understand why this is happening. I've tried copying this code to another solution and the problem does not seem to occur.
I've tried to reproduce your situation, but as I expected I could not. I've tried both the 2.0 and 4.0 runtime, in 32 and 64 bit mode (debugging sometimes behaves differently under x64).
Is the code shown a simplification? Have you checked all your assumptions? I understand you're skipping 3 lines of code, both the if statements and the lock? In that case, even setting the lock object to null does not cause the exception you describe.
(Having _lockRecordingObject set to null causes an ArgumentNullException when leaving the lock scope)
I am writing a class that does operations to multiple streams. Here is a example of what I am doing now
Dictionary<int, int> dict = new Dictionary<int, int>(_Streams.Count);
for (int i = 0; i < _Streams.Count; i++)
{
try
{
dict.Add(i, _Streams[i].Read(buffer, offset, count));
}
catch (System.IO.IOException e)
{
throw new System.IO.IOException(String.Format("I/O exception occurred in stream {0}", i), e);
}
catch (System.NotSupportedException e)
{
throw new System.NotSupportedException(String.Format("The reading of the stream {0} is not supported", i), e);
}
catch (System.ObjectDisposedException e)
{
throw new System.ObjectDisposedException(String.Format("Stream {0} is Disposed", i), e);
}
}
int? last = null;
foreach (var i in dict)
{
if (last == null)
last = i.Value;
if (last != i.Value)
throw new ReadStreamsDiffrentExecption(dict);
last = i.Value;
}
return (int)last;
I would like to simplify my code down to
Dictionary<int, int> dict = new Dictionary<int, int>(_Streams.Count);
for (int i = 0; i < _Streams.Count; i++)
{
try
{
dict.Add(i, _Streams[i].Read(buffer, offset, count));
}
catch (Exception e)
{
throw new Exception(String.Format("Exception occurred in stream {0}", i), e);
}
}
int? last = null;
foreach (var i in dict)
{
if (last == null)
last = i.Value;
if (last != i.Value)
throw new ReadStreamsDiffrentExecption(dict);
last = i.Value;
}
return (int)last;
However if anyone is trying to catch specific exceptions my wrapper will hide the exception that Read threw. How can I preserve the type of exception, add my extra info, but not need to write a handler for every possible contingency in the try block.
I would suggest not catching those exceptions at all...
The information you add could (mostly) be gleaned from the stackdump.
You could use catch-and-wrap to translate to a library-specific exception:
catch (Exception e)
{
throw new ReadStreamsErrorExecption(
String.Format("Exception occurred in stream {0}", i), e);
}
I think you have a bit of an issue here in the way you are working with your exception.
You should not be throwing the base Exception class, but something more specific so they can handle it.
Is the id value something that is really "valuable" from a diagnostic function?
I would review what you are doing, and see if you really need to be wrapping the exception.
I find the first version is better for readability and is the more expressive to my eye. This is how exception handling should be written.
Generally the rule that I've picked up from Eric Lipperts blogs, is that you should only capture an exception if you're going to do something about it.
Here you are just re-throwing the exception with a new message. Just let the client handle the exceptions themselves unless you're going to try and recover from errors. In which case add a
throw;
If you need to bubble the exception backup because you can't handle it.
One little known .NET trick is that you CAN add information to an Exception without wrapping it. Every exception has a .Data dictionary on it that you can stuff with additional information, e.g.
try
{
...
}
catch (FileNotFoundException ex)
{
ex.Data.Add("filename", filename);
throw;
}
Now in your top-level exception handling code you can dump the exception and its associated dictionary out to your log file or into your Exceptions database and thus get far more information than you had before.
In an ASP.NET application you might want to add the URL, the username, the referrer, the contents of the cookies, ... to the .Data dictionary before letting your application error handler take it.
I have a class that contains the following property:
public Dictionary<string, int> CommentCounts {
get {
string cacheKey = "CommentCounts";
HttpContext c = HttpContext.Current;
if (c.Cache[cacheKey] == null) {
c.Cache.Insert(cacheKey, new Dictionary<string, int>(), null, DateTime.UtcNow.AddSeconds(30), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.High, null);
c.Trace.Warn("New cached item: " + cacheKey);
}
return (Dictionary<string, int>)c.Cache[cacheKey];
}
set {
HttpContext.Current.Cache["CommentCounts"] = value;
}
}
It seems that the Trace statement only runs once, and not every 30 seconds after the Cache item has expired. The only way I can get it to refresh the Cached item is to make a code chance and rebuild the project, which is obviously less than ideal.
What am I missing? Thanks in advance...
The set part of the property is probably the cause - Cache["key"] = value is equivalent to calling Cache.Insert with NoAbsoluteExpiration, NoSlidingExpiration which means it never expires. The correct solution would look like this:
public Dictionary<string, int> CommentCounts {
get {
const string cacheKey = "CommentCounts";
HttpContext c = HttpContext.Current;
if (c.Cache[cacheKey] == null) CommentCounts = new Dictionary<string, int>();
return (Dictionary<string, int>)c.Cache[cacheKey];
}
set {
const string cacheKey = "CommentCounts";
c.Cache.Insert(cacheKey, value, null, DateTime.UtcNow.AddSeconds(30), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.High, null);
c.Trace.Warn("New cached item: " + cacheKey);
}
}
I had this problem before and asked a question here; it was never really answered, but there might be some helpful debugging tips in the answers.