c# - 带有 Microsoft 企业库的 MVC Mini Profiler

标签 c# enterprise-library mvc-mini-profiler

我确信可以分析企业库 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);

这会导致以下异常:

Unable to cast object of type 'MvcMiniProfiler.Data.ProfiledDbCommand' to type 'System.Data.SqlClient.SqlCommand'.

最佳答案

异常来自Entlib Database.DoLoadDataSet中的这一行

    ((IDbDataAdapter) adapter).SelectCommand = command; 

在这种情况下,适配器是 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;
       }
    }
    
  2. 在 Web.config 中,将 ProfiledDbProviderFactoryForEntLib 添加到 DbProviderFactories 并将 ProfiledDbProviderFactoryForEntLib 设置为连接字符串的 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>
    

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

  3. 在对数据库进行任何调用之前设置 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); 
        ...
    

    这可能会以更好的方式或在其他地方完成。 MiniProfiler.Current 在这里将为空,因为这里没有分析任何内容。

  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);
                ...
    

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

  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);
    
  2. 从 ProfiledDbProviderFactoryForEntLib 中删除 CreateCommand 方法,让 ProfiledDbProviderFactory 创建分析命令。

  3. 像这样在不创建 ProfiledDbCommand 的情况下执行您的 SP

    Database db = DatabaseFactory.CreateDatabase();
    DbCommand dbCommand = db.GetStoredProcCommand("spGetSomething");
    DataSet ds = db.ExecuteDataSet(dbCommand);
    

关于c# - 带有 Microsoft 企业库的 MVC Mini Profiler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7093944/

相关文章:

c# - 根据按下的按钮执行代码

.net - 带有 Simple.Data 的 Mini-Profiler

c# - 更改 Web Api 2 Post 方法以接受修改后的正文

c# - .NET 中的 WMI 列表架构信息

C# - 以类型安全的方式将输入对象映射到效果对象

c# - 使用 Enterprise Library 5 进行数据库记录

azure - 如何动态/以编程方式设置 Enterprise Library 数据库跟踪监听器连接字符串

azure - 企业库引用导致 Azure DevFabric 崩溃

azure - mvc-mini-profiler - 使用负载平衡的 Web 角色(azure 等)

iis-7.5 - mvc 迷你分析器 (1.4) 和 IIS