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

 

Postal.NET Revisited

Some of you may be aware of my Postal.NET project. It is an open-source library for writing decoupled applications that is available in GitHub and in Nuget. I already blogged about it before.

I recently updated it so that it targets .NET Standard 2.0 and also fixed the namespaces for its companion projects so that they are all under PostalNET. Current version for all projects is 1.2.0.

In a nutshell, Postal.NET publishes messages to channels and topics, either synchronously or asynchronously, and interested parties can subscribe to these.

Besides the core Postal.NET project, there are a few others:

  • PostalConventions.NET: configurable conventions for channels and topics
  • PostalCqrs.NET: a Command-Query Responsibility Segregation library built on top of Postal.NET
  • PostalInterceptor.NET: interception for message publishing
  • PostalRX.NET: Reactive Extensions
  • PostalRequestResponse.NET: a request-response wrapper
  • PostalWhen.NET: “when this, do that”

I still need to write unit tests, but there are many samples available that hopefully will be enough to get you started. If you have interest, please have a look and share your thoughts, either here or by creating issues in GitHub!

User Interface Unit Tests with .NET Core

In a previous post I talked about doing unit tests with .NET Core. What I didn’t cover was unit testing for the user interface (UI). It is actually something quite common, and we will see how we can do it now.

Selenium is a portable software-testing framework for web applications and there is a .NET port of it. We will be using the Selenium.WebDriver package, plus one or more of the following, to target different browsers:

Selenium offers a “minimum” contract that works across all browsers.

I won’t go through all of it, but I will give you some examples on how it works. We start by instantiating a driver:

using (var driver = (IWebDriver) new ChromeDriver(Environment.CurrentDirectory))
{
//...
}
Notice the Environment.CurrentDirectory parameter; it specifies the path where the driver can find the chromedriver.exe file, or geckodriver.exe for Firefox or MicrosoftWebDriver.exe, in the case of IE/Edge. These executables are added automatically by the Nuget packages. If you don’t dispose of the driver, the window will remain open after the unit test finishes. You can also call Quit at any time.
Now, we can navigate to some page:
driver
.Navigate()
.GoToUrl("http://www.google.com");
And find some element from its name:
var elm = driver.FindElement(By.Name("q"));
Besides the name, we can also search by:
  • Id: By.Id
  • CSS class: By.ClassName
  • CSS selector: By.CssSelector
  • Tag name: By.TagName
  • Link text: By.LinkText
  • Partial link text: By.PartialLinkText
  • XPath: By.XPath

Once we find an element, we can access its properties:

var attr = elm.GetAttribute("class");
var css = elm.GetCssValue("display");
var prop = elm.GetProperty("enabled");

Then we can send it text strokes:

elm.SendKeys("asp.net core");

Or click on it:

elm.Click();
As we know, page loading can take some time, so, we can configure the default time to wait for it, probably before we do a GoToUrl:
var timeouts = driver.Manage().Timeouts();
timeouts.ImplicitWait = TimeSpan.FromSeconds(1);
timeouts.PageLoad = TimeSpan.FromSeconds(5);
ImplicitWait is just a time that Selenium waits before searching for an element.
If we need to wait for some period of time, like, until some AJAX request finishes, we can do this:
var waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5));

var logo = waitForElement.Until(ExpectedConditions.ElementIsVisible(By.Id("hplogo")));
The condition passed to ExpectedConditions can be one of:
  • AlertIsPresent
  • AlertState
  • ElementExists
  • ElementIsVisible
  • ElementSelectionStateToBe
  • ElementToBeClickable
  • ElementToBeSelected
  • FrameToBeAvailableAndSwitchToIt
  • InvisibilityOfElementLocated
  • InvisibilityOfElementWithText
  • PresenceOfAllElementsLocatedBy
  • StalenessOf
  • TextToBePresentInElement
  • TextToBePresentInElementLocated
  • TextToBePresentInElementValue
  • TitleContains
  • TitleIs
  • UrlContains
  • UrlMatches
  • UrlToBe
  • VisibilityOfAllElementsLocatedBy
