it-swarm.com.de

Debuggen der Package Manager Console-Update-Datenbank Seed Methode

Ich wollte die Methode Seed() in meiner Entity Framework-Datenbankkonfigurationsklasse debuggen, wenn ich Update-Database aus der Package Manager-Konsole, wusste aber nicht, wie es geht. Ich wollte die Lösung mit anderen teilen, falls sie das gleiche Problem haben.

103
Sachin Kainth

Hier ist ähnlich Frage mit einer Lösung, die wirklich gut funktioniert.
Es erfordert NICHT Thread.Sleep.
Startet einfach den Debugger mit diesem Code.

Aus der Antwort gekürzt

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

Die Lösung bestand darin, eine neue Instanz von Visual Studio und dann dieselbe Lösung in dieser neuen Instanz von Visual Studio zu öffnen. Ich habe dann den Debugger in dieser neuen Instanz an die alte Instanz (devenv.exe) angehängt, während ich den Befehl update-database ausgeführt habe. Dadurch konnte ich die Seed -Methode debuggen.

Um sicherzustellen, dass ich den Haltepunkt nicht verpasst habe, indem ich ihn nicht rechtzeitig anfügte, habe ich einen Thread.Sleep vor dem Haltepunkt hinzugefügt.

Ich hoffe das hilft jemandem.

20
Sachin Kainth

Wenn Sie den Wert einer bestimmten Variablen abrufen müssen, können Sie schnell eine Ausnahme auslösen:

throw new Exception(variable);
11
cederlof

Eine sauberere Lösung (ich denke, dies erfordert EF 6) wäre IMHO, die Update-Datenbank aus dem Code aufzurufen:

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

Auf diese Weise können Sie die Seed -Methode debuggen.

Sie können noch einen Schritt weiter gehen und einen Komponententest (oder genauer gesagt einen Integrationstest) erstellen, der eine leere Testdatenbank erstellt, alle EF-Migrationen anwendet, die Methode Seed) ausführt und löscht die Testdatenbank nochmal:

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

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

Database.Delete("TestDatabaseNameOrConnectionString");

Aber seien Sie vorsichtig, damit dies nicht mit Ihrer Entwicklungsdatenbank in Konflikt gerät!

5
Jesper Mygind

Ich weiß, dass dies eine alte Frage ist, aber wenn alles, was Sie wollen, Nachrichten sind und Sie keine Verweise auf WinForms in Ihr Projekt aufnehmen möchten, habe ich ein einfaches Debug-Fenster erstellt, in dem ich Trace-Ereignisse senden kann.

Für ein ernsthafteres und schrittweises Debuggen öffne ich eine weitere Visual Studio-Instanz, die jedoch für einfache Dinge nicht erforderlich ist.

Das ist der ganze 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);
    }
  }
}

Und auf Ihrem 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!")
      // ...
    }
  }
}
3
Jcl

Äh, Debuggen ist eine Sache, aber vergiss nicht: context.Update ()

Auch nicht einpacken, ohne dass innere Ausnahmen in die Konsole gelangen.
https://coderwall.com/p/fbcyaw/debug-into-entity-framework-code-first with catch (DbEntityValidationException ex)

1
Steven Packham

Ich habe 2 Problemumgehungen (ohne Debugger.Launch(), da es bei mir nicht funktioniert):

  1. Verwenden Sie die folgende Ausnahme, um eine Nachricht in der Package Manager-Konsole zu drucken:
    throw new Exception("Your message");

  2. Eine andere Möglichkeit besteht darin, eine Nachricht in einer Datei zu drucken, indem Sie einen cmd -Prozess erstellen:


    // 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
Gendolph