Top .NET Software Errors: 50 Common Mistakes and How to Fix Them

By: Alexandra
  |  March 5, 2024
Top .NET Software Errors: 50 Common Mistakes and How to Fix Them

Developing in .NET provides several powerful benefits, including less overall code, improved security, ease of updates/changes, and language independence.

That said, the system isn’t without errors and problems. From common exceptions to coding mistakes to incorrect assumptions, most of these issues come down to programmer error.

The list below shares the 50 top .NET software errors from around the web. It includes exceptions, broken data bindings, memory leaks, LINQ issues, mistyping errors, and dozens more. We also look at ways to fix each one.

When you’re ready to start coding, download our free guide to .NET Profilers for some insider knowledge and everything you need to know about code profiling for .NET. And while you’re at it, be sure to check out Prefix, our own lightweight profiler for .NET and Java developers. (And, if you’re thinking about .NET Core, read our opinion on why it’s the next big thing here.)

1. NullReferenceException

This .NET exception gets thrown whenever we try to use a class reference that’s set to null/Nothing, when the code expects otherwise. In the very simple example below, the string “foo” is set to null.

string foo = null;
foo.ToUpper();

The second line above will throw a NullReferenceException because we can’t call the method on a string that points to null.

To fix/avoid this error:

2. DivideByZeroException

The DivideByZeroException error gets thrown whenever a program tries to divide by zero. To handle it gracefully, protect any code that does arithmetic division within try-catch blocks that look for that specific exception. Here’s an example:

try
{
int x = SomeService.Calculate();
int y = 10 / x;
}
catch (DivideByZeroException ex)
{
//TODO: Write code that should run when x is 0
}

Ways to fix/prevent DivideByZeroException:

  • Use Try/Catch blocks to catch the exception.
  • Set guards on functions that throw errors in the event of a zero value.
  • Use validation on critical user inputs to prevent zero values.
  • For more detail on how to handle this .NET error, see this article from Dot Net Perls.

3. Broken Data Bindings in WPF

Data bindings in WPF can be a huge time saver – when they work well. When they break, they’re one of the more frustrating .NET errors out there. In the example below, there’s a TextBlock with a missing data context. Frustratingly, it won’t show errors in Visual Studio’s output window.

    
<Window x:Class="WpfApplication1.MainWindow"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 Title="MainWindow" Height="350" Width="525">
 <Grid>
 <TextBlock Text="{Binding ThereIsNoDataContext}"/>
 </Grid>
</Window>
We can fix this by enabling tracing to the output window to reveal any problems:
    
 <Window x:Class="WpfApplication1.MainWindow"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
 Title="MainWindow" Height="350" Width="525">
 <Grid>
 <TextBlock Text="{Binding ThereIsNoDataContext,
diag:PresentationTraceSources.TraceLevel=High}" />
 </Grid>
</Window>

Here are a couple of other fixes for the broken data bindings error:

  • Add a Value Converter that Breaks into the Debugger.
  • Add a TraceListener so you know right away when a data binding breaks.
  • There’s a great tutorial that gives more detail on fixing this issue here. (@atomicobject)

https://github.com/paologutierrez/.net50/blob/master/brokendatabindingswpf.md

4. Using a Reference Like a Value or Vice Versa

This problem is specific to C#. In C#, the programmer who writes the object decides whether the value assigned to it is a value or a reference to another object. The example below shows a couple of unwanted surprises.

Point point1 = new Point(20, 30);
Point point2 = point1;
point2.X = 50;
Console.WriteLine(point1.X);       // 20 (does this surprise you?)
Console.WriteLine(point2.X);       // 50
  
Pen pen1 = new Pen(Color.Black);
Pen pen2 = pen1;
pen2.Color = Color.Blue;
Console.WriteLine(pen1.Color);     // Blue (or does this surprise you?)
Console.WriteLine(pen2.Color);     // Blue

To fix the problem, look at definitions of the object types. In Visual Studio, do this by putting your cursor over the object’s name and pressing F12.

For a more in-depth explanation of the reference/value error, see this tutorial.

https://github.com/paologutierrez/.net50/blob/master/using-reference-like-value-vice-versa.md

5. Letting Compiler Warnings Accumulate

This very common issue erodes the strict type checking provided by the C# compiler. The temptation to hide warnings in Visual Studio’s “Error List” window can lead to a buildup of hidden or ignored warnings. Unheeded warnings can cause eventual code problems like this:

class Account {
  
      int myId;
      int Id;   // compiler warned you about this, but you didn’t listen!
  
      // Constructor
      Account(int id) {
          this.myId = Id;     // OOPS!
      }
  
  }

Of course, the easy fix for the buildup of compiler warnings is to set aside regular time blocks to address them. Spending a few seconds on each warning now can save hours down the road. See this article for more.

https://github.com/paologutierrez/.net50/blob/master/allowing-compiler-warnings-accumulate.md

6. Losing Scope Before Disposing an Object

Disposing objects before all references to them are out of scope is a housekeeping issue. We might assume the garbage collector will take care of it when it runs the object’s finalizer, but that isn’t always the case.

To fix this error, make sure all .NET objects are explicitly disposed.

  • Use the using statement to wrap all IDisposable objects. Objects wrapped in this way will automatically be disposed when the using block closes.
  • In some cases, the using statement isn’t enough. (@msdev) One example is when nesting constructors are protected by only one exception handler.
  • For additional protection, add specific code to check and dispose variables when needed. The finally block below does this with the tempPort variable.
public SerialPort OpenPort1(string portName)
{
   SerialPort port = new SerialPort(portName);
   port.Open();  //CA2000 fires because this might throw
   SomeMethod(); //Other method operations can fail
   return port;
}
public SerialPort OpenPort2(string portName)
{
   SerialPort tempPort = null;
   SerialPort port = null;
   try
   {
      tempPort = new SerialPort(portName);
      tempPort.Open();
      SomeMethod();
      //Add any other methods above this line
      port = tempPort;
      tempPort = null;
      
   }
   finally
   {
      if (tempPort != null)
      {
         tempPort.Close();
      }
   }
   return port;
}

