doc improvements (#87)
* doc improvements * feedback * Update DE0001.md * feedback * brackets + minor edits * Update PC002.md
This commit is contained in:
Родитель
0b804783ec
Коммит
1b0c080300
|
@ -6,26 +6,28 @@ T:System.Security.SecureString
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
* The purpose of `SecureString` is to avoid having secrets stored in the process
|
* The purpose of [`SecureString`][SecureString] is to avoid having secrets stored in the process
|
||||||
memory as plain text.
|
memory as plain text.
|
||||||
* However, even on Windows `SecureString` doesn't exist as an OS concept
|
* However, even on Windows, [`SecureString`][SecureString] doesn't exist as an OS concept.
|
||||||
- It just makes the window getting the plain text shorter; it doesn't fully
|
* It just makes the window getting the plain text shorter; it doesn't fully
|
||||||
prevent it as .NET still has to convert the string to a plain text
|
prevent it as .NET still has to convert the string to a plain text
|
||||||
representation
|
representation.
|
||||||
- The benefit is that the plain text representation doesn't hang around
|
* The benefit is that the plain text representation doesn't hang around
|
||||||
as an instance of `System.String` -- the lifetime of the native buffer is
|
as an instance of [`System.String`][String] -- the lifetime of the native buffer is
|
||||||
shorter.
|
shorter.
|
||||||
* The contents of the array is unencrypted except on .NET Framework.
|
* The contents of the array is unencrypted except on .NET Framework.
|
||||||
- In .NET Framework, the contents of the internal char array is encrypted.
|
* In .NET Framework, the contents of the internal char array is encrypted.
|
||||||
We've trouble with supporting the encryption in all environments, either
|
.NET doesn't support encryption in all environments, either
|
||||||
due to missing APIs or key management issues.
|
due to missing APIs or key management issues.
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Don't use `SecureString` for new code. When porting code to .NET Core, consider
|
Don't use [`SecureString`][SecureString] for new code. When porting code to .NET Core, consider
|
||||||
that the contents of the array will not be encrypted in memory.
|
that the contents of the array are not encrypted in memory.
|
||||||
|
|
||||||
The general approach of dealing with credentials is to avoid them and instead
|
The general approach of dealing with credentials is to avoid them and instead
|
||||||
rely on other means to authenticate, such as certificates or Windows
|
rely on other means to authenticate, such as certificates or Windows
|
||||||
authentication.
|
authentication.
|
||||||
|
|
||||||
|
[SecureString]: https://docs.microsoft.com/dotnet/api/system.security.securestring
|
||||||
|
[String]: https://docs.microsoft.com/dotnet/api/system.string
|
||||||
|
|
|
@ -6,7 +6,7 @@ N:System.Security.Permissions
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
When .NET Framework was originally it tried to provide a managed sandbox that
|
When .NET Framework was originally created, it tried to provide a managed sandbox that
|
||||||
allows restricting what parts of the process can do. Unfortunately, providing an
|
allows restricting what parts of the process can do. Unfortunately, providing an
|
||||||
additional security boundary on top of the operating system has been proven to
|
additional security boundary on top of the operating system has been proven to
|
||||||
be too difficult. As a result, there have been quite a few exploits that allows
|
be too difficult. As a result, there have been quite a few exploits that allows
|
||||||
|
|
|
@ -9,9 +9,9 @@ T:System.Net.HttpWebRequest
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
`WebRequest`-based APIs are on life-support only (i.e. only critical fixes, no
|
`WebRequest`-based APIs are on life-support only (that is, only critical fixes, no
|
||||||
new improvements, enhancements).
|
new improvements, enhancements).
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Use `HttpClient` instead.
|
Use [`HttpClient`](https://docs.microsoft.com/dotnet/api/system.net.http.httpclient) instead.
|
||||||
|
|
|
@ -6,9 +6,9 @@ T:System.Net.WebClient
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
`WebClient` is on life-support only (i.e. only critical fixes, no new
|
`WebClient` is on life-support only (that is, only critical fixes, no new
|
||||||
improvements, enhancements).
|
improvements, enhancements).
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Use `HttpClient` instead.
|
Use [`HttpClient`](https://docs.microsoft.com/dotnet/api/system.net.http.httpclient) instead.
|
||||||
|
|
|
@ -6,10 +6,9 @@ T:System.Net.Mail.SmtpClient
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
`SmtpClient` does not support many modern protocols. It is compat-only. It's
|
[`SmtpClient`](https://docs.microsoft.com/dotnet/api/system.net.mail.smtpclient) doesn't support many modern protocols. It is compat-only. It's
|
||||||
great for one off emails from tools, but does not scale to modern requirements
|
great for one off emails from tools, but doesn't scale to modern requirements of the protocol.
|
||||||
of the protocol.
|
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Use `MailKit` or other libraries.
|
Use [`MailKit`](https://github.com/jstedfast/MailKit) or other libraries.
|
|
@ -18,38 +18,67 @@ T:System.Collections.CaseInsensitiveHashCodeProvider
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
When .NET was created, generic data types didn't exist, which is why the
|
When .NET was created, generic data types didn't exist, which is why the
|
||||||
collection types in `System.Collections` are untyped. However, since then
|
collection types in the [`System.Collections`][collections] namespace are untyped. However, since then,
|
||||||
generic data types and thus a new set of collections in
|
generic data types were introduced and thus a new set of collections
|
||||||
`System.Collections.Generic` were made available.
|
were made available in the [`System.Collections.Generic`][generic] and
|
||||||
|
[`System.Collections.ObjectModel`][objectmodel] namespaces.
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
For new code, you shouldn't use non-generic collections:
|
For new code, you shouldn't use non-generic collections:
|
||||||
|
|
||||||
* **Error prone**. Since non-generic collections are untyped, it requires frequent
|
* **Error prone**: since non-generic collections are untyped, it requires frequent
|
||||||
casting between `object` and the actual type you're expecting. Since the compiler
|
casting between `object` and the actual type you're expecting. Since the compiler
|
||||||
can't check that your types are consistent it's easer to put the wrong type in
|
can't check that your types are consistent, it's easier to put the wrong type in
|
||||||
the wrong collection.
|
the wrong collection.
|
||||||
|
|
||||||
* **Less performant**. Generic collection have the advantage that value types
|
* **Less performant**: generic collections have the advantage that value types
|
||||||
don't have to be boxed as object. For instance, a `List<int>` stores its data
|
don't have to be boxed as object. For instance, a `List<int>` stores its data
|
||||||
in an `int[]`. That's far better than storing the data in `object[]` as that
|
in an `int[]`. That's far better than storing the data in `object[]` as that
|
||||||
requires boxing.
|
requires boxing.
|
||||||
|
|
||||||
Consult the following table which how the non-generic collection types can be
|
The following table shows how the non-generic collection types can be
|
||||||
replaced by their generic counterparts in `System.Collections.Generic`:
|
replaced by their generic counterparts from the [`System.Collections.Generic`][generic] or
|
||||||
|
[`System.Collections.ObjectModel`][objectmodel] namespaces:
|
||||||
|
|
||||||
| Type | Replacement |
|
| Type | Replacement |
|
||||||
|-----------------------------------|------------------------------------------------------------|
|
|----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|
|
||||||
| `ArrayList` | `List<T>` |
|
| [`ArrayList`][arraylist] | [`List<T>`][list] |
|
||||||
| `Hashtable` | `Dictionary<TKey, TValue>` |
|
| [`CaseInsensitiveComparer`][caseinsensitivecomparer] | [`StringComparer.OrdinalIgnoreCase`][ordinalignorecase] |
|
||||||
| `Queue` | `Queue<T>` |
|
| [`CaseInsensitiveHashCodeProvider`][caseinsensitivehashcodeprovider] | [`StringComparer.OrdinalIgnoreCase`][ordinalignorecase] |
|
||||||
| `Stack` | `Stack<T>` |
|
| [`CollectionBase`][collectionbase] | [`Collection<T>`][collection-1] |
|
||||||
| `SortedList` | `SortedList<TKey, TValue>` |
|
| [`Comparer`][comparer] | [`Comparer<T>`][comparer-1] |
|
||||||
| `DictionaryEntry` | `KeyValuePair<TKey, TValue>` |
|
| [`DictionaryBase`][dictionarybase] | [`Dictionary<TKey, TValue>`][dictionary] or [`KeyedCollection<TKey, TItem>`][keyedcollection] |
|
||||||
| `DictionaryBase` | `Dictionary<TKey, TValue> or KeyedCollection<TKey, TItem>` |
|
| [`DictionaryEntry`][dictionaryentry] | [`KeyValuePair<TKey, TValue>`][keyvaluepair] |
|
||||||
| `CollectionBase` | `Collection<T>` |
|
| [`Hashtable`][hashtable] | [`Dictionary<TKey, TValue>`][dictionary] |
|
||||||
| `ReadOnlyCollectionBase` | `ReadOnlyCollection<T>` |
|
| [`Queue`][queue] | [`Queue<T>`][queue-1] |
|
||||||
| `Comparer` | `Comparer<T>` |
|
| [`ReadOnlyCollectionBase`][readonlycollectionbase] | [`ReadOnlyCollection<T>`][readonlycollection] |
|
||||||
| `CaseInsensitiveComparer` | `StringComparer.OrdinalIgnoreCase` |
|
| [`SortedList`][sortedlist] | [`SortedList<TKey, TValue>`][sortedlist-2] |
|
||||||
| `CaseInsensitiveHashCodeProvider` | `StringComparer.OrdinalIgnoreCase` |
|
| [`Stack`][stack] | [`Stack<T>`][stack-1] |
|
||||||
|
|
||||||
|
[arraylist]: https://docs.microsoft.com/dotnet/api/system.collections.arraylist
|
||||||
|
[caseinsensitivecomparer]: https://docs.microsoft.com/dotnet/api/system.collections.caseinsensitivecomparer
|
||||||
|
[caseinsensitivehashcodeprovider]: https://docs.microsoft.com/dotnet/api/system.collections.caseinsensitivehashcodeprovider
|
||||||
|
[collection-1]: https://docs.microsoft.com/dotnet/api/system.collections.objectmodel.collection-1
|
||||||
|
[collectionbase]: https://docs.microsoft.com/dotnet/api/system.collections.collectionbase
|
||||||
|
[collections]: https://docs.microsoft.com/dotnet/api/system.collections
|
||||||
|
[comparer]: https://docs.microsoft.com/dotnet/api/system.collections.comparer
|
||||||
|
[comparer-1]: https://docs.microsoft.com/dotnet/api/system.collections.generic.comparer-1
|
||||||
|
[dictionary]: https://docs.microsoft.com/dotnet/api/system.collections.generic.dictionary-2
|
||||||
|
[dictionarybase]: https://docs.microsoft.com/dotnet/api/system.collections.dictionarybase
|
||||||
|
[dictionaryentry]: https://docs.microsoft.com/dotnet/api/system.collections.dictionaryentry
|
||||||
|
[generic]: https://docs.microsoft.com/dotnet/api/system.collections.generic
|
||||||
|
[hashtable]: https://docs.microsoft.com/dotnet/api/system.collections.hashtable
|
||||||
|
[keyedcollection]: https://docs.microsoft.com/dotnet/api/system.collections.objectmodel.keyedcollection-2
|
||||||
|
[keyvaluepair]: https://docs.microsoft.com/dotnet/api/system.collections.generic.keyvaluepair-2
|
||||||
|
[list]: https://docs.microsoft.com/dotnet/api/system.collections.generic.list-1
|
||||||
|
[objectmodel]: https://docs.microsoft.com/dotnet/api/system.collections.objectmodel
|
||||||
|
[ordinalignorecase]: https://docs.microsoft.com/dotnet/api/system.stringcomparer.ordinalignorecase
|
||||||
|
[queue]: https://docs.microsoft.com/dotnet/api/system.collections.queue
|
||||||
|
[queue-1]: https://docs.microsoft.com/dotnet/api/system.collections.generic.queue-1
|
||||||
|
[readonlycollection]: https://docs.microsoft.com/dotnet/api/system.collections.objectmodel.readonlycollection-1
|
||||||
|
[readonlycollectionbase]: https://docs.microsoft.com/dotnet/api/system.collections.readonlycollectionbase
|
||||||
|
[stack]: https://docs.microsoft.com/dotnet/api/system.collections.stack
|
||||||
|
[stack-1]: https://docs.microsoft.com/dotnet/api/system.collections.generic.stack-1
|
||||||
|
[sortedlist]: https://docs.microsoft.com/dotnet/api/system.collections.sortedlist
|
||||||
|
[sortedlist-2]: https://docs.microsoft.com/dotnet/api/system.collections.generic.sortedlist-2
|
|
@ -10,8 +10,8 @@ F:System.PlatformID.MacOSX
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
Certain enum values on `System.PlatformID` are no longer in use and will never
|
Certain enum values on [`System.PlatformID`][PlatformID] are no longer in use and will never
|
||||||
be returned from `Environment.OSVersion.Platform`.
|
be returned from [`Environment.OSVersion.Platform`][Platform].
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
|
@ -24,8 +24,11 @@ the correct ones.
|
||||||
| Win32Windows | Unused
|
| Win32Windows | Unused
|
||||||
| WinCE | Unused
|
| WinCE | Unused
|
||||||
| Xbox | Unused
|
| Xbox | Unused
|
||||||
| MacOSX | Replaced. This value was only returned by Silverlight. On .NET Core, it will return `Unix`
|
| MacOSX | Replaced. This value was only returned by Silverlight. On .NET Core, it returns `Unix`.
|
||||||
|
|
||||||
Code that compares `Environment.OSVersion.Platform` to `PlatformID.MacOSX`
|
Code that compares [`Environment.OSVersion.Platform`][Platform] to [`PlatformID.MacOSX`][PlatformID]
|
||||||
should use the newer `RuntimeInformation.IsOSPlatform(OSPlatform.OSX)` API
|
should use the newer [`RuntimeInformation.IsOSPlatform(OSPlatform.OSX)`][IsOSPlatform] method instead.
|
||||||
instead.
|
|
||||||
|
[IsOSPlatform]: https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.runtimeinformation.isosplatform
|
||||||
|
[Platform]: https://docs.microsoft.com/dotnet/api/system.operatingsystem.platform
|
||||||
|
[PlatformID]: https://docs.microsoft.com/dotnet/api/system.platformid
|
|
@ -9,13 +9,17 @@ M:System.Threading.Thread.set_CurrentUICulture(System.Globalization.CultureInfo)
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
These properties don't work consistently across operating systems and runtimes when used against
|
Thread culture properties don't work consistently across operating systems and runtimes when used against
|
||||||
any thread other than the current thread.
|
any thread other than the current thread.
|
||||||
|
|
||||||
* In .NET Core, an `InvalidOperationException` is thrown if a thread tries
|
* In .NET Core, if a thread tries to read or write these properties on a different thread, an [`InvalidOperationException`][InvalidOperationException] is thrown.
|
||||||
to read or write these properties on a different thread.
|
|
||||||
* In .NET Framework, setting these properties isn't reliable for a different thread.
|
* In .NET Framework, setting these properties isn't reliable for a different thread.
|
||||||
|
|
||||||
## Recommendation
|
## Recommendation
|
||||||
|
|
||||||
Use `CultureInfo.CurrentCulture` and `CultureInfo.CurrentUICulture` instead.
|
Use [`CultureInfo.CurrentCulture`][CurrentCulture] and [`CultureInfo.CurrentUICulture`][CurrentUICulture] instead.
|
||||||
|
|
||||||
|
[CurrentCulture]: https://docs.microsoft.com/dotnet/api/system.globalization.cultureinfo.currentculture
|
||||||
|
[CurrentUICulture]: https://docs.microsoft.com/dotnet/api/system.globalization.cultureinfo.currentuiculture
|
||||||
|
[InvalidOperationException]: https://docs.microsoft.com/dotnet/api/system.invalidoperationexception
|
|
@ -2,30 +2,30 @@
|
||||||
|
|
||||||
## Cause
|
## Cause
|
||||||
|
|
||||||
You're calling an API in .NET Core or .NET Standard that will throw
|
You're calling an API in .NET Core or .NET Standard that throws
|
||||||
`PlatformNotSupportedException` in all or some circumstances.
|
[`PlatformNotSupportedException`][PlatformNotSupportedException] in all or some circumstances.
|
||||||
|
|
||||||
## Rule Description
|
## Rule description
|
||||||
|
|
||||||
The goal of this rule is assisting you in writing robust code that will work
|
The goal of this rule is assisting you in writing robust code that will work
|
||||||
across all platforms that your code might run on.
|
across all platforms that your code might run on.
|
||||||
|
|
||||||
## How to Fix Violations
|
## How to fix violations
|
||||||
|
|
||||||
The analyzer has no way to detect whether your code is correctly guarded against
|
The analyzer has no way to detect whether your code is correctly guarded against
|
||||||
`PlatformNotSupportedException`. The fix is to review the API documentation for
|
[`PlatformNotSupportedException`][PlatformNotSupportedException]. The fix is to review the API documentation for
|
||||||
which this rule was triggered for and to do one of the following:
|
which this rule was triggered and to do one of the following:
|
||||||
|
|
||||||
1. Not calling the API
|
1. Not call the API.
|
||||||
2. Guard this call and suppress the specific occurrence of this rule
|
2. Guard this call and suppress the specific occurrence of this rule.
|
||||||
3. Not running your code on the affected platforms and suppressing this rule for
|
3. Not run your code on the affected platforms and suppress this rule for
|
||||||
said platforms
|
said platforms.
|
||||||
|
|
||||||
## When to Suppress Warnings
|
## When to suppress warnings
|
||||||
|
|
||||||
Unless you stop calling the API entirely, you'll have to suppress this warning.
|
Unless you stop calling the API entirely, you have to suppress this warning.
|
||||||
|
|
||||||
If you want to suppress a specific occurrence, use `#pragma warning disable`:
|
If you want to suppress a specific occurrence, use `#pragma warning disable` as shown in the following example:
|
||||||
|
|
||||||
```C#
|
```C#
|
||||||
#pragma warning disable PC001 // API not supported on all platforms
|
#pragma warning disable PC001 // API not supported on all platforms
|
||||||
|
@ -34,11 +34,19 @@ If you want to suppress a specific occurrence, use `#pragma warning disable`:
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to ignore certain platforms, you need to edit your project file and
|
If you want to ignore certain platforms, you need to edit your project file and
|
||||||
add a property `PlatformCompatIgnore` that lists all platforms you don't plan to
|
add a `PlatformCompatIgnore` property that lists all platforms you don't plan to
|
||||||
run your code on:
|
run your code on like in the following example:
|
||||||
|
|
||||||
```XML
|
```XML
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PlatformCompatIgnore>Linux;MacOSX</PlatformCompatIgnore>
|
<PlatformCompatIgnore>Linux;MacOSX</PlatformCompatIgnore>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `PlatformCompatIgnore` property accepts the following values:
|
||||||
|
|
||||||
|
* Linux
|
||||||
|
* macOS
|
||||||
|
* Windows
|
||||||
|
|
||||||
|
[PlatformNotSupportedException]: https://docs.microsoft.com/dotnet/api/system.platformnotsupportedexception
|
||||||
|
|
|
@ -2,26 +2,26 @@
|
||||||
|
|
||||||
## Cause
|
## Cause
|
||||||
|
|
||||||
You're calling an API in .NET Standard that isn't available in .NET Framework
|
You're calling an API in .NET Standard that isn't available in the .NET Framework
|
||||||
4.6.1.
|
4.6.1.
|
||||||
|
|
||||||
## Rule Description
|
## Rule description
|
||||||
|
|
||||||
While .NET Framework 4.6.1 is treated by NuGet as implementing .NET Standard
|
While the .NET Framework 4.6.1 is treated by NuGet as implementing .NET Standard
|
||||||
2.0, it doesn't fully implement it. This was trade-off that is explained in the
|
2.0, it doesn't fully implement it. This trade-off is explained in the
|
||||||
documentation of [.NET Standard][netfx-netstandard].
|
[.NET Standard][netfx-netstandard] specification.
|
||||||
|
|
||||||
## How to Fix Violations
|
## How to fix violations
|
||||||
|
|
||||||
You cannot reasonably guard your code against missing APIs. You only have two
|
You cannot reasonably guard your code against missing APIs. You only have two
|
||||||
options:
|
options:
|
||||||
|
|
||||||
1. Not calling the affected API
|
1. Not call the affected API.
|
||||||
2. Not running your code on .NET Framework 4.6.1
|
2. Not run your code on .NET Framework 4.6.1.
|
||||||
|
|
||||||
## When to Suppress Warnings
|
## When to suppress warnings
|
||||||
|
|
||||||
Unless you stop calling the API entirely, you'll have to suppress this warning:
|
Unless you stop calling the API entirely, you have to suppress this warning as shown in the following example:
|
||||||
|
|
||||||
```C#
|
```C#
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
|
@ -5,18 +5,18 @@
|
||||||
You're P/Invoking into a native API from a .NET Standard project or a UWP
|
You're P/Invoking into a native API from a .NET Standard project or a UWP
|
||||||
project but that API isn't available in UWP.
|
project but that API isn't available in UWP.
|
||||||
|
|
||||||
## Rule Description
|
## Rule description
|
||||||
|
|
||||||
Not all Win32 APIs are available in UWP. While calling the API might work when
|
Not all Win32 APIs are available in UWP. While calling the API might work when
|
||||||
debugging the app, the app store will reject any apps that contain P/Invoke
|
debugging the app, the app store will reject any apps that contain P/Invoke
|
||||||
declarations with unsupported APIs.
|
declarations with unsupported APIs.
|
||||||
|
|
||||||
## How to Fix Violations
|
## How to fix violations
|
||||||
|
|
||||||
Remove the P/Invoke declaration. When targeting .NET Standard, consider cross-
|
Remove the P/Invoke declaration. When targeting .NET Standard, consider cross-
|
||||||
targeting for UWP.
|
targeting for UWP.
|
||||||
|
|
||||||
## When to Suppress Warnings
|
## When to suppress warnings
|
||||||
|
|
||||||
The tool might not be able to detect usages of APIs that part of your
|
The tool might not be able to detect usages of APIs that part of your
|
||||||
application. If it's a native module that you deploy with your app, you should
|
application. If it's a native module that you deploy with your app, you should
|
||||||
|
|
Загрузка…
Ссылка в новой задаче