ASP.NET Core Pitfalls – Session Storage

Previous versions of ASP.NET featured several ways to persist sessions:

  • InProc: sessions would be stored on the server’s process memory
  • SQL Server: sessions would be serialized and stored in a SQL Server database; other vendors offered similar functionality
  • State Server: sessions would be serialized and stored on an instance of the ASP.NET State Service
  • Custom: we had to implement our own persistence mechanism

InProc was probably the most commonly used; it was the fastest, as the items in the session weren’t serialized, but on the other side they would not survive server crashes. Using this approach things usually worked well, because the session object merely provided a reference to the items stored in memory, so manipulating these items didn’t mandate that the session be explicitly saved.

In ASP.NET Core, all of this is gone. By default, sessions are still stored in memory but one can also use one of the available distributed cache mechanisms. The main difference, however, is that even when the session objects are stored in memory, they still need to be serialized and deserialized prior to persisting or retrieving them. It is no longer possible to just store a pointer to a memory object and keep manipulating it transparently; the object to be stored needs to be converted into a byte array first. You can use any serializer you want.

If we think about it seriously, it was probably a good decision: I’ve seen applications where a lot of data was being stored on the session using InProc mode, but then there was a need to switch to another mode to improve scalability, and the application would just stop working, as the objects being stored weren’t serializable. This time, we need to carefully think about it beforehand.

ASP.NET Core Pitfalls – Redirect to Action Keeps Route Parameters

When you redirect after a POST – following the famous Post-Redirect-Get pattern – but your previous view was constructed using a route parameter, then it will be sent to the redirect action as well.

For example, say you are responding to a request for /Filter/Smartphone, where Smartphone is a route parameter, you POST it to some controller action and at the end you redirect to the Index action using the RedirectToAction method:

return this.RedirectToAction(nameof(Index));

The browser will issue the GET request for Index but keeps the Smartphone route parameter, which is not good.

The solution is to pass a routeValues parameter to RedirectToAction that doesn’t contain any of the possible route parameters. One way to do it would be to create a dictionay with all action parameters nullified:

return this.RedirectToAction(nameof(Index), MethodBase.GetCurrentMethod().GetParameters().ToDictionary(x => x.Name, x => (object) null));

The solution to have this done automatically lies in the MethodBase.GetCurrentMethod() method. This way, you are sure to avoid any unwanted route parameters on your next request.

In case you are wondering, passing null, a dictionary without entries or object won’t work, the only other way is to pass an anonymous value with the parameters explicitly set to null.

Entity Framework Core Succinctly Released

My latest (and fifth) ebook for Syncfusion’s Succinctly collection is out: Entity Framework Core Succinctly! It covers Entity Framework Core 2.0 and you can download it for free – need to register first, though.

This book is inspired by my previous one on Entity Framework Code First, but quite a lot has changed.

Huge thanks to Jeff Boenig for the technical review and to Hillary Bowling, Tres Watkins and Jacqueline Bieringer of Syncfusion for all their support.

Entity Framework Core Pitfalls: No TransactionScope Support

Entity Framework Core, as of version 2.0, does not support enlisting in ambient transactions, like those provided by TransactionScope. It is being tracked by issue #9561. This is by design and is related to a limitation of System.Data.SqlClient, which will be fixed when .NET Core 2.1 comes out. The ticket for SqlClient is #3114.

I already talked about the hard relation between Entity Framework and TransactionScope before. This time, however, with EF Core 2.1, it seems that it will be fixed, and this is a good thing. For now, however, you will have to roll out your own transaction management strategy which includes starting your own transactions explicitly and either committing them or rolling them back at the end. Please refer to the Microsoft documentation available at https://docs.microsoft.com/en-us/ef/core/saving/transactions.

Soft Deletes with Entity Framework Core 2 – Part 2

My previous post explained how to setup soft deletes for queries automatically. This time, I’m going to talk about the other part: actually replacing a delete for an update that sets the is deleted column.

The key here is to intercept the SaveChanges method, find out all entities that are ISoftDeletable and are marked for deletion and then set their IsDeleted property and change their state to be modified instead of deleted:

public override int SaveChanges()
{
foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted))
{
if (entry.Entity is ISoftDeletable)
{
entry.Property(_isDeletedProperty).CurrentValue = true;
entry.State = EntityState.Modified;
}
}

return base.SaveChanges();
}
This way Entity Framework will know what to do and just update them instead of deleting them. Next time, they won’t be loaded as they have been marked as deleted.

Soft Deletes with Entity Framework Core 2 – Part 1

Entity Framework Core 2, already covered here, includes a cool feature called global filters. By leveraging global filters, we can apply restrictions automatically to entities, either loaded directly or through a collection reference. If we add this to shadow properties (in the case of relational databases, columns that exist in a table but not on the POCO model), we can do pretty cool stuff.