7. Redundant Nested Exception Handling

While not exactly a .NET error, using too much exception handling with nested methods is definitely a mistake. This one creates a lot of redundant code and a real performance drain. The best practice here is using nested exception handling, which performs the exception handling only once:

 public class NestedExceptionHandling
  {
      public void MainMethod()
      {
          try
          {
              //some implementation
              ChildMethod1();
          }
          catch (Exception exception)
          {
              //Handle exception
          }
      }
  
      private void ChildMethod1()
      {
          try
          {
              //some implementation
              ChildMethod2();
          }
          catch (Exception exception)
          {
              //Handle exception
  	     throw;
  
          }
      }
  
      private void ChildMethod2()
      {
          try
          {
              //some implementation
          }
          catch (Exception exception)
          {
              //Handle exception
              throw;
          }
      }
  }

For a deeper look at this mistake, see this article. (@Codeguru)

https://github.com/paologutierrez/.net50/blob/master/nested-exception-handling.mdown

8. Deferred Execution in LINQ

LINQ makes it a lot easier to query data than if we use for/each loops with conditional logic like nested if blocks. But consider the code below, which uses LINQ-to-SQL to get a customer list:

public IEnumerable GetCustomers()
	{
		using(var context = new DBContext())
		{
			return from c in context.Customers
			       where c.Balance > 2000
			       select c;
		}
	}

The code seems fine until we try to enumerate the collection. At that point, we’ll get an “ObjectDisposedException.” That’s because link won’t actually perform the query until we attempt to enumerate the results.

To fix this, first convert your LINQ queries to a List using ToList(), or to an array using ToArray(). This step will ensure all LINQ queries get evaluated right away. See more on this here. (@VSMdev)

https://github.com/paologutierrez/.net50/blob/master/deferred-execution-in-linq.md

9. Iterating with Values Instead of with LINQ

Here’s another “not quite a .NET error” that’s nonetheless a big mistake. Iterating through long lists of records is far from efficient. Rather than rely on a foreach loop or a for loop, use LINQ. LINQ or Language-Integrated Query is a feature of .NET that makes it easier to query objects like long lists or collections.

foreach (Customer customer in CustomerList) {
   if (customer.State == "FL") {
     tax += customer.Balance;
   }
 }

The code above returns 1,000 customers. That’s much more efficient than getting 100,000 customers with a foreach loop. For more, see this post. (@Upwork)

https://github.com/paologutierrez/.net50/blob/master/iterating-through-values-instead-of-using-linq.md

10. Accessing Virtual Members within a Constructor

This C# error comes from executing code before its time. This can happen when we call an overridden method straight from the constructor of a base class.

In the example below, the virtual method call is made on a class before the class’ constructor has been run.

public class Parent
{
  public Parent()
  {
    Console.WriteLine("Parent Ctor");
    Method();
  }
  public virtual void Method()
  {
    Console.WriteLine("Parent method");
  }
}
public class Child : Parent
{
  public Child()
  {
    Console.WriteLine("Child Ctor");
  }
  public override void Method()
  {
    Console.WriteLine("Child method");
  }
}

To fix the problem, first mark your class as sealed. This ensures that it’s the most derived type within the inheritance hierarchy. That way, when we call the virtual method, we don’t get a warning.

https://github.com/paologutierrez/.net50/blob/master/accessing-virtual-member-in-a-constructor.md

11. Logic Errors

Logic errors happen when we don’t get the result we expected. They don’t always result in error messages because they’re not technically “bugs.” Instead, they’re problems with programming logic. Take a look at the code below. It tries to add up the numbers from one to ten.

private void button1_Click(object, sender, EventArgs e)
{
    int startLoop = 11;
    int endLoop = 1;
    int answer = 0;
    
    for (int i = startLoop; i < endLoop; i++)
    {
        answer = answer + i;
    }
    
    MessageBox.Show("answer =" + answer.ToString());
}

Can you see the error? The answer is zero! The program didn’t run into any code errors, but it gave us the wrong answer. That’s a logic error. We should have set the startLoop variable as 1, and endLoop as 11. To nip logic errors in the bud:

  • Use C# .NET Breakpoints. This is where we tell C# to stop the code, so we can assess what’s in the variables.
  • Use the C# .NET Locals Window. This keeps track of what’s in local variables.
  • Use Try … Catch blocks.
  • For a full tutorial on how to implement the above fixes, click here.

https://github.com/paologutierrez/.net50/blob/master/logic-error.md

12. Mixing Strings and Numbers with +

Most languages use the + sign for both concatenation and arithmetic addition. That means 2 + 2 is 4 and “hello ” + “world” is “hello world.” But what about “hello “ + 2? This would result in “hello 2”. This would be better expressed as “hello ” + “2”.

Here’s a less obvious example:

static void Main(string[] args) {
    int x = 4;
    string y = "12";
    Console.WriteLine(string.Format("{0}", x + y)); // 412
    Console.ReadKey();
}

In this case, x + y is 412, where 4 is a number and “12” is a string.

To head this mistake off:

  • Make sure all values you intend to add are actually numbers.
  • Use string.Format() instead of concatenating with +.
  • Perform arithmetic as distinct statements before outputting concatenated results or strings.
  • For an in-depth tutorial, click here. (@DreamInCode)

https://github.com/paologutierrez/.net50/blob/master/concatenating-rather-than-adding.md

13. Forgetting Strings Are Immutable

Strings are immutable in .NET. That means once we create a string, we can’t change its value. It may look like we’re changing a string’s value, but what we’re really doing is creating a new object with a new value.

The example below shows how forgetting that strings are immutable can lead us into a problem. (@amazedsaint)

string = "Take this out";
s.Replace("this", "that"); //wrong
s = s.Replace("this", "that"); //correct

