Repository navigation
Feature Request - Add .Net Core 3.1 Support #2796
Description
Activity
- pinned this issue
on May 31, 2019 With #2767 it may be possible to load the next CefSharp release (75 at time of writing) with .Net Core 3.0 referencing the current .Net 4.5.2 framework assemblies. I have no personally tested this personally yet. You will have to avoid using the sync JavaScript Binding as it relies on WCF.
Reacted by Bernard Vander Beken, Konstantin Preißer, ourplan9000, Armin and Uwe Keimmichalczerwinski commented
on Jun 16, 2019 on Jun 16, 2019 · Hidden as resolvedshow commentMore actionsHi,
first, many thanks for this great project!I was able to successfully use
CefSharp.WinForms 75.0.110-CI3174on a .NET Core 3.0 (Preview 5) WinForms application (form title in the screenshot contains process filename andRuntimeInformation.FrameworkDescriptionwhen running withdotnet.exe):

I also tested that the
IDownloadHandlerwas working successfully.However, directly adding the NuGet package to the .NET Core project did not work as it didn't resolve the dependencies (probably because they are only declared for .NET Framework 4.5.2).
Instead, I first added it to a .NET Framework project and built it (so all the necessary files would be copied into the
binfolder), and then in the .NET Core 3.0 project I manually added references to theCefSharp.dll,CefSharp.Core.dllandCefSharp.WinForms.dllassemblies. Additionally, I copied all other files from thebinfolder of the .NET Framework app to thebinfolder of the .NET Core app.Another thing to consider is the browser subprocess (
CefSharp.BrowserSubprocess.exe) which is built for .NET Framework 4.5.2, meaning that you still would need to have .NET Framework 4.5.2 or higher installed to run the .NET Core 3.0 app.In order to avoid a dependency on .NET Framework and only use .NET Core, I think you will probably have to provide your own browser subprocess, implemented as a .NET Core app (using the same .NET Core version as your main app so that it can share runtime files when publishing a self-contained app).
(I haven't tested this yet.)Thank you!
Reacted by gokhanyuYou can try setting
<PackageTargetFallback>net452</PackageTargetFallback>in your project file which might restore the nuget package correctly.
https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets#packagetargetfallbackHi @campersau,
You can try setting
<PackageTargetFallback>net452</PackageTargetFallback>in your project file which might restore the nuget package correctly.Thanks for your suggestion! Unfortunately, it did not seem to have an effect when I added that setting to the project file - it still only added
CefSharp.WinForms.dllbut none of the dependencies. I guess the NuGet packages would need to have an additional .NET Core 3.0 target for this to work.
I also had a look at the browser subprocess, and I was also able to successfully provide the subprocess as .NET Core 3.0 app, to avoid a dependency on the .NET Framework 4.5.2.
However, actually using a different project for the subprocess might be a bit cumbersome with .NET Core because the build results (binaries) might different for a normal (framework-dependent) app (e.g. when debugging in Visual Studio) compared to a published (self-contained) app etc., and you would need to copy the correct subprocess binaries near your app binaries each time.I think the easiest way to use CEFSharp including the browser subprocess in .NET Core 3.0 might be to use the same executable for both your regular WinForms app and the browser subprocess.
To test this, I added a reference to
CefSharp.BrowserSubprocess.Core.dllto my .NET Core 3.0 WinForms project, setCefSettings.BrowserSubprocessPath = Process.GetCurrentProcess().MainModule.FileName, and then used aMain()method like this (as I noticed the subprocess will be called with a--type=....argument):[STAThread] static int Main(string[] args) { if (args.Length > 0 && args[0].StartsWith( CefSharpArguments.SubProcessTypeArgument + "=", StringComparison.Ordinal)) { // Run the CEFSharp browser subprocess. return RunBrowserSubprocess(args); } else { // Run the regular application. RunGui(); return 0; } }
Here,
RunBrowserSubprocess()would contain the code from theMain()method of CefSharp.BrowserSubprocess, andRunGui()would do the regularApplication.Run(new Form1()).
(The code ofRunBrowserSubprocess()could also be implemented as utiltiy method in the .NET Core 3.0 package of CefSharp.)This means you won't have to bother with building and copying the correct subprocess executable before running your main application.
(A minor disadvantage of this is that you cannot implement the command line argument--type=for your own use.)What do you think?
Thanks!Reacted by Alexander TäschnerFuture reference for myself https://github.com/dotnet/samples/tree/master/core/hosting/HostWithHostFxr
Regarding the subprocess handling for .NET Core, my idea was the following:
- Switch project
CefSharp.BrowserSubprocessto the .NET Core SDK and multi-target fornet452andnetcoreapp3.0, so that fornet452the result is a EXE (like today) and fornetcoreapp3.0the result is a DLL, e.g.:
<PropertyGroup> <TargetFrameworks>net452;netcoreapp3.0</TargetFrameworks> ... </PropertyGroup> <PropertyGroup Condition="'$(TargetFramework)'!='netcoreapp3.0'"> <OutputType>WinExe</OutputType> <ApplicationManifest>app.manifest</ApplicationManifest> <Prefer32Bit>false</Prefer32Bit> </PropertyGroup>
- Make the
Program.Mainmethod internal and add a public method like the following that is only compiled for .NET Core:
#if NETCOREAPP public static class CefSharpBrowserSubprocess { public static void HandleSubprocess() { // Check if the first argument starts with "--type=", in which case // we run the subprocess logic. Otherwise, we simply return and allow // the app run its own logic. var args = Environment.GetCommandLineArgs().Skip(1); if (args.HasArgument(CefSharpArguments.SubProcessTypeArgument + "=")) { // Run the subprocess. int exitCode = Program.Main(args.ToArray()); // Exit directly so that the remaining application logic is not run. Environment.Exit(exitCode); } } } #endif
- Adjust the NuGet files so that for projects targeting .NET Core, a reference to
CefSharp.BrowserSubprocess.dllis added. - In
CefSharp.Core, adjustCefSettings.BrowserSubprocessPathto specify"CefSharp.BrowserSubprocess.exe"when running on .NET Framework, and specify the current executable path when running on .NET Core (this can be done with a runtime check, e.g. usingRuntimeInformation.FrameworkDescription; but that would require compiling for .NET Framework 4.7.1 or higher).
That way, a user could modify the
Mainmethod in a WinForms project like this when adding CefSharp:[STAThread] static void Main() { Application.SetHighDpiMode(HighDpiMode.SystemAware); + + // Handle the CefSharp browser subprocess logic on start-up. + CefSharpBrowserSubprocess.HandleSubprocess(); + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); }In this case, the application executable would also run the browser subprocess logic, and a separate EXE is no longer needed.
With that change, I think the only other thing needed is to adjust the NuGet spec files to declare dependencies to
.NETCoreApp3.0so the dependencies will resolve when compiling for .NET Core.
(Note: The logic that currently allows to compile .NET Framework projects forAnyCPUmight no longer work on .NET Core, but that shouldn't be a big issue because you will probably publish a self-contained application which is platform-specific.)
On a related note, I think using the same executable for the app and the browser subprocess will also solve a rendering issue that we experienced with a WPF app using
CefSharp.WinForms: When moving the window between monitors with different DPI settings, the browser control starts to display some contents in an incorrect size when moving the mouse, like this:

This seems to occur because the subprocess executable (
CefSharp.BrowserSubprocess.exe) declares<dpiAware>true/PM</dpiAware>(per-monitor DPI aware V1), whereas in our case the application only supports<dpiAware>true</dpiAware>(System DPI aware).Whereas when using the same executable, both processes will use the same DPI settings, so this issue will no longer occur there.
What do you think?
Thanks!
Reacted by Alexander Täschner and Faryan RezagholiReacted by Faryan RezagholiReacted by Christopher-Marcel Esser- Switch project
@kpreisser Thanks for the very detailed summaries, some very useful insights 👍
- Switch project
CefSharp.BrowserSubprocessto the .NET Core SDK and multi-target fornet452andnetcoreapp3.0, so that fornet452the result is a EXE (like today) and fornetcoreapp3.0the result is a DLL, e.g.:
For simplicity we'll just rewrite the
Mainmethod inVC++and move the code intoCefSharp.BrowserSubprocess.Core- Make the
Program.Mainmethod internal and add a public method like the following that is only compiled for .NET Core:
Will keep the changes to
CefSharp.BrowserSubprocessat a minimum, replace theMainbody with a simple call to a method inCefSharp.BrowserSubprocess.Corethat codes the actual work, this can be reused. Will need some fairly descriptive comments.- Adjust the NuGet files so that for projects targeting .NET Core, a reference to
CefSharp.BrowserSubprocess.dllis added.
My initial plan is to create a new
CefSharp.DotNetCoreNuget package, it'll depend onCefSharp.Commonand add the required include forCefSharp.BrowserSubprocess.Core.dll, only minor changes will need to be made to theNugetpackages to support this.- In
CefSharp.Core, adjustCefSettings.BrowserSubprocessPathto specify"CefSharp.BrowserSubprocess.exe"when running on .NET Framework, and specify the current executable path when running on .NET Core (this can be done with a runtime check, e.g. usingRuntimeInformation.FrameworkDescription; but that would require compiling for .NET Framework 4.7.1 or higher).
Some sort of runtime check would be idea, will have to investigate alternatives as
.Net 4.5.2is our current target (I still get people asking to target.Net 4.0). Alternatively we'll provide some sort of helper class in the newDotNetCorespecificNugetpackage.With that change, I think the only other thing needed is to adjust the NuGet spec files to declare dependencies to
.NETCoreApp3.0so the dependencies will resolve when compiling for .NET Core.What does declare dependencies to
.NETCoreApp3.0actually get us? As it stands I don't see any great benefit in compiling an actual.Net Corespecific set of dlls as the current ones appear to load correctly. If we can work out a runtime check then we'll add that to any calls that would requireWCFso that users get an exception.This seems to occur because the subprocess executable (
CefSharp.BrowserSubprocess.exe) declares<dpiAware>true/PM</dpiAware>(per-monitor DPI aware V1), whereas in our case the application only supports<dpiAware>true</dpiAware>(System DPI aware).It's hard to please everyone, the general idea is to provide a sensible set of defaults and let you customise as required. I rewrote the entire
CefSharp.BrowserSubprocess.exequite some time ago so it's just a single file, makes it easy to implement your own when the need arises.- Switch project
Hi @amaitland,
thanks for your reply!
For simplicity we'll just rewrite the
Mainmethod inVC++and move the code intoCefSharp.BrowserSubprocess.CoreWill keep the changes to
CefSharp.BrowserSubprocessat a minimum, replace theMainbody with a simple call to a method inCefSharp.BrowserSubprocess.Corethat codes the actual work, this can be reused. Will need some fairly descriptive comments.Agreed, that way no change to the project file for
CefSharp.BrowserSubprocessis needed - the .NET Core project can then referenceCefSharp.BrowserSubprocess.Core.dllto call that method.What does declare dependencies to
.NETCoreApp3.0actually get us? As it stands I don't see any great benefit in compiling an actual.Net Corespecific set of dlls as the current ones appear to load correctly. If we can work out a runtime check then we'll add that to any calls that would requireWCFso that users get an exception.Sorry, actually here I only meant that the
.nuspecfile probably needs a<group targetFramework=".NETCoreApp3.0">element in addition to<group targetFramework=".NETFramework4.5.2">, so that the transitive dependencies to the other NuGet packages will be resolved correctly for .NET Core projects. The projects itself (CefSharp.WinFormsetc.) don't need to be changed, because like you said the binaries for .NET Framework 4.5.2 already work on .NET Core 3.0.For example, right now if I create a new .NET Core 3.0 project and add
<PackageReference Include="CefSharp.WinForms" Version="75.1.141" />, then the project will have a reference toCefSharp.WinForms, but is missing references toCefSharp.Common,CefSharpetc. and the redist files. Instead I currently have to manually add packages for all references:<PackageReference Include="CefSharp.WinForms" Version="75.1.141" /> <PackageReference Include="CefSharp.Common" Version="75.1.141" /> <PackageReference Include="cef.redist.x64" Version="75.1.14" /> <PackageReference Include="cef.redist.x86" Version="75.1.14" />
However, this also does not yet work in the .NET Core 3.0 project because at runtime it will not find
CefSharp.WinForms.dlleven though the file exists. I think this is because the reference is declared private inCefSharp.WinForms.props:<ItemGroup> <Reference Include="CefSharp.WinForms"> <HintPath>$(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.WinForms.dll</HintPath> <Private>False</Private> </Reference> </ItemGroup>This seems to have the effect that the dependency is not specified in the
.deps.jsonfile when building the project, so that the .NET Core CLR doesn't load the assembly. It should work when using<Private>True</Private>(but I guess this change would mean that the support forAnyCPUwould no longer work; but as said I think we can ignore that for .NET Core projects).
To summarize, CefSharp.WinForms already works today on a .NET Core 3.0 WinForms project (created with
dotnet new winforms) when using a project file like the following, and setting the<Platform>explicitely tox64orx86depending on the used .NET Core runtime – provided that .NET Framework 4.5.2 or higher is installed on the machine as that is currently used byCefSharp.BrowserSubprocess.exe:<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <RootNamespace>MyNetCoreApp</RootNamespace> <UseWindowsForms>true</UseWindowsForms> <Platforms>x86;x64</Platforms> </PropertyGroup> <ItemGroup> <PackageReference Include="CefSharp.WinForms" Version="75.1.141" /> <PackageReference Include="CefSharp.Common" Version="75.1.141" /> <PackageReference Include="cef.redist.x64" Version="75.1.14" /> <PackageReference Include="cef.redist.x86" Version="75.1.14" /> </ItemGroup> <ItemGroup> <Reference Update="CefSharp"> <Private>true</Private> </Reference> <Reference Update="CefSharp.Core"> <Private>true</Private> </Reference> <Reference Update="CefSharp.WinForms"> <Private>true</Private> </Reference> </ItemGroup> </Project>
Thanks!
Additionally, I found that the condition in
CefSharp.WinForms.targetscurrently checks for thePlatformVariable like this:<When Condition="'$(Platform)' == 'x64'">
Maybe this needs to be changed to use
PlatformTargetinstead ofPlatform, because e.g. when you publish a self-contained .NET Core app withdotnet publish -f netcoreapp3.0 -r win-x64, thePlatformTargetwill bex64, butPlatformwill still beAnyCPU; thus the check will currently fail.Thanks!
For example, right now if I create a new .NET Core 3.0 project and add
<PackageReference Include="CefSharp.WinForms" Version="75.1.141" />, then the project will have a reference toCefSharp.WinForms, but is missing references toCefSharp.Common,CefSharpetc. and the redist files. Instead I currently have to manually add packages for all references:It was my understanding (and that's a limited understanding at this point) that transitive dependencies meant that only top level references were included?
This seems to have the effect that the dependency is not specified in the
.deps.jsonfile when building the project, so that the .NET Core CLR doesn't load the assembly. It should work when using<Private>True</Private>(but I guess this change would mean that the support forAnyCPUwould no longer work; but as said I think we can ignore that for .NET Core projects).The files should be copied via the
.targetsfile. What you are seeing may actually be the same as #2642Additionally, I found that the condition in
CefSharp.WinForms.targetscurrently checks for thePlatformVariable like this:The current packages require that you set the solution target, this is a current limitation.
Maybe this needs to be changed to use
PlatformTargetinstead ofPlatform, because e.g. when you publish a self-contained .NET Core app withdotnet publish -f netcoreapp3.0 -r win-x64, thePlatformTargetwill bex64, butPlatformwill still beAnyCPU; thus the check will currently fail.Last I checked this isn't possible,
PlatformTargetis defined after the.propsfiles are included, so it's not actually set early enough to be useful.If you have the time to contribute a
.Net Coreexample to https://github.com/cefsharp/CefSharp.MinimalExample that would make debugging/testing much easier.Hi @amaitland,
For example, right now if I create a new .NET Core 3.0 project and add
<PackageReference Include="CefSharp.WinForms" Version="75.1.141" />, then the project will have a reference toCefSharp.WinForms, but is missing references toCefSharp.Common,CefSharpetc. and the redist files. Instead I currently have to manually add packages for all references:It was my understanding (and that's a limited understanding at this point) that transitive dependencies meant that only top level references were included?
Sorry, I'm not sure if I fully understood what you say here. With 'transitive reference', I meant that if project
MyWinFormsAppreferencesCefSharp.WinForms, andCefSharp.WinFormsreferencesCefSharp.Common, thenMyWinFormsAppwill also get a (transitive) reference toCefSharp.Common.I don't have detailed knowledge about how NuGet packages work, but I think that when the
.nuspecfile ofCefSharp.WinFormswould be changed to contain the following:<dependencies> <group targetFramework=".NETFramework4.5.2"> <dependency id="CefSharp.Common" version="[75.1.141]" /> </group> <group targetFramework=".NETCoreApp3.0"> <dependency id="CefSharp.Common" version="[75.1.141]" /> </group> </dependencies>
then
CefSharp.Commonshould be correctly included when the project only contains<PackageReference Include="CefSharp.WinForms" Version="75.1.141" />. VS will then display the package references as follows:

Currently, when using a .NET Core 3.0 project I also have to add
<PackageReference Include="CefSharp.Common" Version="75.1.141" />, and the VS will display the packages like this:

The files should be copied via the
.targetsfile. What you are seeing may actually be the same as #2642Actually, the files are copied correctly into the output directory, but because the
<Reference>element contains<Private>false</Private>, the references to these DLLs will not be specified in the<exe>.deps.jsonfile when compiling the project, which means the CoreCLR will not load them (as AFAIK it will only load libraries that are specified in that JSON file).Last I checked this isn't possible,
PlatformTargetis defined after the.propsfiles are included, so it's not actually set early enough to be useful.OK, thanks. It might be worth to check if this is also the case with SDK-style (.NET Core) projects.
If you have the time to contribute a
.Net Coreexample to https://github.com/cefsharp/CefSharp.MinimalExample that would make debugging/testing much easier.OK, I will submit a PR with a minimal .NET Core example.
Thank you!
Was testing @kpreisser's method of adding all packages individually and adding the private true in a WPF project and got the following error:
Unable to find an entry point named 'CopyMemory' in DLL 'kernel32.dll'.'
Looking around i found [https://github.com/dotnet/coreclr/issues/24008]https://github.com/dotnet/coreclr/issues/24008 where @vatsan-madhavan points out that:
In .NET Framework there was a special case for a few function names and CopyMemory happened to be one of them. The special case was removed in .NET Core. In order to address this in your code, please update the attribute to include the following: [DllImport EntryPoint="RtlMoveMemory"]. If the EntryPoint property is set as above, the P/Invoke will work in both .NET Framework and .NET Core
Its not just CopyMemory, as you can see in [https://github.com/dotnet/pinvoke/issues/431]dotnet/pinvoke#431, other memory related functions are also affected - MoveMemory, CopyMemory, FillMemory and ZeroMemory at least
Reacted by Vatsan Madhavan52 remaining items
amaitland commented
on Jan 9, 2021 on Jan 9, 2021 · Hidden as outdatedAuthorshow commentMore actions- changed the title
[-]Feature Request - Add .Net Core 3.x Support[/-][+]Feature Request - Add .Net Core 3.1 Support[/+]on Jan 9, 2021 - unpinned this issue
on Jan 15, 2021 The first official release to support
.Net Core 3.1is now available onNuget.org- https://www.nuget.org/packages/CefSharp.WinForms.NETCore/87.1.132
- https://www.nuget.org/packages/CefSharp.Wpf.NETCore/87.1.132
- https://www.nuget.org/packages/CefSharp.OffScreen.NETCore/87.1.132
- A minimum of
.Net Core 3.1is required (for.Net 3.0which is no longer supported byMicrosoftyou'll need to use the older packages). - The MinimalExample has been updated for testing purposes.
- These packages required Visual C++ 2019
They should work for both
.Net Coreand.Net 5.0. In a version of two I'll change the mainCefSharp.WinForms/Wpf/OffScreenpackages to be just meta packages and create a set ofNet452packages, soNugetwill choose the correct package based on framework.See #3284 (comment) for further details.
@amaitland won't the multiple targeting just work ? why create a metapackage instead of direct use multiple-targeting ?
won't the multiple targeting just work ?
@John0King What do you mean by this exactly?
The new net core packages only contain a set of dlls compiled with .Net Core 3.1, whilst the original Nuget package contain dlls compiled using .Net 4.5.2.
@amaitland I'm not familiar with c++/cil , but in just c#, we can just multiple-targeting the
targetframeworks
eg.<TargetFrameworks>net451;net5.0</TargetFrameworks>
and in old formate with.nupkgfile can also do that.it's on nuget package contains multiple set of dlls for different TFM , and will choose the correct dll base on the TFM of user's class library
I'm not familiar with c++/cil
@John0King See #2796 (comment) (which links to https://docs.microsoft.com/en-us/dotnet/core/porting/cpp-cli#ccli-net-core-limitations). There is no multi targeting for C++/CLI or support for the newer SDK project format.
it's on nuget package contains multiple set of dlls for different TFM , and will choose the correct dll base on the TFM of user's class library
Having a single package that contains all versions is a nice idea in theory, the reality is that C++/CLI project support currently makes this very complicated.
In theory the meta package will have the same result from an end user point of view (or at least that's my current understanding).
Reacted by Patrick MorrisAfter reading all the previous comments, I would like to summarize the facts regarding AnyCpu support with .NET Core 3.1.
Is it correct that there is no AnyCpu support for .NET Core 3.1?Is there any example showing the steps needed when someone would like to upgrade from .NET 4.8 with AnyCPU support to the .NET Core 3.1 version?
After reading all the previous comments, I would like to summarize the facts regarding AnyCpu support with .NET Core 3.1.
Is it correct that there is no AnyCpu support for .NET Core 3.1?There is kind of AnyCPU support in .NET Core, when you don't specify a
RuntimeIdentifier(andPlatform) when building a project. In that case, there will be aruntimesdirectory in your project'sbinfolder containing the runtime files for various architectures likewin-x64,win-x86,linux-x64, etc., and then the runtime will dynamically load the ones for the current architecture/OS. This should also work with theCefSharp.NETCorepackages, but @amaitland noted that this might not work in all cases:I strongly suggest setting a RuntimeIdentifier. I've done my best to make it work when no RuntimeIdentifier is specified, there are probably use cases when you will need to specify one for it to work.
However, generally there is no "real" AnyCPU suppot in .NET Core/.NET 5 for application projects, because when building the application, the apphost (
<application>.exeon Windows) will have a specific architecture (x64,x86,arm, orarm64), so the process will only run with that specific architecture. (Except when you run the application withdotnet <application>.dll, which will use the architecture of thedotnethost, but I think that isn't recommended for GUI applications.)This is different from .NET Framework
.exefiles that are compiled asAnyCPU, which use a special feature of the OS to either run as x64 or as x86 (32-bit), depending on the OS architecture.Reacted by johnamaitland commented
on Apr 29, 2021 on Apr 29, 2021 · Hidden as off-topicAuthorshow commentMore actions
With .Net Core 3.0 adding support for WPF and WinForms I'm seeing more and more queries about running CefSharp using .Net Core 3.0. This issue will track the official progress, there is no timeframe yet, please don't ask when this will be implemented, .Net Core isn't even officially out yet. As per https://github.com/dotnet/core/blob/master/roadmap.md#upcoming-ship-dates the release is still some months away.
Microsoft has started implementing C++/CLI as part of .Net Core you can track the issue https://github.com/dotnet/coreclr/issues/18013 They are only adding support for Windows initially. See also https://github.com/dotnet/coreclr/issues/659
.Net Corewill support mixed mode assemblies on Windows Only.https://devblogs.microsoft.com/dotnet/net-core-3-and-support-for-windows-desktop-applications/
The sync JavaScript Binding implementation will not work as Microsoft is not supporting WCF in .Net Core 3.0.