Implementing Missing Features in Entity Framework Core – Part 2

This is the second in a series of posts about missing functionality in EF Core. You can find the first here.

Entity Framework used to support three ways to load related entities (one to one, one to many, many to one, many to many):

Entity Framework Core doesn’t include (yet) the explicit loading and lazy loading mechanisms. Lazy loading is not included because EF Core does not generate proxies for the entities it loads, and I guess nobody bothered to implement explicit loading. Well, that’s exactly what we’ll do here!

The idea is, even if we didn’t require a collection to be loaded when we issued the query, we can still load it afterwards. We should keep a syntax similar to the previous version, when this feature was available:

//load a blog

var blog = ctx.Blogs.Single(b => b.BlogId == 1);

 

//Posts collection is empty

blog.Posts.Count(); //0

 

//eager load all Posts

ctx.Entry(blog).Load(b => b.Posts);

 

//Posts collection is no longer empty

blog.Posts.Count(); //!= 0

 

We will create an extension method over EntityEntry<T>:

public static void Load<TSource, TDestination>(this EntityEntry<TSource> entry, Expression<Func<TSource, IEnumerable<TDestination>>> path, Expression<Func<TDestination, TSource>> pathBack = null) where TSource : class where TDestination : class

{

    var entity = entry.Entity;

    var context = entry.Context;

    var entityType = context.Model.FindEntityType(typeof(TSource));

    var keys = entityType.GetKeys();

    var keyValues = context.GetEntityKey(entity);

    var query = context.Set<TDestination>() as IQueryable<TDestination>;

    var parameter = Expression.Parameter(typeof(TDestination), "x");

    PropertyInfo foreignKeyProperty = null;

 

    if (pathBack == null)

    {

        foreignKeyProperty = typeof(TDestination).GetProperties().Single(p => p.PropertyType == typeof(TSource));

    }

    else

    {

        foreignKeyProperty = (pathBack.Body as MemberExpression).Member as PropertyInfo;

    }

 

    var i = 0;

 

    foreach (var property in keys.SelectMany(x => x.Properties))

    {

        var keyValue = keyValues[i];

 

        var expression = Expression.Lambda(

                Expression.Equal(

                    Expression.Property(Expression.Property(parameter, foreignKeyProperty.Name), property.Name),

                    Expression.Constant(keyValue)),

                parameter) as Expression<Func<TDestination, bool>>;

 

        query = query.Where(expression);

 

        i++;

    }

 

    var list = query.ToList();

 

    var prop = (path.Body as MemberExpression).Member as PropertyInfo;

    prop.SetValue(entity, list);

}

The GetEntityKey method was introduced in the previous post, but I will add it here, for your convenience:

public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class

{

    var state = context.Entry(entity);

    var metadata = state.Metadata;

    var key = metadata.FindPrimaryKey();

    var props = key.Properties.ToArray();

 

    return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray();

}

You can see that the Load method takes two parameters: the first is required, it represents the collection that we with to load, the second is optional, and it represents the go-back property, in case there is more than one property of the root entity’s type. For example:

ctx.Entry(blog).Load(b => b.Posts, p => p.Blog);

In this case, the path p => p.Blog is needless, because a Post only belongs to one Blog.

A similar approach can be used to load explicitly other kinds of relations (one to one and many to one).

Hope you find this useful! Winking smile

Implementing Missing Features in Entity Framework Core

Introduction

By now, we all know that Entity Framework Core 1.0 will not include several features that we were used to. In this post, I will try to explain how we can get over this by implementing them ourselves, or, at least, working out some workaround.

This time, I am going to talk about mimicking the Reload and Find methods, plus, give a set of other useful methods for doing dynamic programming.

Find

Find lets us query an entity by its identifier. We will first define a strongly typed version:

public static TEntity Find<TEntity>(this DbSet<TEntity> set, params object[] keyValues) where TEntity : class

{

    var context = set.GetInfrastructure<IServiceProvider>().GetService<DbContext>();

    var entityType = context.Model.FindEntityType(typeof(TEntity));

    var keys = entityType.GetKeys();

    var entries = context.ChangeTracker.Entries<TEntity>();

    var parameter = Expression.Parameter(typeof(TEntity), "x");

    IQueryable<TEntity> query = context.Set<TEntity>();

 

    //first, check if the entity exists in the cache

    var i = 0;

 

    //iterate through the key properties

    foreach (var property in keys.SelectMany(x => x.Properties))

    {

        var keyValue = keyValues[i];

 

        //try to get the entity from the local cache

        entries = entries.Where(e => keyValue.Equals(e.Property(property.Name).CurrentValue));

 

        //build a LINQ expression for loading the entity from the store

        var expression = Expression.Lambda(

                Expression.Equal(

                    Expression.Property(parameter, property.Name),

                    Expression.Constant(keyValue)),

                parameter) as Expression<Func<TEntity, bool>>;

 

        query = query.Where(expression);

 

        i++;

    }

 

    var entity = entries.Select(x => x.Entity).FirstOrDefault();

 

    if (entity != null)

    {

        return entity;

    }

 

    //second, try to load the entity from the data store

    entity = query.FirstOrDefault();

 

    return entity;

}

And then a loosely-typed one:

private static readonly MethodInfo SetMethod = typeof(DbContext).GetTypeInfo().GetDeclaredMethod("Set");

 

public static object Find(this DbContext context, Type entityType, params object[] keyValues)

{

    dynamic set = SetMethod.MakeGenericMethod(entityType).Invoke(context, null);

    var entity = Find(set, keyValues);

    return entity;

}

Not sure if you’ve had to do queries through an entity’s Type, but I certainly have!

