Performance in .NET – Part 4

Introduction

This is my fourth post on performance in the .NET world. See the first one on object instantiation here and the second on property copying here and the third here. This time I’m going to talk about collections, but focusing on the performance side.This time, I’ll be talking about value types.

Value Types versus Reference Types

Value types – structs and enums – are always allocated in the stack, as opposed to reference types – classes – , which are allocated in the heap. This means that value types are automatically released from memory when they go out of scope – end of the block/method where they are declared, or the class is garbage collected, which is more rare. Value types are thus cheaper to create and do not need to be checked by the garbage collector.

Some aspects, though, need attention.

Instance Comparison

When you compare two value types using the Equals method, if there is no override for it, the value type is compared byte by byte. This is, as you can image, pretty inefficient. Is is recommended that you implement your own Equals (and GetHashCode too) and also that you implement IEquatable<T> interface for comparing two instances of your value type without incurring into boxing and unboxing.

Usage in Lists

Storing value types in array-based lists that permit reordering (random insertions and deletions), such as List<T> is painful, because of the items need to be copied, and copying for value types means byte by byte copying. Avoid if possible.

Usage in Arrays

Value types are great for usage in arrays, because a value type has no object header, so it’s size in memory is very small. The size of the array is therefore small when compared to the same array of reference types.

Conclusion

Do use value types as much as possible, but stay aware of the problems. As always, looking forward to hearing your thoughts. I’ll be back for more.

Visual Studio Tips 5

This is the fifth post of my Visual Studio tips series. See the first one here, the second here, the third here and the fourth here.

  1. Abort build: before exiting Visual Studio or retrieving changes from source control, any ongoing build must finish. If you don’t want to wait, you can abort it by pressing <Ctrl><Break>
  2. Start Visual Studio in safe mode helps in debugging problems introduced by some extensions. In the command line just enter: devenv /SafeMode
  3. Object IDs: you can track variables and fields in the debugger even when they go out of scope by creating an object id (1, 2, etc) for it. First add the variable or field to the watch window and then select Make Object ID:
    image
    Then you can inspect it at any time you want just by adding it to the watch as $1, $2, etc:
    image
  4. You can now add breakpoints to Auto-Properties, in the getter or setter! Cool!image
  5. NuGet Package Suggestion for Unrecognized Types:Visual Studio can suggest automatically installing a specific NuGet package to resolve an unknown type found in the code, or one that you may have typed yourself. This needs to be enabled.image
  6. Query Syntax in Go To All (Ctrl+T): when querying Go To All, you have some prefixes to help narrow your search results:
      • f {file}: for files
      • t {type}: for types

    • m {member}: for any type member
    • # {symbol}: for any symbol
  7. No side effects: sometimes, when debugging, we may need to evaluate an expression (property, method) that causes side effects, like, changes the internal state of some class. When we don’t want this to happen, we can add nse to the end of the expression, and it will prevent any unwanted side effects:image
  8. Copy files upon project build: you can use Visual Studio (or, better, MSBuild) to copy files for you during project build. Just add something like this to your .csproj:image
  9. Paste ring: Visual Studio keeps several items in its internal Clipboard. You can iterate through them all by clicking Ctrl+Shift+V:
    image
  10. Using Visual Studio to compare files. There are two ways:
    1. Using the command line: devenv /diff “Program.cs” “Program – Copy.cs”
    2. Using the Command Window: Tools.DiffFiles “Program.cs” “Program – Copy.cs” (shown below)

image

And this is it for now! Stay tuned for more!

Accessing the HttpContext from a DbContext

Sometimes it might be necessary to access the current HttpContext from inside a DbContext, namely, from inside the OnConfiguring or OnModelCreating methods. Why? Well, for once, because of multitenancy: we may want to be able to decide the connection string to use based on the requesting or the host’s domain, the current user or some other request parameter. Here the internal dependency injection (Instance) can’t help, because it cannot be used inside these methods.

The only option we have is to inject the IHttpContextAccessor class through our DbContext class’ constructor, and, from it, get hold of the HttpContext.

First we need to register the IHttpContextAccessor service in ConfigureServices:

services.AddHttpContextAccessor();

We also need to register our context for dependency injection:

services.AddDbContext<MyContext>();

A context registered this way needs to have a special constructor that has a parameter of type DbContextOptions (or DbContextOptions<MyContext>), in our case, we just need to add an extra parameter of type IHttpContextAccessor:

public class MyContext : DbContext
{
    public MyContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options)
    {
        this.HttpContextAccessor = httpContextAccessor;
    }

    protected IHttpContextAccessor HttpContextAccessor { get; }
}

Finally, when you need to access the HttpContext, you just need to retrieve it from the IHttpContextAccessor:

protected internal override void OnConfiguring(DbContextOptionsBuilder builder)
{
    var httpContext = this.HttpContextAccessor.HttpContext;
    var tenantService = httpContext.RequestServices.GetService<ITenantService>();
    var connectionString = tenantService.GetConnectionString(httpContext);

    builder.UseSqlServer(connectionString);

    base.OnConfiguring(builder);
}

Here the hypothetical ITenantService provides a method GetConnectionString that returns a connection string for the current HttpContext, and we use it with the SQL Server provider.

Hope you find this useful! Winking smile