There’s another great example of an immutable string error here that results in the creation of 10,000 unwanted string variables. (@codeproject) The article presents an elegant solution: using the StringBuilder class to change the text without making thousands of new String class instances.

https://github.com/paologutierrez/.net50/blob/master/forgetting-that-strings-are-immutable.md

14. Incorrect Granularity

Here’s a common C# error that results from a multithreading mistake. This happens when we use lock with poor code synchronization.

The example below checks for curse words in a string, printing a warning if it finds one. It also performs several other operations. The code isn’t synchronized, however, so it’s not thread safe. For instance, two threads might try to update the same counter at the same time, causing an exception.

private static List wordList;
private static List curseWords;
private static int currentWordIndex;
private static Dictionary<string, int> wordCountDict;
public static void CalculateWordCounts() {
	wordList = GetWordList();
	curseWords = GetCurseWords();
	currentWordIndex = 0;
	wordCountDict = new Dictionary<string, int>();
	Thread threadA = new Thread(ThreadDoWork);
	Thread threadB = new Thread(ThreadDoWork);
	Thread threadC = new Thread(ThreadDoWork);
	Thread threadD = new Thread(ThreadDoWork);
	threadA.Start();
	threadB.Start();
	threadC.Start();
	threadD.Start();
	threadA.Join();
	threadB.Join();
	threadC.Join();
	threadD.Join();
}
private static void ThreadDoWork() {
	bool atLeastOneWordRemaining;
	int thisWordIndex = currentWordIndex;
	currentWordIndex = currentWordIndex + 1;
	if (thisWordIndex >= wordList.Count) atLeastOneWordRemaining = false;
	else atLeastOneWordRemaining = true;
	while (atLeastOneWordRemaining) {
		string thisWord = wordList[thisWordIndex];
		bool firstOccurrenceOfWord = !wordCountDict.ContainsKey(thisWord);
		if (curseWords.Contains(thisWord)) Console.WriteLine("Curse word detected!");
		if (firstOccurrenceOfWord) wordCountDict.Add(thisWord, 1);
		else wordCountDict[thisWord] = wordCountDict[thisWord] + 1;
		thisWordIndex = currentWordIndex;
		currentWordIndex = currentWordIndex + 1;
		if (thisWordIndex >= wordList.Count) atLeastOneWordRemaining = false;
	}
}

To repair this:

  • Make sure only one thread can read/update a counter at a time.
  • Lock over checking/updating routines.
  • For a full tutorial on the incorrect granularity error, click here. (@Xenoprimate)

https://github.com/paologutierrez/.net50/blob/master/incorrect-granularity.md

15. Unhandled Exogenous Exceptions

This may sound like the lost Dali painting, but it’s just a fancy way of saying, “unhandled, handleable exceptions.” Since the definition of exogenous is “originating externally,” these exceptions are beyond our control and must be anticipated and handled.

The code below shows a good example.

try 
{   
  using ( File f = OpenFile(filename, ForReading) )   
  {
    // Blah blah blah   
  } 
} 
catch (FileNotFoundException) 
{   
  // Handle file not found 
}

We have to use the try-catch block because something might have happened to our file. Use try-catch blocks to avoid an error arising from these exceptions.

See this tutorial for a good explanation of the different kinds of exceptions, plus whether and how to handle them. (@ericlippert)

https://github.com/paologutierrez/.net50/blob/master/failure-to-handle-exogenous-exceptions.md

16. Protection Level Conflicts

For any class, the default protection level is “internal.” For any member in that class, the default level is “private.” We can run into an issue when we forget those facts.

class MyFirstClass //default protection = internal
{
    public void NameFunction() {
        MySecondClass sc = new MySecondClass();
        sc.strFirstName = "Harry";
        sc.strLastName = "Potter";
        Console.WriteLine("Name: " + sc.FirstName + " " + sc.strLastName);
    }
}
public class MySecondClass
{
    string strFirstName = "Roy";
    string strLastName = "Weasley"; //default protection = private
}

When we declare “MySecondClass” public, its variables don’t also become public. If we want MyFirstClass to be able to access the variables in MySecondClass, we’ll need to set MyFirstClass and the MySecondClass variables to “public.” See this post for more details. (@DeveloperDrive)

https://github.com/paologutierrez/.net50/blob/master/protection-level-conflicts.md

17. StackOverflowException

Apart from being a popular developer forum, this is also a common error. This one is something like an OutOfMemoryException because it means your code has exceeded a memory boundary. The stack is finite, which means if we have too many memory allocations in it, we’ll get an overflow exception.

The simple C# example below shows an infinite recursion that will trigger a StackOverflowException.

class Program
{
    private static int hitCount;
    static void Main(string[] args)
    {
        hitCount = 0;
        MyRecursiveExample(null);
    }
    static void MyRecursiveExample(string value)
    {
        hitCount++;
        if (value == null)
        {
            MyRecursiveExample(value);
        }
        else
        {
            System.Console.WriteLine(value);
        }
    }
}

To avoid the StackOverflowException error, try not to have objects mutually reference each other whenever possible. See this discussion and this article for more insight. (@StackOverflow and @ExpertsExchange)

https://github.com/paologutierrez/.net50/blob/master/stack-overflow-exception.md

18. Busy-Wait and Thread.Sleep

Using busy-wait instead of correct thread synchronization can deliver a troublesome error. The code below will suck up 100% of the CPU core while the thread in Example() processes the while loop.

private static string userInput;
private static void Example() {
	userInput = null;
	GetUserInput(); // tells the UI to request user input on the UI thread
	
	while (userInput == null) ; // wait for user input
	
	ProcessUserInput(userInput); // now use that input
}

Some developers will try to use something like Thread.Sleep(100) to interrupt an infinite loop. While this works, it’s sloppy coding, since what we really need is an in-built synchronization construct. In general, we should only use Thread.Sleep:

  • To make some kind of timer functionality
  • For testing, but not for production
  • For a more in-depth look at how to dodge the busy-wait and thread.sleep error, click here. (@Xenoprimate)