The Find method will first look in the DbContext local cache for an entity with the same keys, and will return it if it finds one. Otherwise, it will fallback to going to the data store, for that, it needs to build a LINQ expression dynamically.

Sample usage:

//strongly typed version

var blog = ctx.Blogs.Find(1);

 

//loosely typed version

var blog = (Blog) ctx.Find(typeof(Blog), 1);

Getting an Entity’s Id Programmatically

This is also important: getting an entity’s id values dynamically, that is, without knowing beforehand what are the properties (normally just one) that keeps them. Pretty simple:

public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class

{

    var state = context.Entry(entity);

    var metadata = state.Metadata;

    var key = metadata.FindPrimaryKey();

    var props = key.Properties.ToArray();

 

    return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray();

}

Here’s how to use:

Blog blog = ...;

var id = ctx.GetEntityKey(blog);

Reload

The Reload method tells Entity Framework to re-hydrate an already loaded entity from the database, to account for any changes that might have occurred after the entity was loaded by EF. In order to properly implement this, we will first need to define the two methods shown above (no need for the loosely-coupled version of Find, though):

public static TEntity Reload<TEntity>(this DbContext context, TEntity entity) where TEntity : class

{

    return context.Entry(entity).Reload();

}

 

public static TEntity Reload<TEntity>(this EntityEntry<TEntity> entry) where TEntity : class

{

    if (entry.State == EntityState.Detached)

    {

        return entry.Entity;

    }

 

    var context = entry.Context;

    var entity = entry.Entity;

    var keyValues = context.GetEntityKey(entity);

 

    entry.State = EntityState.Detached;

 

    var newEntity = context.Set<TEntity>().Find(keyValues);

    var newEntry = context.Entry(newEntity);

 

    foreach (var prop in newEntry.Metadata.GetProperties())

    {

        prop.GetSetter().SetClrValue(entity, prop.GetGetter().GetClrValue(newEntity));

    }

 

    newEntry.State = EntityState.Detached;

    entry.State = EntityState.Unchanged;

 

    return entry.Entity;

}

Here’s two versions of Reload: one that operates on an existing EntityEntry<T>, and another for DbContext; one can use them as:

Blog blog = ...;

 

//first usage

ctx.Entry(blog).Reload();

 

//second usage

ctx.Reload(blog);

You will notice that the code is updating the existing instance that was already loaded by EF, if any, and setting its state to Unchanged, so any changes made to it will be lost.

Local

EF Core 1.0 also lost the Local property, which allows us to retrieve cached entities that were previously loaded. Here’s one implementation of it:

public static IEnumerable<EntityEntry<TEntity>> Local<TEntity>(this DbSet<TEntity> set, params object [] keyValues) where TEntity : class

{

    var context = set.GetInfrastructure<IServiceProvider>().GetService<DbContext>();

    var entries = context.ChangeTracker.Entries<TEntity>();

 

    if (keyValues.Any() == true)

    {

        var entityType = context.Model.FindEntityType(typeof(TEntity));

        var keys = entityType.GetKeys();

        var i = 0;

 

        foreach (var property in keys.SelectMany(x => x.Properties))

        {

            var keyValue = keyValues[i];

            entries = entries.Where(e => keyValue.Equals(e.Property(property.Name).CurrentValue));

            i++;

        }

    }

 

    return entries;

}

the keyValues parameter is optional, it is the entity’s identifier values. If not supplied, Local will return all entries of the given type:

//all cached blogs

var cachedBlogs = ctx.Set<Blog>().Local();

 

//a single cached blog

var cachedBlog = ctx.Set<Blog>().Local(1).SingleOrDefault();

Evict

Entity Framework has no Evict method, unlike NHibernate, but it is very easy to achieve the same purpose through DbEntityEntry.State (now EntityEntry.State, in EF Core). I wrote an implementation that can evict several entities or one identified by an identifier:

public static void Evict<TEntity>(this DbContext context, TEntity entity) where TEntity : class

{

    context.Entry(entity).State = EntityState.Detached;

}

 

public static void Evict<TEntity>(this DbContext context, params object [] keyValues) where TEntity : class

{

    var tracker = context.ChangeTracker;

    var entries = tracker.Entries<TEntity>();

 

    if (keyValues.Any() == true)

    {

        var entityType = context.Model.FindEntityType(typeof (TEntity));

        var keys = entityType.GetKeys();

 

        var i = 0;

 

        foreach (var property in keys.SelectMany(x => x.Properties))

        {

            var keyValue = keyValues[i];

 

            entries = entries.Where(e => keyValue.Equals(e.Property(property.Name).CurrentValue));

 

            i++;

        }

    }

 

    foreach (var entry in entries.ToList())

    {

        entry.State = EntityState.Detached;

    }

}

As usual, an example is in order:

var blog = ...;

var id = ctx.GetEntityKey(blog);

 

//evict the single blog

ctx.Evict(blog);

 

//evict all blogs

ctx.Evict<Blog>();

 

//evict a single blog from its identifier

ctx.Evict<Blog>(id);

Conclusion

Granted, some of the missing functionality will give developers a major headache, but, even with what we have, it’s not impossible to go around them. Of course, this time, it was simple stuff, but in future posts I will try to address some more complex features.

Payloads as dynamic Objects in ASP.NET MVC

Even though the dynamic type seems to be everywhere these days, ASP.NET MVC still doesn’t support having dynamic parameters in controller action methods out of the box; which is to say, this doesn’t work as expected:

[HttpPost]

public ActionResult Post(dynamic payload)

{

    //payload will be an object without any properties

 

    return this.View();

}