In this example, I am going to create a soft delete global filter to all entities in the model that implement a marker interface ISoftDeletable.

public interface ISoftDeletable
{
}
We just need to override the DbContext’s OnModelCreating method to automatically scan all known entities to see which implement this interface and then create the restriction automatically:
private const string _isDeletedProperty = "IsDeleted";
private static readonly MethodInfo _propertyMethod = typeof(EF).GetMethod(nameof(EF.Property), BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(typeof(bool));

private static LambdaExpression GetIsDeletedRestriction(Type type)
{
var parm = Expression.Parameter(type, "it");
var prop = Expression.Call(_propertyMethod, parm, Expression.Constant(_isDeletedProperty));
var condition = Expression.MakeBinary(ExpressionType.Equal, prop, Expression.Constant(false));
var lambda = Expression.Lambda(condition, parm);
return lambda;
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
if (typeof(ISoftDeletable).IsAssignableFrom(entity.ClrType) == true)
{
entity.AddProperty(_isDeletedProperty, typeof(bool));

modelBuilder
.Entity(entity.ClrType)
.HasQueryFilter(GetIsDeletedRestriction(entity.ClrType));
}
}

base.OnModelCreating(modelBuilder);
}
So, for each entity known from the context we add a shadow property called IsDeleted of type bool. Of course, needless to say, it must also exist on the database. The reason I’m making it a shadow property is to avoid people tampering with the entities, by setting or unsetting its value. This way, the restriction is always performed and it is invisible to us. After we create the property, we add a restriction to the entity’s type.
Simple, don’t you think? This way, if you want to enable or disable it for a number of entities, just have them implement the ISoftDeletable interface.

Mastering ASP.NET Core 2.0

Mastering ASP.NET Core 2.0 Book Cover

My new book is out! It is called Mastering ASP.NET Core 2.0 and was edited by Packt Publishing, as my previous one, Entity Framework Core Cookbook – Second Edition.

It was big challenge – the book has over 480 pages – and it spanned multiple .NET Core versions – 1.1 and 2.0. I tried to cover the most important things, even with some detail. The chapters are:

  1. Getting Started with ASP.NET Core: .NET Core, ASP.NET Core, platforms, DI & IoC, MVC pattern, OWIN, hosting, environments
  2. Configuration: providers
  3. Routing: templates, handlers, constraints, areas, error handling
  4. Controllers and Actions: controller lifecycle, API controllers, versioning, documentation, globalization, binding
  5. Views: areas, layouts, Razor pages, globalization
  6. Using Forms and Models: metadata, templates, binding, validation
  7. Security: authentication, authorization, anti-forgery, CORS, HTTPS
  8. Reusable Components: partial views, view components, tag helpers and tag helper components
  9. Filters: authorization, resource, action, result, exception, Razor page
  10. Logging, Tracing and Diagnostics: custom middleware, logging, DiagnosticSource, ELM, AppInsights, HealthCheck
  11. Testing: xUnit, integration tests, UI tests with Selenium
  12. Client-Side Development: Bower, Node.js/NPM, Gulp, Grunt, TypeScript, LESS
  13. Improving the Performance and Scalability: asynchronous methods, profiling, bundling and minification, caching, response compression
  14. Real-Time Communication: SignalR
  15. Other Topics: areas, static files, application lifetime events, conventions, embedded resources, hosting extensions, URL rewriting
  16. Deployment: Visual Studio, IIS, Azure, AWS, Nginx, Apache, Docker, Windows Service

Whenever there are important differences, I mention the differences between ASP.NET Core 1.x and 2.x, although I think this will be less important over time.

Overall, it was an exciting task, but not one without obstacles. I must thank the team at Packt Publishing, namely, Siddhi Chavan and Abhishek Sharma for all their patience and support.

Do have a look and share your feedback! It is available from the Packt Publishing site, Amazon and others, either in hardcopy or ebook format. The source code is available at https://github.com/PacktPublishing/Mastering-ASP.NET-Core-2.0.

Entity Framework Core Extensions: Getting Primary Keys and Dirty Properties

Two simple hacks: finding the primary key values:

public static IDictionary<string, object> GetKeys(this DbContext ctx, object entity)
{
if (ctx == null)
{
throw new ArgumentNullException(nameof(ctx));
}

if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}

var entry = ctx.Entry(entity);
var primaryKey = entry.Metadata.FindPrimaryKey();
var keys = primaryKey.Properties.ToDictionary(x => x.Name, x => x.PropertyInfo.GetValue(entity));

return keys;
}

This returns a dictionary because some entities may have composite primary keys.

As for getting the dirty (modified) properties’ names for an entity:

public static IEnumerable<string> GetDirtyProperties(this DbContext ctx, object entity)
{
if (ctx == null)
{
throw new ArgumentNullException(nameof(ctx));
}

if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}

