We have a confusing case, where code that runs normally hundreds of times suddenly stopped working. It is an application that usually runs for weeks.
The question is, do XmlSerializer(Type) have some cache somewhere, which can be corrupted?
The background:
It happened at startup, at one occasion, that we got a lot of exceptions. After a restart when the problem was detected (a few days later), it ran normally again.
We have tracked down the problem to this code:
internal static class StateManager
{
private static XmlSerializer queueSerializer = new XmlSerializer(typeof(List<QueueItem>));
private static readonly string queuePath = Path.Combine(SubSystem.PersistentDirectory, "Queue.xml");
internal static void SaveQueue(List<QueueItem> upcomingTasks)
{
XmlWriter xmlWriter = XmlWriter.Create(queuePath, xmlSettings);
queueSerializer.Serialize(xmlWriter, upcomingTasks);
xmlWriter.Close();
}
internal static List<QueueItem> GetQueue()
{
var queue = new List<QueueItem>();
try
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(queuePath);
using (XmlReader reader = XmlReader.Create(new StringReader(xmlDoc.OuterXml)))
{
queue = queueSerializer.Deserialize(reader) as List<QueueItem>;
}
}
catch (Exception e)
{
AppTrace.Write(TraceLevel.Error, string.Format("Failed to load State Queue: {0}", e.Message));
}
return queue;
}
}
and the error we get is:
Failed to load State Queue: The type initializer for 'StateManager' threw an exception.
As we understand it, this leaves two possibilities for the culprit:
private static XmlSerializer queueSerializer = new XmlSerializer(typeof(List<QueueItem>));
or
private static readonly string queuePath = Path.Combine(SubSystem.PersistentDirectory, "Queue.xml");
We have checked SubSystem.PersistentDirectory carefully, and believe it to be innocent.
Since this happened in the field at a client's machine, and we cannot reproduce it, checking the inner exception is not possible.
You should catch that ! I see there is no static ctor there, you might attempt something like this, deferring initialization so you're able to know more:
internal static class StateManager
{
private static XmlSerializer queueSerializer;
private static readonly string queuePath;
internal static StateManager(){
try
{
queueSerializer = new XmlSerializer(typeof(List<QueueItem>));
queuePath = Path.Combine(SubSystem.PersistentDirectory, "Queue.xml");
}
catch(Exception ex)
{
// Log, log, log!
throw; // Essential: you MUST rethrow!
}
}
}
As far as the actual offending line, there is no way to tell for sure without a trace: all you know is that your type could not be initialized, with no indications about the why.
The most likely causes, as far as I can guess, are:
Something is broken in the data you feed to the XmlSerializer (not the XmlSerializer itself: I highly doubt that anything coming from the System namespace is prone to blowing up at random)
Your SubSystem.PersistentDirectory contains broken data
(Unlikely, but you never know...) Something else is broken and the exception is not actually related to the offending code, which might reside elsewhere
Related
Rookie here so please be nice!! I have had so much fun learning to program and gotten some great help along the way when google failed me. But alas, I'm stuck again.
I have a C# program that looks like this (It's MWS if anyone is familiar)
I've tried so many different ways to get this to effectively loop through a list of values in a text file. The problem I'm having is that the Main function is where I have to set the loop, but the BuildClass is where I need to cycle through the values in the text file (sentinel). I've included some stuff that probably isn't necessary just in case it is messing my code up and I don't realize it.
Here's what I've tried:
setting the loop inside the BuildClass - didn't expect it to work but it threw an exception before getting to the sentinel.
Reference the sentinel within the main function by changing the "using" or "var" in the main function sentinel to public - turned EVERYTHING red in visual studio
moving the string sentinel outside the main function so that the function and the BuildClass would recognize it - main function did not recognize it anymore.
I've tried so many other things unsuccessfully. I've gotten it to loop with the same sentinel value passed from BuildClass to the function over and over again but that's about it.
What I think I need:
A destructive version of streamReader that will remove the value from the text file when reading it. I'll put this inside the BuildClass, so that the next loop of the main function, the next value will be read and passed into the main function until the file is empty, terminating the loop.
an understanding of why changing sentinel to public destroys the code so badly. I have a decent understanding of why the other attempts wouldn't work.
namespace MainSpace
{
public class MainClass
{
int i;
public static void Main(string[] args)
{
ClientClass client = new ClientInterface(appName, appVersion, password, config);
MainClass sample = new MainClass(client);
string sentinel;
using (var streamReader = new StreamReader(#"sample.txt", true))
while((sentinel = streamReader.ReadLine()) != null)
{
try
{
//stuff
response = sample.InvokeBuild();
Console.WriteLine("Response Stuff");
string responseXml = response.ToXML();
Console.WriteLine(responseXml);
StreamWriter FileWrite = new StreamWriter("FileTest.xml", true);
FileWrite.WriteLine(responseXml);
FileWrite.Close();
}
catch (ExceptionsClass)
{
// Exception stuff
throw ex;
}
}
}
private readonly ClientInterface client;
public MainClass(ClientInterface client)
{
this.client = client;
}
public BuildClass InvokeBuild()
{
{
using (var streamReader = new StreamReader("sample.txt", true))
{
string sentinel = streamReader.ReadLine();
Thread.Sleep(6000);
i++;
Console.WriteLine("attempt " + i);
// Create a request.
RequestClass request = new RequestClass();
//Password Stuff
request.IdType = idType;
IdListType idList = new IdListType();
idList.Id.Add(sentinel);
request.IdList = idList;
return this.client.RequestClass(request);
}
}
}
}
I'm using HockeyApp to collect crash data for my app, but for some reason it doesn't provide the stack trace.
What I have is something like that:
MyNamespace!<BaseAddress>+0x5d1287
MyNamespace!<BaseAddress>+0x5f18d5
MyNamespace!<BaseAddress>+0x5f1827
Microsoft.HockeyApp.Extensibility.Windows.UnhandledExceptionTelemetryModule.CoreApplication_UnhandledErrorDetected(Object sender, ApplicationModel.Core.UnhandledErrorDetectedEventArgs e)
so it's kinda hard to find out what's happening.
The exception message is helpful tho, as it says
Element not found. Cannot find credential in Vault
and there's just one place in which I'm using PasswordVault.
The problem here is that I'm using it inside a try/catch block, so I really don't understand why I'm getting this report, and I can't even reproduce it.
This is the full PasswordVaultService class, so that you can see exactly what I'm doing.
public class PasswordVaultService
{
private static readonly PasswordVault Vault = new PasswordVault();
public static string RetrieveSecret(Entry entry)
{
try
{
var results = Vault.FindAllByResource(entry.Name);
if (results.Count == 0) return null;
var result = results[0];
result.RetrievePassword();
return result.Password;
}
catch (Exception)
{
return null;
}
}
public static void StoreSecret(Entry entry, string secret)
{
Vault.Add(new PasswordCredential(entry.Name, entry.Name, secret));
}
public static void DeleteSecret(Entry entry)
{
var results = Vault.FindAllByResource(entry.Name);
if (results.Count == 0) return;
var result = results[0];
Vault.Remove(result);
}
}
I've been getting this error for some time now, and I don't understand what's going on because the class is quite simple. Before posting I've even searched for Vault inside the project and this is the only place where I'm using the PasswordVault.
I'm VERY new to C# so please allow me some ignorance :)
(I've tried searching around to understand the reason for the difference in performance I'm seeing but as of yet don't have a definitive answer so I thought I'd ask the knowledgable audience on here...)
Basically... if I use streamwriter something like:
public static class Logging
{
readonly static object DebugWriter = new object();
public static void Log(string msg)
{
lock (DebugWriter)
{
using (StreamWriter writer = new StreamWriter("Debug.txt", true))
{
writer.WriteLine(DateTime.UtcNow.ToString("HH:mm:ss.ffff") + " " + msg);
}
}
}
}
then assuming I send a large amount of text out via this class I see a noticeable hit on CPU.
However if I instead write it something along the lines of:
public static class Logging
{
readonly static object DebugWriter = new object();
static StreamWriter lwriter = new StreamWriter("LocalDrivenDebug.txt", true) { AutoFlush = true };
public static void Log(string msg)
{
lock (DebugWriter)
{
lwriter.WriteLine(DateTime.UtcNow.ToString("HH:mm:ss.ffff") + " " + msg);
}
}
}
Then I see pretty much no hit on the CPU at all.
Is the above caning the CPU purely through inialisation and disposal caused by the using statement? (If so what the hell is C# doing to eat so much CPU???) - Given it's a static class and I've forced autoflush, surely the same applies to the second version or does its disposal get acted on differently and hence chew up less CPU time?
I can only assume I'm missing something obvious. So hopefully someone out there can enlighten me as I 'thought' you were supposed to use the using statement as a safer/more convenient way of doing the disposal?
The second snippet has two properties :
- It doesn't recreate the writer, which can help if you call log many times.
- It doesn't dispose the writer, which means the text you are writing is not flushed to disk yet, but rather kept in memory for later flushing ! On the other end, you write on disk every call to log with the first snippet.
All in all, these two effects should explain the noticeable difference you see :)
I am new to developing in .NET and C#, but have been a long-time developer, working with C, C++, Java, PHP, etc.
I have an MVC3 extension class for my data models that refers to the database. It is set as "private static" in the class, but I think that it is not keeping up with database changes. In other words, when I change data in the controllers, those changes aren't "noticed" in the db because it is static. Currently, I am creating and disposing of the variable for each use, to compensate.
My questions are:
Am I correct that a static db variable could behave that way?
Is it necessary to dispose of the dynamic variable in the static class, or will garbage collection still take care of it automatically?
Here is a relevant snippet of the class:
namespace PBA.Models {
using System;
using System.Text.RegularExpressions;
using PBA.Models;
using PBA.Controllers;
public static class Extensions {
private static PbaDbEntities db = null;
public static PbaDbEntities GetDb() {
// TODO: find out about static memory/disposal, etc.
//
if (db != null) {
db.Dispose();
}
db = new PbaDbEntities();
return db;
}
public static string GetCheckpointState(this Activity activity, long memberProjectId) {
GetDb(); // TODO: Do I need to do this each time, or will a one-time setting work?
string state = CheckpointController.CHECKPOINT_STATUS_NOT_STARTED;
try {
var sub = db.ActivitySubmissions.
Where(s => s.activityId == activity.activityId).
Where(s => s.memberProjectId == memberProjectId).
OrderByDescending(s => s.submitted).
First();
if (sub != null) {
state = sub.checkpointStatusId;
}
}
catch (Exception e) {
// omitted for brevity
}
return state;
}
}
}
Your code will fail horribly in production.
DataContexts are not thread-safe; you must not share a context between requests.
Never put mutable objects in static fields in multi-threaded applications.
Ignoring exceptions that way is a terrible idea, if you don't want to handle exceptions just don't try/catch, or catch & rethrow. Think about it like this, after you've buried the exception, your program is in an invalid state, b/c something you have no control over error'd out. Now, b/c you've buried the exception, your program can continue to operate but it's in a bad state.
If your code makes it to production, 3.5 yrs from now some jr. programmer is going to get involved in some middle of the night firestorm because all of a sudden the website is broken, even though it used to work. It will be completely impossible to track down where the exception is happening so, this poor guy is going to spend 48 straight hours adding logging code all over the place to track down the problem. He will find that some DBA somewhere decided to rename the column MemberProjectId to MemberProjectIdentifier, which caused your linq to blow up.
Think of the children, handle exceptions, don't bury them.
btw - yes, i have been that guy that has to figure out these types of mistakes.
It seems like you need to read about mvc3 and entity framework before writing coding and asking in here for help on something that's coded full of bad practices.
Answering your questions:
1- no
2- makes no sense as the answer to 1
Do it right, here are some useful documentation: http://msdn.microsoft.com/en-us/library/ie/gg416514(v=vs.98).aspx
EDIT: Adding some explicit fix
You could access your dbcontext from an static class, something like this:
var context = DbProvider.CurrentDb;
The idea is to access your db from here always: from your extension methods and from your controller actions.
Then, the implementation of the DbProvider.CurrentDb will be something like this:
public static classDbProvider {
public static void Initialize(){
HttpContext.Current.ApplicationInstance.BeginRequest += CreateDb;
HttpConetxt.Current.ApplicationInstance.EndRequest += DisposeDb;
}
private static void CreateDb(object sender, EventArgs e) {
HttpContext.Items.Add("CurrentDb", new PbaDbEntities(););
}
private static void DisposeDb(object sender, EventArgs e)
{
Current.Dispose();
HttpContext.Items.Remove("CurrentDb");
}
public static PbaDbEntities CurrentDb{
get {
return (PbaDbEntities)HttpContext.Current.Items["CurrentDb"];
}
}
}
As you can see, it will create a new Db per each request and it will be available ONLY in that request. In that way, your db will be disposed at the end of each request. This pattern is called Open-Session-in-View.
Finally, you need to initialize the DbProvider calling the method
Initialize() in your Global.asax file, in the event Application_start.
Hope it helps.
I don't have any idea of the context here-- if db is simply a connection-like object or not, but it appears you are throwing away and recreating whatever it is unnecessarily.
Best to create a property (for whatever your doing) so to be consistent.
private static Thing _thing;
private static Thing thing{
get{
if(_thing==null){
_thing=new Thing();
}
return _thing;
}
}
I know the answer must be out there somewhere, I applied suggestions both from many other questions and from MSDN itself but I'm probably overlooking something here.
This is my method, I use it to dump output to file. lock object declaration attached for clarity.
private static Object fileLock = new Object();
private static void WriteToFile(string msg, bool WriteLine)
{
lock (fileLock)
{
msg = DateTime.Now.ToShortTimeString() + " - " + msg;
FileInfo F = new FileInfo("dump.txt");
using (StreamWriter writer = F.Exists ? F.AppendText() : F.CreateText()) //<--THIS LINE THROWS
{
if (WriteLine)
writer.WriteLine(msg);
else
writer.Write(msg);
}
}
}
Question is: Why does the using line above throws an IOException complaining another process is using the file the 2nd time I call the method ?
I'm calling it like this around my code:
Console.WriteLine(something)
#if(DEBUG)
Extensions.WriteToFile(something,true);
#endif
Again, I'm sure this is a trivial issue and someone else asked something like this getting the right answer, but I'm unable to dig it up.
UPDATE
Refactoring out the FileInfo object and switching to File.XXX methods made the code work fine. I still wonder what the issue was, anyway the issue looks like solved.
#Guffa: declaration has to be private static object fileLock = new object();
#alex: Your code works just fine on my machine although it's a bit too complicated for the task imo.
static void Write(string text, string file)
{
using (StreamWriter sw = File.AppendText(file))// Creates or opens and appends
{
sw.WriteLine(text);
}
}
Maybe some antivirus or indexer locks your dump file.