패키지 관리자 콘솔 업데이트-데이터베이스 시드 방법 디버깅


106

패키지 관리자 콘솔에서 Seed()실행할 때 Entity Framework 데이터베이스 구성 클래스 의 메서드 를 디버깅하고 싶었지만 Update-Database수행 방법을 몰랐습니다. 같은 문제가있을 경우 다른 사람들과 솔루션을 공유하고 싶었습니다.

답변:


158

정말 잘 작동하는 솔루션에 대한 비슷한 질문 이 있습니다.
필요하지 않습니다 Thread.Sleep.
이 코드를 사용하여 디버거를 시작합니다.

답변에서 잘림

if (!System.Diagnostics.Debugger.IsAttached) 
    System.Diagnostics.Debugger.Launch();

@tchelidze migrate.exe는 콘솔에서 호출 하여 현재 실행중인 Visual Studio를 연결할 수 있습니다 . 이 답변에 대한 추가 정보를 원하시면 : stackoverflow.com/a/52700520/350384
MARIUSZ Pawelski

20

이 문제를 해결 한 방법은 Visual Studio의 새 인스턴스를 연 다음이 새 Visual Studio 인스턴스에서 동일한 솔루션을 여는 것입니다. 그런 다음 update-database 명령을 실행하는 동안이 새 인스턴스의 디버거를 이전 인스턴스 (devenv.exe)에 연결했습니다. 이를 통해 Seed 메서드를 디버깅 할 수있었습니다.

시간에 연결하지 않음으로써 중단 점을 놓치지 않았는지 확인하기 위해 중단 점 앞에 Thread.Sleep을 추가했습니다.

누군가에게 도움이되기를 바랍니다.


12

특정 변수의 값을 가져와야하는 경우 빠른 해킹은 예외를 던지는 것입니다.

throw new Exception(variable);

3
신속하고 더러운 :
DanKodi

5

더 깨끗한 솔루션 (EF 6이 필요하다고 생각합니다)은 IMHO가 코드에서 update-database를 호출하는 것입니다.

var configuration = new DbMigrationsConfiguration<TContext>();
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();

이렇게하면 Seed 메서드를 디버깅 할 수 있습니다.

한 단계 더 나아가 빈 테스트 데이터베이스를 만들고, 모든 EF 마이그레이션을 적용하고, Seed 메서드를 실행하고, 테스트 데이터베이스를 다시 삭제하는 단위 테스트 (또는 더 정확하게는 통합 테스트)를 구성 할 수 있습니다.

var configuration = new DbMigrationsConfiguration<TContext>();
Database.Delete("TestDatabaseNameOrConnectionString");

var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();

Database.Delete("TestDatabaseNameOrConnectionString");

그러나 개발 데이터베이스에 대해 실행하지 않도록주의하십시오!


1
EF Core에는 DbMigrationsConfiguration 클래스가 없으므로 대신 myDbContext.Database.GetPendingMigrations ()를 사용합니다.
stevie_c

3

이것이 오래된 질문이라는 것을 알고 있지만 원하는 것이 메시지 뿐이고 프로젝트에 WinForms에 대한 참조를 포함하지 않으려는 경우 Trace 이벤트를 보낼 수있는 간단한 디버그 창을 만들었습니다.

보다 진지하고 단계별 디버깅을 위해 다른 Visual Studio 인스턴스를 열 겠지만 간단한 작업에는 필요하지 않습니다.

이것은 전체 코드입니다.

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

그리고 표준 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!")
      // ...
    }
  }
}

1
물론 디버그 창은 원하는만큼 복잡 할 수 있습니다 (디자이너를 사용하여 완전한 양식을 만들고 전달하여 SeedInternal메서드에서 사용할 수 있음)
Jcl


0

두 가지 해결 방법이 있습니다 ( Debugger.Launch()나에게 적합하지 않기 때문에).

  1. 패키지 관리자 콘솔에서 메시지를 인쇄하려면 예외를 사용하십시오.
    throw new Exception("Your message");

  2. 또 다른 방법은 cmd프로세스 를 생성하여 파일에 메시지를 인쇄하는 것입니다.


    // 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);
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.