Code

14 .NET packages I always recommend

Save time and make your applications better. Check out this list of open source .NET libraries I love to use and recommend.


Luke Lowrey
Luke Lowrey
- 8 min read
14 .NET packages I always recommend

This post lists open source libraries available on Nuget.org that I regularly use and recommend. These packages will save you time and make your applications better. They have good documentation and a great developer experience.

MediatR

MediatR is a simple in-process implementation of the mediator pattern. It helps developer write clean, decoupled and extendable code. Mediator is configured using dependency injection with out of the box support for .NET Core, Autofac and others. The documentation on Github is the best place to get started.

I like to use MediatR to write simple command query type requests using the IRequest interface. IRequest handle messages sent to a single handler. Examples of types of IRequests in a standard web application might be "GetUserQuery" or "UpdateCartCommand". The example below uses an internal nested class to keep the query model and query handler together in one class.

//a simple "query" type request
public class GetUserQuery : IRequest<User>
{
    public int UserID { get; set; }

    internal class GetUserQueryHandler : IRequestHandler<UserGetQuery, UserDto>
    {
        private readonly UserService _userService;

        public UserGetQueryHandler(UserService userService)
        {
            _userService = userService;
        }

        public async Task<UserDto> Handle(GetUserQuery request, CancellationToken cancellationToken)
        {
            //normlly something more extensive here...
            return await _userService.GetUser(request.UserID);
        }
    }
}

//calling code
var user = await mediator.Send(new GetUserQuery(1));
A simple "query" type mediatr request

Mediatr also supports notification messages which can have multiple handlers through INotification. Notifications work in a similar way to requests but don't return values. They are great for exposing a "extension point" in your application that you may need to build on later.

As a side note: everything Jimmy Bogard writes code or otherwise is great.

Serilog

Serilog provides structured logging which can target output to just about anywhere. Structured logs capture your log statements and objects as json. They give much more context into what is happening in your application and with the right tools they can be queried and analysed in more detail than standard text logs.

var position = new { Latitude = 25, Longitude = 134 };
var elapsedMs = 34;

log.Information("Processed {@Position} in {Elapsed:000} ms.", position, elapsedMs);

//log output
//{"Position": {"Latitude": 25, "Longitude": 134}, "Elapsed": 34}
Example from Serilog website

One of the best things about Serilog is the community has written sinks - which write logs to an provider for just about every service you can think of. The provided sinks Github page has a full list. A couple I recommend checking out:

  • Seq - self hosted structured log viewer
  • Sentry - exception reporting service that plugs in automatically to error log events

Hangfire

Hangfire is an easy way to perform scheduled or fire-and forget background jobs for .NET Core and Framework applications. I love how easy it is to get up an running as the jobs can run in your app's main process without requiring a dedicated service.

//Fire and forget
BackgroundJob.Enqueue(() => {
	Console.WriteLine("This will run once, in the background");
});

//Recurring job
RecurringJob.AddOrUpdate(
    () => {
    	Console.WriteLine("This will run daily");
    },
    Cron.Daily
);

//Calling a dependency injection job
BackgroundJob.Enqueue<MyService>(myService => myService.Execute());
Example Hangfire jobs

Hangfire has a great built in dashboard, dependency injection support and storage options for SQL server, PostgreSQL, Redis and more.

Hangfire dashboard

FluentEmail

FluentEmail (written by me) helps you implement complete email sending functionality in your app in less than 10 minutes. It features built in providers for the most popular email senders including SendGrid and Mailgun along with Razor templates out of the box. I recently wrote a full guide to .NET email using FluentEmail that will get you started.

var email = await Email
    .From("bill.gates@microsoft.com")
    .To("luke.lowrey@example.com", "Luke")
    .Subject("Hi Luke!")
    .Body("Fluent email looks great!")
    .SendAsync();
Send an email with FluentEmail

LazyCache

LazyCache is an easy to use, thread safe and developer friendly wrapper for in-memory caching in .NET Core. I've written a bit about LazyCache in the past and I still reach for it every time I need a cache provider.

LazyCache uses a "GetOrAdd" pattern for caching where you request an item from the cache and at the same time provide the function to add that item to the cache if it is missing.

var model = await cache.GetOrAddAsync("HomePageData", 
   async () =>
   {
       return homePageService.GetData(); //function to get cachable data
   }
   , new TimeSpan(12, 0, 0) //12 hour cache expiry
); 
Example cache GetOrAdd call

LazyCache is easy to extend so if you need to move beyond a simple in memory cache to something distributed the step up should be pretty seamless.

Dapper

Sometimes SQL data access with Entity Framework is overkill or just too slow. When you want to run raw SQL but still get some nice object mapping Dapper is the way to go.

Dapper is a NuGet library that you can add in to your project that will extend your IDbConnection interface.

Dapper takes your existing database connection and adds extension methods to run raw SQL and map it back to C# classes.

public class Dog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

var dogs = connection.Query<Dog>(
    "select * from Dogs where Age > @Id", //sql query, @ parameters
    new { Age = 5 } //anonymous object to map parameters
);
Example dapper query

MiniProfiler

MiniProfiler is a simple performance profiler for .NET Core and framework (also Ruby, Go and Node) web applications. It attaches automatically to the key parts of your application - mainly database access. MiniProfiler will then render an awesome little timing result directly on your app. It is great for running during development to pick up rogue LINQ queries.

MiniProfiler results

MiniProfiler has great setup documentation with a heap of options. For security reasons, I normally only have it enabled during development.

LinqKit

LINQKit is a set of extensions for querying Entity Framework with Linq. LINQKit allows you to build linq queries and conditions as predicates.