https://github.com/paologutierrez/.net50/blob/master/busy-waiting-and-thread-sleep.md

19. Handling Non-Exogenous Exceptions

Certain .NET errors in the form of exceptions that can’t be foreseen and that originate from outside our control must be handled. For example, let’s say our program does a check for File.Exists. The file does exist, but between the check and the next operation, the file gets deleted. That said, most exceptions should be avoided whenever possible by writing code that renders them unnecessary. Consider the following three exceptions:

string val = null;
  int value = int.Parse(str); //Will throw ArgumentNullException
  string val = "100.11";
  int value = int.Parse(val); //Will throw FormatException
  string val = "999999999999999999999999999999999999999999";
  int value = int.Parse(val); //Will throw OverflowException››

If we use the int.TryParse() method instead of an exception, we get a 0 response. That means this method avoids the need for complex and potentially buggy exception handling.

https://github.com/paologutierrez/.net50/blob/master/avoiding-exceptions-instead-of-working-with-them.mdown

20. Unsafe Assumptions in Multithreading

Certain assumptions about how multithreading works can lead us to unexpected problems. These are especially likely when working with shared state. Often, the mistakes arise when we think multithreaded code works in the same way as single-threaded code.

One example is a torn read from non-atomic access to a variable. The following code will return unwanted values:

private const int NUM_ITERATIONS = 20000;
private const decimal DENOMINATOR = 200m;
private const decimal MAX_POSSIBLE_VALUE = NUM_ITERATIONS / DENOMINATOR;
private static decimal sharedState;
public static decimal SharedState {
	get {
		return sharedState;
	}
	set {
		sharedState = value;
	}
}
static void Main(string[] args) {
	Thread writerThread = new Thread(WriterThreadEntry);
	Thread readerThread = new Thread(ReaderThreadEntry);
	writerThread.Start();
	readerThread.Start();
	writerThread.Join();
	readerThread.Join();
	Console.ReadKey();
}
private static void WriterThreadEntry() {
	for (int i = 0; i < NUM_ITERATIONS; ++i) {
		SharedState = i / DENOMINATOR;
	}
}
private static void ReaderThreadEntry() {
	for (int i = 0; i < NUM_ITERATIONS; ++i) { var sharedStateLocal = SharedState; if (sharedStateLocal > MAX_POSSIBLE_VALUE) Console.WriteLine("Impossible value detected: " + sharedStateLocal);
	}
}

The problem occurs because one thread can read the value of sharedState halfway through a write by another thread. This forces the variable into values we hadn’t anticipated (or wanted).

To fix the problem, make access to the variable atomic. To do this:

  • Use the lock statement
  • Use the Interlocked

For a detailed breakdown of incorrect multithreading assumptions in .NET and how to fix them, see this in-depth tutorial. (@Xenoprimate)

https://github.com/paologutierrez/.net50/blob/master/unsafe-assumptions-on-multithreading.md

21. The Nullable Paradox

A nullable value passed to the stack will create garbage. Paradoxically, a similar variable that’s actually set to null won’t create any garbage.

private static void DoTestA() {
    int? maybeInt = null;
    for (int i = 0; i < 100000; ++i) {
        DoSomething(maybeInt);
    }
}
 
private static void DoTestB() {
    int? maybeInt = 3;
    for (int i = 0; i < 100000; ++i) {
        DoSomething(maybeInt);
    }
}
 
private static void DoSomething(object o) {
    // Do something...
}

In the example above, DoTestA() creates zero garbage, while DoTestB() quickly racks up a large amount.

The best way to fix this is to generify our DoSomething method:

Private static void DoSomething<T>(T o) {
// Do something...
}

For a more detailed explanation of this paradox and how to fix it, see this post. (@Xenoprimate)

https://github.com/paologutierrez/.net50/blob/master/nullable-paradox.md

22. Failure to Log Exceptions

This common mistake is really one of omission. It can result in user problems with no indication of what went wrong. Consider the case of a user registration functionality with unlogged exceptions. In this case, if registration fails, our log stays empty.

public class UserService
{
    private readonly IMessagingService _messagingService;
    public UserService(IMessagingService messagingService)
    {
        _messagingService = messagingService;
    }
    public bool RegisterUser(string login, string emailAddress, string password)
    {
        // insert user to the database
        // generate an activation code to send via email
        // save activation code to the database
        // create an email message object
        try
        {
            _messagingService.SendRegistrationEmailMessage(message);
        }
        catch (Exception)
        {
            // boom!
        }
        return true;
    }
}

Of course, the fix for this error is to add logging to the try-catch block. To see the full tutorial, click here. (@codeproject)

https://github.com/paologutierrez/.net50/blob/master/eating-exceptions.md

23. Unnecessary Contention in Multithreading

Contention happens when two or more threads try to access the same resource at the same time. They contend for the resource. This situation causes several issues.

Even when we use thread-safe coding, contention can still add overhead. For example, when we use the lock keyword, we force some threads to wait while one thread accesses a scope.

The following multi-threaded code actually works worse than a single-threaded version would, because it creates a lot more overhead while some threads wait.

