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
|
||||
|
||||
* 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.
|
||||
* However, even on Windows `SecureString` doesn't exist as an OS concept
|
||||
- It just makes the window getting the plain text shorter; it doesn't fully
|
||||
* 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
|
||||
prevent it as .NET still has to convert the string to a plain text
|
||||
representation
|
||||
- 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
|
||||
representation.
|
||||
* The benefit is that the plain text representation doesn't hang around
|
||||
as an instance of [`System.String`][String] -- the lifetime of the native buffer is
|
||||
shorter.
|
||||
* The contents of the array is unencrypted except on .NET Framework.
|
||||
- In .NET Framework, the contents of the internal char array is encrypted.
|
||||
We've trouble with supporting the encryption in all environments, either
|
||||
* In .NET Framework, the contents of the internal char array is encrypted.
|
||||
.NET doesn't support encryption in all environments, either
|
||||
due to missing APIs or key management issues.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Don't use `SecureString` for new code. When porting code to .NET Core, consider
|
||||
that the contents of the array will not be encrypted in memory.
|
||||
Don't use [`SecureString`][SecureString] for new code. When porting code to .NET Core, consider
|
||||
that the contents of the array are not encrypted in memory.
|
||||
|
||||
The general approach of dealing with credentials is to avoid them and instead
|
||||
rely on other means to authenticate, such as certificates or Windows
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
|
|
@ -9,9 +9,9 @@ T:System.Net.HttpWebRequest
|
|||
|
||||
## 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).
|
||||
|
||||
## 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
|
||||
|
||||
`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).
|
||||
|
||||
## 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
|
||||
|
||||
`SmtpClient` does not support many modern protocols. It is compat-only. It's
|
||||
great for one off emails from tools, but does not scale to modern requirements
|
||||
of the protocol.
|
||||
[`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 doesn't scale to modern requirements of the protocol.
|
||||
|
||||
## 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
|
||||
|
||||
When .NET was created, generic data types didn't exist, which is why the
|
||||
collection types in `System.Collections` are untyped. However, since then
|
||||
generic data types and thus a new set of collections in
|
||||
`System.Collections.Generic` were made available.
|
||||
collection types in the [`System.Collections`][collections] namespace are untyped. However, since then,
|
||||
generic data types were introduced and thus a new set of collections
|
||||
were made available in the [`System.Collections.Generic`][generic] and
|
||||
[`System.Collections.ObjectModel`][objectmodel] namespaces.
|
||||
|
||||
## Recommendation
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
* **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
|
||||
in an `int[]`. That's far better than storing the data in `object[]` as that
|
||||
requires boxing.
|
||||
|
||||
Consult the following table which how the non-generic collection types can be
|
||||
replaced by their generic counterparts in `System.Collections.Generic`:
|
||||
The following table shows how the non-generic collection types can be
|
||||
replaced by their generic counterparts from the [`System.Collections.Generic`][generic] or
|
||||
[`System.Collections.ObjectModel`][objectmodel] namespaces:
|
||||
|
||||
| Type | Replacement |
|
||||
|-----------------------------------|------------------------------------------------------------|
|
||||
| `ArrayList` | `List<T>` |
|
||||
| `Hashtable` | `Dictionary<TKey, TValue>` |
|
||||
| `Queue` | `Queue<T>` |
|
||||
| `Stack` | `Stack<T>` |
|
||||
| `SortedList` | `SortedList<TKey, TValue>` |
|
||||
| `DictionaryEntry` | `KeyValuePair<TKey, TValue>` |
|
||||
| `DictionaryBase` | `Dictionary<TKey, TValue> or KeyedCollection<TKey, TItem>` |
|
||||
| `CollectionBase` | `Collection<T>` |
|
||||
| `ReadOnlyCollectionBase` | `ReadOnlyCollection<T>` |
|
||||
| `Comparer` | `Comparer<T>` |
|
||||
| `CaseInsensitiveComparer` | `StringComparer.OrdinalIgnoreCase` |
|
||||
| `CaseInsensitiveHashCodeProvider` | `StringComparer.OrdinalIgnoreCase` |
|
||||
| Type | Replacement |
|
||||
|----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|
|
||||
| [`ArrayList`][arraylist] | [`List<T>`][list] |
|
||||
| [`CaseInsensitiveComparer`][caseinsensitivecomparer] | [`StringComparer.OrdinalIgnoreCase`][ordinalignorecase] |
|
||||
| [`CaseInsensitiveHashCodeProvider`][caseinsensitivehashcodeprovider] | [`StringComparer.OrdinalIgnoreCase`][ordinalignorecase] |
|
||||
| [`CollectionBase`][collectionbase] | [`Collection<T>`][collection-1] |
|
||||
| [`Comparer`][comparer] | [`Comparer<T>`][comparer-1] |
|
||||
| [`DictionaryBase`][dictionarybase] | [`Dictionary<TKey, TValue>`][dictionary] or [`KeyedCollection<TKey, TItem>`][keyedcollection] |
|
||||
| [`DictionaryEntry`][dictionaryentry] | [`KeyValuePair<TKey, TValue>`][keyvaluepair] |
|
||||
| [`Hashtable`][hashtable] | [`Dictionary<TKey, TValue>`][dictionary] |
|
||||
| [`Queue`][queue] | [`Queue<T>`][queue-1] |
|
||||
| [`ReadOnlyCollectionBase`][readonlycollectionbase] | [`ReadOnlyCollection<T>`][readonlycollection] |
|
||||
| [`SortedList`][sortedlist] | [`SortedList<TKey, TValue>`][sortedlist-2] |
|
||||
| [`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
|
||||
|
||||
Certain enum values on `System.PlatformID` are no longer in use and will never
|
||||
be returned from `Environment.OSVersion.Platform`.
|
||||
Certain enum values on [`System.PlatformID`][PlatformID] are no longer in use and will never
|
||||
be returned from [`Environment.OSVersion.Platform`][Platform].
|
||||
|
||||
## Recommendation
|
||||
|
||||
|
@ -24,8 +24,11 @@ the correct ones.
|
|||
| Win32Windows | Unused
|
||||
| WinCE | 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`
|
||||
should use the newer `RuntimeInformation.IsOSPlatform(OSPlatform.OSX)` API
|
||||
instead.
|
||||
Code that compares [`Environment.OSVersion.Platform`][Platform] to [`PlatformID.MacOSX`][PlatformID]
|
||||
should use the newer [`RuntimeInformation.IsOSPlatform(OSPlatform.OSX)`][IsOSPlatform] method 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
|
||||
|
||||
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.
|
||||
|
||||
* In .NET Core, an `InvalidOperationException` is thrown if a thread tries
|
||||
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 Core, if a thread tries to read or write these properties on a different thread, an [`InvalidOperationException`][InvalidOperationException] is thrown.
|
||||
|
||||
* In .NET Framework, setting these properties isn't reliable for a different thread.
|
||||
|
||||
## 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
|
||||
|
||||
You're calling an API in .NET Core or .NET Standard that will throw
|
||||
`PlatformNotSupportedException` in all or some circumstances.
|
||||
You're calling an API in .NET Core or .NET Standard that throws
|
||||
[`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
|
||||
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
|
||||
`PlatformNotSupportedException`. The fix is to review the API documentation for
|
||||
which this rule was triggered for and to do one of the following:
|
||||
[`PlatformNotSupportedException`][PlatformNotSupportedException]. The fix is to review the API documentation for
|
||||
which this rule was triggered and to do one of the following:
|
||||
|
||||
1. Not calling the API
|
||||
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
|
||||
said platforms
|
||||
1. Not call the API.
|
||||
2. Guard this call and suppress the specific occurrence of this rule.
|
||||
3. Not run your code on the affected platforms and suppress this rule for
|
||||
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#
|
||||
#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
|
||||
add a property `PlatformCompatIgnore` that lists all platforms you don't plan to
|
||||
run your code on:
|
||||
add a `PlatformCompatIgnore` property that lists all platforms you don't plan to
|
||||
run your code on like in the following example:
|
||||
|
||||
```XML
|
||||
<PropertyGroup>
|
||||
<PlatformCompatIgnore>Linux;MacOSX</PlatformCompatIgnore>
|
||||
</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
|
||||
|
||||
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.
|
||||
|
||||
## Rule Description
|
||||
## Rule description
|
||||
|
||||
While .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
|
||||
documentation of [.NET Standard][netfx-netstandard].
|
||||
While the .NET Framework 4.6.1 is treated by NuGet as implementing .NET Standard
|
||||
2.0, it doesn't fully implement it. This trade-off is explained in the
|
||||
[.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
|
||||
options:
|
||||
|
||||
1. Not calling the affected API
|
||||
2. Not running your code on .NET Framework 4.6.1
|
||||
1. Not call the affected API.
|
||||
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#
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
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.
|
||||
|
||||
## Rule Description
|
||||
## Rule description
|
||||
|
||||
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
|
||||
declarations with unsupported APIs.
|
||||
|
||||
## How to Fix Violations
|
||||
## How to fix violations
|
||||
|
||||
Remove the P/Invoke declaration. When targeting .NET Standard, consider cross-
|
||||
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
|
||||
application. If it's a native module that you deploy with your app, you should
|
||||
|
|
Загрузка…
Ссылка в новой задаче