As you can see, you have a wealth of conditions that you can use. If the condition is not met before the timer expires, then the value returned by Until is null.
This can be a nice complement to your unit tests. Hope you find this useful! Winking smile

SignalR in ASP.NET Core

Introduction

SignalR is a Microsoft .NET library for implementing real-time web sites. It uses a number of techniques to achieve bi-directional communication between server and client; servers can push messages to connected clients anytime.

It was available in pre-Core ASP.NET and now a pre-release version was made available for ASP.NET Core. I already talked a few times about SignalR.

Installation

You will need to install the Microsoft.AspNetCore.SignalR.Client and Microsoft.AspNetCore.SignalR Nuget pre-release packages. Also, you will need NPM (Node Package Manager). After you install NPM, you need to get the @aspnet/signalr-client package, after which, you need to get the signalr-client-1.0.0-alpha1-final.js file (the version may be different) from the node_modules\@aspnet\signalr-client\dist\browser folder and place it somewhere underneath the wwwroot folder, so that you can reference it from your pages.

Next, we need to register the required services in ConfigureServices:, before Use

services.AddSignalR();

We will be implementing a simple chat client, so, we will register a chat hub, in the Configure method:

app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("chat");
});

A note: UseSignalR must be called before UseMvc!

You can do this for any number of hubs. as long as you have different endpoints. More on this in a moment.

In your view or layout file, add a reference to the signalr-client-1.0.0-alpha1-final.js file:

<script src="libs/signalr-client/signalr-client-1.0.0-alpha1-final.js"></script>

Implementing a Hub

A hub is a class that inherits from (you guessed it) Hub. In it you add methods that may be called by JavaScript. Since we will be implementing a chat hub, we will have this:

public class ChatHub : Hub
{
public async Task Send(string message)
{
await this.Clients.All.InvokeAsync("Send", message);
}
}

As you can see, we have a single method, Send, which, for this example, takes a single parameter, message. You do not need to pass the same parameters on the broadcast call (InvokeAsync), you can send whatever you want.

Going back to the client side, add this code after the reference to the SignalR JavaScript file:

    <script>
     
        var transportType = signalR.TransportType.WebSockets;
        //can also be ServerSentEvents or LongPolling
        var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
        var chatHub = new signalR.HttpConnection(`http://${document.location.host}/chat`, { transport: transportType, logger: logger });
        var chatConnection = new signalR.HubConnection(chatHub, logger);
     
        chatConnection.onClosed = e => {
            console.log('connection closed');
       };
    
       chatConnection.on('Send', (message) => {
           console.log('received message');
       });
    
       chatConnection.start().catch(err => {
           console.log('connection error');
       });
    
       function send(message) {
           chatConnection.invoke('Send', message);
       }
    
</script>

Notice this:

  1. A connection is created pointing to the current URL plus the chat suffix, which is the same that was registered in the MapHub call
  2. It is initialized with a specific transport, in this case, WebSockets, but this is not required, that is, you can let SignalR figure out for itself what works; for some operating systems, such as Windows 7, you may not be able to use WebSockets, so you have to pick either LongPolling or ServerSentEvents
  3. The connection needs to be initialized by calling start
  4. There is an handler for the Send method which takes the same single parameter (message) as the ChatHub’s Send method

So, whenever someone accesses this page and calls the JavaScript send function, it invokes the Send method on the ChatHub class. This class basically broadcasts this message to all connected clients (Clients.All). It is also possible to send messages to a specific group (we’ll see how to get there):

await this.Clients.Group("groupName").InvokeAsync("Send", message);
or to a specific client:
await this.Clients.Client("id").InvokeAsync("Send", message);
You can add a user, identified by a connection id and and a ClaimsPrincipal, if using authentication, as this:
public override Task OnConnectedAsync()
{
this.Groups.AddAsync(this.Context.ConnectionId, "groupName");

return base.OnConnectedAsync();
}
Yes, the OnConnectedAsync is called whenever a new user connects, and there is a similar method, OnDisconnectedAsync, for when someone disconnects:
public override Task OnDisconnectedAsync(Exception exception)
{
return base.OnDisconnectedAsync(exception);
}
The exception parameter is only non-null if there was some exception while disconnecting.
The Context property offers two properties, ConnectionId and User. User is only set if the current user is authenticated, but ConnectionId is always set, and does not change, for the same user.

