This post was most recently updated on October 4th, 2022.
4 min read.This post describes the easiest way to debug the issues that may stop your Seed-method in Configuration.cs from going through. This problem concerns typically your ASP.NET MVC projects, either on .NET Framework or .NET Core – the same basic idea should work for both situations.
The solution here shows you, how you can get a little bit more information out of the process, without attaching the debugger (there’s another blog post for that: How to launch the visual studio debugger from code/)
Description
Entity Framework’s code-first migrations are a beautiful and easy way of managing database schema changes and populating some preliminary data there. Personally I also sometimes use the method for adding some enrichment to data or custom property values mapping that would otherwise require an additional/external console program.
Problem: running the Seed-method is by default undebuggable
Okay – so seeding data is cool. You do that within your Configuration.cs -file when running Update-Database to insert some default or baseline data to your database.
That’s fine and dandy, but debugging the issues in the function while running Update-Database is NOT so cool. You can’t run the Seed-method with the debugger turned on. Hence, when you run into issues, you only get the stacktrace and exception message – and that’s not always that informative.
In my other blog post, I describe how you CAN in fact debug the Seed-method, by launching a debugger instance manually from the method itself. See the other solution here:
This blog post shows an alternative to that – you can also modify the error messages thrown during the Seed method!
See this:
update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending explicit migrations.
Running Seed method.
System.InvalidOperationException: Sequence contains more than one element
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.b__2[TResult](IEnumerable`1 sequence)
at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
at System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate[TEntity](DbSet`1 set, IEnumerable`1 identifyingProperties, InternalSet`1 internalSet, TEntity[] entities)
at System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate[TEntity](IDbSet`1 set, Expression`1 identifierExpression, TEntity[] entities)
at ....Migrations.Configuration.Seed(ApplicationDbContext db) in C:\...\Migrations\Configuration.cs:line 345
at System.Data.Entity.Migrations.DbMigrationsConfiguration`1.OnSeed(DbContext context)
at System.Data.Entity.Migrations.DbMigrator.SeedDatabase()
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase()
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.b__b()
at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Sequence contains more than one element.
Okay, so “Sequence contains more than one element”. Cool. I’m probably failing an AddOrUpdate-call somewhere, but I hate going through the exception to find the Configuration.cs:345 (or similar) row that actually tells where the exception was when I could have the exception tell me what went wrong. Unfortunately, the exception just shows me the message of the thrown exception – which is NOT descriptive.
Oh, but wait: There is a solution!
Solution
Time needed: 15 minutes
By wrapping the whole stuff in a try-catch-block, catching the thrown exception, wrapping a new exception with a custom message around it, and including the original one as an internal exception, we get the data from the original exception AND our custom message – which in my case tells how far in the Seed-method (or just in which part of seeding/mapping the data we are in) we’ve proceeded. You can even make it tell the line where we’ve gotten to!
- So, in my Configuration.cs class (in Migrations), I have this first:
<pre lang="csharp">internal class Configuration : DbMigrationsConfiguration<applicationdbcontext>
{
private bool _debug = false;
private string _customExceptionMessage = "";
...
</applicationdbcontext></pre> - Then, further down the line when seeding my data, I have these little calls:
<pre lang="csharp">db.Companies.AddOrUpdate(p => p.CompanyIdentifier,
new Company
{
...
},
new Company
{
...
}
);
db.SaveChanges();
_customExceptionMessage += "Companies saved ok;";
</pre> - This goes on for a while, but I’ve wrapped the whole method in a try-catch, like below:
<pre lang="csharp">/// <summary>
/// This method will be called after migrating to the latest version.
/// </summary>
/// <param name="db">
protected override void Seed(ApplicationDbContext db)
{
try
{
_customExceptionMessage += "Running Seed method in Configuration.cs;";
db.Companies.AddOrUpdate(p => p.CompanyIdentifier,
new Company
{
...
},
new Company
{
...
}
);
db.SaveChanges();
_customExceptionMessage += "Companies saved ok;"
...
}
catch (Exception ex)
{
Exception ex2 = new Exception(_customExceptionMessage, ex);
throw ex2;
}
}
</pre> - Now the exception in the Package Manager Console will be something like this:
<pre lang="csharp">// Omitted for clarity
...
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Running Seed method in Configuration.cs;Companies saved ok;User added to company ok;Contacts saved ok;</pre> - So, now you get this:
<pre>Running Seed method in Configuration.cs;Companies saved ok;User added to company ok;Contacts saved ok;</pre>
To let you know how far you got in the execution.
This is, at least to me, a small improvement. Pretty? Ha, no. Much faster than launching a debugger? Yes!
Also, very hack-ish, but better than the normal functionality. And combined with launching the debugger from the code (as described here), quite an improvement over just getting a stacktrace.
- M365 Copilot claiming “You have turned off web search in the work mode”? Easy fix! - November 19, 2024
- “Performing cleanup” – Excel is stuck with an old, conflicted file and will never recover. - November 12, 2024
- How to add multiple app URIs for your Entra app registration? - November 5, 2024