private static List wordList;
private static List curseWords;
private static int currentWordIndex;
private static Dictionary<string, int> wordCountDict;
private static readonly object wordCountCalculatorSyncObj = new object();
public static void CalculateWordCounts() {
	wordList = GetWordList();
	curseWords = GetCurseWords();
	currentWordIndex = 0;
	wordCountDict = new Dictionary<string, int>();
	Thread threadA = new Thread(ThreadDoWork);
	Thread threadB = new Thread(ThreadDoWork);
	Thread threadC = new Thread(ThreadDoWork);
	Thread threadD = new Thread(ThreadDoWork);
	threadA.Start();
	threadB.Start();
	threadC.Start();
	threadD.Start();
	threadA.Join();
	threadB.Join();
	threadC.Join();
	threadD.Join();
}
private static void ThreadDoWork() {
	bool atLeastOneWordRemaining;
	int thisWordIndex;
	lock (wordCountCalculatorSyncObj) {
		thisWordIndex = currentWordIndex;
		currentWordIndex = currentWordIndex + 1;
	}
	if (thisWordIndex >= wordList.Count) atLeastOneWordRemaining = false;
	else atLeastOneWordRemaining = true;
	while (atLeastOneWordRemaining) {
		string thisWord = wordList[thisWordIndex]
			.ToUpper()
			.Replace("-", String.Empty)
			.Replace("'", String.Empty)
			.Trim();
		if (curseWords.Contains(thisWord)) Console.WriteLine("Curse word detected!");
		lock (wordCountCalculatorSyncObj) {
			bool firstOccurrenceOfWord = !wordCountDict.ContainsKey(thisWord);
		
			if (firstOccurrenceOfWord) wordCountDict.Add(thisWord, 1);
			else wordCountDict[thisWord] = wordCountDict[thisWord] + 1;
			thisWordIndex = currentWordIndex;
			currentWordIndex = currentWordIndex + 1;
		}
		if (thisWordIndex >= wordList.Count) atLeastOneWordRemaining = false;
	}
}

The solution to this is to split the work into equal chunks before it’s processed. Then, let each thread perform a local count before it updates the global one. To see how that works, take a look at this article. (@Xenoprimate)

https://github.com/paologutierrez/.net50/blob/master/unnecessary-contention-in-multithreading.md

24. Using Weak Cryptographic Algorithms

Using old, outdated cryptographic algorithms is one of the most easily avoided errors. Algorithms like TripleDES, SHA1, and RIPEMD160 can’t deliver the level of security that their more modern counterparts can.

using System.Security.Cryptography;   
...   
var hashAlg = SHA1.Create();  

To avoid the CA5350 CheckID, use stronger algorithms.

  • Instead of TripleDES, use Aes encryption.
  • Instead of SHA1 or RIPEMD160, use SHA512, SHA384, or SHA256.
  • See this page from Microsoft for full documentation. (@msdev)

https://github.com/paologutierrez/.net50/blob/master/using-weak-cryptography.md

25. Using the Wrong Collection Type

In .NET, using the right collection type can save time and avoid errors. Below is a list of the most commonly used C# collections.

var list = new List();
  var dictionary = new Dictionary<int, Customer>();
  var hashSet = new HashSet();
  var stack = new Stack();
  var queue = new Queue();
  • The List collection type can grow in size to accommodate growing data sets.
  • The Dictionary collection type is useful for fast lookups by keys.
  • The HashSet collection type works best for very fast lookups in a list of unique items.
  • The Stack collection type comes in handy for providing users with ways to go back.
  • This great tutorial gives a great explanation of how to avoid errors by using the right collection type for the job. (@moshhamedani)

https://github.com/paologutierrez/.net50/blob/master/Not-using-the-correct-collection-type-depending-on-the-situation.mdown

26. Unregistered Events

This common mistake happens when we create an event handler that handles events occurring in an object, but we don’t clear the link when we’ve finished. This oversight can leave behind an unwanted strong reference.

In the code below, we subscribe to an OnPlaced event in our Order class, and the following code executes on a button click:

Order newOrder=new Order
(“EURUSD”, DealType.Buy, Price ,PriceTolerance, TakeProfit, StopLoss);
newOrder.OnPlaced+=OrderPlaced;
m_PendingDeals.Add(newOrder);

When the OrderPlaced method is called, the following code executes:

Void OrderPlace(Order pladedOrder)
{
m_PendingDeals.Remove(placedOrder);
}

However, a reference to the Order object is still held by the OrderPlaced event handler. The Order object is therefore kept alive, even though we removed it from the collection. For more information on this, see:

https://github.com/paologutierrez/.net50/blob/master/unregistered-events.md

27. Readonly Shorthand Property Declaration

This WCF error happens when we fail to keep both getter and setter in our code when using the ReadOnly shorthand property declaration with the DataMember attribute. Without the setter part, we’ll get an error.

//Data Contract attribute applied to class to make it available to client.
//Data Member attribute applied to the 'MyVar' readonly property.
    [DataContract]
    public class MyValueObject
    {
        [DataMember]
        public int MyVar
        {
            get;
        //This will not work, as WCF needs both getter and setter to access property.
        }
    }  
    //Correct version with both getters and setter defined.
    [DataContract]
    public class MyValueObject
    {
        [DataMember]
        public int MyVar
        {
            get; 
            set {}
            //Empty setter block is supplied for readonly property. 
        }
    }

We can circumvent this problem by setting a block with empty brackets, as shown in this article. (@codeproject)

https://github.com/paologutierrez/.net50/blob/master/readonly-shorthand-property-declaration-in-wcf.md

28. Mistyping the WF/WCF Service Configuration Name

When we use WCF with Visual Studio, we can run into a problem that comes from default configurations.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

The code above doesn’t specify a <services> section. It therefore adds a set of default endpoints to your service. This can result in the use of an incorrect service name. To fix this situation, we’ll need to manually change the name of our service in the configuration file. See this tutorial for more. (@msdev)

https://github.com/paologutierrez/.net50/blob/master/mistyping-the-wf-wcf-service-configuration-name.md

29. Modifying SMSvcHost.exe.config for WCF

We can run into several WCF errors when we modify the SMSvcHost.exe.config file improperly. The sample settings for the file are shown below:

<net.tcp listenBacklog=”10? maxPendingConnections=”100? maxPendingAccepts=”2? receiveTimeout=”00:00:10? teredoEnabled=”false”>
<allowAccounts>
// LocalSystem account
<add securityIdentifier=”S-1-5-18?/>
// LocalService account
<add securityIdentifier=”S-1-5-19?/>
// Administrators account
<add securityIdentifier=”S-1-5-20?/>
// Network Service account
<add securityIdentifier=”S-1-5-32-544? />
// IIS_IUSRS account (Vista only)
<add securityIdentifier=”S-1-5-32-568?/>
</allowAccounts>
</net.tcp>

