Подтвердить что ты не робот

Использование профилирования базы данных mvc-mini-profiler с использованием кода Entity Framework First

Я использую mvc-mini-profiler в моем проекте, построенном с использованием кода ASP.Net MVC 3 и Entity Framework.

Все работает отлично, пока я не попытаюсь добавить профилирование базы данных, завернув соединение в ProfiledDbConnection, как описано в документации. Поскольку я использую DbContext, способ, которым я пытаюсь обеспечить соединение, - через конструктор, используя статический метод factory:

public class MyDbContext : DbContext
{                
    public MyDbContext() : base(GetProfilerConnection(), true)
    { }

    private static DbConnection GetProfilerConnection()
    {
        // Code below errors
        //return ProfiledDbConnection.Get(new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString));

        // Code below works fine...
        return new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString);
    }

    //...
}

При использовании ProfiledDbConnection я получаю следующую ошибку:

ProviderIncompatibleException: The provider did not return a ProviderManifestToken string.

Трассировка стека:

[ArgumentException: The connection is not of type 'System.Data.SqlClient.SqlConnection'.]
   System.Data.SqlClient.SqlProviderUtilities.GetRequiredSqlConnection(DbConnection connection) +10486148
   System.Data.SqlClient.SqlProviderServices.GetDbProviderManifestToken(DbConnection connection) +77
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +44

[ProviderIncompatibleException: The provider did not return a ProviderManifestToken string.]
System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +11092901
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +11092745
   System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) +221
   System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) +61
   System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input) +1203482
   System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +492
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +26
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +89
   System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() +21
   System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider() +44
   System.Linq.Queryable.Where(IQueryable`1 source, Expression`1 predicate) +135

Я прошел шаг, и тип, возвращаемый ProfiledDbConnection.Get, имеет тип ProfiledDbConnection (Даже если текущий MiniProfiler имеет значение null).

Метод MiniProfiler.Start() вызывается в глобальном методе Application_BeginRequest() до создания экземпляра DbContext. Я также вызываю метод "Пуск" для каждого запроса независимо, но вызываю стоп, если пользователь не в правильной роли:

    protected void Application_BeginRequest()
    {
        // We don't know who the user is at this stage so need to start for everyone
        MiniProfiler.Start();
    }

    protected void Application_AuthorizeRequest(Object sender, EventArgs e)
    {
        // Now stop the profiler if the user is not a developer
        if (!AuthorisationHelper.IsDeveloper())
        {
            MvcMiniProfiler.MiniProfiler.Stop(discardResults: true);
        }
    }

    protected void Application_EndRequest()
    {
        MiniProfiler.Stop();
    }

Я не уверен, что это влияет на вещи, но я также использую StructureMap в качестве IoC для DbContext, используя следующий инициализатор:

For<MyDbContext>().Singleton().HybridHttpOrThreadLocalScoped();

Я понимаю, что здесь есть аналогичный вопрос с хорошим объяснением того, что происходит для этого пользователя, однако оно, похоже, не решает мою проблему.

EDIT:

Для ясности. Я пытаюсь передать соединение как ProfiledDbConnection, чтобы профилировать сгенерированный sql из Entity Framework Code First.

Profiled Sql

В Entity Framework ожидается соединение с типом SqlConnection, которое, конечно же, это не так.

Вот пример моей строки подключения (обратите внимание на имя поставщика)

<add name="MyDbContext" connectionString="Server=.\SQLEXPRESS; Database=MyDatabase;Trusted_Connection=true;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />

Я попытался создать свою собственную версию ProfiledDbConnection, наследующую от SqlConnection, но это запечатанный класс.

Если есть какой-то способ сообщить Entity Framework о настраиваемом типе подключения, возможно, это сработает. Я попытался установить providerName в строке подключения на MvcMiniProfiler.Data.ProfiledDbConnection, но это не сработало.

Итак. Возможно, эволюция вопроса будет заключаться в следующем: как вы можете перенести собственный тип соединения в Entity Framework Code First?

4b9b3361

Ответ 1

Теперь это полностью поддерживается, проверьте последний источник или возьмите пакет из nuget.

Вам понадобится пакет MiniProfiler.EF, если вы используете nuget. (1.9.1 и выше)

Поддержка этого включала большой набор модификаций базового прокси-объекта для поддержки того, что он является первым прокси-сервером EF-кода.

Чтобы добавить эту поддержку:

Во время выполнения Application_Start:

MiniProfilerEF.Initialize();

Примечание: Код EF Сначала будут храниться метаданные таблицы в таблице с именем: EdmMetadata. Эти метаданные используют поставщика как часть ключа сущности. Если вы инициализировали своего провайдера как непрофилированного провайдера, вам придется перестроить эти метаданные. Удаление всех строк из EdmMetadata может сделать трюк, иначе некоторые более умные провайдеры смогут обрабатывать это прозрачно.

Ответ 2

У меня все еще были проблемы с работой, и я обнаружил, что мне нужно переименовать или удалить строку подключения, чтобы получить Database.DefaultConnectionFactory для работы.

Подробнее см. в этом ответе.

Ответ 3

Эта ошибка в моем опыте всегда была неправильной строкой соединения или отсутствием подключения к БД, например "Ошибка сетевой службы при подключении...".

Также обратите внимание, что для DbContext требуется только "connectionStringKey" в конструкторе, например

public MyDbContext() : 
     base("MyConnectionName", true)
    { }