Another example, imagine you wanted to send timer ticks into all connected clients, through a timer hub. You could do this in the Configure method:

TimerCallback callback = (x) => {
var hub = serviceProvider.GetService<IHubContext<TimerHub>>();
hub.Clients.All.InvokeAsync("Notify", DateTime.Now);
};

var timer = new Timer(callback);
timer.Change(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(10));
Here we are starting a Timer and, from there, we are getting a reference to the timer hub and calling its Notify method with the current timestamp. The TimerHub class is just this:
public class TimerHub : Hub
{
}
Notice that this class has no public method, because it is not meant to be callable by JavaScript, it merely is used to broadcast messages from the outside (the Timer callback).

Sending Messages Into a Hub

Finally, it is also possible to send messages from the outside into a hub. When using a controller, you need to inject into it an instance of IHubContext<ChatHub>, from which you can send messages into the hub, which will then be broadcast to where appropriate:
private readonly IHubContext<ChatHub> _context;

[HttpGet("Send/{message}")]
public IActionResult Send(string message)
{
//for everyone
this._context.Clients.All.InvokeAsync("Send", message);
//for a single group
this._context.Clients.Group("groupName").InvokeAsync("Send", message);
//for a single client
this._context.Clients.Client("id").InvokeAsync("Send", message);

return this.Ok();
}

Note that this is not the same as accessing the ChatHub class, you cannot easily do that, but, rather, the chat hub’s connections.

Conclusion

SignalR has not been released yet, and it may still undergo some changes. For now, things appear to be working. On a future post I will talk more about SignalR, including its extensibility mechanisms and some more advanced scenarios. Stay tuned!

What’s New and Changed in Entity Framework Core 2

Introduction

By now you should know that EF Core 2 was released on August 14th. It brought something new and some breaking changes too. Alas, it still does not include some of the features that used to be in pre-Core editions and are in high demand, such as lazy loading and support for group by translation. See the list here.

.NET Standard 2.0

Entity Framework Core 2 now targets .NET Standard 2.0, which was also released just now. This means that it will be useful in other scenarios, on any platform that supports it.

Improved SQL Generation

Improvements include:

  • Unneeded nested sub-queries are not created
  • Select only requested columns (projections)
  • No more creating multiple SQL queries for a single LINQ query

Owned Entities

Complex types are back, and they are now called owned entities. Remember that a difference between a complex type and an entity is that the former does not have an identity. Think, for example, of an Address class and several properties, Personal, Work, etc; all of these properties can be mapped to this class, and they will be stored in the same table as the containing entity. It looks like this:

modelBuilder
.Entity<Customer>()
.OwnsOne(c => c.PersonalAddress);

You can also put the content for these properties in another table, and you do it like this:

modelBuilder
.Entity<Customer>()
.OwnsOne(c => c.PersonalAddress)
.ToTable(“CustomerAddress”);

Of course, you can “own” multiple properties at once. Not possible to declare owned entities through attributes at this time.

Table Splitting

You can now have different classes that point to the same physical table, Entity Framework Core will not complain. These classes will probably expose different properties.

Entity State Listener

There’s a new interface that is registered by default, ILocalViewListener, that can be used to track entity changes – not materialized entities, unfortunately:

var events = ctx.GetService<ILocalViewListener>();
events.RegisterView((entry, state) =>
{
//entry contains the entity and state its current state
});

In case you are wondering, you cannot use this to cancel changes, because it is only called after the actual event took place.

Pluralization

There is a new IPluralizer interface and a dummy implementation NullPluralizer. It can be used to pluralize table names when EF is generating the database (dotnet ef database update) or entities when generating classes from it (Scaffold-DbContext). The way to use it is somewhat tricky, as we need to have a class implementing IDesignTimeServices, and this class will be discovered automatically by these tools:

