带有Microsoft Enterprise Library的MVC Mini Profiler

goa*_*960 9 c# enterprise-library mvc-mini-profiler

我确信可以分析Enterprise Library SQL命令,但我无法弄清楚如何包装连接.这就是我想出的:

Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand(PROC);

ProfiledDbCommand cmd = new ProfiledDbCommand(dbCommand, dbCommand.Connection, MvcMiniProfiler.MiniProfiler.Current);
db.AddInParameter(cmd, "foo", DbType.Int64, 0);

DataSet ds = db.ExecuteDataSet(cmd);
Run Code Online (Sandbox Code Playgroud)

这导致以下异常:

无法将类型为"MvcMiniProfiler.Data.ProfiledDbCommand"的对象强制转换为"System.Data.SqlClient.SqlCommand".

Jon*_*nas 12

例外来自Entlib Database.DoLoadDataSet中的这一行

    ((IDbDataAdapter) adapter).SelectCommand = command; 
Run Code Online (Sandbox Code Playgroud)

在这种情况下,适配器的类型为SqlDataAdapter,它需要一个SqlCommand,ProfiledDbProviderFactory创建的命令的类型为ProfiledDbCommand,如异常所示.

此解决方案将通过覆盖ProfiledDbProviderFactory中的CreateDataAdapter和CreateCommand为EntLib提供通用DbDataAdapter.它似乎可行,但如果我监督了这个黑客可能造成的任何不必要的后果(或者它可能造成的眼睛疼痛),我道歉.在这里:

  1. 创建两个新类ProfiledDbProviderFactoryForEntLib和DbDataAdapterForEntLib

    public class ProfiledDbProviderFactoryForEntLib : ProfiledDbProviderFactory
    {
        private DbProviderFactory _tail;
        public static ProfiledDbProviderFactory Instance = new ProfiledDbProviderFactoryForEntLib();
    
        public ProfiledDbProviderFactoryForEntLib(): base(null, null)
        {
        }
    
        public void InitProfiledDbProviderFactory(IDbProfiler profiler, DbProviderFactory tail)
        {
            base.InitProfiledDbProviderFactory(profiler, tail);
            _tail = tail;
        }
    
        public override DbDataAdapter CreateDataAdapter()
        {
            return new DbDataAdapterForEntLib(base.CreateDataAdapter());
        }
    
        public override DbCommand CreateCommand()
        {
            return _tail.CreateCommand(); 
        }        
    }
    
    public class DbDataAdapterForEntLib : DbDataAdapter
    {
        private DbDataAdapter _dbDataAdapter;
        public DbDataAdapterForEntLib(DbDataAdapter adapter)
        : base(adapter)
       {
            _dbDataAdapter = adapter;
       }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在Web.config中,将ProfiledDbProviderFactoryForEntLib添加到DbProviderFactories并将ProfiledDbProviderFactoryForEntLib设置为您的connectionstring的providerName

    <configuration>
        <configSections>
            <section name="dataConfiguration" type="..."  />
        </configSections>
        <connectionStrings>
            <add name="SqlServerConnectionString" connectionString="Data Source=xyz;Initial Catalog=dbname;User ID=u;Password=p"
      providerName="ProfiledDbProviderFactoryForEntLib" />
        </connectionStrings>
        <system.data>
            <DbProviderFactories>
              <add name="EntLib DB Provider"
               invariant="ProfiledDbProviderFactoryForEntLib"
               description="Profiled DB provider for EntLib"
               type="MvcApplicationEntlib.ProfiledDbProviderFactoryForEntLib,     MvcApplicationEntlib, Version=1.0.0.0, Culture=neutral"/>
            </DbProviderFactories>
        </system.data>
        <dataConfiguration defaultDatabase="..." />
        <appSettings>... <system.web>... etc ...
    </configuration>
    
    Run Code Online (Sandbox Code Playgroud)

    (MvcApplicationEntlib是我的测试项目的名称)

  3. 在对DB进行任何调用之前设置ProfiledDbProviderFactoryForEntLib(对黑客敏感的读者会被警告,这就是丑陋的地方)

    //In Global.asax.cs 
        protected void Application_Start()
        {
    
            ProfiledDbProviderFactoryForEntLib profiledProfiledDbProviderFactoryFor = ((ProfiledDbProviderFactoryForEntLib)DbProviderFactories.GetFactory("ProfiledDbProviderFactoryForEntLib"));
            DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient"); //or whatever predefined factory you want to profile
            profiledProfiledDbProviderFactoryFor.InitProfiledDbProviderFactory(MiniProfiler.Current, factory); 
        ...
    
    Run Code Online (Sandbox Code Playgroud)

    这可能是以更好的方式或在其他地方完成的.MiniProfiler.Current在这里将为null,因为此处没有任何内容.

  4. 像从头开始一样调用存储过程

    public class HomeController : Controller
        {
            public ActionResult Index()
            { 
                Database db = DatabaseFactory.CreateDatabase();
                DbCommand dbCommand = db.GetStoredProcCommand("spGetSomething");
                DbCommand cmd = new ProfiledDbCommand(dbCommand, dbCommand.Connection, MiniProfiler.Current);
                DataSet ds = db.ExecuteDataSet(cmd);
                ...
    
    Run Code Online (Sandbox Code Playgroud)

编辑:好的不确定你想如何使用它.跳过手动创建ProfiledDbCommand.需要使用miniprofiler为每个请求启动ProfiledDbProviderFactory.

  1. 在Global.asax.cs中,删除对Application_Start所做的更改(上面步骤3中的出厂设置),将其添加到Application_BeginRequest中.

    ProfiledDbProviderFactoryForEntLib profiledProfiledDbProviderFactoryFor = ((ProfiledDbProviderFactoryForEntLib) DbProviderFactories.GetFactory("ProfiledDbProviderFactoryForEntLib"));
    DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
    profiledProfiledDbProviderFactoryFor.InitProfiledDbProviderFactory(MvcMiniProfiler.MiniProfiler.Start(), factory);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 从ProfiledDbProviderFactoryForEntLib中删除方法CreateCommand,让ProfiledDbProviderFactory创建profiled命令.

  3. 执行您的SP而不创建ProfiledDbCommand,就像这样

    Database db = DatabaseFactory.CreateDatabase();
    DbCommand dbCommand = db.GetStoredProcCommand("spGetSomething");
    DataSet ds = db.ExecuteDataSet(dbCommand);
    
    Run Code Online (Sandbox Code Playgroud)