However, because MVC is so extensible, it is very easy to achieve it. For that, we need to build a custom model binder and apply it to our action method parameter. We’ll assume that the content will come as JSON from the HTTP POST payload. Note that this does not happen with Web API, but still happens with MVC Core!

There are a couple of ways by which we can bind a model binder to a parameter:

First, let’s focus on the actual model binder, the core for any of the above solutions; we need to implement the IModelBinder interface, which isn’t really that hard to do:

public sealed class DynamicModelBinder : IModelBinder

{

    private const string ContentType = "application/json";

 

    public DynamicModelBinder(bool useModelName = false)

    {

        this.UseModelName = useModelName;

    }

 

    public bool UseModelName { get; private set; }

 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

    {

        dynamic data = null;

 

        if ((controllerContext.HttpContext.Request.AcceptTypes.Any(x => x.StartsWith(ContentType, StringComparison.OrdinalIgnoreCase) == true) &&

            (controllerContext.HttpContext.Request.ContentType.StartsWith(ContentType, StringComparison.OrdinalIgnoreCase) == true)))

        {

            controllerContext.HttpContext.Request.InputStream.Position = 0;

 

            using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream))

            {

                var payload = reader.ReadToEnd();

 

                if (string.IsNullOrWhiteSpace(payload) == false)

                {

                    data = JsonConvert.DeserializeObject(payload);

 

                    if (this.UseModelName == true)

                    {

                        data = data[bindingContext.ModelName];

                    }

                }

            }

        }

 

        return data;

    }

}

Nothing fancy here; it will check to see if both the Accept and the Content-Type HTTP headers are present and set to application/json, the official MIME type for JSON, before parsing the posted content. If any content is present, JSON.NET will parse it into it’s own object. The UseModelName property is used to bind to a specific property of the payload, for example, say you are binding to a parameter called firstName, and you want it populated with the contents of the firstName field in the payload. In our case, we don’t need it, we want the whole thing, so it is set to false.

Now, the way I recommend for applying this model binder is through a custom attribute:

[Serializable]

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]

public sealed class DynamicModelBinderAttribute : CustomModelBinderAttribute

{

    public DynamicModelBinderAttribute(bool useModelName = false)

    {

        this.UseModelName = useModelName;

    }

 

    public bool UseModelName { get; private set; }

 

    public override IModelBinder GetBinder()

    {

        return new DynamicModelBinder(this.UseModelName);

    }

}

It goes like this:

[HttpPost]

public ActionResult Post([DynamicModelBinder] dynamic payload)

{

    //payload will be populated with the contents of the HTTP POST payload

 

    return this.View();

}

Or, if you want to do it for several dynamic parameters, just set a global model binder provider for type Object; this is safe, because we would never have a parameter of type Object:

public sealed class DynamicModelBinderProvider : IModelBinderProvider

{

    public static readonly IModelBinderProvider Instance = new DynamicModelBinderProvider();

 

    public IModelBinder GetBinder(Type modelType)

    {

        if (modelType == typeof (object))

        {

            return new DynamicModelBinder();

        }

 

        return null;

    }

}

And we register is as this:

ModelBinderProviders.BinderProviders.Insert(0, DynamicModelBinderProvider.Instance);

And that’s it. This is one of what I consider to be ASP.NET MVC flaws, and they will deserve another post, soon. Web API already solves this problem, but it is still there in the future version of MVC Core, and can be solved in the same way.

Detecting Default Values of Value Types

Func<object, bool> func = (obj) => obj.Equals(default(Int32));

Func<object, bool> func = (obj) => obj.Equals(default(Int32));

Introduction

I don’t know if this happened to you: the need to find out if some instance of a class is the class’ default value. For reference types – which include nullables -, it is always null, and for value types, it is the value that you get if you do not initialize a field of that type or if you call its default parameterless constructor – false for Boolean, 0 for numbers, the 0 member of an enumeration, etc. So, the problem is, how can we tell if some instance represents this default value, dynamically, that is, for any value type, not just a specific one.

Again, nothing special, just the result of a lazy Saturday afternoon, still, hope you see some value in it! Winking smile

Take 0: Direct Comparison

How would we compare a built-in type instance, like int, with its default value? Just compare it with 0. This is useful to see how each of the other techniques compare to it.

static bool IsDefaultDirect(int obj)

{

    return obj.Equals(0);

}

Take 1: Comparison With a New Instance

An easy way is to compare the value we have with a new instance of the same type, like this:

static bool IsDefaultUsingConstruction(ValueType obj)

{

    return obj.Equals(Activator.CreateInstance(obj.GetType()));

}

Activator.CreateInstance knows how to create a default instance of a value type, so we’re good.

Take 2: Using Generics Directly

Another option is to use the ability to compare a generic variable with the default value for the generic type. This cannot be used in exactly the same way as #1, because here we need to explicitly call the comparison method with a generic parameter:

static bool IsDefaultUsingGeneric<T>(T obj) where T : struct

{

    return obj.Equals(default(T));

}

Notice the struct constraint, it is exactly the same as declaring the parameter as ValueType, because it is the base class for all value types.

Take 3: Using Generics Dynamically

You can make the previous example dynamic, with the cost of an additional method invocation, like this:

static bool IsDefaultUsingReflection(ValueType obj)

{

    //cache this, please

    var isDefaultUsingGenericMethod = typeof(Program).GetMethod("IsDefaultUsingGeneric", BindingFlags.Static | BindingFlags.NonPublic);

    var method = isDefaultUsingGenericMethod.MakeGenericMethod(obj.GetType());

    return (bool) method.Invoke(null, new object[] { obj });

}

Take 4: Using a LINQ Expression Bound to a Specific Type

Another option is to dynamically compile a LINQ expression that performs the comparison, something like this:

Func<T, bool> func = (obj) => obj.Equals(default(T));

We can create this expression dynamically, and bind it to the desired value type:

static bool IsDefaultUsingLinq(ValueType obj)

{

    var argType = obj.GetType();

    var arguments = new Expression[] { Expression.Default(argType) };

    var paramExpression = Expression.Parameter(argType, "x");

 

    var equalsMethod = argType.GetMethod("Equals", new Type[] { argType });

    var call = Expression.Call(paramExpression, equalsMethod, arguments);

 

    var lambdaArgType = typeof(Func<,>).MakeGenericType(argType, typeof(bool));

    var lambdaMethod = LambdaMethod.MakeGenericMethod(lambdaArgType);

 

    var expression = lambdaMethod.Invoke(null, new object[] { call, new ParameterExpression[] { paramExpression } }) as LambdaExpression;

 

    //cache this, please

    Delegate func = expression.Compile();

 

    return (bool)func.DynamicInvoke(obj);

}

Take 5: Using a LINQ Expression Bound to Object

A very similar option to #4 is to use Object.Equals instead of the value type’s specific Equals method, like this:

Func<object, bool> func = (obj) => obj.Equals(default(int));

Of course, the int parameter depends on the actual type of the value type parameter being passed:

static readonly MethodInfo LambdaMethod = typeof(Expression).GetMethods(BindingFlags.Static | BindingFlags.Public).First(x => x.Name == "Lambda" && x.GetParameters()[1].ParameterType == typeof(ParameterExpression[]));

static readonly MethodInfo EqualsMethod = typeof (object).GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public);

 

static bool IsDefaultUsingLinqObject(ValueType obj)

{

    var argType = typeof(object);

    var arguments = new Expression[] { Expression.Convert(Expression.Default(obj.GetType()), argType) };

    var equalsMethod = EqualsMethod;

    var paramExpression = Expression.Parameter(argType, "x");

    var call = Expression.Call(paramExpression, equalsMethod, arguments);

    var lambdaArgType = typeof(Func<object, bool>);

    var lambdaMethod = LambdaMethod.MakeGenericMethod(lambdaArgType);

    var expression = lambdaMethod.Invoke(null, new object[] { call, new ParameterExpression[] { paramExpression } }) as Expression<Func<object, bool>>;

 

    //cache this, please

    Func<object, bool> func = expression.Compile();

 

    return func(obj);

}

Because the comparison expression, of type Func<object, bool>, is strongly typed, we avoid the need to call Delegate.DynamicInvoke, the performance increases substantially.

Take 6: Using Formatter Services

A long, long time ago, in a distance galaxy, I already mentioned, en passant, the usage of FormatterServices.GetUninitializedObject to create instances of a type. Picking up example #1, let’s replace Activator.CreateInstance by FormatterServices.GetUninitializedObject and see the gains:

static bool IsDefaultUsingFormatterServices(ValueType obj)

{

    return obj.Equals(FormatterServices.GetUninitializedObject(obj.GetType()));

}

Take 7: Using a LINQ Expression Bound to a Specific Type and Using Invocation Through Dynamics

What a long name… Smile Well, this one is identical to #4, but without Delegate.DynamicInvoke. Instead, I make use of the dynamic type’s late binding to invoke the delegate, which results in even better performance:

static readonly MethodInfo LambdaMethod = typeof(Expression).GetMethods(BindingFlags.Static | BindingFlags.Public).First(x => x.Name == "Lambda" && x.GetParameters()[1].ParameterType == typeof(ParameterExpression[]));

 

static bool IsDefaultUsingLinqAndDynamic(ValueType obj)

{

    var argType = obj.GetType();

    var arguments = new Expression[] { Expression.Default(argType) };

    var paramExpression = Expression.Parameter(argType, "x");

    var equalsMethod = argType.GetMethod("Equals", new Type[] { argType });

    var call = Expression.Call(paramExpression, equalsMethod, arguments);

    var lambdaArgType = typeof(Func<,>).MakeGenericType(argType, typeof(bool));

    var lambdaMethod = LambdaMethod.MakeGenericMethod(lambdaArgType);

    var expression = lambdaMethod.Invoke(null, new object[] { call, new ParameterExpression[] { paramExpression } }) as LambdaExpression;

 

    //cache this, please

    Delegate func = expression.Compile();

 

    dynamic arg = obj;

    dynamic del = func;

 

    return del(arg);

}

Measuring

I put in two methods for measuring calls and doing averages:

static long MeasureTicks(Action action)

{

    var watch = Stopwatch.StartNew();

 

    action();

 

    return watch.ElapsedTicks;

}

 

static float Measure(int times, Action action)

{

    var avg = 0L;

 

    for (var i = 0; i < times; ++i)

    {

        avg += MeasureTicks(action);

    }

 

    return (float)avg / times;

}

I used a Stopwatch to obtain the ElapsedTicks of the method to be exercised. I changed the methods I presented, namely, #4, #5 and #7, so as to cache the types and delegates created dynamically, this is crucial, and I leave that as an exercise to you – just remember that each method can potencially be called with different values, of different types. Then I added a warm-up step, which exercises the code using an integer parameter:

static void Warmup(int value)

{

    var times = 1;

    Measure(times, () => IsDefaultDirect(value));

    Measure(times, () => IsDefaultUsingConstruction(value));

    Measure(times, () => IsDefaultUsingGeneric(value));

    Measure(times, () => IsDefaultUsingReflection(value));

    Measure(times, () => IsDefaultUsingLinq(value));

    Measure(times, () => IsDefaultUsingLinqObject(value));

    Measure(times, () => IsDefaultUsingFormatterServices(value));

    Measure(times, () => IsDefaultUsingLinqAndDynamic(value));

}

