I am trying to create a class library that'll contain common objects (mainly DTOs) of a WebAPI (using ASP.NET 5) and a consuming UWP App. However, I have not yet figured out how to create the class library such that it can be referenced from both other projects.
What I have tried so far:
First, I tried a Class Library (Package), which can be found under Web. This type of library can be referenced from the ASP.NET project without problems, but when trying to reference it from the UWP project, I get the following message:
A reference to 'ClassLibrary1' could not be added.
Next, I tried a Class Library (Windows Universal), which can be found under Windows > Universal. This can easily be references from the UWP project, but when trying to reference it from ASP.NET, I get:
The following projects are not supported as references :
- The project ClassLibrary2 has a target framework that is incompatible or has version higher than the current project and cannot be referenced.
So: How can I create a class library that can be used in both an ASP.NET 5 project and an UWP project?
What you need is a Portable Class Library (under Windows).
Since you're only targetting ASP.NET 5 and Windows 10, you can limit the platforms to these two only, but there's no "error" in supporting more platforms (it can limit how much of the shared API is available though).
The .Net Standard class library should be thought of as a successor to the portable class library. Both aim to facilitate sharing code (in this case model objects/DTOs) between different .Net platforms.
In Visual Studio 2017, you can now choose a .Net Standard class library template. This class library can bet set to target different versions of the .Net Standard. The version of the .Net Standard that you should target will depend upon what .Net platforms you wish share code between.
For this particular question, we wish to support a Universal Windows Platform (UWP) app and Asp.Net Core app. So, we should refer to this compatibility table to determine the version of the .Net Standard that will support both of these platforms. In this case, it would be .Net Standard 1.4. Once you have set the class library to target the .Net Standard 1.4, you can add references to the class library from your UWP and Asp.Net core projects.
In order to better understand what the .Net Standard is and how it facilitates code sharing, I suggest reviewing the following:
Introducing .NET Standard
Video Series on .NET Standard (this is particularly good)
.Net Standard FAQ
Related
My understanding is that, starting with ASP.NET Core 3.0, .NET Framework is an unsupported target framework, and thus you can only run on the .NET Core runtime.
If this is the case, what NuGet packages can be imported into an ASP.NET Core 3 app?
I assume that you could reference any package that targets netstandard, but what about packages that only target the full framework (i.e., a legacy package that only targets net45)?
What happens if the package you import references an assembly that's not part of .NET Core—i.e., System.Drawing?
TL;DR: You can still reference (packages which depend upon) .NET Framework assemblies from .NET Core 3 and even .NET 5, but you will receive a runtime error if you call into any code which relies upon APIs or libraries not (yet) supported by .NET Core. You can discover these using Microsoft's .NET Portability Analyzer
Background
First off, you're correct that ASP.NET Core 3.x applications can no longer target the .NET Framework, as announced by Microsoft in 2018. That capability previously allowed ASP.NET Core applications to call into .NET Framework libraries, and thus offered an intermediate solution for web applications migrating to .NET Core.
Note: Since the .NET Framework only runs on Windows machines, writing ASP.NET Core web applications which targeted the .NET Framework implicitly restricted those applications to running on Windows.
Behavior
Even when targeting .NET Core or now .NET 5, however, you're still able to reference .NET Framework packages and assemblies, assuming you're on a Windows machine and have the corresponding .NET Framework installed. The inner workings of this are a bit involved, but the short of it is that .NET Core and .NET 5 will evaluate .NET Framework assembles as though they are .NET Standard assemblies. If the API call is also implemented in the .NET Core runtime, it will work fine—but if the API call is exclusively part of .NET Framework, you'll receive an exception.
Surprise! It's really important to emphasize that this is a runtime exception. You will still be able to reference the .NET Framework assembly, write calls to problematic members, and compile your code without any warnings. But as soon as you call into code dependent on a .NET Framework-specific assembly, you'll receive the runtime exception.
Example
With .NET 3.0, a significant portions of .NET Framework libraries have been ported over to .NET Core. In fact, this includes most of the System.Drawing libraries you referenced as an example—though there are good reasons you may not want to use them. If you dig a bit deeper, however, there are plenty of libraries which remain unsupported. One obvious example is the WebConfigurationManager, which could be used to access configuration settings from web.config files.
.NET Framework Code
So, as an example, let's say you have the following function in a .NET Framework class library, which returns an array of keys from your web.config's <AppSetting>s element:
public static class Configuration
{
public static string[] GetAppSettings() => System.Web.Configuration.WebConfigurationManager.AppSettings.AllKeys;
}
ASP.NET Core Code
And then, in an ASP.NET Core controller, you expose an endpoint to retrieve this data:
public class MyController: Controller
{
public IActionResult ApplicationKeys() => Content(String.Join(", ", Configuration.GetAppSettings()));
}
Exception
In an ASP.NET Core 2.x application targeting the .NET Framework, this will work just fine. In an ASP.NET Core 3.x or ASP.NET Core 5 application, however, you'll receive the following runtime error when you call the /My/ApplicationKeys/ route:
System.TypeLoadException: 'Could not load type 'System.Web.Configuration.WebConfigurationManager' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.'
Avoiding Surprises
If you're anything like me, this will make you incredibly nervous. You'd much rather receive design-time errors—or, at least, compile-time warnings—as soon as you attempt to call into a library relying upon unsupported code. Fortunately, Microsoft offers a .NET Portability Analyzer, which is also available as a Visual Studio Extension, for exactly this purpose.
As of .NET 5, there's also a compatibility analyzer built into the SDK which will identify calls that are not supported by the .NET 5 runtime on particular platforms. This requires that target libraries explicitly annotate their types with the [SupportedOSPlatform()] attribute, so you won't get any warnings for legacy .NET Framework types. But this will help identify similar types of compatibility issues for libraries targeting a variety of platforms.
Example
If you run the Portability Analyzer on the above sample code, for example, it will output an Excel spreadsheet identifying that T:System.Web.Configuration.WebConfigurationManager is Not Supported in e.g. .NET Core,Version=v3.1 or .NET Standard + Platform Extensions,Version=v2.0.
Note: Microsoft used to offer an API Analyzer as a NuGet package, which promised to provide design-time analysis in Visual Studio. Unfortunately, the code hasn't been updated in two years, and the latest release is 0.2.12-alpha. In my evaluation, it was not effective at identifying issues.
Sample Project
I've put together a sample project on GitHub which demonstrates the above behavior. It includes the following projects:
ASP.NET Core 2.0 Website targeting .NET Framework 4.8
ASP.NET Core 3.1 Website targeting .NET Core 3.1
.NET Framework class library with calls to the legacy WebConfigurationManager
Both ASP.NET Core websites include two endpoints which call into the same .NET Framework 4.8 class library. The first is a "Hello world" example which will execute fine on both projects, since it relies exclusively on common APIs:
http://localhost:5000/Basic/Index
The second will fail on the ASP.NET Core 3.1 project, since it calls into the legacy WebConfigurationManager API:
http://localhost:5000/Basic/Configuration
Disclaimer: This is a quick and dirty repository that I put together to verify my understanding prior to posting this. If there's interest, I'll tidy it up and document it. For now, however, it may prove useful for those of you who need to see this in action.
Acknowledgments
#Chris Pratt offered an excellent answer covering similar material last year. It's worth reading.
Our project structure is like,
native.dll :- This contains pure native code written in c\c++.
This native.dll exposes some functions using *def file.
Wrapper Library(wrapper.dll compiled with .Net framework v4.0) :-
In order to use functionality of native.dll, a Wrapper lib(wrapper.dll)
is written in C++\CLI using :clr\oldsyntax. This wrapper has all
code of Interoperability and Marshalling.
Application(Console App v4.0) directly uses wrapper.dll to use functionality provided
by native.dll.
Now this project needs to run in .Net Core. This means we will have an
.Net Core application that will reference wrapper.dll that in turn will refer
native.dll.
I know this will not directly work. But the issue is whether .Net Core(CoreCLR) supports
C++\CLI (clr\oldsyntax) runtime environment ?
If no, what can be the possible solutions to this application work ?
whether .Net Core(CoreCLR) supports C++\CLI (clr\oldsyntax) runtime environment ?
As far as I know there is no plan to support C++/CLI with .NET Core.
If no, what can be the possible solutions to this application work ?
You can (should) provide a C API. Mono e. g. supports P/Invoke and .NET Core also supports P/Invoke (see also this Stack overflow question and this DllMap related ticket).
Update (2022-09-02): This answer is from 2016. See the other answers (e.g., this) for what is possible with recent .Net Core versions.
Officially announced eventually...
(next wish... support linux # .Net 5 ^^)
https://devblogs.microsoft.com/cppblog/the-future-of-cpp-cli-and-dotnet-core-3/
C++/CLI will have full IDE support for targeting .NET Core 3.1 and higher. This support will include projects, IntelliSense, and mixed-mode debugging (IJW) on Windows. We don’t currently have plans for C++/CLI for targeting macOS or Linux. Additionally, compiling with “/clr:pure” and “/clr:safe” won’t be supported for .NET Core.
The first public previews for C++/CLI are right around the corner. Visual Studio 2019 16.4 Preview 1 includes an updated compiler with “/clr:netcore”
Updat: From replied of origin url:
"We are still working on the IDE and MSBuild integration, so I can’t share a sample project quite yet. Once it’s available, likely with 16.4 Preview 2 or 3"
(16.4 Preview1 cannot create C++/CLI with .NetCore project.)
191015
16.4 Preview2 Released.
I'v tried asp.net core 3.1 with c++/CLI dll, it works.
(need set plateform to x64 both asp.net core and c++/CLI dll)
.net Core team will only commit (now?) to supporting C++/CLI for Windows only.
The intention was to deliver it for .net Core 3.0. While I haven't found explicit mention of it yet in the release notes, C++/CLI support was a prerequisite for delivering WPF (windows-only), which is now supported in .net Core 3.0.
Support mixed-mode assemblies on Windows - #18013
This issue (#18013) will track progress toward supporting loading and running
mixed-mode assemblies on CoreCLR. The main goal is to provide support
for WPF and other existing C++/CLI code on .NET Core. Some of the work
will be dependent on updates to the MSVC compiler.
The github issue (#659) mentioned above by #Tomas-Kubes, Will CoreCLR support C++/CLI crossplat? - #659, is about cross-platform C++/CLI.
BTW, I am getting compiler warnings on "clr\oldsyntax" with VS2017/.net-4.7. So this compiler flag is already deprecated.
UPDATE: This isn't coming till .Net Core 3.1
Another potential solution (though obviously quite a difficult task) if you want to stick with C++ (i.e. expose an OO interface to .NET) might be to have a look at CppSharp from the mono project. It is able to expose native C++ code through an automatically generated C# wrapper. It supports Windows, Linux as well as OSX. However, I don't know if the generated code can be compiled to a .NET standard target (didn't try to). I can only suppose it would because the generated code does not use any fancy API (it is basically interop and marshalling code); and, by the way, it is also possible to customize the generation process (although, once again, probably not an easy task).
For those who are looking at this for general .Net Core stuff without specific clr parameters (as this is a high result on google) Microsoft have written a guide on how to port C++/CLI to .Net Core:
https://learn.microsoft.com/en-us/dotnet/core/porting/cpp-cli
Port a C++/CLI project
To port a C++/CLI project to .NET Core, make the following changes to the .vcxproj file. These migration steps differ from the steps needed for other project types because C++/CLI projects don't use SDK-style project files.
Replace <CLRSupport>true</CLRSupport> properties with <CLRSupport>NetCore</CLRSupport>. This property is often in configuration-specific property groups, so you may need to replace it in multiple places.
Replace <TargetFrameworkVersion> properties with <TargetFramework>netcoreapp3.1</TargetFramework>.
Remove any .NET Framework references (like <Reference Include="System" />). .NET Core SDK assemblies are automatically referenced when using <CLRSupport>NetCore</CLRSupport>.
Update API usage in .cpp files, as necessary, to remove APIs unavailable to .NET Core. Because C++/CLI projects tend to be fairly thin interop layers, there are often not many changes needed. You can use the .NET Portability Analyzer to identify unsupported .NET APIs used by C++/CLI binaries just as with purely managed binaries.
Build without MSBuild
It's also possible to build C++/CLI projects without using MSBuild. Follow these steps to build a C++/CLI project for .NET Core directly with cl.exe and link.exe:
When compiling, pass -clr:netcore to cl.exe.
Reference necessary .NET Core reference assemblies.
When linking, provide the .NET Core app host directory as a LibPath (so that ijwhost.lib can be found).
Copy ijwhost.dll (from the .NET Core app host directory) to the project's output directory.
Make sure a runtimeconfig.json file exists for the first component of the application that will run managed code. If the application has a managed entry point, a runtime.config file will be created and copied automatically. If the application has a native entry point, though, you need to create a runtimeconfig.json file for the first C++/CLI library to use the .NET Core runtime.
There are some more nuances but these are the actual steps to port
I testing an UWP application and I want to use a proxy to consume a WCF service. I have a proxy that is a library for .net 4.6 but I can't add this project as reference in the project of universal application. It is normal because is a library for .net 4.6.
So I am trying to create a portable library and I have two options, to create a portable library. This option let me say what targets can I use. I select .net 4.6 and windows universal 10.0. The problem is that I can't add a reference to the System.ServiceModel that I need to use the proxy.
The other option is portable library for windows universal. In this cases I can't select the target projects, it has sense because it is only for universal applications. In this case I can add the reference to the System.ServiceModel.
I know that in a portable library I only can use the libraries of the target project more restrictive, in this case I guess that is windows universal, no .net 4.6. But then, why do I can add the reference in the portable library for universal applications and not in the portable library in which I am using .net?
I would like to have a generic portable library to be able to use the proxy in WPF applications and universal windows applications.
Thanks.
Unfortunately there isn't a simple subset relationship between different target frameworks; i.e. in your case UWP is not a subset of .NET 4.6, therefore when you create a portable class library targeting both, you don't simply have all the APIs from the smaller framework available.
When dealing with clientside System.ServiceModel code the situation is even more confusing: although both target platforms include basic support for WCF proxies, the APIs are different enough that there is no portable equivalent that would be available when creating a PCL. This is the reason for the behavior that you are seeing: you can create a proxy both in a .NET 4.6 class library and in a UWP class library, but you can't create it in a portable class library targeting both of them. You will need to create 2 separate libraries.
If you're only going to call the proxies from the platform specific WPF an UWP code, then this shouldn't really be a problem, but I suspect that you would like to call them from the business logic code which you would prefer to implement in a portable class library.
You can achieve this as follows:
Create an interface for the proxy class in a common portable class library for UWP and .NET 4.6.
Reference this common library from both platform specific class libraries: UWP and .NET 4.6. The proxies in these 2 libraries should implement the common portable interface. I haven't tried it, but if you configure the service references to reuse the types from your portable class library, the generated proxies should already implement your interfaces. This way you could avoid create wrappers around your proxies in each of the platform specific class libraries.
You can now write business logic in the common portable class library and only ever work with proxies using the common interface. To get concrete instances of this interface on each platform use a portable dependency injection framework, such as Ninject.
In application code for each platform you will then initialize the dependency injection framework by registering the correct proxy implementation of the interface, either UWP one or .NET 4.6 one. Of course you will also reference the common portable class library from both applications, as well as the correct platform specific class library in each application.
I'm having a problem with assembly resolution on an end-user machine and I believe it's related to using Portable Class Libraries....
I have a .NET 4.0 application that was originally written in Visual Studio 2010. Recently we upgraded to Visual Studio 2012 and we've created a few projects that are Portable Class Libraries. I don't believe we need these features now, but we're also building a Windows 8 Store application that might benefit from these libraries.
When I compile my project, what exactly does the portable library feature do? I expect that it allows me to run it on different frameworks without modification or recompiling.
When I look at the library in reflector dotPeek it shows the Platform attribute as:
.NETPortable,Version=v4.0,Profile=Profile5
And the references seem 2.0-ish:
mscorlib, Version=2.0.5.0
System, Version=2.0.5.0
System.Runtime.Serialization, Version=2.0.5.0
When I run the application on this end-user's machine, I see an error in the log file:
Could not load file or assembly, 'System.Core, Version=2.0.5.0...'
Googling System.Core 2.0.5.0 seems to refer to SilverLight -- which appears to be one of the targeted frameworks.
This machine does not have Visual Studio installed, but has .NET 4.0 (4.0.3 update)
Is there something I should be doing differently to compile, something I should investigate in my dependencies or something I should be looking to install on the end-user machine? What does the 2.0.5.0 refer to?
For .NET 4, you need an update (KB2468871) for Portable Class Libraries to work. From the KB Article:
Feature 5
Changes to the support portable libraries. These changes include API
updates and binder modifications. This update enables the CLR to bind
successfully to portable libraries so that a single DLL can run on the
.NET Framework 4, on Silverlight, on Xbox, or on the Windows Phone.
This update adds public Silverlight APIs to the .NET Framework 4 in
the same location. The API signatures will remain consistent across
the platform. All modifications are 100 percent compatible and will
not break any existing code.
Also see the "Deploying A .NET Framework App" section of the MSDN Portable Class Library Documentation.
EDIT: Actually, if the machine has .NET 4.0.3 installed as you mention, that should be sufficient. Can you double-check to make sure that it is actually installed?
When sharing code between Windows Phone 8 and Windows 8, the two core options for developers are 1) Windows Runtime Components and 2) Portal Class Libraries.
Windows Runtime Components use WinRT and can be projected into all the supported languages. They require linked files in separate projects (binaries) when used on different platforms. They, however, share 90% of the available WinRT APIs.
Portable Class Libraries are a subset (sometimes a significant subset) of the BCL that has binary compatibility across platforms. They can be used on WinRT applications but also on other project types like Silverlight, Xbox, etc.
When a developer is choosing a "sharing strategy" which project type is the go-to technique to do the best job sharing code between Windows Phone 8 and Windows 8? Thanks.
It depends what form of sharing you need:
1) If you have a common C++ business logic layer you can use Windows Runtime (WinRT) components to expose this to both Windows Phone and Windows Store app (that's the only use-case for Windows Phone as you can't write a WP8 app using JavaScript or use .NET to author a WinRT component).
You'd have to build two separate WinRT components however, one for Phone and one for Windows Store. It should be possible to share the C++/CX code of your WinRT interop layer using preprocessor directives (#if) to mark the platform specific code.
2) You have business logic in C#/VB that only has dependencies on the .NET APIs which are available in a Portable Class Library. Then you can use Portable Class Library (PCL) to contain that logic. Basically if you can build your library into a PCL DLL then this should work. You can then reference this PCL in binary form in both Windows Phone and Windows Store app.
However as Martin has said you need to take care when using 3rd party libraries as these will also need to be built for PCL. Some 3rd party libraries are already available in PCL form (JSON.NET for example).
3) You want to share code for that has platform API dependencies (or 3rd party library dependencies) which are not supported by PCL. Then you'd need to create separate DLL libraries, one per platform. You can avoid code duplication using linked C#/VB source files and use a build flag (#if again) to allow small code changes between your target platforms.
If you want to share code between Windows Phone 8 and Windows 8, then you cannot use Windows Runtime Components, because there are different components used for Windows 8 and different for Windows Phone 8 and they are not interchangeable.
I would go for either Portable Class Libraries for some simple generic libraries, or for code sharing via links and #if WP8 compilation directives - this just works and is more powerful than Portable libs.
Keep also in mind that most external libraries like MVVM Light cannot be referenced in Portable Libs, so if you want to use them, you have to use the code sharing via file references.
For some guidance on how to effectively use Portable Class Libraries to share code between platforms, see this blog post: How to Make Portable Class Libraries Work for You
This question is no longer relevant with the introduction of Windows
Phone 8.1 Universal Apps in Visual Studio 2013 Update 2 which supports
Shared Projects.
Wait a moment, as for me even in Visual Studio 2013 Update 4 this question is still relevant because there are two types of projects there:
Class Library (Portable for Universal Apps) - PCL
and
Windows Runtime Component (Portable for Universal Apps) - WinMD
I can see only one big difference between them:
WinMD uses only WinRT and PCL could be used also with .Net and Silverlight. But I also want to know more about which one and when better to choose.