Some common problems that arise from modifying the file include:

  • Modifying the wrong SMSvcHost.exe.config file.
  • Changing dummy settings in a comment within the file.
  • Failing to restart Net.Tcp Port Sharing service after making changes to the file.

For steps to avoid making these common mistakes, see this blog post from Microsoft. (@msdev)

https://github.com/paologutierrez/.net50/blob/master/modifying-smsvchost-exe-config.md

30. Leaving Tracing Enabled in Web-Based Applications

Tracing is a very useful .NET debugging tool. It’s also an excellent way for a hacker to access your system if it’s left in place in a production environment. Don’t fall into the trap shown below:

<configuration>
<system.web>
<trace enabled="true" localOnly="false">

In the configuration above, any user can access a detailed list of all recent requests to the app. How? By browsing the page “trace.axd.” The trace log provides a plethora of useful information to the hacker.

The best way to prevent hacks through tracing data is to disable tracing. Do this by setting “enabled” to “false” for the <trace> element. For more info, see this tutorial. (@dotnetstories)

https://github.com/paologutierrez/.net50/blob/master/leaving-tracing-enabled-in-web-Based-applications.md

31. Custom Errors Disabled

Disabling custom errors in .NET gives clients detailed error messages by default.

<configuration>
<system.web>
<customErrors mode=”Off“>

With the above configuration, hackers get good information about the source of errors that can help them learn to pick our coding locks. Default ASP.NET error messages show our ASP.NET version and framework, plus the exception type.

To fix the problem:

  • Set customErrors mode to RemoteOnly or Doing this displays more generic, nondescript error messages.
  • Set the defaultRedirect attribute of the <customErrors> element to redirect the user to a new page.
  • See this post for a more detailed walk-through of fixing this issue. (@dotnetstories)

https://github.com/paologutierrez/.net50/blob/master/custom-errors-disabled.md

32. Binding Leak

WPF has several data binding options. If we break them, they can cause memory leaks within our applications. For example, look at the class shown below:

class Person
{
    public Person(string name)
    {
        Name = name
    }
    
    public string Name {get; set;}
}

With the example above, in certain cases, WPF will create a runtime leak by creating a reference to the System.Component.Model.PropertyDescriptor class. When this happens, runtime doesn’t know when to deallocate the reference. Therefore, our source object remains in memory.

  • Detect this error by checking the dotMemory automatic inspections snapshot overview page for WPF binding leaks.
  • Fix the problem by making the object a DependencyProperty. For complete instructions, see this tutorial. (@jetbrains)

https://github.com/paologutierrez/.net50/blob/master/binding-leak.md

33. Forgetting to an XSRF Token to the Client

XRSF tokens protect against cross-site request forgeries. We need to use them any time the browser can authenticate the user implicitly. That includes automatic authentication with cookies, or apps using Windows authentication.

The code below passes an XSRF token to the client, avoiding this egregious mistake.

[Route("api/[controller]")]
public class XsrfTokenController : Controller
{
    private readonly IAntiforgery _antiforgery;
 
    public XsrfTokenController(IAntiforgery antiforgery)
    {
        _antiforgery = antiforgery;
    }
 
    [HttpGet]
    public IActionResult Get()
    {
        var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
 
        return new ObjectResult(new {
            token = tokens.RequestToken,
            tokenName = tokens.HeaderName
        });
    }
}

Read the full tutorial on this here. (@OdeToCode)

https://github.com/paologutierrez/.net50/blob/master/not-protecting-clients-with-xsrf-tokens.md

34. DispatcherTimer Leak

A DispatcherTimer leak is an error where improper use of the DispatcherTimer causes a memory leak.

In the example below, the count variable gets updated once per second by the DispatcherTimer. The reference is held by the Dispatcher, which keeps each UserControl alive, causing a memory leak.

public byte[] myMemory = new byte[50 * 1024 * 1024];
System.Windows.Threading.DispatcherTimer _timer = new System.Windows.Threading.DispatcherTimer();
int count = 0;

private void MyLabel_Loaded(object sender, RoutedEventArgs e)
{
    _timer.Interval = TimeSpan.FromMilliseconds(1000);
    _timer.Tick += new EventHandler(delegate(object s, EventArgs ev)
    {
        count++;
        textBox1.Text = count.ToString();
    });
    _timer.Start();
}

Fixing this is easy. Just stop the timer and set it to null. (@Simple_Talk)

_timer.Stop();
_timer=null;

https://github.com/paologutierrez/.net50/blob/master/dispatcher-timer-leak.md

35. x:Name leak

Building UIs in software lets us add convenient functionality, such as removing certain controls from the UI after the user performs a given action. However, if we don’t build the UI correctly, we can introduce a memory leak.

Every time we declare a UI element in XAML using the x:Name directive, WPF will create a strong global reference.

We may think we can dynamically remove the element, but the control will stay in memory, even after we remove it from the Children collection of the parent control:

private void DeleteData_OnClick(object sender, RouteEventArgs e)
{
    if (personEditor != null)
    {
        _grid.Children.Remove(personEditor);
        personEditor = null;
    }
}

Here’s how to fix this common issue:

  • To detect the problem, click the button to remove the control, then take a snapshot in dotMemory. The snapshot will show that the control stayed in memory.
  • Fix it by calling the parent control’s UnregisterName method.
  • For a full brief on this error and its fix, see here. (@jetbrains)

https://github.com/paologutierrez/.net50/blob/master/x-name-leak.md

36. TextBox Undo Leak

This isn’t actually a leak, but rather an intended behavior. When an app updates large strings to text boxes over several iterations, we can see a buildup of data on their undo stacks.

The default settings will create this problem by enabling undo and/or by setting the UndoLimit at -1, which means the number of actions will be limited only by the amount of available memory.

textBox1.IsUndoEnabled=true;
textBox1.UndoLimit=-1

To rectify this, either set IsUndoEnabled to false, or set an UndoLimit other than -1 (such as 100).

