Debugging Package Manager Console Update-Database Seed Method

前端 未结 7 777
北恋
北恋 2020-12-07 12:53

I wanted to debug the Seed() method in my Entity Framework database configuration class when I run Update-Database from the Package Manager Console

相关标签:
7条回答
  • 2020-12-07 13:19

    I know this is an old question, but if all you want is messages, and you don't care to include references to WinForms in your project, I made some simple debug window where I can send Trace events.

    For more serious and step-by-step debugging, I'll open another Visual Studio instance, but it's not necessary for simple stuff.

    This is the whole code:

    SeedApplicationContext.cs

    using System;
    using System.Data.Entity;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace Data.Persistence.Migrations.SeedDebug
    {
      public class SeedApplicationContext<T> : ApplicationContext
        where T : DbContext
      {
        private class SeedTraceListener : TraceListener
        {
          private readonly SeedApplicationContext<T> _appContext;
    
          public SeedTraceListener(SeedApplicationContext<T> appContext)
          {
            _appContext = appContext;
          }
    
          public override void Write(string message)
          {
            _appContext.WriteDebugText(message);
          }
    
          public override void WriteLine(string message)
          {
            _appContext.WriteDebugLine(message);
          }
        }
    
        private Form _debugForm;
        private TextBox _debugTextBox;
        private TraceListener _traceListener;
    
        private readonly Action<T> _seedAction;
        private readonly T _dbcontext;
    
        public Exception Exception { get; private set; }
        public bool WaitBeforeExit { get; private set; }
    
        public SeedApplicationContext(Action<T> seedAction, T dbcontext, bool waitBeforeExit = false)
        {
          _dbcontext = dbcontext;
          _seedAction = seedAction;
          WaitBeforeExit = waitBeforeExit;
          _traceListener = new SeedTraceListener(this);
          CreateDebugForm();
          MainForm = _debugForm;
          Trace.Listeners.Add(_traceListener);
        }
    
        private void CreateDebugForm()
        {
          var textbox = new TextBox {Multiline = true, Dock = DockStyle.Fill, ScrollBars = ScrollBars.Both, WordWrap = false};
          var form = new Form {Font = new Font(@"Lucida Console", 8), Text = "Seed Trace"};
          form.Controls.Add(tb);
          form.Shown += OnFormShown;
          _debugForm = form;
          _debugTextBox = textbox;
        }
    
        private void OnFormShown(object sender, EventArgs eventArgs)
        {
          WriteDebugLine("Initializing seed...");
          try
          {
            _seedAction(_dbcontext);
            if(!WaitBeforeExit)
              _debugForm.Close();
            else
              WriteDebugLine("Finished seed. Close this window to continue");
          }
          catch (Exception e)
          {
            Exception = e;
            var einner = e;
            while (einner != null)
            {
              WriteDebugLine(string.Format("[Exception {0}] {1}", einner.GetType(), einner.Message));
              WriteDebugLine(einner.StackTrace);
              einner = einner.InnerException;
              if (einner != null)
                WriteDebugLine("------- Inner Exception -------");
            }
          }
        }
    
        protected override void Dispose(bool disposing)
        {
          if (disposing && _traceListener != null)
          {
            Trace.Listeners.Remove(_traceListener);
            _traceListener.Dispose();
            _traceListener = null;
          }
          base.Dispose(disposing);
        }
    
        private void WriteDebugText(string message)
        {
          _debugTextBox.Text += message;
          Application.DoEvents();
        }
    
        private void WriteDebugLine(string message)
        {
          WriteDebugText(message + Environment.NewLine);
        }
      }
    }
    

    And on your standard Configuration.cs

    // ...
    using System.Windows.Forms;
    using Data.Persistence.Migrations.SeedDebug;
    // ...
    
    namespace Data.Persistence.Migrations
    {
      internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
      {
        public Configuration()
        {
          // Migrations configuration here
        }
    
        protected override void Seed(MyContext context)
        {
          // Create our application context which will host our debug window and message loop
          var appContext = new SeedApplicationContext<MyContext>(SeedInternal, context, false);
          Application.Run(appContext);
          var e = appContext.Exception;
          Application.Exit();
          // Rethrow the exception to the package manager console
          if (e != null)
            throw e;
        }
    
        // Our original Seed method, now with Trace support!
        private void SeedInternal(MyContext context)
        {
          // ...
          Trace.WriteLine("I'm seeding!")
          // ...
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-07 13:21

    Uh Debugging is one thing but don't forget to call: context.Update()

    Also don't wrap in try catch without a good inner exceptions spill to the console.
    https://coderwall.com/p/fbcyaw/debug-into-entity-framework-code-first with catch (DbEntityValidationException ex)

    0 讨论(0)
  • 2020-12-07 13:24

    The way I solved this was to open a new instance of Visual Studio and then open the same solution in this new instance of Visual Studio. I then attached the debugger in this new instance to the old instance (devenv.exe) while running the update-database command. This allowed me to debug the Seed method.

    Just to make sure I didn't miss the breakpoint by not attaching in time I added a Thread.Sleep before the breakpoint.

    I hope this helps someone.

    0 讨论(0)
  • 2020-12-07 13:33

    Here is similar question with a solution that works really well.
    It does NOT require Thread.Sleep.
    Just Launches the debugger using this code.

    Clipped from the answer

    if (!System.Diagnostics.Debugger.IsAttached) 
        System.Diagnostics.Debugger.Launch();
    
    0 讨论(0)
  • 2020-12-07 13:37

    If you need to get a specific variable's value, a quick hack is to throw an exception:

    throw new Exception(variable);
    
    0 讨论(0)
  • 2020-12-07 13:41

    I have 2 workarounds (without Debugger.Launch() since it doesn't work for me):

    1. To print message in Package Manager Console use exception:
      throw new Exception("Your message");

    2. Another way is to print message in file by creating a cmd process:

    
        // Logs to file {solution folder}\seed.log data from Seed method (for DEBUG only)
        private void Log(string msg)
        {
            string echoCmd = $"/C echo {DateTime.Now} - {msg} >> seed.log";
            System.Diagnostics.Process.Start("cmd.exe", echoCmd);
        }
    
    0 讨论(0)
提交回复
热议问题