public class CustomPluralizerDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
{
services.AddSingleton<IPluralizer, CustomPluralizer>();
}
}

public class CustomPluralizer : IPluralizer
{
public string Pluralize(string name)
{
return ...;
}

public string Singularize(string name)
{
return ...;
}
}

Because the tools also rely on the dependency injection framework, we are providing an alternative implementation of the IPluralizer interface through it.

DbContext Pools

Normally when a DbContext is injected somewhere by the dependency injection framework, a new instance is created every time. With this, we can have a pool of instances, 128 by default. It is a performance improvement and it is configured like this:

services.AddDbContextPool<DataContext>(options =>
{
//...
}, poolSize: 256);

Attach

The Attach method, for attaching existing entities, is now more clever: if any of the entities in the graph being attached has its key set, it will be treated as unchanged, and if not, as new.

Entity Type Configuration

We can now store entity configuration in separate classes, similar to what we used to have:

public class MyEntityTypeConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> builder)
{
//...
}
}

only these classes are not discovered automatically any more:

modelBuilder.ApplyConfiguration(new MyEntityTypeConfiguration());

Global Filters

Global filters already existed, for entities, not collections, in pre-Core EF. They are useful in essentially two scenarios:

  • For multitenant apps
  • For soft deletes

Its configuration goes like this for soft deletes:

modelBuilder
.Entity<Post>()
.HasQueryFilter(p => !p.IsDeleted);

Or, for a multi-tenant:

modelBuilder
.Entity<Blog>()
.HasQueryFilter(p => p.TenantId == this.TenantId);

It will apply filtering to any entities loaded as the result of a query (including eager loads) or from a one-to-many collection, but it will not filter a query by id, a one-to-one or many-to-one.

You can explicitly disable any existing filters by calling the IgnoreQueryFilters extension method:

ctx
.Blog
.IgnoreQueryFilters()
.ToList();

Disabling Client-Side Evaluation

You may be aware that EF Core can do client-side evaluation of methods that it does not know about, that is, cannot be translated to database calls. This happens transparently and may turn into a performance issue. Should you need to disable this, you now can by configuring the logging infrastructure to throw an exception when client evaluation occurs:

var builder = new DbContextOptionsBuilder<DataContext>()
.ConfigureWarnings(options =>
{
options.Throw(RelationalEventId.QueryClientEvaluationWarning);
options.Default(WarningBehavior.Log);
});

Like

We now have support for SQL’s LIKE function, although in the past we also supported something similar, through the String.Contains method. It goes like this:

ctx
.Posts
.Where(x => EF.Functions.Like(x.Title, “%NET%”)
.ToList();

Unfortunately, Microsoft didn’t make Like an extension method, which I think would be easier to use.

Calling Scalar Functions

Support for calling scalar functions is back too, with some minor caveats:

  • These functions need to be static and declared on the context class
  • They can only return and take as parameters scalar values

An example, first, the declaration, using the T-SQL built-in SOUNDEX function, through the [DbFunction] attribute:

[DbFunction]
public static string Soundex(string name)
{
throw new NotImplementedException();
}

Or by code:

modelBuilder.HasDbFunction(this.GetType().GetMethod(“Soundex”));

In either case you can specify both the schema or the function’s name, if it is different from the method to be used:

[DbFunction("FuncName", Schema = "dbo")]

modelBuilder.HasDbFunction(this.GetType().GetMethod("FuncName"), options =>
{
options.HasName("FuncName");
options.HasSchema("dbo");
});

And its usage:

var sounds = ctx
.MyEntity
.Select(x => x.Soundex(x.Name))
.ToList();

String Interpolation Support

Now, the FromSql and ExecuteSqlCommand methods support interpolated strings, and will happily produce parameters as needed. You do not have to worry about those nasty SQL injection attacks and performance issues due to query plan creation! It goes like this:

ctx
.Database
.ExecuteSqlCommand($"UPDATE Record SET Value = {value} WHERE Id = {id}");

Explicitly Compiled Queries

Entity Framework Core included query caching since version 1, but there is still some overhead associated with calculating the key from the query and getting it from the cache. Therefore, version 2 introduced a capability that existed in LINQ to SQL and Entity Framework pre-Core: explicit query compilation and execution. By this, we are able to pre-compile a query and use it in whatever context we want (of a compatible type, of course). We can even eagerly fetch associated collections or entities:

static readonly Func<MyEntityContext, int, IEnumerable<MyEntity>> 
CompiledQuery = EF.CompileQuery<MyEntityContext, int, MyEntity>((ctx, id) =>
ctx.MyEntities.Where(x => x.Id == id).Include(x => x.Others).OrderBy(x => x.Name));

As you can see, it returns a delegate that we can invoke passing it the proper parameters – in this example, a context and a parameter, but you can have up to 8 parameters, of different types:

var results = CompiledQuery(ctx, 100).ToList();

Breaking Changes

The IDbContextFacfory<T> interface was replaced by IDesignTimeDbContextFactory<T>. The signature of the CreateDbContext method changed also:

public class DummyContextFactory : IDesignTimeDbContextFactory<DummyContext>
{
    public DummyContext CreateDbContext(string[] args)
    {
        var builder = new DbContextOptionsBuilder<DummyContext>();
        builder.UseSqlServer("…");
        return new DummyContext(builder.Options);
    }
}

UseInMemoryDatabase now needs a name:

optionsBuilder.UseInMemoryDatabase("MyDatabase")

Package Microsoft.EntityFrameworkCore.SqlServer.Design is deprecated in favor of Microsoft.EntityFrameworkCore.Design (now provider-agnostic).

Only 2.0 providers will work, so any existing providers that target EF Core 1.x will need to be rewritten.

Logging event IDs have changed from the previous version and they are now identical to those used by corresponding ILogger messages. The logger categories now come from subclasses of DbLoggerCategory, such as DbLoggerCategory.Database.Command, DbLoggerCategory.Migrations, DbLoggerCategory.Infrastructure, etc, all of which offer a Name property.

What’s Still Not Here

Still missing are (not a complete list, mind you):

You can find a more thorough list here: https://weblogs.asp.net/ricardoperes/missing-features-in-entity-framework-core.

Conclusion

Still a long way to go; especially, GroupBy translation, many to many and lazy loading seems to be taking forever, both are scheduled for the next version (2.1) though. Non-relational providers are also nowhere to be seen. This new version has interesting new stuff and Microsoft seems to be going in the right direction, but it strikes me as odd that such high demand features are still absent. Let’s see how things evolve.

References

https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-entity-framework-core-2-0

https://docs.microsoft.com/en-us/ef/core/what-is-new

https://github.com/aspnet/EntityFrameworkCore/wiki/Roadmap

https://github.com/aspnet/EntityFrameworkCore/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.0.0

https://weblogs.asp.net/ricardoperes/missing-features-in-entity-framework-core

Fusion Tech Talk #2

(Portuguese only, sorry)

600_459917064 600_459917055

Esta terça-feira, 4, teve lugar nas instalações da Fusion Cowork o segundo evento Fusion Tech Talk! Podem encontrar informação sobre o primeiro aqui. Desta vez, foi transmitida em directo na página do Facebook da Simplifydigital.

Duas grandes apresentações, uma pelo João Nogueira (http://joaonogueira.eu), sobre R, que podem encontrar aqui. A segunda, pelo Alberto São Marcos (@albertocsm) sobre problemas com sistemas distribuídos. A apresentação está disponível aqui.

Estiveram presentes cerca de 30 pessoas, bom ambiente, boas conversas e quem sabe boas oportunidades! Lembro que podem sugerir temas (e oradores) para os próximos eventos, tentaremos organizar pelo menos de 2 em dois meses.

Mais uma vez, obrigado à Fusion Cowork e à Simplifydigital por organizarem o evento, ao João e ao Alberto por apresentarem e a todos os que apareceram! Contamos ver-vos muito em breve! Winking smile

Implementing Missing Features in Entity Framework Core – Part 7: Entity Configuration in Mapping Classes

This is the seventh 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

This time I’m going to cover automatic entity configuration in mapping classes, that is, outside of the DbContext.OnModelCreating method. If you remember, Entity Framework Code First supported having classes inheriting from EntityTypeConfiguration in the same assembly as the context, and these classes would be loaded automatically. This made it much simpler to add new mapping classes to a project without touching the context.

This functionality hasn’t been ported to Entity Framework Core yet, but it is being developed for the next version, and is tracked by ticket 2805. My implementation finds mapping classes in the same assembly as the context automatically, or it can load configuration explicitly from a mapping class. Here is my contract for the mapping class:

public interface IEntityTypeConfiguration<T> where T : class
{
void Configure(EntityTypeBuilder<T> entityTypeBuilder);
}

As you can see, this needs to be implemented in a concrete generic class and bound to a specific entity type.

The actual implementation goes like this:

public static class EntityTypeConfigurationExtensions
{
private static readonly MethodInfo entityMethod = typeof(ModelBuilder).GetTypeInfo().GetMethods().Single(x => (x.Name == "Entity") && (x.IsGenericMethod == true) && (x.GetParameters().Length == 0));

private static Type FindEntityType(Type type)
{
var interfaceType = type.GetInterfaces().First(x => (x.GetTypeInfo().IsGenericType == true) && (x.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)));
return interfaceType.GetGenericArguments().First();
}

private static readonly Dictionary<Assembly, IEnumerable<Type>> typesPerAssembly = new Dictionary<Assembly, IEnumerable<Type>>();

public static ModelBuilder ApplyConfiguration<T>(this ModelBuilder modelBuilder, IEntityTypeConfiguration<T> configuration) where T : class
{
var entityType = FindEntityType(configuration.GetType());

dynamic entityTypeBuilder = entityMethod
.MakeGenericMethod(entityType)
.Invoke(modelBuilder, new object[0]);

configuration.Configure(entityTypeBuilder);

return modelBuilder;
}

public static ModelBuilder UseEntityTypeConfiguration(this ModelBuilder modelBuilder)
{
IEnumerable<Type> configurationTypes;
var asm = Assembly.GetEntryAssembly();

if (typesPerAssembly.TryGetValue(asm, out configurationTypes) == false)
{
typesPerAssembly[asm] = configurationTypes = asm
.GetExportedTypes()
.Where(x => (x.GetTypeInfo().IsClass == true) && (x.GetTypeInfo().IsAbstract == false) && (x.GetInterfaces().Any(y => (y.GetTypeInfo().IsGenericType == true) && (y.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)))));
}

var configurations = configurationTypes.Select(x => Activator.CreateInstance(x));

foreach (dynamic configuration in configurations)
{
ApplyConfiguration(modelBuilder, configuration);
}

return modelBuilder;
}
}