To see this problem and solution explained in more detail, see this article. (@Simple_Talk)

https://github.com/paologutierrez/.net50/blob/master/textbox-undo-leak.md

37. Event Handler Leak

Yet another memory leak error is the event handler leak. In C#, we don’t always get a leak when we subscribe to an event and then forget to unsubscribe. In most cases, the events don’t stay in memory.

However, when an event publisher is long lived, then all its subscribers will be kept alive too, as in the following example:

public class ShortLivedEventSubscriber
{
    public static int Count;
    public string LatestText { get; private set; }
    public ShortLivedEventSubscriber(Control c)
    {
        Interlocked.Increment(ref Count);
        c.TextChanged += OnTextChanged;
    }
    private void OnTextChanged(object sender, EventArgs eventArgs)
    {
        LatestText = ((Control) sender).Text;
    }
    ~ShortLivedEventSubscriber()
    {
        Interlocked.Decrement(ref Count);
    }
}

Here’s the code that creates the instances:

private void OnShortLivedEventSubscribersClick(object sender, EventArgs eventArgs e)
    {
intcount = 10000;
for (int n = 0; n < count; n++        
{ 
var shortlived2 = new ShortLivedEventSubscriber(this);
}
shortlivedEventSubscriberCreated += count;
}

The solution here is simple. Any time you subscribe to an event, if it’s raised by a service that has a long life, you must unsubscribe from it.

https://github.com/paologutierrez/.net50/blob/master/event-handler-leak.md

38. Potentially Dangerous Request.Form Value

Here’s a workaround for an error caused when we want to send HTML code to a server. By default, we’ll get an error, since ASP.NET MVC disables sending this type of code to the server in order to avoid Cross Site Scripting (XSS) attacks.

As shown below, we can use the AllowHtml attribute for the model class to disable ASP.NET MVC validation for that particular property.

public class PersonModel
{
    [Display(Name = "Resume:")]
    [AllowHtml]
    public string Resume { get; set; }
}

For the full rundown of using the AllowHtml attribute to avoid this issue, see this tutorial. (@ASPSnippets)

https://github.com/paologutierrez/.net50/blob/master/potentially-dangerous.md

39. “The Remote Name Could Not Be Resolved” (WCF/Azure Error)

Sometimes a service that works fine on a local machine doesn’t play well with Azure. In that case, we get a “failed to invoke the service” notification.

Inner Exception: The remote name could not be resolved: ‘rd00155d3ad8c4'    
at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
at System.Net.HttpWebRequest.GetRequestStream()
at System.ServiceModel.Channels.HttpOutput.WebRequestHttpOutput.GetOutputStream()

This can be an extremely frustrating problem since there’s no obvious reason for it to happen in the first place and there’s no obvious fix. Alter the web.config file as follows:

<behavior name=”MexGet”>
<serviceMetadata httpGetEnabled=”true”  />
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme=”http” port=”81? />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>

This sets up your service to operate in a load-balanced environment like Azure.

https://github.com/paologutierrez/.net50/blob/master/error-in-wcf-azure.md

40. PRB: “Access is Denied”

When remotely debugging an ASP.NET application using Visual Studio, we can get the following error message:

“Error while trying to run project: Unable to start debugging on the web server. Access is denied. Check the DCOM configuration settings for the machine debug manager. Would you like to disable future attempts to debug ASP.NET pages for this project?”

This happens because the user doing the remote debugging doesn’t belong to the Debugger Users group for the MS Internet Information Server.

To solve this problem, add the user to the appropriate group by following the steps shown in this Microsoft support page. (@MicrosoftHelps)

PRB: “Access is Denied”

41. ViewBag Does Not Exist in the Current Context

This issue can arise after upgrading an application from ASP MVC 4 to ASP MVC 5.

To fix the problem, install the ASP.NET Web Helpers Library, then open the project’s web.config file and update the bindings as follows:

<dependentAssembly>
<assemblyIdentity name=”System.Web.Mvc” publicKeyToken=”31bf3856ad364e35? />
<bindingRedirect oldVersion=”0.0.0.0-5.2.2.0? newVersion=”5.2.2.0” />
</dependentAssembly>

In the appsettings, find “webpages:Version” and update to version 3.0.0.0. Then restart Visual Studio. See this blog post for more. (@AhmedAlAsaad)

https://github.com/paologutierrez/.net50/blob/master/viewbag-does-not-exist.md

42. Error While Trying to Run Project

This error comes about when debugging an ASP.NET app with Visual Studio. The full error message is:

“Error while trying to run project: Unable to start debugging on the web server. The project is not configured to be debugged.”

Error While Trying to Run Project

We can run into this error for two reasons:

  • The ASP.NET app is missing a web.config file.
  • The project folder’s Execute Permissions property in Internet Services Manager is set to

To fix the problem, either add a web.config file (if it’s missing) or set Execute Permissions to Scripts only. For more info, see this Microsoft help page. (@MicrosoftHelps)

43. Not Taking Advantage of Dependency Injection

Let’s say our Controller needs a FooService that lets it fetch a Foo that it can render to the user, like so:

public class FooController
{
    public IActionResult Index()
    {
        var fooService = new FooService(new BarService(), new BazService());
        return View(fooService.GetFoo());
    }
}

The trouble is, our Controller needs fine details about how to create a FooService. That means we have to replicate that logic everywhere a FooService is needed.

ASP.NET 5 MVC 6 gives us a baked-in feature called Dependency Injection. This lets us declare the dependency in the constructor. The ASP.NET 5 framework will then pass it in for us.

To see all the steps to take advantage of this powerful feature, see this tutorial. (@ArmenShimoon)

https://github.com/paologutierrez/.net50/blob/master/not-taking-advantage-of-dependency-injection.md

44. Misuse of the ‘var’ Keyword

Misuse and overuse of the var keyword is a common and basic error. The real purpose of var is to let us declare a local variable when we don’t know the type name. This is usually true with anonymous types when we don’t get the type name until compile time.

Yet some developers use var every time they declare a variable. In a local variable declaration, the type name gives us an added layer of description:

// let's say we have a static method called GetContacts()
// that returns System.Data.DataTable
var individuals = GetContacts(ContactTypes.Individuals);
// how is it clear to the reader that I can do this?
return individuals.Compute("MAX(Age)", String.Empty);

Other reasons to limit the use of var:

  • It encourages Hungarian notation.
  • It destroys the layer of context provided by type names.
  • It increases reliance on IntelliSense.
  • It doesn’t provide backward compatibility.

For an in-depth argument about var as an error, see this article.

https://github.com/paologutierrez/.net50/blob/master/misuse-of-var-keyword.md

45. Incorrectly using IoC Containers

Dependency injection is a powerful .NET tool we can use to avoid redundant code and save time and effort. Without dependency injection, we would have to reproduce the following code within multiple methods:

public class HomeController
{
  private readonly IExampleService _service;
  public HomeController()
  {
    _service = new ExampleService();
  }
  public ActionResult Index()
  {
    return View(_service.GetSomething());
  }
}

However, when we use dependency injection improperly in the following ways, we run into errors:

  • Using the container to retrieve dependencies instead of injecting them.
  • Abstracting the container.
  • Accessing the container to resolve components dynamically.

For an in-depth tutorial on using IoC containers correctly, click here. (@DevTrends)

https://github.com/paologutierrez/.net50/blob/master/incorrectly-using-ioc-containers.md

46. .ToLower() Not Working in LINQ Query

The String.ToLower method returns a copy of a string, converted to lowercase. However, this can cause a confusing error when we try to use it to compare values from different sources. Take the example below:

list = (from sr in dbContext.SERVICE_REQUEST
             join sc in dbContext.SERVICE_CUSTOMER on sr.CUSTOMER_ID equals sc.CUSTOMER_ID)
              where  (sr.SERVICE_REQUEST_NO.ToLower().Contains(objtobeAdvSearch.ServiceRequestNumber.ToLower()))

One solution (@ExpertsExchange) is to avoid the use of .ToLower here and instead use IndexOf with the case-insensitive OrdinalIgnoreCase (@msdev) property within the request:

list = (from sr in dbContext.SERVICE_REQUEST
join sc in dbContext.SERVICE_CUSTOMER on sr.CUSTOMER_ID equals sc.CUSTOMER_ID)
Where (sr.SERVICE_REQUEST_NO.IndexOf(objtobeAdvSearch.ServiceRequestNumber, StringComparison.OrdinalIgnoreCase) != -1))