My most common use for LINQKit is simplifying queries with lots of criteria (think grids with filters) using the PredicateBuilder.

//base linq query
var users = from u in context.Users
            select u;

//add conditions as required
var predicate = PredicateBuilder.New<User>(true);

if (!string.IsNullOrWhiteSpace(filters.Name))
    predicate.And(u => u.Name.Contains(filters.Name));

if (!string.IsNullOrWhiteSpace(filters.Email))
    predicate.And(u => u.Email.Contains(filters.Email));

//apply conditions to query
var filteredUsers = users.AsExpandable().Where(predicate);
Example LINQKit predicate usage to add optional query conditions

FluentMigrator or DbUp

If you are looking for an alternative to running EntityFramework code first migrations both FluentMigrator and DbUp will do the job.

DbUp works best if you like raw SQL and simple scripts. You simply create a console application and add SQL files as embedded resources. Some simple code in Program.cs will run your migration scripts in order - easy to integrate into a devops pipeline.

Embedded scripts
static int Main(string[] args)
{
    var connectionString = args.FirstOrDefault(); //or some configuration

    var upgrader =
        DeployChanges.To
            .SqlDatabase(connectionString)
            .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
            .LogToConsole()
            .Build();

    var result = upgrader.PerformUpgrade();
    //omitted error handling...
    return 0;
}
Program.cs

FluentMigrator takes a similar concept with a more code-based approach. Instead of adding raw scripts you create small classes for each migration. This approach gives you more flexibility in building migrations (and saves you remembering the create foreign key sql syntax) and allows for more complete up/down migration scenarios.

using FluentMigrator;

namespace Migrations
{
    [Migration(20180430121800)]
    public class AddLogTable : Migration
    {
        public override void Up()
        {
            Create.Table("Log")
                .WithColumn("Id").AsInt64().PrimaryKey().Identity()
                .WithColumn("Text").AsString();
        }

        public override void Down()
        {
            Delete.Table("Log");
        }
    }
}
Example migration creating a Log table

CsvHelper

CsvHelper is my go to package for reading and writing csv files.  The library is flexible enough that you can creating custom mapping classes and rules for your C# classes or use the low level row and column methods directly.

//import csv to a class
using (var reader = new StreamReader("importfile.csv"))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
   csv.Context.RegisterClassMap<YourClassMap>(); //optionally use a mapping class
   var records = csv.GetRecords<YourClass>();
}

//use a mapping class
public class YourClass
{
    public int Id { get; set; }
    public string Name { get set; }
}

public sealed class YourClassMap : ClassMap<YourClass>
{
    public FooMap()
    {
        Map(m => m.Id).Name("Identifier"); //overrider column names and more
        Map(m => m.Name).Name("TheName");
    }
}

//or access columns directly
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.ReadHeader();
    while (csv.Read())
    {
        var id csv.GetField<int>("Id"),
        var name = csv.GetField("Name");
    }
}
Import csv file examples

There are similar options for exporting csv files either with direct column writes or using classes and mapping.

using (var writer = new StreamWriter("path\\to\\file.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
   csv.WriteRecords(records);
}
Simple export csv example

Hashids

Hashids for .NET generates short, unique string identifiers from integers - similar to YouTube video ids. It is great for turning one or more integers into a single short, non sequential hashes to use in urls and sharing. Just don't use it in place of security.

var hashids = new Hashids("example salt");

//creates "R9tGSE" hash
var id = hashids.Encode(1, 2, 3);

//decodes "R9tGSE" back into int[] {1, 2, 3}
var numbers = hashids.Decode(id);

Humanizer

Humanizer is for turning dates, numbers, enums and more in human friendly readable strings. It supports lots of data types and can be used with multiple languages.

//These are some methods I use all the time, check out the documentation for the full list

//dates
DateTime.UtcNow.AddHours(-25).Humanize() => "yesterday"
DateTime.UtcNow.AddHours(4).Humanize() => "4 hours from now"

//timespan
TimeSpan.FromDays(16).Humanize() => "2 weeks"

//Pluralize and singularize
"Dog".Pluralize() => "Dogs"
"Dogs".Singularize() => "Dog"

//truncate
"Long text to truncate".Truncate(10) => "Long text…"
Common Humanizer methods

Bogus

Bogus is a "fake" data generator for .NET. I shudder at the thought of generating "demo" data and "test" data but Bogus takes a bit part of that pain away.

Bogus allow you to map you C# classes to fake data to quickly generate lots of data. It is also possible to access the underlying methods directly and generate a phone number, email address etc on demand.

//map a class
var userIds = 0;
var testUsers = new Faker<User>()
	.RuleFor(b => b.Id, (f, u) => userIds++)
	.RuleFor(u => u.FirstName, (f, u) => f.Name.FirstName(u.Gender))
	.RuleFor(u => u.LastName, (f, u) => f.Name.LastName(u.Gender))
	.RuleFor(u => u.Avatar, f => f.Internet.Avatar())
	.RuleFor(u => u.UserName, (f, u) => f.Internet.UserName(u.FirstName, u.LastName))
	.RuleFor(u => u.Email, (f, u) => f.Internet.Email(u.FirstName, u.LastName));

//generate users
var user = testUsers.Generate();

//use methods directly
var faker = new Faker("en");
faker.Internet.DomainName(); //eg "sylvester.com"
faker.Company.Bs().Dump(); // eg "enable leading-edge architectures"
Simple Bogus data generation examples

Honourable mentions

I also love these libraries but this post was taking me forever to finish.


If you enjoyed the post, please share the thread on Twitter and let me know if I missed out your favourite libraries.

Want more? for a massive community list of .NET resources check out quozd/awesome-dotnet.