Is it okay to initialize/seed a database data during Startup of an application? - asp.net-core

We would like to programmatically ensure that a database table has a certain set of rows (based on a sometimes-changing enum). We are using EF Core 2.2 with code-first migrations and are looking for the right place to seed this data. We had thought that adding a seeding method to our Startup.cs would be a good idea, but Microsoft's documentation says
The seeding code should not be part of the normal app execution as this can cause concurrency issues when multiple instances are running and would also require the app having permission to modify the database schema.
Is the code in Startup.cs considered "part of the normal app execution"?
Our app currently only runs with 1 instance, but there might be multiple in the future. Plus, we have an Azure Functions app and a console app which might also need to ensure that the database table has the correct rows before executing. Despite these concerns, I have seen accepted and upvoted answers on other threads saying that initializing as part of Startup.cs is okay. Will we be shooting ourselves in the foot by doing this?

From the docs:
Depending on the constraints of your deployment the initialization code can be executed in different ways:
Running the initialization app locally.
Deploying the initialization app with the main app, invoking the initialization routine and disabling or removing the initialization app.
My interpretation from this is that you could deploy a console app using publishing profiles that ensured the database seed at launch.

Related

Entity Framework 5 entity in separate dll

I have a DLL that is a logging component that we use in many different projects. This logging component is designed to be entirely self-contained, and thus it must have its database connection string internal to it. In this project, it is completely unacceptable to require that its connection string be copied to the app.config of any project that uses it.
This has been working great for years, but now we have found that mixing its older ADO tech with new apps that use EF results in horrible performance when the logging is being done. For example, adding a single log entry when the application starts results in a > 30 second delay before the app opens.
So to combat this, I have re-written this component to use EF.
The problem is under the current EF (version 4.4 since we are targeting .Net Framework 4.0) does not offer a constructor to DBContext that allows you to specify the entire connection string. The code attempts to change the Database.Connection.ConnectionString, but the DBContext object insists on looking in the App.Config for the connection string even though we are giving it a new one.
I must get around this behavior.

WebSecurity.Initialized is true but tables don't exist

My web app has a self-installation process; it detects (correctly) that the database isn't initialized, and initializes it (via migrations); I also have automated integrational tests that test installation works under these circumstances, and smoke-tests logging in and registering the first user (provided on the installation form).
I recently switched from MVC3 to MVC4. I used the built-in storage provider (in MVC3, the aspnet_* tables; in MVC4, WebSecurity with the UserProfile table).
Instead of hand-running all the MVC3 stored procedures from a .SQL file, I now have calls to WebSecurity.InitializeDatabaseConnection. In fact, my code snippet is:
if (!WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("ApplicationServices", "UserProfile", "UserId", "UserName", true);
MigrationsWrapper.MigrateToLatestVersion(); // wrapper around migratordotnet
}
Unfortunately, I've noticed an interesting "bug." When I compile my server code and run my installation tests, it passes (as expected) after a fresh install (empty database). If I immediately run the tests again, it fails.
The reason for failure? In my installation test, I nuke all the DB tables, and expect installation to recreate them. However, in this case, WebSecurity.Initialized returns true instead of false. So, I never hit the second line (initialize and create tables). If I move that line outside, I will get an exception that I'm double-initializing.
Unfortunately, what I really need here is a method like WebSecurity.CreateTables(), which doesn't exist. I am therefore quite stuck at an impasse. How do I handle this?
Also, if I try recreating the UserProfile table myself, I run into an issue with UserId (primary key) being inserted as null -- presumably because I'm missing the other tables.
How should I handle this scenario?
The only work-around I have right now is to reset IIS. Sad, but true; doing this will reset WebSecurity.Initialized and everything works.
Since I need to at app start, I can programatically reset IIS with Process.Start.

Dynamically change connection string for UI tests

