Using Devart Entity Developer with Entity Framework 6. I have my main class library project. I had a different Winform project altogether that uses Entity Developer/Entity Framework that I developed to do some database work with Sql. I decided to add this secondary Winform project to the main class library.
First I tried adding the Winform project to the solution. That did not work well. Even though I added a reference to the exe of the Winform project it seems not to find it ok. I removed that project from the solution.
As a second attempt. I copied the classes from the Winform project (two of them) to the main class library project and recreated the Entity Developer/Entity Framework stuff. Now when I run the project everything runs (including the new form) but I cannot connect to the database. I get the error:
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
The line that has the error is the line calling base:
public SWPDMEngVaultEntities() :
base(#"name=SWPDMEngVaultEntitiesConnectionString", "SWPDMEngVaultEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
My connection string is in the app.config file and looks like this:
<connectionStrings>
<add name="SWPDMEngVaultEntitiesConnectionString" connectionString="metadata=res://*/DataModel1.csdl|res://*/DataModel1.ssdl|res://*/DataModel1.msl;provider=System.Data.SqlClient;provider connection string="Data Source=XXXXXX\SQLEXPRESS;Initial Catalog=XXXXXX;Integrated Security=False;Persist Security Info=True;User ID=XXXXXX;Password=XXXXXX""
providerName="System.Data.EntityClient" />
</connectionStrings>
All of the XXXXXX's in the above string have been confirmed as correct. Also, Entity Developer has a "Test Connection" and the test connection connects just fine. Entity Developer also gets the database information OK so I know it is able to connect without issue. The problem is at runtime on the solution.
I have looked at other posts about this error and they all seem to be saying make sure your connection string is good. What else should I check?
The answer to this issue came from Devart. Class libraries do not use app.config files for settings. By default the connection string in the Devary generated templates are stored in the app.config file. There is a place to turn this off when the model is generated.
I'm trying to create a Code First Entity Framework ASP.NET Core 2 project in Visual Studio Code. I've been following the Create a Web API with ASP.NET Core MVC and Visual Studio Code on Linux, macOS, and Windows tutorial, which uses an in-memory datastore as its DbContext. I'm trying to move this to LocalDB.
The tutorial Getting Started with EF Core on ASP.NET Core with a New database suggests I should be able to do this with a migration.
Once you have a model, you can use migrations to create a database.
Open the PMC:
Tools –> NuGet Package Manager –> Package Manager Console
Run Add-Migration InitialCreate to scaffold a migration to create the initial set of tables for your model. If you receive an error stating The term 'add-migration' is not recognized as the name of a cmdlet, close and reopen Visual Studio.
Run Update-Database to apply the new migration to the database. This command creates the database before applying migrations.
The VS Code equivalent of using the Package Manager Console seems to be:
dotnet ef migrations add InitialCreate
I've added EF's Design namespace with...
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet restore
And have the reference in my csproj:
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>
But when I try that the dotnet ef migrations add command afterwards, it acts like the table for my TodoItems model needed to already exist in the database. It was my understanding that the migration would create the tables based on my models.
c:\Projects\TodoApi>dotnet ef migrations add InitialCreate -v
Using project 'c:\Projects\TodoApi\TodoApi.csproj'.
Using startup project 'c:\Projects\TodoApi\TodoApi.csproj'.
Writing 'c:\Projects\TodoApi\obj\TodoApi.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\UserName\AppData\Local\Temp\tmp945E.tmp /verbosity:quiet /nologo c:\Projects\TodoApi\TodoApi.csproj
Writing 'c:\Projects\TodoApi\obj\TodoApi.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\UserName\AppData\Local\Temp\tmp96FF.tmp /verbosity:quiet /nologo c:\Projects\TodoApi\TodoApi.csproj
dotnet build c:\Projects\TodoApi\TodoApi.csproj /verbosity:quiet /nologo
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:02.29
dotnet exec --depsfile c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.deps.json --additionalprobingpath C:\Users\UserName\.nuget\packages --additionalprobingpath "C:\Program Files (x86)\Microsoft SDKs\NuGetPackagesFallback" --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.runtimeconfig.json C:\Users\UserName\.nuget\packages\microsoft.entityframeworkcore.tools.dotnet\2.0.0\tools\netcoreapp2.0\ef.dll migrations add InitialCreate --assembly c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.dll --startup-assembly c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.dll --project-dir c:\Projects\TodoApi\ --verbose --root-namespace TodoApi
Using assembly 'TodoApi'.
Using startup assembly 'TodoApi'.
Using application base 'c:\Projects\TodoApi\bin\Debug\netcoreapp2.0'.
Using working directory 'c:\Projects\TodoApi'.
Using root namespace 'TodoApi'.
Using project directory 'c:\Projects\TodoApi\'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding BuildWebHost method...
Using environment 'Development'.
Using application service provider from BuildWebHost method on 'Program'.
Found DbContext 'DatabaseContext'.
Finding DbContext classes in the project...
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM [TodoItems] AS [t])
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
System.Data.SqlClient.SqlException (0x80131904): Invalid object name 'TodoItems'.
What needs to be done to ensure tables are created based on my models?
The only gotcha I can think of offhand is that I have the connection string inline rather than in appsettings.json, but I'm not sure why that'd be a big deal, unless the migration is looking for a config by default.
public void ConfigureServices(IServiceCollection services)
{
// In memory: services.AddDbContext<DatabaseContext>(opt => opt.UseInMemoryDatabase("TodoList")); // <<< REMOVED
string strCxn = "Server=(localdb)\\mssqllocaldb;Database=Contacts;Trusted_Connection=True;MultipleActiveResultSets=true"; // <<< ADDED
services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(strCxn)); // <<< ADDED
services.AddMvc();
}
Fwiw, those are the only changes I've made to the TodoApi tutorial's code to move from the in-memory db to LocalDB.
Update: Fwiw, I tried changing the database name in the connection string..
string strCxn = "Server=(localdb)\\mssqllocaldb;Database=Contacts2;Trusted_Connection=True;MultipleActiveResultSets=true";
(Changing Contacts to Contacts2, just in case it thought that, since it found the Contacts db initially, a migration had already taken place...)
That didn't work either, though the error changed in a way that suggests the connection string is working and being read.
Cannot open database "Contacts2" requested by the login. The login failed.
Login failed for user 'COMPUTER-NAME\UserName'.
As part of the DbContext's constructor, I was seeding data...
public class DatabaseContext : DbContext {
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
this.MinimallySeedDatabase();
}
public void MinimallySeedDatabase()
{
State NY = this.States.Where(s => s.Abbr.Equals("NY")).FirstOrDefault();
if (null == NY)
{
NY = new State {
Name = "New York",
Abbr = "NY"
};
this.States.Add(NY);
this.SaveChanges();
}
// etc etc etc...
}
public DbSet<Contact> Contacts {get; set;}
public DbSet<Address> Addresses {get; set;}
public DbSet<AddyType> AddyTypes {get; set;}
public DbSet<State> States {get; set;}
}
Part of the migration's execution involves instantiating the DbContext obviously before the tables for the DbSets are migrated over. Since the constructor, in this example, requires accessing States, and because the migration hasn't gotten to the point it's created the States table to pull from yet, the migration blows up.
As Kirk mentions, if I take out the seeding, I'm fine. And if you want to seed, you need to move that somewhere other than the constructor, even though the seeding in the constructor works fine outside of a migration attempt/in normal Kestrel testing.
For me, I just commented out this.MinimallySeedDatabase(); when I ran the migration.
I've created a simple unit test project to read an app.config file. Target framework is Core 2.0. I also created a Core 2.0 console app, to sanity-check myself to make sure I wasn't doing anything weird (same test passed as expected in a .NET 4.6.1 unit test project).
The console app reads the app.config fine, but the unit test method fails and I cannot figure out why. Both are using a copy of the same app.config (not added as a link) and both have the System.Configuration.ConfigurationManager v4.4.1 NuGet package installed.
The App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Test1" value ="This is test 1."/>
<add key="Test2" value ="42"/>
<add key="Test3" value ="-42"/>
<add key="Test4" value="true"/>
<add key="Test5" value="false"/>
<add key="Test6" value ="101.101"/>
<add key="Test7" value ="-1.2345"/>
</appSettings>
</configuration>
The Unit Test
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Configuration;
namespace ConfigTest
{
[TestClass]
public class UnitTest1
{
[TestMethod()]
public void ConfigTest()
{
foreach (string s in ConfigurationManager.AppSettings.AllKeys)
{
System.Console.WriteLine(s);
System.Diagnostics.Debug.WriteLine(s);
}
//AllKeys.Length is 0? Should be 7...
Assert.IsTrue(ConfigurationManager.AppSettings.AllKeys.Length == 7);
}
}
}
The Console App
using System;
using System.Configuration;
namespace ConfigTestApp
{
class Program
{
static void Main(string[] args)
{
foreach (string s in ConfigurationManager.AppSettings.AllKeys)
{
Console.WriteLine(s);
System.Diagnostics.Debug.WriteLine(s);
}
//Outputs 7 as expected
Console.WriteLine(ConfigurationManager.AppSettings.AllKeys.Length);
}
}
}
Given that I'm still pretty new to the whole .NET Core world, am I doing something totally incorrect here? I sort of just feel crazy at the moment...
Looking through the github issue's comments, I found a work around that can go in the msbuild file...
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
</Target>
This makes it easier to verify existing tests under .NET Core before porting the configuration data over to json configuration files.
Edit
If running under Resharper, the previous answer doesn't work as Resharper proxies the assembly, so you need
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\ReSharperTestRunner64.dll.config" />
</Target>
If you check the result of the call to ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
It should tell you where the required configuration file should be while running unit tests for that assembly.
I found that instead of having an app.config file, ConfigurationManager was looking for a testhost.dll.config file.
This was for a project targeting netcoreapp2.1, with a reference to Microsoft.NET.Test.Sdk,NUnit 3.11 and Nunit3TestAdapter 3.12.0
.CORE 3.1
To find out what dll.config file was being used, I debugged the test by adding this line and looking to see what the value is.
string path = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
Then I found out resharper was using testhost.dll.config and VStest was using testhost.x86.dll.config. I needed to add the following lines to the project file.
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" />
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.x86.dll.config" />
</Target>
I came across the same issue with my xunit tests and solved it by using the instance of Configuration from ConfigurationManager. I put the static (normal) way it works in core, framework (but not unit tests) before I show the alternative way it works in all three:
var appSettingValFromStatic = ConfigurationManager.AppSettings["mySetting"];
var appSettingValFromInstance = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["mySetting"].Value;
And here is a similar/related issue. In case anyone needs to get a section you can do a similar thing, though the type must change in the app config:
<configSections>
<section name="customAppSettingsSection" type="System.Configuration.AppSettingsSection"/>
<section name="customNameValueSectionHandlerSection" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<customAppSettingsSection>
<add key="customKey" value="customValue" />
</customAppSettingsSection>
<customNameValueSectionHandlerSection>
<add key="customKey" value="customValue" />
</customNameValueSectionHandlerSection>
Code to grab section:
var valFromStatic = ((NameValueCollection)ConfigurationManager.GetSection("customNameValueSectionHandlerSection"))["customKey"];
var valFromInstance = ((AppSettingsSection)ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).GetSection("customAppSettingsSection")).Settings["customKey"].Value;
I feel like I am also crazy, and I know there are newer ways of doing config in core, but if one wants to do something cross-platform this is the only way I know how. I'd be very interested if anyone has alternatives
For my mixed .NET-Core & .NET-Framework project, I added the following to the unit test global setup:
#if NETCOREAPP
using System.Configuration;
using System.IO;
using System.Reflection;
#endif
...
// In your global setup:
#if NETCOREAPP
string configFile = $"{Assembly.GetExecutingAssembly().Location}.config";
string outputConfigFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
File.Copy(configFile, outputConfigFile, true);
#endif
This copies the config file to the output path testhost.dll.config but should be resilient enough to account for future changes in the testing framework.
Or you can copy to below, which amounts to the same thing:
string outputConfigFile = Path.Combine(Path.GetDirectoryName(configFile), $"{Path.GetFileName(Assembly.GetEntryAssembly().Location)}.config");
Credit to #stop-cran and #PaulHatcher's solutions, this is a combination of those two.
None of the answers given here provide a viable workaround when you're dealing with code accessing directly the static ConfigurationManager properties such as AppSettings or ConnectionStrings.
The truth is, it is not possible at the moment. You can read through the discussion here to understand why:
https://github.com/dotnet/corefx/issues/22101
There is talk to implement the support for it here:
https://github.com/Microsoft/vstest/issues/1758
In my opinion it makes sense to support this scenario since it's been working on the .NET Framework plus System.Configuration.ConfigurationManager is a .NET Standard 2.0 library now.
A hacky, but working way is to copy the config to the same folder as an entry assembly, whatever it is:
[SetUpFixture]
public class ConfigKludge
{
[OneTimeSetUp]
public void Setup() =>
File.Copy(
Assembly.GetExecutingAssembly().Location + ".config",
Assembly.GetEntryAssembly().Location + ".config",
true);
[OneTimeTearDown]
public void Teardown() =>
File.Delete(Assembly.GetEntryAssembly().Location + ".config");
}
Apart from adding this class, the only thing to make it work is to include app.config file in test project (without any copying options). It should be copied to the output folder as <your test project name>.dll.config at the build step, because it's kind of default logic.
Note the documentation for OneTimeSetUpAttribute:
Summary:
Identifies a method that is called once to perform setup before any child tests are run.
Although it should work for parallel test runs for a single project, there could be obvious troubles when running two test projects simultaneously, since the config would get overwritten.
However, it is still suitable for containerized test runs, like in Travis.
When we answer such well-researched and well-articulated question, we should better assume that it is being asked by an informed and intelligent being. And instead of patronizing them with the obvious about new, great ways of writing tonnes of boilerplate code to parse all sort of JSON et al, being forced on us and shoved down our throat by know-betters, we should focus on answering to the point.
Since the OP is already using System.Configuration to access settings, they already know how to arrive at this point. The only thing that is missing is one little touch: adding this line to the post-build event:
copy $(OutDir)<appname>.dll.config $(OutDir)testhost.dll.config
where <appname> is the project being unit-tested.
I applaud everyone who is still using (originally lame but workable) implementation of app.config because doing so protects our and our clients' investment in technology instead of reinventing the wheel. Amen.
Mercifully there is now a way to set the name of the expected configuration file at runtime. You can set the APP_CONFIG_FILE data for the current app domain.
I created the following SetUpFixture to do this automatically:
[SetUpFixture]
public class SetUpFixture
{
[OneTimeSetUp]
public void OneTimeSetUp()
{
var testDllName = Assembly.GetAssembly(GetType())
.GetName()
.Name;
var configName = testDllName + ".dll.config";
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", configName);
}
}
The relevant GitHub discussions are:
ConfigurationManager doesn't find config file with "dotnet test" · Issue #22720 · dotnet/runtime
Provide a way to override the global configuration file path · Issue #931 · dotnet/runtime
Respect AppContext.SetData with APP_CONFIG_FILE key by krwq · Pull Request #56748 · dotnet/runtime
The ConfigurationManager API will only use the configuration of the app that is currently running. In a unit test project, this means the app.config of the test project, not the console application.
.NET Core Applications aren't supposed to use app.config or ConfigurationManager, as it is a legacy "full framework" configuration system.
Consider using Microsoft.Extensions.Configuration instead to read JSON, XML or INI configuration files. See this doc: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration
Usually in .NET Framework projects, any App.config file was copied to the bin folder by Visual Studio, with the name of your executable (myApp.exe.config) so it could be reachable in runtime. Not anymore in .NET Standard or Core Framework. You must manually copy and set the file in the bin/debug or release folder. After that it could be get with something like:
string AssemblyName = System.IO.Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().GetName().CodeBase);
AppConfig = (System.Configuration.Configuration)System.Configuration.ConfigurationManager.OpenExeConfiguration(AssemblyName);
While app.config exists in the root project folder add below string to Post-build event command line
xcopy /Y $(ProjectDir)app.config $(ProjectDir)$(OutDir)testhost.dll.config*
Add the configuration file
First, add a appconfig.json file to the Integration test project
Configure the appconfig.json file to be copied to the output
directory by updating
Add NuGet package
Microsoft.Extensions.Configuration.Json
Use the configuration in your unit tests
[TestClass]
public class IntegrationTests
{
public IntegrationTests()
{
var config = new ConfigurationBuilder().AddJsonFile("appconfig.json").Build();
_numberOfPumps = Convert.ToInt32(config["NumberOfPumps"]);
_numberOfMessages = Convert.ToInt32(config["NumberOfMessages"]);
_databaseUrl = config["DatabaseUrlAddress"];
}
}
In my ASP.NET EF 6 app, I have the following Configuration:
internal sealed class Configuration : DbMigrationsConfiguration<Gcim.Management.Module.BusinessObjects.ManagementDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(Gcim.Management.Module.BusinessObjects.ManagementDbContext context)
{
}
}
In my project, I have EF code-first migrations enabled.
I'm able to run add-migration, as well as update-database from the VS Package Manager prompt.
However, when my entities change, adding a migration, and updating database only works in dev environment.
When I publish my ASP.NET project, install it on production IIS, and run, I still get this error:
The model backing the 'ManagementDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
What else do I need to do in order to force the incremental DB changes in production, without data loss?
You can execute a given migration file against a given environment (in this case, your production environment) by using the migrate.exe application included as part of the Entity Framework nuget package. You'll need to execute your latest migration against your production environment before publishing your web application - once this has been done, the newly deployed application will work correctly.
You do this by specifying the connection string and .dll containing the migration class(es), as well as possibly a specific migration. For example:
Migrate.exe Gcim.Management.Module.BusinessObjects.dll /connectionString="Data Source=[YourProductionDatabase];Initial Catalog=[YourTable];Integrated Security=SSPI" /connectionProviderName="System.Data.SqlClient" /targetMigration="[NameofYourMigration]"
Documentation on migrate.exe can be found here: https://msdn.microsoft.com/en-us/data/jj618307.aspx
I am facing a problem with my UnitTest. I want to Test my Data-Access which is done using a repository based on NPoco. I have therefore written a couple of tests and the test project retrieves NUnit, NPoco, System.Data.SQLite, and some other Stuff via NuGet.
This is the app.config of the TestProject:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="RepositoryTests.Properties.Settings.ConnectionString" connectionString="Data Source=db.sqlite;Version=3" />
</connectionStrings>
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite"/>
<add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
</DbProviderFactories>
</system.data>
</configuration>
In VS, the Project builds fine. Triggering the tests in Visual Studio works as well.
Building the Projects with MSBUILD works as well. Running the tests via nunit after building them with msbuild.exe raises a Exception though:
Unable to find the requested .Net Framework Data Provider. It may not be installed.
This is only the case, when executing the tests using nunit directly (sth. like nunit-console.exe myproject.csproj /config:Release). Triggering them in VS is no problem.
Does anybody know how to solve this problem?
The problem is caused by the nunit test runner having its own app.config in which your settings are not present.
The simplest way to solve the problem is to move the configuration out of your app.config and into the code itself. Whatever you have in app.config can be done inside code.
Another solution is to move the configuration into a seperate file and then explicitly load that file's configuration using code. Just make sure that the file is copied to the output folder on build.
You could use something like:
public static class TestFactory
{
public static DatabaseFactory DbFactory { get; set; }
public static void Setup()
{
var fluentConfig = FluentMappingConfiguration.Configure(new OurMappings());
//or individual mappings
//var fluentConfig = FluentMappingConfiguration.Configure(new UserMapping(), ....);
DbFactory = DatabaseFactory.Config(x =>
{
// Load the connection string here or just use a constant in code...
x.UsingDatabase(() => new Database("connString");
x.WithFluentConfig(fluentConfig);
x.WithMapper(new Mapper());
});
}
}
See here for more details.
Then in the test fixture:
[TestFixture]
public class DbTestFixture
{
[TestFixtureSetUp]
public void Init()
{
TestFactory.Setup();
}
[Test]
public void YourTestHere()
{
var database = TestFactory.DbFactory.GetDatabase();
...
}
}
I got it working by creating an copy of the app.config-file and give that copy the name of the Test-Project, followed by .config. So if we assume, that the project is named Test.Project the copy must be named Test.Project.config. Nunit doesn't seem to load the automatically generated Test.Project.dll.config. This info can be found somewhat disguised in the NUnit-docs (Configuration Files -> Test Configuration File -> 3rd paragraph, last sentence).
In VS, in the Properties-Section of that copied file, i set the copy-to-output-directory-property to always.
Executing the tests with nunit-console.exe then lead to another exception (Bad-Image), which was caused by NUnit not finding the SQLite.Interop.dll-file. This could be solved kind of hacky by adding that file, which already resides in the x64 or x86 folder, as an existing element to the solution in VS and also setting the copy-to-output-dir-property to always.