In the past, I learned that a warm-up method – or lack of it – makes a huge difference.

I executed each option 100 times and got its results:

static void Measure()

{

    var times = 100;

    var value = 100;

 

    Warmup(value);

 

    var m0 = Measure(times, () => IsDefaultDirect(value));

    var m1 = Measure(times, () => IsDefaultUsingConstruction(value));

    var m2 = Measure(times, () => IsDefaultUsingGeneric(value));

    var m3 = Measure(times, () => IsDefaultUsingReflection(value));

    var m4 = Measure(times, () => IsDefaultUsingLinq(value));

    var m5 = Measure(times, () => IsDefaultUsingLinqObject(value));

    var m6 = Measure(times, () => IsDefaultUsingFormatterServices(value));

    var m7 = Measure(times, () => IsDefaultUsingLinqAndDynamic(value));

}

The results I got were:


Method Ticks Difference
#0: Direct Comparison 1.82 131.88%
#1: Comparison With a New Instance 1.92 139.13%
#2: Using Generics Directly 1.46 105.80%
#3: Using Generics Dynamically 6.9 500%
#4: Using a LINQ Expression Bound to a Specific Type 3.05 221.01%
#5: Using a LINQ Expression Bound to Object 1.61 116.67%
#6: Using Formatter Services 1.53
#7: Using a LINQ Expression Bound to a Specific Type and Using Invocation Through Dynamics 1.38 100%

Conclusion

I was really surprised that the direct comparison is actually – at least for integers – not the best way to see if a value is the default for its type! There’s a big range in results, and I can say that I was expecting that for #3. I knew that FormatterServices.GetUninitializedObject would give better results than Activator.CreateInstance, but I imagine this cannot be used with all types, because it doesn’t run the type’s constructor, possibly skipping some default initializations. I also knew that the performance of Delegate.DynamicInvoke is less than ideal, but it was interesting to see that dynamics can improve it.

As always, I’d love to see what you have to say! Do you see flaws in my approach, or do you know of any better solutions? Fire away! Winking smile

Encrypted JavaScript in ASP.NET MVC Core

To complete the Data URI saga, here is another technique that you may find interesting: this time, it’s about encrypting JavaScript contents, so as to make them more difficult to tamper with.

Data URIs can be used for serving any content that would normally come from an external resource, such as a JavaScript/CSS file or an image. What we will do here is, using ASP.NET MVC Core’s Tag Helpers, we get hold of the JavaScript that is defined inside a SCRIPT tag and we turn into a Data URI. Pretty simple, yet the result is also pretty cool!

Show me the code, I hear you say:

[HtmlTargetElement("script")]

[HtmlTargetElement("script", Attributes = "asp-encrypt")]

[HtmlTargetElement("script", Attributes = "asp-src-include")]

[HtmlTargetElement("script", Attributes = "asp-src-exclude")]

[HtmlTargetElement("script", Attributes = "asp-fallback-src")]

[HtmlTargetElement("script", Attributes = "asp-fallback-src-include")]

[HtmlTargetElement("script", Attributes = "asp-fallback-src-exclude")]

[HtmlTargetElement("script", Attributes = "asp-fallback-test")]

[HtmlTargetElement("script", Attributes = "asp-append-version")]

public class InlineScriptTagHelper : ScriptTagHelper

{

    public InlineScriptTagHelper(ILogger<ScriptTagHelper> logger, IHostingEnvironment hostingEnvironment,

        IMemoryCache cache, IHtmlEncoder htmlEncoder, IJavaScriptStringEncoder javaScriptEncoder,

        IUrlHelper urlHelper) : base(logger, hostingEnvironment, cache, htmlEncoder, javaScriptEncoder, urlHelper)

    {

    }

 

    [HtmlAttributeName("asp-encrypt")]

    public bool Encrypt { get; set; }

 

    public override void Process(TagHelperContext context, TagHelperOutput output)

    {

        if ((this.Encrypt == true) && (string.IsNullOrWhiteSpace(this.Src) == true))

        {

            var content = output.GetChildContentAsync().GetAwaiter().GetResult().GetContent();

            var encryptedContent = Convert.ToBase64String(Encoding.ASCII.GetBytes(content));

            var script = $"data:text/javascript;base64,{encryptedContent}";

 

            output.Attributes.Add("src", script);

            output.Content.Clear();

        }

 

        base.Process(context, output);

    }

}

You can see that this tag helper inherits from ScriptTagHelper, which is the OOTB class that handles SCRIPT tags. Because of this inheritance, we need to add all the HtmlTargetElementAttributes, so that all the rules get applied properly. For this one, we need to add an extra rule, which forces the SCRIPT tag to have an asp-encrypt attribute.

So, say you have this in your Razor view:

<script asp-encrypt="true">
   1:  

   2:     window.alert('hello, world, from an encrypted script!');

   3:  

</script>

What you’ll end up with in the rendered page is this:

<script src="data:text/javascript;base64,DQoNCiAgICB3aW5kb3cuYWxlcnQoJ2hlbGxvLCB3b3JsZCwgZnJvbSBhbiBlbmNyeXB0ZWQgc2NyaXB0IScpOw0KDQo="></script>

Cool, wouldn’t you say? Of course, no JavaScript that runs on the client can ever be 100% secure, and you should always keep that in mind. But for some purposes, it does pretty well! Winking smile

Entity Framework Pitfalls: Attaching New Entities With Existing Related Ones

One of the patterns in EF 6.x for attaching new entities to a context is to simply change it’s state to Added:

ctx.Entry(myEntity).State = EntityState.Added;