I'm using WebAii library for UI testing - I want to test whether my component displays the same records as there are in database therefore I need to switch my application's connection string to point to the test database just for the time of running tests. What is the best way to do it? How to dynamically change the connection string prior to running the app? Thanks
Are you storing the connection string in the Web.config file? If so, I would deploy a new Web.config just before starting the test and then use the command line to send an IISRESET.
FYI, these are the kinds of questions we answer all day long on our public forum dedicated to WebAii.
Cody
Telerik Technical Support
What kind of application is it? This is first probably an indication of not-well-factored code. Next, it is common to have a separate environment for testing code.
If you are, for example, deploying to ASP.NET with Visual Studio, you can use Web.config file transformations to set a different value when you deploy to e.g. test.contoso.com vs. www.contoso.com. The transformation syntax allows you to define a new connection string, or change an existing one from the base Web.config, when deploying a different configuration.
If you have a single environment, and control over it, you could probably write a couple of (Power)shell scripts to copy a web.config with "test" connection strings to your app root prior to the test. Then run a second script to reset the original web.config after the test is run.
If you have access to your deploy directory within the context you will be running your tests, you could even simply have a Web.test.config file included in your unit test project. In [AssemblyInitialize]:
File-copy _\\{your app server}{your app directory}\Web.config to \\{your app server}{your app directory}\Web.config.orig.
File-copy Web.test.config to \\{your app server}{your app directory}\Web.config.
Sleep for a few seconds?
Then do the reverse in [AssemblyCleanup].
Other strategies exist, too. You could build in an override to your application when in debug mode, that checks various things (special file, additional config, cookies, extra query string). Or you could have a Settings manager in your app that you can instrument in test setup when arranging your test (click through UI to change DB settings).
Very likely, however, you may get the best compounding rewards by factoring your code to reduce dependencies. Then you can write unit tests which stub/mock/fake the database. You can use code coverage tools to verify that you've tested specific scenarios, or to see that additional integration tests would be duplication of coverage at that point.

RavenDb Config and DocumentStore abstraction?

I am using RavenDb across multiple projects and solutions to access three different databases that are all part of the same product. For instance, I have multiple MVC projects that fetch user info and some data out of the 'web' centric database and the 'backend' database, using '-' for the id override (but I need this only for a subset of classes in the 'web' db). And then I have another 'backend' database that is used by services (as well as the MVC projects). And finally a third temp/scratch database I use by another set of services to build the backend db. And of course, all of these are being accessed from different class libraries and even console test, seed, and integration test apps.
Managing all of these is becoming quite a nuisance. Every time I create a new console app or class library that access the db, I have to setup config and raven packages for each project, make sure indexes are built, etc.... Not to mention running update on all nuget updates, or in my case, installing a new unstable version of the server/client binaries.
Is there an easier way to manage this?
I tried to abstract the DocumentStore creation and initialization, as well as index creation into it own project and reference that. But the other projects then had to manually add newtonsoft.json (and nlog) from the package directory.
As well, I am getting the following when I try and abstract the DocumentStore into a class with a static property:
StackTrace of un-disposed document store recorded. Please make sure to dispose any document store in the tests in order to avoid race conditions in tests.
Anyone have any thoughts on handling these issues?
Thanks
I don't think that the manual addition of the references is a big issue, but you can add the actual nuget references as well.
Note that the DocumentStore not disposed error is something that only happened in the unstable (debug builds), and won't happen on release builds.

Nhibernate Profiler - Shows no information other than "session"?

So I am having problems getting NHibernate intergated in my MVC project. I therefore, installed the NHProfiler and initialized it in the Global.asax.cs file (NhibernateProfiler.Initialize();).
However, all I can see in the NHProf is a Session # and the time it took to come up. But selecting it or any other operations doesn't show me any information about the connection to the database or any information at all in any of the other windows such as:
- Statements, Entities, Session Usage
The Session Factory Statistics only shows Start time, execution time, and thats it.
Any thoughts.
Do you have any custom log4net configuration? Just thinking that might be overwriting NHProf's log4net listener after startup. If you refresh the page (and hence start another session*), does NHProf display another Session start? Also verify that your HibernatingRhinos.Profiler.Appender.dll (or HibernatingRhinos.Profiler.Appender.v4.0.dll if you're using .NET 4) is the same one as the current version of NHProf.
* I'm assuming that you're using Session-per-Request since this is a web app.