C-Sharp 9 Tips and Tricks

What Not To Do When Developing in C-sharp MVC Application

1. Do not mix Async and Sync function calls in one function, this produces a weird behavior that is really hard to debug.

   - The Synchronous function calls might block the Main Thread when there is no data on the Que, while using the Async Await directives this scales better as the UI Thread or Main Thread is not blocked when do reading IO data. The throughput is also maximized by using Async Await as other workers are able to pop items off the Que.

[Tip] Instead of creating New Arrays or Lists, just create one List, and then if you need another temp list for sorting purposes just clone/deep copy the existing list into a new one. If using an Array do, Array.Copy() function this will create an array of references to the original Array and will save you allocating object on the Heap Memory. 

2. Do not retrieve a lot of data more than you need, always choose the columns that are needed.
3. Do not convert all objects loaded into the application to .ToList(), this creates another buffer in the application, remember EF Core creates an internal buffer so when you convert objects to .ToList() all the time you need some sort of a list to enumerate then you are creating or buffering data again, this has a performance disadvantage. 

4. Be aware of the Hardware your application is running on, e.g. Memory, IO, Number of Cores, Network Cards, and always benchmark performance to find the bottlenecks and don't assume something before proving the hypothesis.

[NB] Always or mostly use AsEnumerable() that is derived from IEnumerable, this will choose the Collection that is suitable for the current scenario as Enumerables are a collection of different Non-Generic Collections like List, Dictionary, HashSet, and Array.
Read here



6/17/21 [In lieu of Finding ways to reduce object allocation]

1. I found out that you could call the database right on top of the foreach loop, this is called "Streaming" in EF Core, it is another method of retrieving data in a non Synchronous Way, the data retrieved is buffered and streamed to the caller without blocking the Worker Thread. It is fast and user gets the result as soon as the first data node is retrieved from the database.

await foreach(var post in _context.Posts.Include(e => e.Tags)){
foreach(var tags in post.Tags){

2. You can use ArrayPool<T>.Shared.Rent(100); to minimize object allocation on the Heap (the less the Garbage Collect collects the better performant your application becomes) See code below. Read about how Garbage Collection works here.

var arraypool = ArrayPool<Bills>.Shared.Rent(50);

//Do your work here

3. Use Stack Alloc in C# to create a short-lived variable. 
  - Spans are more than just a way to access subset arrays. They can also be used to refer to data on the stack. 
     Span<byte> b = stackalloc byte[2];
     b[0] = 42; //Will allocate the 42 on the Stack. But b[0] can not be access outside the function, only short lived within the function.

4. Use try{}finally{} code directive and all objects instantiated in the finally block gets cleaned up before the execution leaves the function.


6/14/21 [C# 9 Language Feature]
1. Did you know you could write code as 

   if(MyVariable is not null and MyOtherVariable is null)

1. Registering the Database Context as Singleton in the Startup.cs has some consequences. Every time you try to retrieve the Entity and do some operations on it then try to SaveChanges(); an error most of the time occurred. 
Error: InvalidOperaton: Cannot track the Entity Type 'yourEntityHere' because it is being tracked by another instance of this Context.

Entity Framework not Saving Changed Entity State to the Database
1. When EF Core does not persist or save changes to the Database after calling SaveChanges() function is called,
    do: _context.ChangeTracker.AutoDetectChangesEnabled = true;
     before calling _context.SaveChanges()


6/3/2021: Use Array.Copy

1. Use Array.Copy to create a shallow copy of the list or array to work with. This does not create the object on the Heap or possibly push the object to Gen 1 and Gen 2 Memory buckets that cause the GC to kick up.

2. Use CompareTo(string or int) to compare two object values, 0 means Yes, 1 means no.

6/2/21: Did you Know [HotChocolate] library
1. Did you know that you could actually inject a service on a Field Level? on a Property Level
   e.g. public IQueryable<Book> getBook([Service] DatabaseContext _context);
           //You could do this in the Interface and get access to the DatabaseContext Service through the field you have just initialized.

6/2/21: Understanding Span<T> (Span of T)

1. You can only use span in the function context, this prevents the Compiler from allocating another object in memory that might end up on the HEAP and eventually on Gen2 Memory HEAP. When an object a big it ends up getting allocated on Gen2 Memory HEAP the Garbage Collecter might at some get triggered to clean up resources/memory. When this happens Performance of an application suffers.

- The reason for working with Spans is that you rent memory on the STACK, when you complete using the slice then the memory is freed right away. That is why you can't access the Span Object outside the function, when the function is complete all objects utilized inside that function get disposed of.

2. Use Array Pooling if possible, this prevents unnecessary creation of big object on the HEAP, instead of when you want to use some sort of a Collection you rent the space from the Array Pool<T>, and when you are done, retain it.

- Be careful sometimes when you rent the Array space might contain something it, and the idea of emptying the space every time you rent and use the Array pool would be costly.


1. Enumerating the List Asynchronously: Add an Await in front of the foreach to enumerate through the list as data become available

5/25/21 [Dealing with File IO Exception]

1. If you have code that writes and reads from a file, you might experience IO Exception that writing to the file was not successful due to the file is in Use.
Please Login to see the rest of the answer

Answer: Check to see if the file is in use first before writing to it. 


          FileStream st = file.Open(FileMode.Open,fileAccess.Read, FileShare.None)
         }catch(IOException ex){
           return true;

- Also if you want to log the exception, instead of logging the ex.Message log ex.StackTrace to get more information about the error.

5/24/21: Wisdom learned through experience

1. When building C# Asp.Net 5 Application, not all functions or code should be implemented nor utilize Async Await directives.
    - I found out that the response or the results of the Async function is not guaranteed as this would cause inconsistencies. We don't know if the operation succeeded or not.
       In case of writing to the file in the Function, when we call an Async Function that writes to the file, sometimes the execution won't complete since the code utilizes Async Await, if you haven't Awaited the Request, the code execution in the present/current function will go on executing and might call another function that overrides the Business Logic needed for the function that writes to the file to complete its operation.
- The best way is to observe the situation and see if it is appropriate to implement Async Await.
- [update]: I also found out that combining Async calling with non-Async calling of function inside the Async function produces really weird results. 
                        This is because if the Async function called along with the none Async function both execution will be executed at different times and the dependencies will be messed up.
Write an Article

If you log in, you will be notified when someone leaves a comment.

Other users would like to know if this solution helped you.

© 2022 - ErnesTech - Privacy