I am looking at System.Security.Cryptography.ProtectedData.Protect
# https://learn.microsoft.com/en-gb/dotnet/api/
as we are looking to port a library from .NET Framework 4.7 to .NET Standard 2.0 to be used by .NET Core 2.0.
I did a search and it only available in the full .NET Framework and .NET Core.
My question is, why is it not available in .NET Standard 2.0?
I would have thought that if it can be used in, for example, .NET Framework 4.7 and .NET Core 2.0 then it would also be part of .NET Standard 2.0
This API is not available "in" .NET Standard 2.0, but it is available "for" .NET Standard 2.0 as a "Platform Extension" which means that there is a NuGet package you have to add to get support for it.
If you add a reference to the System.Security.Cryptography.ProtectedData NuGet package, you can develop a .NET Standard library that uses these APIs.
However, this support only works when run on Windows, since those APIs are described as
Provides access to Windows Data Protection Api.
so it won't work on platforms other than Windows. Depending on your needs, this may be just fine.
If you are looking to implement similar concepts cross-platform, I suggest looking into the ASP.NET Core Data Protection APIs which could also be used outside of the context of an ASP.NET Core app since it is made out of NuGet packages that provide cryptographic logic and key storage solutions (e.g. directory, windows certificate stores, Azure KeyVault).
ProtectedData uses DPAPI from Windows. I created the library CrossProtectedData that uses ProtectedData in Windows and AspNetCore.DataProtection when running in non-Windows.
To use, simply add the NuGet package CrossProtect and replace any calls to ProtectedData with CrossProtect. Example:
using Integrative.Encryption;
using System;
using System.Security.Cryptography;
using System.Text;
namespace CrossProtectedExample
{
class Program
{
static void Main(string[] args)
{
// our text to protect
var text = "Hello!";
// get bytes from text
var bytes = Encoding.UTF8.GetBytes(text);
// optional entropy
var entropy = new byte[] { 100, 25, 31, 213 };
// protect (encrypt)
var protectedBytes = CrossProtect.Protect(bytes, entropy,
DataProtectionScope.CurrentUser);
// unprotect (decrypt)
var unprotected = CrossProtect.Unprotect(protectedBytes, entropy,
DataProtectionScope.CurrentUser);
// convert bytes back to text
var result = Encoding.UTF8.GetString(unprotected);
// print result
Console.WriteLine(result);
Console.ReadKey();
}
}
}
Firstly
I can't answer for Microsoft
tl;dr
A lot of these questions can be answered with: if you need APIs found in .NET Framework, use the .NET Framework.
Longer form answer
A large number of the APIs found in .NET Framework either rely on underlying Windows libraries (which aren't available on MacOs or Linux distros) or they are currently too complex to implement, as such they are not available for .NET Core.
If there is an API you need access to which is only available in .NET Framework, then (for the time being) it's best to use .NET Framework rather than .NET Core/Mono/etc.
If you have a compelling reason for something to be included in .NET Standard, then I would head over to the .NET Standard GitHub repo and ask for it to be implemented there.
Related
We have a commercial library that I am working to port to .NET Core. There are a couple of calls in it I want to retain to use only if running in .NET standard. (For the curious, one set is to read a file on a Windows server that requires credentials to access.)
Is there:
A call that will tell me if I am running under .NET Standard vs. .NET Core.
Is there a way to have a class that is only going to be instantiated/called if running under standard, but the DLL will still load fine under Core?
Also asked on MSDN
Since what you describe, having a single nuget package and being able to specify different behaviours or dependencies depending on the framework the nuget package is installed into, can only be reached through Multi Targeting I will assume you are doing that or will be doing it.
Once you have specified target frameworks, you have pre-defined variables to use in precompile blocks:
#if NETFRAMEWORK
// use full framework class here. You were installed into a full framework app or library
#elif NETCOREAPP
// use .NET Core class here. You were installed into a .NET Core app or library
#else NETSTANDARD
// uh... okay... you were installed into another .NET Standard library,
// we still have no idea where *that* might be installed... help?
// Maybe make it configurable after all?
#endif
.NET Standard is not a runtime, it is a set of APIs that a runtime must implement in order to be compatible. So basically this allows people to have a library target .NET Standard and have one code-base that will run in all supported runtimes because it is guaranteed that those runtimes will have an implementation for those APIs.
.NET Standard doesn't have implementation at all, it just defines a set contract of APIs which is used at compile time, but at runtime the APIs used will be the ones in the runtime the consumer decided to target their application for.
A better runtime detection would be to use RuntimeInformation.FrameworkDescriptor APIs. We do that for our framework tests to know what we're running our tests on: https://github.com/dotnet/runtime/blob/master/src/libraries/Common/tests/CoreFx.Private.TestUtilities/System/PlatformDetection.cs#L21
You could also achieve this via reflection by doing something like: typeof(string).Assembly... if the assembly is System.Private.CoreLib you're on .NET Core, if it is mscorlib, you're in .NET Framework.
I am developing a server in ASP NET Core 3.1 preview edition and now i see that for all my async methods when calling await i get CA2007 warning (as it is when some task is running asynchronous).
Is there any significant change in how the way async await works in .NET Core 3.1 that i am not aware of thus i should use ConfigureAwait?
P.S If there is not change , is there any way for it to stop highlighting all await's with green for which i am not using configureawait ?
You specify ASP.NET Core 3.1 in your question but not what version you're coming from. However, in ASP.NET Core (since the beginning?) you don't need to call ConfigureAwait(false) from ASP.NET Core. See: ASP.NET Core SynchronizationContext by Stephen Cleary.
To stop the warning I put this in my GlobalSuppressions.cs:
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Design", "RCS1090:Call 'ConfigureAwait(false)'.",
Justification = "ASP.NET Core doesn't have a SynchronizationContext. https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html",
Scope = "NamespaceAndDescendants",
Target = "YourProjectNamespace.Controllers")]
Note the Target = "YourProjectNamespace.Controllers". I try to be specific where I suppress the warnings. Since I can't control where my library code will be called from I want to ensure that my libraries still call ConfigureAwait(false). But in ASP.NET Core controllers I don't need to, thus the suppression.
I have an ASP.NET MVC 5 project which works well and it also references a .NET Framework 4.7.2 Class library which produces some CrystalReports. CrystalReports does not support .NET Core, so the class library will stay with full .NET Framework.
Now, if I upgrade the ASP.NET MVC 5 to ASP.NET Core 2 (or 3), will I be able to reference the class library and possibly generate those CrystalReports?
.NET Core doesn't support inclusion of .NET Framework libraries. Period. However, .NET Core supports .NET Standard, and since .NET Framework also implements .NET Standard, Microsoft made a special exception in the compiler to allow you include .NET Framework libraries, with the caveat that they may not actually function at all or totally. You get a warning to this effect when you include a .NET Framework library in a .NET Core project, and it's on you to ensure that the library works correctly end-to-end.
The largest majority of .NET Framework libraries do work, as long as they don't utilize .NET Framework-specific APIs (most notably Windows-specific APIs). If they do, then they will not work.
Here, it seems this library does utilize Windows-specific APIs, meaning it is incompatible with .NET Core. In such a situation, you can still create an ASP.NET Core project, but you must target .NET Framework, not .NET Core. That is, until ASP.NET Core 3.0, which cannot target .NET Framework. ASP.NET Core 3.0+ depends on .NET Standard 2.1, which no version of .NET Framework supports or ever will.
As such, if you need to use a .NET Framework library that is not 100% .NET Standard 2.0 compliant, you must target .NET Framework, and if you must target .NET Framework, you are then version-locked at 2.2 of ASP.NET Core.
UPDATE
This answer is a little old now, but just in case it might still be helpful, the way I've dealt with this kind of thing personally is to create a very small and simple API. Basically, you create a ASP.NET Core 2.1 (LTS) app targeting .NET Framework, and all this app does is interact with the .NET Framework library. Here that would mean creating the report. Then, you're free to create your actual app as an ASP.NET Core 3.1+ app targeting .NET Core, and you just call out to the API to get the data, report, whatever you need. It's sort of like a lightweight microservice approach.
Chris has already provided an excellent and accurate answer but I'll try to add a bit more color by sharing the results of an experiment I did.
Experiment: I have a web application targerting .Net Core 3.1. It calls a library that targets the Full Framework. In that library I specifically make a call to a Full Framework API that is not available in .Net Core 3.1, in this case that type is SHA512Cng.
My library code is:
/// <summary>
/// Returns a base64 encoded Sha512 hash of the text specified.
/// Uses the SHA512Cng implementation to do the hashing.
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string Sha512Hash(string text) {
using (SHA512Cng sha512Cng = new SHA512Cng()) {
byte[] bytes = Encoding.ASCII.GetBytes(text);
byte[] hashButes = sha512Cng.ComputeHash(bytes);
return Convert.ToBase64String(hashButes);
}
}
In the home controller of my web application I make a call to use that Library method like so:
public IActionResult Index() {
string hash = App.Lib.Sha512Hash("hello world");
return View();
}
Pretty simple experiment. This code is running on a windows machine that has the full framework installed. If I call this library from a website targeting the Full Framework it works perfectly.
When I call this method in the Library from a .Net Core 3.1 website, what happens? That's the questions I wanted this experiment to answer.
And the answer is...
It throws the following exception:
System.TypeLoadException: 'Could not load type 'System.Security.Cryptography.SHA512Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.'
Screenshot:
So the takeaway is this: It really doesn't matter whether your code is running on a box with the Full Framework or not. If you reference a Full Framework Library from a website targeting Asp.Net Core 3 and make a call into a method that references a type that is incompatible with Asp.Net Core 3, then it's gonna throw.
With the release of .NET Standard 2.0, it's advised to target .NET Standard 2.0, even if you target 1.x already.
https://learn.microsoft.com/en-us/dotnet/standard/net-standard:
However, targeting lower .NET Standard versions introduces a number of support dependencies. If your project targets .NET Standard 1.x, we recommend that you also target .NET Standard 2.0. This simplifies the dependency graph for users of your library that run on .NET Standard 2.0 compatible frameworks, and it reduces the number of packages they need to download.
Now another big change is near! .NET Core 3 and I see that Microsoft also is targeting .NET Core 3 for Microsoft packages.
For example, Microsoft.Extensions.Logging is targeting .NET Standard 2.0 and also .NET Core 3 (.NETCoreApp 3.0):
I compared the XML files and both APIs look the same (maybe not the best way to compared them)
Now the question ;)
As a library maintainer that depends on Microsoft.Extensions.Logging, who trying to support .NET Core 3:
Should I also target .NET Core 3 - or is just .NET Standard 2.0 good enough if I don't need specific stuff of .NET Core 3?
Short answer
You don't have to target .NET Core 3 if you don't want to use anything from it, or if you don't want to offer any .NET Core 3 optimizations. On the other hand, double targeting doesn't cost you anything and may allow you to get rid of library references that are now built into .NET Core 3. At the very least you may be able to get rid of some library references that now come with the runtime.
Long answer
It depends entirely on what you're doing, what you want to do. A library doesn't have to target .NET Core 3.0 just because its dependencies include it in their targets.
For example, the source code shows that Microsoft.Extensions.Logging doesn't seem to have any C# 8/.NET Core 3.0 specific code. It targets 3.0 because it's part of that wave of extensions, so double-targeting doesn't require any modifications.
On the other hand, Config.Json doesn't have to reference System.Text.Json and System.Threading.Tasks.Extensions because they are part of the runtime.
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Reference Include="System.Text.Json" />
<Reference Include="System.Threading.Tasks.Extensions" />
</ItemGroup>
Other benefits
For maintainers, .NET Core 3.0/.NET Standard 2.1 offer a lot of sanity preserving features like:
Nullable Reference Types. You'll avoid a lot of NREs in your own code. You'll probably catch a lot of hidden bugs too.
Default interface members. You won't have to worry about breaking users' code when you add a new member to a public interface.
IAsyncEnumerable. No more waiting for all results from a bunch of asynchronous operations
The switch expression and far more powerfull pattern matching and deconstruction syntax.
For some of those features you can add only a few methods that will be available only for .NET Core. For example, the ChannelReader class adds a single ReadAllAsync() method in a partial file that reads items from a channel and returns an IAsyncEnumerable<>, eg :
public virtual async IAsyncEnumerable<T> ReadAllAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
{
while (await WaitToReadAsync(cancellationToken).ConfigureAwait(false))
{
while (TryRead(out T item))
{
yield return item;
}
}
}
This is a small but very convenient addition. It allows you to receive messages with :
await foreach(var msg from reader.ReadAllAsync())
{
....
}
NRTs on the other hand will help even for .NET Standard 2.0 because they help you catch nullability bugs in the source code when compiling for .NET Core 3.0.
As a library maintainer that dependents on
Microsoft.Extensions.Logging, who trying to support .NET Core 3:
Should I also target .NET Core 3 - or is just .NET Standard 2.0 good
enough if I don't need specific stuff of .NET Core 3?
Targeting .NET Standard 2.0 in your library is good enough for as long as all of your dependencies target .NET Standard 2.0 as well, including Microsoft.Extensions.Logging.
As Panagiotis Kanavos said, there can be benefits of targeting .NET Core 3.0 for the consumers of your library, so if that's the case and it doesn't cost you too much, then by all means target .NET Core 3.0 in addition to .NET Standard 2.0.
As karann said, nuget will always select the best matching assets for every package in the graph. i.e.
App A uses your library and targets .NET Core 3.0. Your library targets .NET Standard 2.0 only. NuGet will use that, and it's fine.
App A uses your library and targets .NET Core 3.0. Your library targets both .NET Standard 2.0 and .NET Core 3.0. NuGet will choose .NET Core 3.0
When someone installs a package, NuGet uses the assets from TFM that best matches the TFM of the project. It does this for the transitive dependencies too.
For example - if the project target netcore30 and package A has assets under lib/netcore30 and lib/netstandard20, nuget will select lib/netcore30. Let's say package A depends on B, and package B has assets for netstandard20, net472, nuget will select netstandard20.
Bottom line is, nuget will select the best matching assets for every package in the graph. So, as a library maintainer, you don't need to add two TFMs to support netcore30. You can target netstandard21 which implies support for netcore30 based on this doc https://learn.microsoft.com/en-us/dotnet/standard/net-standard
I'm currently creating a common library from my work that would implement an abstracted logger using NLog.
I've created a .NET Core class library targeting .NET 4.6.1 and implemented NLog, but when I try to execute a unit test that I've created, I've noticed that the nlog.config file is not being picked up. I've also followed the instruction stated https://github.com/NLog/NLog.Extensions.Logging, but I've noticed that it only targets Asp.Net Core and not for .NET Core Class Library solution.
My question is, (given that it is my first time to foray to .NET core) is the instructions stated on the link above applicable for .Net Core class libraries too, or is there a different way to implement this?
Or should I end up not using .Net Core and go for more traditional .NET Class library implementation instead?
Many thanks!
I've created a .NET Core class library targeting .NET 4.6.1 and implemented NLog, but when I try to execute a unit test that I've created, I've noticed that the nlog.config file
It difficult to find the config file when running as unit test. Different frameworks are using different locations. The following options should work
Manually find the config file location as pass it to NLog. Use
LogManager.Configuration = new XmlLoggingConfiguration(filePath, true);
instead of ConfigureNLog() , or
Create a config with the API, or
Create the XML as string and feed it to NLog: instead of ConfigureNLog, use
XElement element = XElement.Parse(configXml);
LogManager.Configuration = new XmlLoggingConfiguration(element.CreateReader(), "nlog.config");
I've noticed that it only targets Asp.Net Core and not for .NET Core Class Library solution.
It works with or without ASP.NET. The ASP.NET parts will be moved to the NLog.Web package in the future