Where can I find the console or debug output from code executed in the package manager window? - entity-framework

I'm using EntityFramework code first with migrations. From the package manager console, I'm running "update-database". This executes Configuration.Seed(context) which I have overridden.
protected override void Seed(WebContext context)
{
Console.WriteLine("Console Test");
Debug.WriteLine("Debug Test");
Trace.WriteLine("Trace Test");
}
Where can I find that output?
Better yet, How do I output back to the package manager window?
Thx,
Dan

A quick hack I use to be able to quickly find a value in my Seed method is simply to throw an exception with a value I care about, e.g.
throw new Exception(yourValue);
This errors out the Seed, but my exception/value appears in my package manager console.

Where can I find that output?
Sorry, but the quick answer is basically nowhere.
To be precise at least not in the package manager console.
Debug.WriteLine("Debug Test");
Trace.WriteLine("Trace Test");
You can see the output of the Debug... and Trace... methods if you attach another Visual Studio to debug the Visual Studio instance which is running the update-database command. Then in the debuggin VS you can see the output in the Output Window.
Console.WriteLine("Console Test");
You can see the output of the Console... methods if you run the migrations with the
migrate.exe command line tool which comes with EF:
How do I output back to the package manager window?
I have here also bad news, after a quick "reflectoring": with the current implementation of the EF migrations it's not supported to display custom information during execution of the update-database (or any other command).

Running a SQL print command will write to the Package Manager Console. Here is a helper method that I use:
/// <summary>
/// write a message to the Package Manager Console
/// </summary>
public void Debug(string s, params object[] args)
{
var fullString = string.Format(s, args).Replace("'", "''");
Sql(string.Format("print '{0}'", fullString));
}