You can see that it uses some dynamic magic to make things simpler, otherwise we’d need to have even more reflection. Dynamics take care of these things quite nicely.

The code essentially looks at the entry assembly and finds all non-abstract public types that implement IEntityTypeConfiguration<T>. For each of those, it creates an instance, extracts the template argument and creates an EntityTypeBuilder<T> from calling the Entity<T> method of the ModelBuilder class and calls the IEntityTypeConfiguration<T>.Configure method of the instantiated mapping class passing it the EntityTypeBuilder<T> which allows it to supply mapping configuration for the mapped entity (T).

We need to explicitly call this extension inside DbContext.OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseEntityTypeConfiguration();
base.OnModelCreating(modelBuilder);
}

And it takes care of everything for us. Or, if we want to load a single mapping class explicitly, we can also do so:

modelBuilder.UseEntityTypeConfiguration<MyEntityTypeConfiguration>();

Finally, a simple mapping class might be:

public class MyEntityTypeConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> entityTypeBuilder)
{
entityTypeBuilder.ToTable("MyEntity");
entityTypeBuilder.Property(x => x.MyEntityId).HasColumnName("Id");
}
}

In case you’re interested, this feature is similar to the one being implemented for .NET Core, except that it doesn’t find mapping classes automatically. The IEntityTypeConfiguration<T> interface is exactly the same.