Entity Framework 6.x will traverse the entity graph of all the related entities and set all their states to Added too. This might be a problem.

Imagine we want to attach a disconnected (new) entity that is linked to an existing one, for which we already have a reference. In this case, we don’t want this reference to be added, because doing so will raise a violation on the database and it will come out as an exception.

What we need to do is to explicitly set the state of any of these existing instances to Unchanged. Fortunately, Entity Framework Core will solve this with the introduction of a new TrackGraph API.

Thanks for Tony Sneed (@tonysneed) for reminding me.

Fluent Validation in JavaScript

A recent discussion with my colleagues about fluent validation in JavaScript made me realize that I didn’t know of any such library. I take it for granted that some may exist, but I have never actually used one. To be clear, I mean a validation library that I can use in unit tests, for asserting conditions. Because I had a free Saturday morning, I decided to write my own!

Nothing fancy, just a couple of methods for dealing with common validations. It can be used in both browsers and in Node.js apps. Several validations can be chained and it any fails, an error is thrown. It goes like this:

/**

 * Builds a new Validation object

 * @param {object} obj The object to validate

 */

function Validation(obj) {    

    this.obj = obj;

    this.negated = false;

    this.reporting(null);

}

 

/**

 * Try to find the first argument of a given type

 * @param {array} args An array of arguments

 * @param {string} type The type to find

 * @returns {object} The first argument that matches the given type, or undefined

 */

function findFirstOfType(args, type) {

    for (var i = 0; i < args.length; ++i) {

        if (typeof args[i] === type) {

            return args[i];

        }

    }

    return undefined;

}

 

/**

 * Either returns the first argument as an array or the arguments implicit parameter

 * @param {array} args A possibly array parameter

 * @param {array} array An array of arguments

 * @returns {array} An array of arguments

 */

function getArguments(args, array) {

    var newArray = args;

    

    if (!(args instanceof Array))

    {

        newArray = [ args ];

        for (var i = 1; i < array.length; ++i) {

            newArray.push(array[i]);

        }

    }

    

    return newArray;

}

 

/**

 * Throws an exception in case of an error

 * @param {boolean} error An error flag

 * @param {string} msg An error message

 */

Validation.prototype.assert = function(error, msg) {

    if (error != this.negated) {

        this.report(msg);

    }

};

 

/**

 * Changes the reporting function in case of a validation error. The default is to throw an Error

 * @param {function} fn A reporting function

 * @returns {object} The Validation object

 */

Validation.prototype.reporting = function(fn) {

    if ((!fn) || (typeof fn !== 'function')) {

        fn = function(msg) {

            throw new Error(msg);

        };

    }

    

    this.report = fn;

    return this;

};

 

/**

 * Uses an external validation function

 * @param {function} fn A validation function

 * @param {string} msg An optional error message

 */