var entry = ctx.Entry(entity);
var originalValues = entry.OriginalValues;
var currentValues = entry.CurrentValues;

foreach (var prop in originalValues.Properties)
{
if (object.Equals(originalValues[prop.Name], currentValues[prop.Name]) == false)
{
yield return prop.Name;
}
}
}
Picking on the last one, if we wish to reset an entity to it’s original values:
public static void Reset(this DbContext ctx, object entity)
{
if (ctx == null)
{
throw new ArgumentNullException(nameof(ctx));
}

if (entity == null)
{
throw new ArgumentNullException(nameof(entity));
}

var entry = ctx.Entry(entity);
var originalValues = entry.OriginalValues;
var currentValues = entry.CurrentValues;

foreach (var prop in originalValues.Properties)
{
currentValues[prop.Name] = originalValues[prop.Name];
}

entry.State = EntityState.Unchanged;
}

Mind you, this one will not reset collections or references, just plain properties.

Hope it helps!

Getting the HTML for a ViewResult in ASP.NET Core

This is another post tagged “hack”: this time, how to get the HTML for a rendered view, in code. This is a standard solution that does not use any kind of reflection (or other) magic.

So, the idea is to pick up a ViewResult (it will also work for a PartialViewResult, but, alas, they do not share a common class – see #6984) and call some method, say, ToHtml, to get the rendered output. This method can look like this:

public static class ViewResultExtensions
{
public static string ToHtml(this ViewResult result, HttpContext httpContext)
{
var feature = httpContext.Features.Get<IRoutingFeature>();
var routeData = feature.RouteData;
var viewName = result.ViewName ?? routeData.Values["action"] as string;
var actionContext = new ActionContext(httpContext, routeData, new ControllerActionDescriptor());
var options = httpContext.RequestServices.GetRequiredService<IOptions<MvcViewOptions>>();
var htmlHelperOptions = options.Value.HtmlHelperOptions;
var viewEngineResult = result.ViewEngine?.FindView(actionContext, viewName, true) ?? options.Value.ViewEngines.Select(x => x.FindView(actionContext, viewName, true)).FirstOrDefault(x => x != null);
var view = viewEngineResult.View;
var builder = new StringBuilder();

using (var output = new StringWriter(builder))
{
var viewContext = new ViewContext(actionContext, view, result.ViewData, result.TempData, output, htmlHelperOptions);

view
.RenderAsync(viewContext)
.GetAwaiter()
.GetResult();
}

return builder.ToString();
}
}
To use it, just do:
var view = this.View(“ViewName”);
var html = view.ToHtml();

Have fun! Winking smile

This is the eight post in a series of posts about bringing the features that were present in Entity Framework pre-Core into EF Core. The others are:

  • Part 1: Introduction, Find, Getting an Entity’s Id Programmatically, Reload, Local, Evict

  • Part 2: Explicit Loading

  • Part 3: Validations

  • Part 4: Conventions

  • Part 5: Getting the SQL for a Query

  • Part 6: Lazy Loading

  • Part 7: Entity Configuration in Mapping Classes

This time I’m going to talk about the possibility to log the generated SQL to the output. In the past, we could do it by assigning a writer to DbContext.Database.Log:

ctx.Database.Log = Console.Log;
This would cause all SQL statements to be sent to the console. We can do something similar in EF Core, by leveraging the logging framework:
var loggerFactory = new LoggerFactory()
.AddDebug((categoryName, logLevel) => (logLevel == LogLevel.Information) && (categoryName == DbLoggerCategory.Database.Command.Name))
.AddConsole((categoryName, logLevel) => (logLevel == LogLevel.Information) && (categoryName == DbLoggerCategory.Database.Command.Name));

var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
.UseLoggerFactory(loggerFactory)
.UseSqlServer(@"<connectionString>");

var ctx = new MyContext(optionsBuilder.Options);
We are creating a new logger factory and populating it with the console and debug providers. You will need to add the Microsoft.Extensions.Logging.Console and Microsoft.Extensions.Logging.Debug NuGet packages (you don’t need both). For each of these providers, we are filtering the output by LogLevel.Information and category DbLoggerCategory.Database.Command.Name (“Microsoft.EntityFrameworkCore.Database.Command”), which are the values used when outputting SQL.

Then, we are creating a DbContextOptionsBuilder and in it we are replacing the default logger factory with our own. We then use it to create an option which we pass to our DbContext’s constructor, or we could do the same in the OnConfiguring method.

The output will look something like this:

SELECT [p].[ProjectId], [p].[CreatedAt], [p].[CreatedBy], [p].[CustomerId], [p].[Description], [p].[End], [p].[Name], [p].[Start], [p].[UpdatedAt], [p].[UpdatedBy]
FROM [Projects] AS [p]

Hope this helps! Winking smile