My needs were similar to yours so I figured I'd document them here in case they could help someone else out. My goal was to display all of the output from the migrations including all of the sql run as part of the Seed method. As a side effect of this solution, you will also be able to see any Debug.Write message in your code.
First create a DebugMigrationsLogger that will write all migration output to Debug.WriteLine (thanks to http://whiteknight.github.io/2013/01/26/efcodeonlymigrations.html):
public class DebugMigrationsLogger : System.Data.Entity.Migrations.Infrastructure.MigrationsLogger
{
public override void Info(string message)
{
Debug.WriteLine(message);
}
public override void Verbose(string message)
{
Debug.WriteLine(message);
}
public override void Warning(string message)
{
Debug.WriteLine("WARNING: " + message);
}
}
Next make sure you have a subclass of DbMigrationsConfiguration for your DbContext:
public class MyDbMigrationsConfiguration : DbMigrationsConfiguration<MyDbContext>
{
public MyDbMigrationsConfiguration()
{
}
protected override void Seed(MartusDb db)
{
//...
}
}
Next you run your migrations as an on-demand unit test so your test runner can capture the output. My unit test looks something like this:
public void MigrateDb_Test()
{
var config = new MyDbMigrationsConfiguration { AutomaticMigrationDataLossAllowed = true };
var migrator = new DbMigrator(config);
var loggingDecorator = new MigratorLoggingDecorator(migrator, new DebugMigrationsLogger());
loggingDecorator.Update();
}
Lastly, set the Database.Log in your DbContext constructor:
public class MyDbContext : DbContext
{
public MyDbContext()
{
Database.Log = message => Debug.WriteLine(message);
}
}
Now whenever you run the MigrateDb_Test() you will see all the output, it has made debugging migrations so much easier for me!

Dirty workaround extending George's answer.
protected override void Seed(YourContext context)
{
using (var seedout = new StringWriter())
{
// do your work
context.Authors.AddOrUpdate(x => x.Id,
new Author() { Id = 1, Name = "Jane Austen" }
);
// some message
seedout.WriteLine("some message");
// commit your work
context.SaveChanges();
seedout.WriteLine("Seed successfully completed.");
// dummy exception to show message on package manager console
throw new Exception(seedout.ToString());
}
}

Related

Unity3d JsonUtility.FromJson() read from TextAsset works in app, fails in Test Runner

The following code works fine in my application (Unity 2019.3.0f6). It reads from Assets/Resources/lesson-text.json and writes the expected logs to the console:
// file to read lessons from
public TextAsset jsonFile;
internal JsonLessonList LoadLessonFromFile()
{
JsonLessonList testLessonList = JsonUtility.FromJson<JsonLessonList>(jsonFile.text);
foreach (JsonLesson lesson in testLessonList.jsonLessonList)
{
Debug.Log("Found lesson: " + lesson.Name);
}
return testLessonList;
}
I'm wanting to read the same file when using Unity's Test Runner:
[UnityTest]
public IEnumerator TestFileParsesOkTest()
{
JsonLessonList testLessonList = jsonReader.LoadLessonFromFile();
Assert.IsNotNull(testLessonList);
yield return null;
}
but I keep getting this exception:
TestFileParsesOkTest (0.019s)
Unhandled log message: '[Exception] NullReferenceException: Object reference not set to an instance of an object'. Use UnityEngine.TestTools.LogAssert.Expect
JsonReader.LoadLessonFromFile () (at Assets/Scripts/JsonReader.cs:68)
JsonReader.Start () (at Assets/Scripts/JsonReader.cs:37)
NullReferenceException: Object reference not set to an instance of an object
I know the file format is ok because it works from the app. I think the problem is that "TextAsset jsonFile" that is set through the unity editor is not being seen by the Test Runner. How do I make this work?
[Test]
public void JsonFileResourceTest()
{
Assert.IsNotNull(jsonReader.jsonFile);
}
results in:
JsonFileResourceTest (0.020s)
Expected: not null
But was: null
(The test driven development tag is because I got the very simplest read of a file with one field working, and now I want to back up and write a unit test for it and then write tests before coding going forward.)
I figured it out:
[SetUp]
public void Setup()
{
jsonReader = new GameObject().AddComponent<JsonReader>();
jsonReader.jsonFile = Resources.Load("lesson-test") as TextAsset;
}
// Verify class exists
[Test]
public void JsonReaderClassExists()
{
Assert.IsNotNull(jsonReader);
Assert.IsNotNull(jsonReader.jsonFile);
}

I have "Roach Motel Data" - data go into DB fine, cannot get back out

I'm using Xamarin.Forms with EF and SqLite. I've installed the "Microsoft.EntityFrameworkCore.Sqlite" Nuget package in my project. The code issue is in the shared code project, .NetStandard 2.0.
I have created a simple class, let's say CAT class to hold my DB table objects
I can use the "ensurecreated" command and that works fine
I can create a CAT, set properties and SaveChanges() to the DB; this works fine, I can see the data in the DB
I cannot get the data back out; I get an "object not set to a reference..." error.
Ignore my couple of outer curly braces; new to posting code and only way to get it all together in one block. I have handled the platform-specific (Android & iOS) code for obtaining the dbPath to the SqLite .db3 file (not shown here).
Cannot figure what I'm missing that no data will come back out of DB. Any help much appreciated!
{
public class DatabaseContext : DbContext
{
string _dbPath;
public DbSet<Cat> Cats { get; set; }
public DatabaseContext(string dbPath)
{
_dbPath = dbPath;
Database.EnsureCreatedAsync();
}
public async Task<IEnumerable<Cat>> GetCats()
{
var allCats = await Cats.ToListAsync().ConfigureAwait(false);
return allCats;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite($"Filename={_dbPath}");
}
}
List<Cat> itemSource;
// Create Database & Tables
using (var db = new DatabaseContext(App.dbPath))
{
// Ensure database is created
db.Database.EnsureCreated();
// Insert Data
db.Add(new Cat() { IdCat = "111", Fname = "Felix1" });
db.SaveChanges();
// Retreive Data
//method 1
// RESULT: no data are in "itemsource", info reads "exception count = 1"
itemSource = db.Cats.ToList();
// method 2
// RESULTS: crashes with error "System.NullReferenceException: Object reference not set to an instance of an object."
Task<IEnumerable<Cat>> p = db.GetCats();
itemSource = db.Cats.ToList();
}
}

NLog callback possible?

I am in the process of converting a home grown logging system to NLog and am wondering if there is a way to add an event to a Logger or otherwise support a mechanism where when I log a message I can get a callback with the final formatted message and the LogLevel. I currently use something like this to send server messages back to a connected client.
Thx
This is an MCVE of what I was talking about in the comments. Create a target that accepts some callback functions:
[Target("MyFirst")]
public sealed class MyFirstTarget : TargetWithLayout
{
private readonly Action<string>[] _callbacks;
public MyFirstTarget(params Action<string>[] callbacks)
{
_callbacks = callbacks;
}
protected override void Write(LogEventInfo logEvent)
{
foreach (var callback in _callbacks)
{
callback(logEvent.FormattedMessage);
}
}
}
Configure NLog to use the target. I do this programmatically since the callbacks are passed in the constructor. You can also configure the target in the NLog.config, but your target will need to be a singleton then so you can register the callbacks in code.
class Program
{
public static void Main()
{
LogManager.Configuration.AddTarget("MyFirst", new MyFirstTarget(s => Debug.WriteLine(s)));
var logger = LogManager.GetCurrentClassLogger();
logger.Debug("test");
}
}
With no other NLog configuration (copy this code into an empty project and add the NLog nuget package), this will emit a message to your debug window.

Unit testing "object reference not set to an instance " at NUnit

i have a ASP.Net project and Nunitasp framework work for unit testing,i have a object in account.aspx.cs file when i tried to test the object(NugetplatformModel) value i get"object reference not set to an instance" error,
my account page code is given below
public partial class Account : System.Web.UI.Page
{
public NugetPlatformModel NugetPlatformModels;
public string result = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
if (!WebSecurity.IsAuthenticated)
{
Response.Redirect("/login", true);
}
else
{
result = "success";
NugetPlatformModels = new NugetPlatformModel();
}
}
my test case code is given below
[Test]
public void AccountPage_ValidCredential_AccessModel()
{
Browser.GetPage(domain + "account");
string ExpectedPage = domain + "account";
logon();
Account acccountPage = new Account();
AssertEquals("success", acccountPage.result);
AssertEquals("should have license",true,acccountPage.NugetPlatformModels.IsHavingLicense);
}
How can I access and test that code behind variables? when start the testing the NUgetplatformmodel has been assigned i have checked it by debugging but after that in nunit gui it displays null reference error, i thought there is a problem in accessing variable in testcase..please help me..
It seems your code is not complete. From what I see here your account needs to run Page_Load in order to fill result and NugetPlatformModels. But I do not see how this method is launched in your test. Is it run from the constructor of Account?
It would be helpfull if you put all the code for Account in your post.

Configuring EF to throw if accessing navigation property not eager loaded (and lazy-load is disabled)

We have a few apps that are currently using an EF model that has lazy-loading enabled. When I turn off the lazy-loading (to avoid implicit loads and most of our N+1 selects), I'd much rather have accessing a should-have-been-eager-loaded (or manually Load() on the reference) throw an exception instead of returning null (since a specific exception for this would be nicer and easier to debug than a null ref).
I'm currently leaning towards just modifying the t4 template to do so (so, if reference.IsLoaded == false, throw), but wondered if this was already a solved problem, either in the box or via another project.
Bonus points for any references to plugins/extensions/etc that can do source analysis and detect such problems. :)
I wanted to do the same thing (throw on lazy loading) for several performance-related reasons - I wanted to avoid sync queries because they block the thread, and in some places I want to avoid loading a full entity and instead just load the properties that the code needs.
Just disabling lazy loading isn't good enough because some entities have properties that can legitimately be null, and I don't want to confuse "null because it's null" with "null because we decided not to load it".
I also wanted to only optionally throw on lazy loading in some specific code paths where I know lazy loading is problematic.
Below is my solution.
In my DbContext class, add this property:
class AnimalContext : DbContext
{
public bool ThrowOnSyncQuery { get; set; }
}
Somewhere in my code's startup, run this:
// Optionally don't let EF execute sync queries
DbInterception.Add(new ThrowOnSyncQueryInterceptor());
The code for ThrowOnSyncQueryInterceptor is as follows:
public class ThrowOnSyncQueryInterceptor : IDbCommandInterceptor
{
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
OptionallyThrowOnSyncQuery(interceptionContext);
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
OptionallyThrowOnSyncQuery(interceptionContext);
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
OptionallyThrowOnSyncQuery(interceptionContext);
}
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
}
private void OptionallyThrowOnSyncQuery<T>(DbCommandInterceptionContext<T> interceptionContext)
{
// Short-cut return on async queries.
if (interceptionContext.IsAsync)
{
return;
}
// Throw if ThrowOnSyncQuery is enabled
AnimalContext context = interceptionContext.DbContexts.OfType<AnimalContext>().SingleOrDefault();
if (context != null && context.ThrowOnSyncQuery)
{
throw new InvalidOperationException("Sync query is disallowed in this context.");
}
}
}
Then in the code that uses AnimalContext
using (AnimalContext context = new AnimalContext(_connectionString))
{
// Disable lazy loading and sync queries in this code path
context.ThrowOnSyncQuery = true;
// Async queries still work fine
var dogs = await context.Dogs.Where(d => d.Breed == "Corgi").ToListAsync();
// ... blah blah business logic ...
}
jamesmanning, the creator of the project https://github.com/jamesmanning/EntityFramework.LazyLoadLoggingInterceptor, managed to intercept lazy-loaded calls by reading the stack trace.
So in you could create DbCommandInterceptor that does something like:
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
// unfortunately not a better way to detect whether the load is lazy or explicit via interceptor
var stackFrames = new StackTrace(true).GetFrames();
var stackMethods = stackFrames?.Select(x => x.GetMethod()).ToList();
var dynamicProxyPropertyGetterMethod = stackMethods?
.FirstOrDefault(x =>
x.DeclaringType?.FullName.StartsWith("System.Data.Entity.DynamicProxies") == true &&
x.Name.StartsWith("get_"));
if (dynamicProxyPropertyGetterMethod != null)
{
throw new LazyLoadingDisallowedException();
}
I know that reading the stack trace frames can be expensive, although my guess would be that in normal circumstances where data access is occurring, the cost is negligible compared to the data access itself. However you will want to assess the performance of this method for yourself.
(As a side note, what you are after is one of the many nice features that NHibernate has had for many many years).
You shouldn't have to modify the T4. Based on mention of "T4" I'm guessing you are using EDMX. The properties window of the container has the lazyloadingenabled property. It's set to true when you create a new model. You can change it to false. T4 template will see that and add the code into the ctor.
Also if you're using Microsoft's POCO templates, they'll add the virtual keyword to your nav properties. Virtual + lazyloadingenabled is the necessary combination to get lazy loading. If you remove the virtual keyword then the property will never be lazy loaded, eve if lazyloading is enabled.
hth
julie