Validation.prototype.isValid = function(fn, msg) {

    var self = this;

    msg = msg || 'Validation failed: custom validation function';

    var error = (fn(self.obj) !== true);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is one of a set of passed values

 * @param {array} args An optional array of arguments

 */

Validation.prototype.isOneOf = function(args) {

    var self = this;

    var msg = 'Validation failed: objects do not match';

    var error = arguments.length > 0;

    args = getArguments(args, arguments);

    

    for (var i = 0; i < args.length; ++i) {

        if (self.obj == args[i]) {

            error = false;

            break;

        }

    }

    

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is not in a set of passed values

 * @param {array} args An optional array of arguments

 */

Validation.prototype.isNoneOf = function(args) {

    var self = this;

    var msg = 'Validation failed: objects do not match';

    var error = false;

    args = getArguments(args, arguments);

        

    for (var i = 0; i < args.length; ++i) {

        if (self.obj == args[i]) {

            error = true;

            break;

        }

    }

    

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate contains a supplied value

 * @param {object} value A value to find

 * @param {string} msg An optional error message

 */

Validation.prototype.contains = function(value, msg) {

    var self = this;

    msg = msg || 'Validation failed: object does not contain target';

    var error = self.obj.length != 0;

    

    for (var i = 0; i < self.obj.length; ++i) {

        if (self.obj[i] == value) {

            error = false;

            break;

        }

    }

    

    this.assert(error, msg);

    return this;    

};

 

/**

 * Checks if the value to validate is equal to a supplied value

 * @param {object} value A value to compare against

 * @param {object} arg1 An optional argument

 * @param {object} arg2 An optional argument

 */

Validation.prototype.isEqualTo = function(value, arg1, arg2) {

    var self = this;

    var caseInsensitive = findFirstOfType([arg1, arg2], 'boolean') || false;

    var msg = findFirstOfType([arg1, arg2], 'string') || 'Validation failed: objects do not match';

    var left = self.obj.toString();

    var right = value.toString();

            

    if (caseInsensitive) {

        left = left.toLowerCase();

        right = right.toLowerCase();

    }

 

    var error = (left != right);

    

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a string

 * @param {string} msg An optional error message

 */

Validation.prototype.isString = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a string';

    var error = ((typeof self.obj !== 'string') && (self.obj.toString() != obj));

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is neither null nor a whitespace string

 * @param {string} msg An optional error message

 */

Validation.prototype.isNotNullOrWhitespace = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is null or whitespace';

    var error = ((self.obj === null) || (self.obj.toString().trim().length == 0));

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a number

 * @param {string} msg An optional error message

 */

Validation.prototype.isNumber = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a number';

    var error = ((typeof self.obj !== 'number') && (Number(self.obj) != self.obj));

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a positive number

 * @param {string} msg An optional error message

 */

Validation.prototype.isPositive = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a number';

    var error = (Number(self.obj) <= 0);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a negative number

 * @param {string} msg An optional error message

 */

Validation.prototype.isNegative = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a number';

    var error = (Number(self.obj) >= 0);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is an odd number

 * @param {string} msg An optional error message

 */

Validation.prototype.isOdd = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not odd';

    var error = (Number(self.obj) % 2 === 0);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is an even number

 * @param {string} msg An optional error message

 */

Validation.prototype.isEven = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not even';

    var error = (Number(self.obj) % 2 !== 0);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a finite number

 * @param {string} msg An optional error message

 */

Validation.prototype.isFinite = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is infinite';

    var error = !isFinite(self.obj);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a function

 * @param {string} msg An optional error message

 */

Validation.prototype.isFunction = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a function';

    var error = (typeof self.obj !== 'function');

    this.assert(error, msg);

    return this;    

};

 

/**

 * Checks if the value to validate is a boolean

 * @param {string} msg An optional error message

 */

Validation.prototype.isBoolean = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a boolean';

    var error = (typeof self.obj !== 'boolean');

    this.assert(error, msg);

    return this;    

};

 

/**

 * Checks if the value to validate is defined

 * @param {string} msg An optional error message

 */

Validation.prototype.isDefined = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is undefined';

    var error = (self.obj === undefined);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is null

 * @param {string} msg An optional error message

 */

Validation.prototype.isNull = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not null';

    var error = (self.obj !== null);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is of a primitive type

 * @param {string} msg An optional error message

 */

Validation.prototype.isPrimitive = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not of a primitive type';

    var type = typeof self.obj;

    var error = ((type !== 'number') && (type !== 'string') && (type !== 'boolean'));

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is an array

 * @param {string} msg An optional error message

 */

Validation.prototype.isArray = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not an array';

    var error = !Array.isArray(self.obj);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate matches a regular expression

 * @param {string} regex A regular expression

 * @param {string} msg An optional error message

 */

Validation.prototype.isMatch = function(regex, msg) {

    var self = this;

    msg = msg || 'Validation failed: object does not match regular expression';

    var error = !(new RegExp(regex).test(self.obj.toString()));

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is valid JSON

 * @param {string} msg An optional error message

 */

Validation.prototype.isJSON = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not valid JSON';

    var error = false;

    try

    {

        error = (typeof JSON.parse(self.obj) !== 'object');

    }

    catch(e)

    {

        error = true;

    }

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate has a given length

 * @param {number} max The maximum length

 * @param {object} arg1 An optional argument

 * @param {object} arg2 An optional argument

 */

Validation.prototype.hasLength = function(max, arg1, arg2) {

    var self = this;

    var msg = findFirstOfType([arg1, arg2], 'string') || 'Validation failed: length does not fall between the given values';    

    var min = findFirstOfType([arg1, arg2], 'number') || 0;        

    var str = self.obj.toString();

    var error = str.length > max;

 

    if (!error) {

        error = (str.length < min);

    }

    

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a Promise

 * @param {string} msg An optional error message

 */

Validation.prototype.isPromise = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a promise';

    var error = ((typeof Promise === 'undefined') || !(self.obj instanceof Promise));

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is a Date

 * @param {string} msg An optional error message

 */

Validation.prototype.isDate = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not a date';

    var error = !(self.obj instanceof Date);

    this.assert(error, msg);

    return this;

};

 

/**

 * Checks if the value to validate is an Error

 * @param {string} msg An optional error message

 */

Validation.prototype.isError = function(msg) {

    var self = this;

    msg = msg || 'Validation failed: object is not an error';

    var error = !(self.obj instanceof Error);

    this.assert(error, msg);

    return this;

};

 

/**

 * Negates the validation logic

 * @returns {object} The Validation object

 */

Validation.prototype.not = function() {

    this.negated = !this.negated;

    return this;

};

 

/**

 * Validates an object

 * @returns {object} The Validation object

 */

Object.prototype.validate = function() {

    return Validation.validate(this);

};

 

Validation.validate = function(obj) {

    var val = new Validation(obj);

    return val;

};

 

if (typeof module !== 'undefined') {

    module.exports = Validation;

}

It’s usage is simple, as would be expected from a fluent library:

//the object to validate

var obj = '1';

 

//fire a bunch of validations - not all make sense

Validation

    .validate(obj)

    .isDefined()

    .isPrimitive()

    .isValid(function(x) { return true })

    .contains('1')

    .isOdd()

    .isOneOf('1', '2', '3')

    .isNoneOf('4', '5', '6')

    .isEqualTo(1)

    .isNotNullOrWhitespace()

    .isString()

    .isNumber()

    .hasLength(2, 1)

    .isMatch('\\d+')

    .isPositive();

The included checks are:

  • isValid: takes a JavaScript function to validate the object;
  • isOneOf, isNoneOf: check to see if the target object is contained/is not contained in a set of values;
  • contains: checks if the object to validate – possibly an array – contains in it a given value;
  • isEqualTo: performs a string comparison, optionally case-insensitive;
  • isString, isNumber, isFunction, isArray, isDate, isJSON, isPromise, isError, isBoolean, isPrimitive: what you might expect from the names;
  • isNotNullOrWhitespace: whether the target object’s string representation is neither null or white spaces;
  • isDefined, isNull: checks if the target is defined (not undefined) or null;
  • isMatch: checks if the object matches a given regular expression;
  • hasLength: validates the object’s length (maximum and optional minimum size);
  • isOdd, isEven, isPositive, isNegative, isFinite: whether the object is odd, even, positive, negative or finite.

All of the checks can be negated as well by using not:

Validation

    .validate(obj)

    .not()

    .isNull()

    .isEven()

    .isNegative()

    .isPromise()

    .isArray()

    .isFunction()

    .isDate()

    .isError()

    .isJSON();

And most can also take an optional message, that will be used instead of the default one:

Validation

    .validate(obj)

    .isNull('Hey, I'm null!');

The actual bootstrapping Validation “class” is actually optional, because of the Object prototype extension method validate:

obj

    .validate()

    .isDefined();

The checks that accept array parameters (isOneOf, isNoneOf) can either take a single array argument or an undefined number or arguments (notice the difference):

obj

    .validate()

    .isOneOf([ 1, 2, 3])

    .isNoneOf(4, 5, 6);

Finally, the actual outcome of a failed validation can be controlled through the reporting function, for example, if you prefer to log to the console instead of raising an exception:

Validation

    .validate(obj)

    .reporting(function(msg) { console.log(msg) })

    .isDefined();

The code is available in GitHub: https://github.com/rjperes/FluentValidationJS/. Please use it as you like, and let me know if you face any issues. By all means, improve it as you like, but let me hear about it! Winking smile

Entity Framework Pitfalls: Cascade Deletes

Introduction

Entity Framework supports cascading deletes for all of its associations:

  • One to one
  • One to many
  • Many to many

Meaning, when we remove an entity, it will automatically descend to its dependent entities (cascade) and delete them too.

Of course, cascading deletes of many to one really does not make much sense. The problem with cascade deletes configuration in EF is, sometimes it cannot be done with attributes, which is a mapping mechanism that most people like and use, and the different associations need different approaches.

One to One

For one to one relations, we need to use code mappings, say, we have an entity Master associated with a dependent entity Detail:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

{

    modelBuilder

        .Entity<Master>()

        .HasOptional(x => x.Detail)

        .WithRequired(x => x.Master)

        .WillCascadeOnDelete(true);

 

    base.OnModelCreating(modelBuilder);

}

Deleting a Master will also delete the Detail, but, of course, not the other way around. If you are curious, EF does this through an ON DELETE CASCADE INDEX, so it is done by the database, not by EF – more on this later.

image

One to Many

We just need to mark the one endpoint with a [Required] attribute, like in a Detail entity that is a child of a Master:

public class Detail

{

    public int Id { get; set; }

 

    [Required]

    public virtual Master Master { get; set; }

}

This way, when we delete the Master entity, it will first delete all of its related Detail entities. This is also achieved through the automatically created ON DELETE CASCADE INDEX.

It is also certainly possible to achieve this using code configuration, but not really necessary – and more verbose:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

{

    modelBuilder

        .Entity<Master>()

        .HasMany(x => x.Details)

        .WithRequired(x => x.Master)

        .WillCascadeOnDelete();

 

    base.OnModelCreating(modelBuilder);

}

Many to Many

This one is the best: guess what, we don’t have to do anything, it just works out of the box!

Conclusion

Because Entity Framework relies on INDEXes to cascade the deletes, you cannot just change the code mappings after you created the model – either by adding attributes or through fluent configuration – and expect things to work. If you do, you will likely need to update the database. Do so by creating and applying a new migration. One thing that is still (as of EF 6.x) not supported is deleting orphans, but I already talked about it. EF Core will handle it properly.

.NET Encore

Wiktionary defines encore as “A brief extra performance, done after the main performance is complete”. Guess what, it kind of describes what .NET Core is!

Some of you may be asking: why do we need this at all? Don’t we already have Portable Class Libraries (PCL), Windows Phone (WP) and Universal Windows Platform (UWP) apps? Well, for once, UWP is just for Windows 10, Windows Phone targets the current – soon to go away – versions of Windows Phone 8.x, and PCLs are a terrible mess.

What developers have been asking for is a true One platform: cross platform (pardon the repetition), open source, modular and modern, meaning, fully embracing separation of concerns, dependency injection, inversion of control and all the other patterns that we have been using for quite some time now. That’s what .NET Core is!

In a nutshell, .NET Core is a set of APIs that are made available as open source and cross platform, meaning, the same functionality will be available on Windows, Mac, FreeBSD and Linux, but also, why not, Android and iPhone. It was (and is currently being) written from scratch with performance, modularity and scalability as first order concerns. It is composed of several Nuget packages, and this fragmentation will likely be a problem to start, because people won’t know what is the package to add for something that they have been doing for ages without the need of one, or maybe just one – Entity Framework Core, for example, is spread around EntityFramework.SqlServer, EntityFramework.Commands, EntityFramework.Core, EntityFramework.Migrations, etc. Fortunately, sites such as http://packagesearch.azurewebsites.net can help with this process.

This raises some challenges but also opens new opportunities. Let’s face it, Windows Server licenses are not exactly cheap, and having the possibility to deploy backend applications to Linux is very attractive. Yes, people have been using the .NET framework to build powerful enterprise-level application on Windows, and can continue to do so, but now we can reach out to other operating systems knowing that it is going to be fully supported by Microsoft. To make it lighter, the upcoming Windows “Nano” Server will only run .NET Core and will no longer feature a user interface. You can now contribute to .NET Core, you have access to the code and you can send your modification requests.

Yes, we won’t be able to use WPF, Windows Forms and Web Forms with .NET Core, at least, for now. WPF and Windows Forms have strong dependencies on Windows internals, and Web Forms has been deprecated in favor of MVC, but I guess it will just take some time until a clone of it appears on .NET Core, there’s nothing preventing it, quite the opposite. These APIs are still there, and will definitely continue and evolve. We will need to get accustomed to the new names, tools – welcome back, command line! – and APIs, but, as soon as Microsoft finally stabilizes the names, it won’t take long.

Interesting times, for sure! Winking smile