Hibernating Rhinos

Zero friction databases

Entity Framework Profiler support for Entity Framework 6 alpha 2

Recently a lot of our users asked us to support Entity Framework 6 alpha 2 in Entity Framework Profiler. We started to look on how we can support it right away but we found that we could not support it easily.

The main issue was that Entity Framework 6 alpha 2 expose a class called DbConfiguration which you can use as an injection point to EF. But the way that EF currently works, it looks for this class only in the same assembly that uses the DbContext, which is your application executable/dll but not our appender dll.

So we contact the EF team (which they were very helpful and responsive) and discussed some of the issues that we saw. While a few of the issues was been addressed already by the EF team and committed to the EF repository, the good news that we found a way to support Entity Framework 6 alpha 2 by adding just one source file to your application.

Take the following file and add to your application: https://gist.github.com/4539561.

Now make sure to use the use build #2111 or later of Entity Framework Profiler and it will work.

I’m also attaching the same source code from the above gist to here. Enjoy using Entity Framework Profiler!

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity.Config;
using System.Data.Entity.Core.Common;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Migrations.Sql;
using System.Data.Entity.SqlServer;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.EntityFramework;
using HibernatingRhinos.Profiler.Appender.ProfiledDataAccess;

namespace HibernatingRhinos.Profiler.IntegrationTests.EntityFramework6Beta2
{
    public class ProfiledDbConfiguration : DbConfiguration
    {
        public ProfiledDbConfiguration()
        {
            AddDependencyResolver(new ProfiledDbDependencyResolver(this));
        }
    }

    public class ProfiledDbDependencyResolver : IDbDependencyResolver
    {
        private readonly IDbDependencyResolver rootResolver;

#if DEBUG
        public static HashSet<string> types = new HashSet<string>();
#endif

        public ProfiledDbDependencyResolver(DbConfiguration originalDbConfiguration)
        {
            // Get the original resolver
            var internalConfigProp = originalDbConfiguration.GetType().GetProperty("InternalConfiguration", BindingFlags.Instance | BindingFlags.NonPublic);
            var internalConfig = internalConfigProp.GetValue(originalDbConfiguration, null);
            var rootResolverProp = internalConfig.GetType().GetProperty("RootResolver", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            rootResolver = (IDbDependencyResolver)rootResolverProp.GetValue(internalConfig, null);
        }

        public object GetService(Type type, object key)
        {
#if DEBUG
            types.Add(type.Name);
#endif

            if (type == typeof(IDbProviderFactoryService))
            {
                var innerFactoryService = (IDbProviderFactoryService) rootResolver.GetService(type, key);
                return new ProfiledDbProviderFactoryService(innerFactoryService);
            }

            if (type == typeof (DbProviderServices))
            {
                var inner = (DbProviderServices)rootResolver.GetService(type, key);
                var appender = new EntityFrameworkAppender(typeof (SqlProviderServices).Name);
                var profiledDbProviderServicesType = EntityFrameworkProfiler.CompiledAssembly.GetType("HibernatingRhinos.Profiler.Appender.EntityFramework.ProfiledDbProviderServices");
                if (profiledDbProviderServicesType == null)
                    throw new InvalidOperationException("Could not get the profiled DbProviderServices.");
                return Activator.CreateInstance(profiledDbProviderServicesType, new object[] {inner, appender});
            }

            if (type == typeof(MigrationSqlGenerator))
            {
                if (rootResolver.GetService(type, key) is SqlServerMigrationSqlGenerator)
                {
                    return new ProfiledMigrationSqlGenerator();
                }
            }

            return null;
        }
    }

    public class ProfiledDbProviderFactoryService : IDbProviderFactoryService
    {
        private readonly IDbProviderFactoryService innerFactoryService;

        public ProfiledDbProviderFactoryService(IDbProviderFactoryService innerFactoryService)
        {
            this.innerFactoryService = innerFactoryService;
        }

        public DbProviderFactory GetProviderFactory(DbConnection connection)
        {
            if (connection is ProfiledConnection)
            {
                var connectionType = connection.GetType();
                if (connectionType.IsGenericType)
                {
                    var innerProviderFactory = connectionType.GetGenericArguments()[0];
                    var profiledDbProviderFactory = EntityFrameworkProfiler.CompiledAssembly.GetType("HibernatingRhinos.Profiler.Appender.EntityFramework.ProfiledDbProviderFactory`1").MakeGenericType(innerProviderFactory);
                    return (DbProviderFactory) Activator.CreateInstance(profiledDbProviderFactory);
                }
            }

            if (connection is EntityConnection)
                return innerFactoryService.GetProviderFactory(connection);

            throw new InvalidOperationException("Should have ProfiledConnection but got " + connection.GetType().FullName + ".If you got here, you probably need to modify the above code in order to satisfy the requirements of your application. This code indented to support EF 6 alpha 2.");
        }
    }

    public class ProfiledMigrationSqlGenerator : SqlServerMigrationSqlGenerator
    {
        protected override DbConnection CreateConnection()
        {
            return DbProviderFactories.GetFactory("System.Data.SqlClient").CreateConnection();
        }
    }
}
Tags:

Posted By: Fitzchak Yitzchaki

Published at

Originally posted at

Comments

No comments posted yet.

Comments have been closed on this topic.