I'm migrating a custom ORM library from .NET Framework 4.5 to .NET standard 2.0. I've configured the solution to be multitarget: .NET Framework 4.5.2 and .NET Core 2.2.
The biggest change is how to manage the Configuration files in .NET Core.
The library is made to refer always to the internal config file (that use ConfigurationManager) to retrieve all kind of configuration options, even the connectionstrings.
Here is an example on how this config class is structured
public static class MyConfig
{
public static string MyCnString
{
get
{
if (string.IsNullOrEmpty(_mycnstring))
_mycnstring=ConfigurationManager.ConnectionStrings["mycnstring"]
return _mycnstring;
}
}
public static string MySetting
{
get
{
if (string.IsNullOrEmpty(_myappsetting))
_myappsetting = ConfigurationManager.AppSettings["MyAppSetting"];
return _myappsetting;
}
}
}
This class is mainly used inside the library.
Now I would like to understand how to refactor this class to be .NET core compatible, and allow the library to be used in .NET Core app or Site.
I cannot figure how to use IConfiguration or IOption in a startup.cs to initilize the MYCOnfig class and then be used as a static class by the library as in .NET Framework.
Related
I have an issue where I need to upgrade my projects to the latest version of .NET, currently all projects are .NET 4.7 or .NET Standard 2.0 using Entity Framework 6 this is then exposed through a WCF service which gets its instantiations via Unity.
The plan was to start with an upgrade from EF 6 to EF Core 3 and then also decouple it using Inversion of control to be able to change the underlying data access if needed, this has been started with all repository calls reference the interface IMyDbContext and seems to be okay.
Now i have an issue of how to resolve IMyDbContext from the Unity container in the WCF app given that it is .Net 4.7 and the project containing MyDbContext is .net core 3.
Any pointers/references would be greatly appreciated.
For a solution with multiple projects, some on .Net Framework and some on .Net Core I use something like this:
public class MyContext : DbContext
{
static MyContext()
{
Database.SetInitializer<MyContext>(null);
}
[InjectionConstructor] //Used to specify the constructor to Unity
public MyContext()
: base("Name=MyContext")
{
}
public MyContext(string connectionString) //Used to resolve de dependency in .net Core
: base(connectionString)
{
}
}
Startup.cs in .Net Core MVC project
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddScoped<MyContext>(_ => new MyContext(Configuration.GetConnectionString("DefaultConnection")));
}
And in the .Net Framework project is passed as a parameter to a repository, IDoStuffRepo, which is registered like this:
public override void Initialize(){
this.Container.RegisterType<IDoStuffRepo, DoStuffRepo>(new DisposableTransientLifetimeManager());
}
I want to build a WPF app that uses entity framework core so that I can handle SQLite databases.
I then do the following, for instance:
Using Visual Studio 2017 (15.5.2), create a WPF application.
Open the nuget package manager and install Microsoft.EntityFrameworkCore.Sqlite and Microsoft.EntityFrameworkCore.Tools.
Drop a button onto my MainWindow.xaml and add an event handler to the Click event such that the xaml looks like:
<Window x:Class="WPFEFCoreDeploymentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Click="ButtonBase_OnClick"></Button>
</Grid>
</Window>
Drop the following code onto the code behind file MainWindow.xaml.cs
namespace WPFEFCoreDeploymentTest
{
using System.Linq;
using System.Windows;
using Microsoft.EntityFrameworkCore;
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
using (var context = new SomeContext())
{
if (context.Database.GetPendingMigrations().Any())
{
context.Database.Migrate();
}
}
}
}
public class SomeContext : DbContext
{
public DbSet<Test> Tests { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=local.db");
}
}
public class Test
{
public int Id { get; set; }
}
}
Use package manager console to create the migration script: Add-Migration Migration1
Build and run the application
Now, if I go to the bin/Debug folder for my project, I notice that there are many DLLs that I assume to be the .NET core's implementation of the .NET standard (maybe I'm just being very stupid), for instance:
System.Collections.Immutable.dll
System.ComponentModel.Annotations.dll
System.Data.Common.dll
System.Net.Http.dll
the list goes on
So, if I understand correctly, when no redirects are added to the config app.config, these signed assemblies have to be accessible to the executable, meaning if I create an installer, I have to deploy these assemblies along with my application. But .NET framework already implement these, and .NET framework must be installed if someone wants to execute the WPF application on their machines. This makes me wonder:
Can I replace these .net core implementation assemblies with .net framework's implementation? Is it possible?
If the former point is technically possible, should it work or this may create all sorts of problems?
If not possible, is it expected that mixing both .net framework and .net core will potentially lead to having duplicate implementations of assemblies referenced directly or indirectly by your application (maybe other modules of my application uses .net framework's System.Net.Http.dll classes but EF core or its dependencies references .net core's System.Net.Http.dll as well)?
Short answer to:
Can I replace these .net core implementation assemblies with .net
framework's implementation? Is it possible?
No. If your application is written in .NET Core you can't. Also you shouldn't. I would rather go with the .NET Core assemblies, when possible.
Edit:
Because you are using .NET Framework for your WPF appliation already you could uninstall the .NET Core implementations and just install the .NET Framework. But if you play to go with your app on another platform than windows you should be going with .NET Core assemblies.
I'm trying to get .Net Framework and NetStandard assemblies to communicate with each other (to learn what is possible). I currently have four projects, two Framework 4.5.2 projects and two NetStandard1.2 projects:
Framework452.Library
NetStandard12.CentralLibrary
NetStandard12.BaseLibrary
Framework452.Tests
The referencing structure is:
Framework452.Tests references NetStandard12.CentralLibrary: working by adding the NetStandard.Library nuget package to Framework452.Tests.
NetStandard12.CentralLibrary references NetStandard12.BaseLibrary: working without modification.
NetStandard12.CentralLibrary references Framework452.Library: Not working, even when Framework452.Library has the NetStandard.Library nuget package installed.
Can NetStandard projects reference Framework projects? If so, what do I need to do to get them to communicate? At the moment I can add the reference, but it is not visible to the code.
Update
I recreated the solution and added the code below, which when I try to compile gives the following error from the Framework452.Tests project:
Error CS0006: Metadata file
'~\TryNETStandard\NetStandard12.CentralLibrary\bin\Debug\netstandard1.2\NetStandard12.CentralLibrary.dll'
could not be found.
namespace Framework452.Library
{
public class Returner452 {
public static bool ReturnTrue() { return true; }
}
}
using Xunit;
namespace Framework452.Tests
{
public class Class1 {
[Fact]
public void FrameworkTest() {
Assert.True(NetStandard12.CentralLibrary.Class1.Return452());
}
[Fact]
public void NetStandardTest() {
Assert.True(NetStandard12.CentralLibrary.Class1.Return12());
}
}
}
namespace NetStandard12.BaseLibrary
{
public class Returner12 {
public static bool ReturnTrue() { return true; }
}
}
using Framework452.Library;
using NetStandard12.BaseLibrary;
namespace NetStandard12.CentralLibrary
{
public class Class1
{
public static bool Return452() { return Returner452.ReturnTrue(); }
public static bool Return12() { return Returner12.ReturnTrue(); }
}
}
According to this page https://learn.microsoft.com/en-us/dotnet/standard/net-standard#net-platforms-support you should be able to achieve your purpose because .NET Standard 1.2 support .NET Framework 4.5.1 (UPDATE: This statement is not 100% correct. Please see the Update section below.)
I tried to set up a solution in VS 2017 and set the references as you described. Here is the result.
and this is the Class1.cs in NetStandard12.CentralLibrary
The code compiles fine without any errors.
Note: your code may fail if the Framework452.Library uses an API that is not supported by .NET Standard 1.2 (e.g Winforms, Win32 API or any Microsoft proprietary library that does not make sense for cross platform).
I recommend this youtube playlist on the .NET standard introduction from one of the MSFT https://www.youtube.com/watch?v=YI4MurjfMn8&list=PLRAdsfhKI4OWx321A_pr-7HhRNk7wOLLY
In .NET Standard - Checking Compatibilty , he recommended tools to help you find out what API is not supported in the .NET Standard.
Thing will become easier with .NET Standard 2.0 and 'compat shim'
UPDATE:
After trying again with more data provided by the question, it's true that a library targeting (depends) .NET Standard could not depend on a library that target .NET Framework. For some strange reason, the compiler allows me to compile the example that I gave above. This could be a bug in tooling.
After a little more research, I found a good example demonstrate the relationship between NetStandard and NetFramework: How .NET Standard relates to .NET Platform.
The graph here show the dependencies
According to the graph, there is no way a library that depends on .NET Standard could see/use the .NET framework implementation.
When .NET Standard 2 is released, this may change a little bit and you could reference .NET Framework via Compatibility Shim. See this video for more in-depth explanation https://youtu.be/vg6nR7hS2lI?list=PLRAdsfhKI4OWx321A_pr-7HhRNk7wOLLY&t=169
No, .NET Standard projects cannot reference framework projects.
.NET Standard projects need to be usable across platforms, forcing a dependency on the .NET framework by referencing an assembly targeting it makes this impossible.
Note that with some of the magic Microsoft is doing with .NET Standard 2.0 this is less true but the overall idea still stands.
We've got a .NET Framework .dll that we're porting to .NET Core. Currently we're inheriting from ConfigurationElement and ConfigurationSection from System.Configuration to create custom configuration sections in the app.config (or it's .NET Core equivalent)
Questions:
It appears the .NET Core way is Microsoft.Extensions.Configuration. Is that correct? Because it lives on ASP.NET Core's github project instead of .NET Core's github project. We have no ASP parts.
If so, any .NET Core examples on creating and loading custom configuration sections not relying on startup.cs ? Ideally we'd like to read from a text source (XML or JSON) directly into a POCO object graph for strongly typed benefits.
With .NET Core 2.0, will there be any support for the traditional ConfigurationElement and ConfigurationSection negating the need for any such porting efforts to begin with ? Reason I ask is the .NET Core 2.0 Roadmap says
.NET Core gain over 5,000 APIs from .NET Framework as part of this work making it a broader platform.
I am not aware of app.config and System.Configuration support in .NET Core. Probably, no, but that's just a guess. You can setup configuration for .NET Core application in Main method:
class Program
{
static void Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var poco = new Poco();
configuration.Bind(poco);
Console.WriteLine(poco);
Console.ReadKey();
}
}
class Poco
{
public bool Enabled { get; set; }
public Sort Sort { get; set; }
public override string ToString()
{
return $"Enabled={Enabled}, SortOrder={Sort.Order}";
}
}
class Sort
{
public int Order { get; set; }
}
appsettings.json is following:
{
"enabled": true,
"sort": {
"order": 2
}
}
Outputs:
Enabled=True, SortOrder=2
You need to reference Microsoft.Extensions.Configuration.Json and Microsoft.Extensions.Configuration.Binder packages.
No dependency on ASP.NET Core.
Microsoft.Extensions.Configuration is quite extensible, it can use different settings providers like environment variables, command line arguments, etc. So it is possible to implement custom provider for ConfigurationSection-like configuration if needed.
Based on this comment they are not going to bring System.Configuration to NetStandard 2.0.
With the dust settling down from .NET Standard 2.0 release it is possible to use your usual System.Configuration even in .NET Core 2.0 on Linux!
Here is a test example:
Created a .NET Standard 2.0 Library (say MyLib.dll)
Added the NuGet package System.Configuration.ConfigurationManager v4.4.0. This is needed since this package isn't covered by the meta-package NetStandard.Library v2.0.0
All your C# classes derived from ConfigurationSection or ConfigurationElement go into MyLib.dll. For example MyClass.cs derives from ConfigurationSection and MyAccount.cs derives from ConfigurationElement. Implementation details are outof scope here but Google is your friend
Create a .NET Core 2.0 app (e.g. a console app, MyApp.dll). .NET Core apps end with .dll rather than .exe in Framework.
Create an app.config in MyApp with your custom configuration sections. This should obviously match your class designs in #3 above. For example:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="myCustomConfig" type="MyNamespace.MyClass, MyLib" />
</configSections>
<myCustomConfig>
<myAccount id="007" />
</myCustomConfig>
</configuration>
That's it - you'll find that the app.config is parsed properly within MyApp and your existing code within MyLib works just fine. Don't forget to run dotnet restore if you switch platforms from Windows (dev) to Linux (test).
Besides described way of migration to Microsoft.Extensions.Configuration (which totally makes sense) as it should (at least I hope) be possible to use the same types from System.Configuration on .NET Core 2.
Here's System.Configuration types in corefx:
https://github.com/dotnet/corefx/tree/master/src/System.Configuration.ConfigurationManager
I can't tell you that they are fully compatible with the ones from full .NET. But at least it's something that takes us a hope )
So it looks like .NET Core 2 will have that old System.Configuration stuff but not netstandard2. Probably it's because MS doesn't want to share these types among other platforms (Xamarin).
I have been developing a managed extensibility framework application for the last several months using the community preview. I have been using the GetExportedValues() method and the PartCreationPolicy(CreationPolicy.NonShared) to fake a class factory (since only the silverlight version supports a factory). This was working great until I upgraded the project to use .net 4.0. There is no error, it just doesn't work.
So why did this code stop working? The code follows:
The factory method:
public static IEnumerable<DataActionBase> GetActionsFromDirectory(string PluginsFolder)
{
IEnumerable<DataActionBase> result = null;
var catalog = new DirectoryCatalog(PluginsFolder);
var container = new CompositionContainer(catalog: catalog);
result = container.GetExportedValues<DataActionBase>();
return result;
}
Example Export Class:
[Export(typeof(DataActionBase))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class AnAction : DataActionBase
{
....
}
Have you recompiled your extensions against .NET 4.0? If the extensions reference the codeplex preview version of MEF, then the .NET 4.0 MEF won't pick them up. This is because the export attribute would be coming from an assembly with a different strong name, which .NET 4.0 MEF knows nothing about.