Technologies to Follow in 2017

Introduction

A lot is happening and it’s difficult to keep track of everything. Based on my work and on what I see over the Internet, I decided to write a post about the technologies – tools, languages, servers, operating systems, etc – that I find more interesting and promising. I know, some of these will be controversial, others are not exactly new, I am even mixing totally different things together, but, hey, it’s my opinion – feel free to share your objections here! Winking smile

I am not going to cover the myriad of JavaScript frameworks, because they’re just too many. I will only talk about what I know. For that same reason, I’m not talking about Akka, Go, Scala, Python, Ruby, Erlang, etc, because, honestly, I never used them. Also, I don’t cover Java, although Kafka is written in Java, because I haven’t used Java in anger for more than 10 years. I read that it’s having some problems, with some key people leaving Oracle, persisting security problems and the delaying of releases, but I’m sure Java is here to stay. Others will be more fit to talk about it.

.NET Core

.NET Core is Microsoft’s next version .NET framework, only this time totally modular, open source and multi-platform. Runs on Linux and MacOS, not just Windows. Still doesn’t have all the features of classic .NET, but it will get there: next version (2.0) will more than double the supported APIs. Right now, it’s perfect for writing .NET MVC apps and web APIs that need to run in other operating systems, including inside Docker containers. Get it from https://github.com/dotnet/core.

Node.js

A JavaScript runtime for the desktop instead of the browser. Uses an event-driven, asynchronous I/O model for high performance and scalability. Has probably the largest ecosystem of open source libraries in the world – NPM. Free and open source, with new features continuously being released. Currently uses Google’s V8 engine, but Microsoft submitted a patch to allow it to run Chakra, it’s JavaScript engine! Exciting times! Its site is https://nodejs.org.

Docker

You favorite container technology! Now supported in both Amazon Web Services and Azure, and with native support in Windows Server 2016. This is a must have for highly scalable applications. Free but it’s possible to get a paid repository online. A lot going on around it, the only problem is that things tend to change in non-retro-compatible ways, still need maturing. See more at http://docker.com.

Elasticsearch

A distributed and open source search engine based on Lucene. A blazing fast NoSQL database with replication capabilities, it is the most widely known component of the ELK stack, together with Kibana (for reporting and visualizations), Logstash (for data import) and Beats (for data shipping). Even Azure Search uses it behind the covers. Free but some tools are paid. Get it from http://elastic.co.

ECMAScript 2015

The next generation JavaScript, also known as ECMAScript 6. Heavily influenced by TypeScript, it offers a number of features from compiled languages, such as lambda functions, classes, type safety, etc. Before it’s available everywhere, people are using Babel.js to compile it to classic JavaScript. Google Chrome’s V8 engine already supports a great deal of it, as does Firefox. The specification is available here: http://www.ecma-international.org/ecma-262/6.0/.

HTML5

Is there any other, I hear you ask? Well, except if you need to support that old two-letter browser who had an infamous version 8, not really. Together with HTML 5 came a wealth of APIs that now allow us to have near-desktop quality apps on the web, and in some mobile browsers too. Latest standard is 5 but 5.1 is due to come out this year. Interestingly, HTML5 is more and more not just about web applications but also being used for desktop ones: for example, the Spotify desktop client is an HTML5 app. The specification is available at https://www.w3.org/TR/html5.

Kafka

A high throughput, low-latency open source message broker from the Apache foundation. Can stream data in real-time for massive simultaneous clients and has bindings for several languages. Similar to a distributed transaction log with exactly once semantics. More info here: https://kafka.apache.org.

TypeScript

A superset of JavaScript offering type safety and class-based object-oriented features. Nice wrappers around promises using similar syntax to C#’s async/await. It is compiled to JavaScript, so it can run anywhere JavaScript can. Free license. The official site is https://www.typescriptlang.org.

MongoDB

An open source NoSQL document database designed for high performance and with interesting clustering features. Mappings for all common languages, including scripting ones. With it you get JSON storage, indexes and automatic expiration. With free and commercial licenses. See more at http://www.mongodb.com.

