We previously discussed that COM Interop does not function in .NET Core 1.0. What about .NET Core 2.0? The answer is YES… with limitations.
The first and most obvious is that COM Interop only works with Windows, not other platforms.
The second limitation is that the .NET Core implementation does not include IDispatch, which means that late binding is not supported. Almost 10 years ago, Microsoft introduced the dynamic keyword in C# 4.0, which made late binding with COM and other platforms much easier.
dynamic excel = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application", true)); excel.Visible = true; Console.WriteLine("Press Enter to close Excel."); Console.ReadLine(); excel.Quit();
The above code will function in .NET Framework, but in .NET Core 2.0, an exception occurs:
‘System.__ComObject’ does not contain a definition for ‘Visible’
If you look in Task Manager, you’ll see that Excel.exe has indeed started, but the object members cannot be access directly without IDispatch. To work around this, you can use interop techniques that pre-date the dynamic keyword.
Interop assemblies are wrappers that enable .NET Core to interact with COM objects using early binding. Microsoft provides interop assemblies for Office automation on NuGet and elsewhere. Once the assemblies are installed, this code will work:
using Excel = Microsoft.Office.Interop.Excel; ... var excel = new Excel.Application(); excel.Visible = true; Console.WriteLine("Press Enter to close Excel."); Console.ReadLine(); excel.Quit();
Aside: For web applications, Office automation is not recommended. Check out the Open XML SDK.
What about your own COM objects? .NET Core projects do not provide a means to reference them directly. However, you can create a .NET Framework 4.x project and add a reference to the COM object. This will create an Interop.MyCOMObject.dll assembly in the obj/Debug folder, which you can then reference directly in the .NET Core project.
A COM object may return other objects that are not part of the type library, and early binding is not an option. This happens often in my Visual FoxPro interop code. You can use reflection to access the object members.
object excel = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application", true)); excel.GetType().InvokeMember("Visible",BindingFlags.SetProperty, Type.DefaultBinder, excel, new object[] { true }); Console.WriteLine("Press Enter to close Excel."); Console.ReadLine(); excel.GetType().InvokeMember("Quit", BindingFlags.InvokeMethod, null, excel, null);
The dynamic keyword makes for more natural code, but you can make reflection less cumbersome than above with your own wrapper methods.
For the adventurous, the Powershell team has created their own implementation of IDispatch. I don’t know how reusable this implementation is, but it may be worth a look.
If you’re using in-process (DLL) COM servers, be aware of 32-bit vs 64-bit issues. For web applications, take a look a Rick Strahl’s post on STA components. I don’t know if these techniques are available in .NET Core. In my experience, these issues do not apply with out-of-process (EXE) COM servers, but your mileage may vary.
Lastly, keep in mind that ASP.NET Core 2.0 continues to run on .NET Framework 4.x, in addition to .NET Core. If you’re already restricted to Windows, there aren’t many reasons to prefer .NET Core over the full framework (yet), so it remains the best option for COM Interop. That said, it’s good to know these possibilities exist with .NET Core.
Microsoft has been choosy about what they bring over to .NET Core. Over time, they have been finding their way towards more parity with .NET Framework. It was recently announced that WinForms/WPF will be coming to .NET Core 3.0. They may find that a lot of existing code relies on late binding. I would not be surprised if IDispatch makes a comeback.
” Lastly, keep in mind that ASP.NET Core 2.0 continues to run on .NET Framework 4.x, in addition to .NET Core.”
Any source on this statement?
There was actually some controversy about this during ASP.NET Core 2.0 preview. At the time, it only ran on .NET Core, but by release it ran on full framework. I am currently running ASP.NET Core 2.1 on .NET 4.6.1. A couple of references:
https://blog.codeinside.eu/2018/03/31/running-aspnet-core-2-under-the-full-dotnet-framework/
https://github.com/aspnet/home/issues/2022
Hi Joel,
> What about your own COM objects? .NET Core projects do not provide a means to reference them directly. However, you can create a .NET Framework 4.x project and add a reference to the COM object. This will create an Interop.MyCOMObject.dll assembly in the obj/Debug folder, which you can then reference directly in the .NET Core project.
When I use a .Net Core project to refer to an interop DLL generated by a .Net Framework 4.x project I get REGDB_E_CLASSNOTREG. I can refer to the same DLL from a .Net Framework project with no problems. Any ideas?
Thanks!
The issue was 32-bit vs. 64-bit as you had already warned…
Thanks for the guidance.