https://github.com/paologutierrez/.net50/blob/master/tolower-not-working.md

47. Be Careful with Optional Parameters

We can get errors in C# 4.0 when we don’t keep an eye on our use of optional parameters. The following code shows a common misuse:

public class Base
{
    public virtual void Foo(Int32 x = 1) 
    {}   
}
public class Derived
{
    public override void Foo(Int32 x = 2)
    {}
}
...
Base f0 = new Base();
f0.Foo();                // Invokes Foo(1)
Base f1 = new Derived();
f1.Foo();               // Also invokes Foo(1)
Derived f2 = new Derived();
f2.Foo();               // Invokes Foo(2)

Here, the member function takes different arguments for different static types. With this code, we’re violating the principle of least surprise. Avoid this construction whenever possible. (@ElegantCode)

https://github.com/paologutierrez/.net50/blob/master/be-careful-with-optional-parameters.md

48. Overloading Methods Defined in Base Classes

We can cause hard-to-find errors in our C# code when we overload methods defined in base classes. When we do this, we increase the chance of ambiguity and the chance that our interpretation of the spec differs from the compiler’s.

The code below uses overloading improperly.

public class B
{
    public void Foo2(IEnumerable parm)
    {
        Console.WriteLine("In B.Foo2");
    }
}
public class D : B
{
    public void Foo2(IEnumerable parm)
    {
        Console.WriteLine("In D.Foo2");
    }
}
var sequence = new List { new D2(), new D2() };
var obj2 = new D();
obj2.Foo2(sequence);

For a deep look at why overloading methods defined in base classes causes trouble, see this tutorial. (@InformIT)

https://github.com/paologutierrez/.net50/blob/master/overloading-methods-defined-in-base-class.md

49. Using “” Instead of String.Empty Instead

The use of “” when we mean String.Empty can cause a subtle error. The difference between the two is, “” is a constant, while String.Empty isn’t. It’s a read-only field assigned to a constant.

string s2="";

Another reason to use String.Empty instead of quotes is that String.Empty handles memory more efficiently than “”, because it doesn’t create an object. Therefore, operations using “String.Empty happen faster.

See this discussion for more. (@codeproject)

https://github.com/paologutierrez/.net50/blob/master/using-quotation-insteadof-string-empty.md

50. Storing Secrets in Web.config

This arises from a temptation to avoid extra hassle by storing cryptographic secrets in a web.config file. Below is a sample from an ASP.NET 4.6 web config XML file:

<appSettings>
<add key="name" value="someValue" />
<add key="name" value="someSECRETValue" />
</appSettings>

We should never store secrets in a web.config file like that. Instead, we need to refer the code to a protected file, like this:

<appSettings file=”Web.SECRETS.config”>
<add key=”name” value=”someValue” />
</appSettings>

For a full breakdown of how this works, see here. (@shanselman)

https://github.com/paologutierrez/.net50/blob/master/storing-secrets-in-web-config.md

Conclusion

We hope you found this list of 50 .NET software errors helpful. Do you have a better fix for any of the errors and mistakes above? Do you have a software error you think ought to be included in our list? Give us a shout in the comments below.

Improve Your Code with Retrace APM

Stackify's APM tools are used by thousands of .NET, Java, PHP, Node.js, Python, & Ruby developers all over the world.
Explore Retrace's product features to learn more.

Learn More

Want to contribute to the Stackify blog?

If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]