Git

A free and open source distributed source control from the author of Linux. Now being used everywhere, even Microsoft is using it instead of their own TFS. Not an easy beast to master, I may add. Also worth mentioning GitFlow, a proposed workflow for branching and release management. The official site is https://git-scm.com.

Nginx

A high performance web server, HTTP cache and reverse proxy server for several TCP protocols. Can serve .NET and any other language, probably best used as a reverse proxy, particularly in the case of .NET Core. Runs on Windows and several UNIX flavors. It is free to use. Available from https://www.nginx.com.

Octopus Deploy

An automated deployment and release management tool for .NET applications. Latest versions can deploy both web apps as well as Windows services. Plays nicely with Continuous Integration and build tools such as Jenkins and TeamCity. Both free and commercial licenses. The web site is https://octopus.com.

Azure

Microsoft’s Cloud offering, the competitor of Amazon Web Services. Loaded with powerful services and features, which include amazing machine learning services, containerization as a service, queuing, and anything that can be expected from a Cloud service. Possible to get a time-limited trial for free. The official site is https://azure.microsoft.com.

Amazon Web Services

One of the two major players in the Cloud market, the other being Azure. Still has the biggest market share and offers a number of interesting features. Leaning slightly more towards Java and JavaScript than to .NET. Anyone can get a free account, as long as a credit card is supplied. See more at https://aws.amazon.com.

Linux

The free and open source operating system that just a few years ago Microsoft compared to a virus! Based on UNIX, now not just for geeks, it is everywhere, especially with the arriving of Docker. Several distributions available, to match anyone’s preferences, some free and some commercial. Windows 10 now even runs bash natively! See more at https://kernel.org.

Visual Studio Code

A powerful and extensible yet lightweight IDE from Microsoft based on GitHub’s Electron, which can run in a number of platforms, from Windows and Linux to MacOS. Includes support for a number of languages, Git integration, debugging capabilities – which make it stand from others such as Sublime or Atom – and an extension mechanism. Hey, it’s free! Get it from http://code.visualstudio.com.

Xamarin

A cross-platform implementation of .NET, for Windows Phone, Android and iOS. Before .NET Core came along – in fact, even after that – it is the preferred tool for creating applications that need to target multiple platforms. Now offered for free by Microsoft. but the Enterprise version will require a Visual Studio paid license. Microsoft promised to make it open source. Official site is https://www.xamarin.com.

Google Analytics

A web analytics service offered for free by Google, although paid subscriptions also exist. Can be used to track not only traffic but also custom events, and also in mobile apps. It’s unbelievable the amount of information that one can get out of it. See it in https://analytics.google.com.

SQL Server 2016

In-memory tables, JSON support, Query Store, integrated R, row and column-level security, etc, make this one of the most interesting versions of SQL Server ever. Available for free with limitations as Express edition, and as a paid license. More info from http://microsoft.com/sqlserver.

Let’s Encrypt

Free SSL certificates for the masses! No need to pay for a certificate, now you can get any number for free. Easily installable in any server (even IIS), but expires every 90 days. Get yours from https://letsencrypt.org.

TensorFlow

TensorFlow is Google’s second generation open source library for machine intelligence. It uses data flow graphs to represent mathematical operations and is the core of several Google products, such as Gmail, Google Photos and others. It offers Python and C++ bindings and recently it compiles on Windows as well as Linux and Mac OSX. Get it from https://github.com/tensorflow/tensorflow.

GitLab

GitLab is a free (with an enterprise license too) repository manager built on Git. It is fast moving with a plethora of very useful features. You can install it on premises or run it in the cloud. Offers integration with LDAP servers for authentication, offers a pretty decent Continuous Integration feature, plus a lot of other cool stuff. Check it out at https://about.gitlab.com.

Redis

A distributed cache with open source implementations in Linux and Windows. Currently, probably the most used one. Offered by both Azure and AWS. Not just BLOB cache, offers interesting structures. Learn about it at https://redis.io.

Conclusion

So, what are your thoughts – am I missing something? Do you agree or disagree with my choices? I’d love to hear from you!