diff --git a/.gitignore b/.gitignore
index 4ce6fdd..9ba4100 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,8 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+*.tar
+
# User-specific files
*.rsuser
*.suo
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..6bfba01
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,36 @@
+{
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/FlightSystem2/bin/Debug/netcoreapp3.0/FlightSystem.Api.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/FlightSystem2",
+ "stopAtEntry": false,
+ // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/class.cs-template b/.vscode/solution-explorer/class.cs-template
new file mode 100644
index 0000000..015da46
--- /dev/null
+++ b/.vscode/solution-explorer/class.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public class {{name}}
+ {
+ }
+}
diff --git a/.vscode/solution-explorer/class.ts-template b/.vscode/solution-explorer/class.ts-template
new file mode 100644
index 0000000..ff2edef
--- /dev/null
+++ b/.vscode/solution-explorer/class.ts-template
@@ -0,0 +1,3 @@
+export class {{name}} {
+
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/class.vb-template b/.vscode/solution-explorer/class.vb-template
new file mode 100644
index 0000000..38ef67f
--- /dev/null
+++ b/.vscode/solution-explorer/class.vb-template
@@ -0,0 +1,9 @@
+Imports System
+
+Namespace {{namespace}}
+
+ Public Class {{name}}
+
+ End Class
+
+End Namespace
diff --git a/.vscode/solution-explorer/default.ts-template b/.vscode/solution-explorer/default.ts-template
new file mode 100644
index 0000000..04af870
--- /dev/null
+++ b/.vscode/solution-explorer/default.ts-template
@@ -0,0 +1,3 @@
+export default {{name}} {
+
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/enum.cs-template b/.vscode/solution-explorer/enum.cs-template
new file mode 100644
index 0000000..7d4cdee
--- /dev/null
+++ b/.vscode/solution-explorer/enum.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public enum {{name}}
+ {
+ }
+}
diff --git a/.vscode/solution-explorer/interface.cs-template b/.vscode/solution-explorer/interface.cs-template
new file mode 100644
index 0000000..6b5dec1
--- /dev/null
+++ b/.vscode/solution-explorer/interface.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public interface {{name}}
+ {
+ }
+}
diff --git a/.vscode/solution-explorer/interface.ts-template b/.vscode/solution-explorer/interface.ts-template
new file mode 100644
index 0000000..3ea404b
--- /dev/null
+++ b/.vscode/solution-explorer/interface.ts-template
@@ -0,0 +1,3 @@
+export interface {{name}} {
+
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/template-list.json b/.vscode/solution-explorer/template-list.json
new file mode 100644
index 0000000..2849622
--- /dev/null
+++ b/.vscode/solution-explorer/template-list.json
@@ -0,0 +1,46 @@
+{
+ "templates": [
+ {
+ "name": "Class",
+ "extension": "cs",
+ "file": "./class.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Interface",
+ "extension": "cs",
+ "file": "./interface.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Enum",
+ "extension": "cs",
+ "file": "./enum.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Class",
+ "extension": "ts",
+ "file": "./class.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Interface",
+ "extension": "ts",
+ "file": "./interface.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Default",
+ "extension": "ts",
+ "file": "./default.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Class",
+ "extension": "vb",
+ "file": "./class.vb-template",
+ "parameters": "./template-parameters.js"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/template-parameters.js b/.vscode/solution-explorer/template-parameters.js
new file mode 100644
index 0000000..daba8b2
--- /dev/null
+++ b/.vscode/solution-explorer/template-parameters.js
@@ -0,0 +1,17 @@
+var path = require("path");
+
+module.exports = function(filename, projectPath, folderPath) {
+ var namespace = "Unknown";
+ if (projectPath) {
+ namespace = path.basename(projectPath, path.extname(projectPath));
+ if (folderPath) {
+ namespace += "." + folderPath.replace(path.dirname(projectPath), "").substring(1).replace(/[\\\/]/g, ".");
+ }
+ namespace = namespace.replace(/[\\\-]/g, "_");
+ }
+
+ return {
+ namespace: namespace,
+ name: path.basename(filename, path.extname(filename))
+ }
+};
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..deb2b4b
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/FlightSystem2/FlightSystem.Api.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/FlightSystem2/FlightSystem.Api.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/FlightSystem2/FlightSystem.Api.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/FlightSystem2.ndproj b/FlightSystem2.ndproj
deleted file mode 100644
index 3cba6e7..0000000
--- a/FlightSystem2.ndproj
+++ /dev/null
@@ -1,12517 +0,0 @@
-
-
- .\NDependOut
-
-
-
-
-
-
- C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.0.0
- C:\Program Files\dotnet\sdk\NuGetFallbackFolder
- C:\Users\Paulius\.nuget\packages
-
- True
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
- 1
- 0
- 0
- $ManDay$
- 50
- USD
- After
- 18
- 240
- 8
- 5
- 10
- 20
- 50
- 1200000000
- 12000000000
- 72000000000
- 360000000000
-
-
-
-
- Quality Gates Evolution
-from qg in QualityGates
-let qgBaseline = qg.OlderVersion()
-let relyOnDiff = qgBaseline == null
-let evolution = relyOnDiff ? (TrendIcon?)null :
- // When a quality gate relies on diff between now and baseline
- // it is not executed against the baseline
- qg.ValueDiff() == 0d ?
- TrendIcon.Constant :
- (qg.ValueDiff() > 0 ?
- ( qg.MoreIsBad ? TrendIcon.RedUp: TrendIcon.GreenUp) :
- (!qg.MoreIsBad ? TrendIcon.RedDown: TrendIcon.GreenDown))
-select new { qg,
- Evolution = evolution,
-
- BaselineStatus = relyOnDiff? (QualityGateStatus?) null : qgBaseline.Status,
- Status = qg.Status,
-
- BaselineValue = relyOnDiff? (null) : qgBaseline.ValueString,
- Value = qg.ValueString,
-}
-
-//
-// Show quality gates evolution between baseline and now.
-//
-// When a quality gate relies on diff between now and baseline (like *New Debt since Baseline*)
-// it is not executed against the baseline and as a consequence its evolution is not available.
-//
-// Double-click a quality gate for editing.
-// ]]>
-
-failif value < 70%
-warnif value < 80%
-codeBase.PercentageCoverage
-
-//
-// Code coverage is a measure used to describe the degree to which the source code of a program
-// is tested by a particular test suite. A program with high code coverage, measured as a percentage,
-// has had more of its source code executed during testing which suggests it has a lower chance of
-// containing undetected software bugs compared to a program with low code coverage.
-//
-// Code coverage is certainly the most important quality code metric. But coverage is not enough
-// the team needs to ensure that results are checked at test-time. These checks can be done both
-// in test code, and in application code through assertions. The important part is that a test
-// must fail explicitely when a check gets unvalidated during the test execution.
-//
-// This quality gate define a warn threshold (70%) and a fail threshold (80%). These are
-// indicative thresholds and in practice the more the better. To achieve high coverage and
-// low risk, make sure that new and refactored classes gets 100% covered by tests and that
-// the application and test code contains as many checks/assertions as possible.
-//]]>
-
-failif value < 70%
-warnif value < 80%
-let newMethods = Application.Methods.Where(m => m.WasAdded() && m.NbLinesOfCode > 0)
-let locCovered = newMethods.Sum(m => m.NbLinesOfCodeCovered)
-let loc = newMethods.Sum(m => m.NbLinesOfCode)
-select 100d * locCovered / loc
-
-//
-// *New Code* is defined as methods added since the baseline.
-//
-// To achieve high code coverage it is essential that new code gets properly
-// tested and covered by tests. It is advised that all non-UI new classes gets
-// 100% covered.
-//
-// Typically 90% of a class is easy to cover by tests and 10% is hard to reach
-// through tests. It means that this 10% remaining is not easily testable, which
-// means it is not well designed, which often means that this code is especially
-// **error-prone**. This is the reason why it is important to reach 100% coverage
-// for a class, to make sure that potentially *error-prone* code gets tested.
-//
-]]>
-
-failif value < 70%
-warnif value < 80%
-let newMethods = Application.Methods.Where(m => m.CodeWasChanged() && m.NbLinesOfCode > 0)
-let locCovered = newMethods.Sum(m => m.NbLinesOfCodeCovered)
-let loc = newMethods.Sum(m => m.NbLinesOfCode)
-select 100d * locCovered / loc
-
-//
-// *Refactored Code* is defined as methods where *code was changed* since the baseline.
-//
-// Comment changes and formatting changes are not considerd as refactoring.
-//
-// To achieve high code coverage it is essential that refactored code gets properly
-// tested and covered by tests. It is advised that when refactoring a class
-// or a method, it is important to also write tests to make sure it gets 100% covered.
-//
-// Typically 90% of a class is easy to cover by tests and 10% is hard to reach
-// through tests. It means that this 10% remaining is not easily testable, which
-// means it is not well designed, which often means that this code is especially
-// **error-prone**. This is the reason why it is important to reach 100% coverage
-// for a class, to make sure that potentially *error-prone* code gets tested.
-//
-]]>
-
-failif count > 0 issues
-from i in Issues
-where i.Severity == Severity.Blocker
-select new { i, i.Severity, i.Debt, i.AnnualInterest }
-
-//
-// An issue with the severity **Blocker** cannot move to production, it must be fixed.
-//
-// The severity of an issue is either defined explicitely in the rule source code,
-// either inferred from the issue *annual interest* and thresholds defined in the
-// NDepend Project Properties > Issue and Debt.
-//
-
-]]>
-
-failif count > 10 issues
-warnif count > 0 issues
-
-from i in Issues
-where i.Severity == Severity.Critical
-select new { i, i.Severity, i.Debt, i.AnnualInterest }
-
-//
-// An issue with a severity level **Critical** shouldn't move to production.
-// It still can for business imperative needs purposes, but at worst it must
-// be fixed during the next iterations.
-//
-// The severity of an issue is either defined explicitely in the rule source code,
-// either inferred from the issue *annual interest* and thresholds defined in the
-// NDepend Project Properties > Issue and Debt.
-//]]>
-
-failif count > 0 issues
-from i in Issues
-where i.Severity.EqualsAny(Severity.Blocker, Severity.Critical, Severity.High) &&
- // Count both the new issues and the issues that became at least Critical
- (i.WasAdded() || i.OlderVersion().Severity < Severity.High)
-select new { i, i.Severity, i.Debt, i.AnnualInterest }
-
-
-//
-// An issue with the severity **Blocker** cannot move to production, it must be fixed.
-//
-// An issue with a severity level **Critical** shouldn't move to production.
-// It still can for business imperative needs purposes, but at worth it must be fixed
-// during the next iterations.
-//
-// An issue with a severity level **High** should be fixed quickly, but can wait until
-// the next scheduled interval.
-//
-// The severity of an issue is either defined explicitely in the rule source code,
-// either inferred from the issue *annual interest* and thresholds defined in the
-// NDepend Project Properties > Issue and Debt.
-//
-]]>
-
-failif count > 0 rules
-from r in Rules where r.IsCritical && r.IsViolated()
-select new { r, issues = r.Issues() }
-
-//
-// The concept of critical rule is useful to pinpoint certain rules that
-// should not be violated.
-//
-// A rule can be made critical just by checking the *Critical button* in the
-// rule edition control and then saving the rule.
-//
-// This quality gate fails if any critical rule gets any violations.
-//
-// When no baseline is available, rules that rely on diff are not counted.
-// If you observe that this quality gate count slightly decreases with no apparent reason,
-// the reason is certainly that rules that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-failif value > 30%
-warnif value > 20%
-let timeToDev = codeBase.EffortToDevelop()
-let debt = Issues.Sum(i => i.Debt)
-select 100d * debt.ToManDay() / timeToDev.ToManDay()
-
-//
-// % Debt total is defined as a percentage on:
-//
-// • the estimated total effort to develop the code base
-//
-// • and the the estimated total time to fix all issues (the Debt)
-//
-// Estimated total effort to develop the code base is inferred from
-// # lines of code of the code base and from the
-// *Estimated number of man-day to develop 1000 logicial lines of code*
-// setting found in NDepend Project Properties > Issue and Debt.
-//
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-//
-// This quality gates fails if the estimated debt is more than 30%
-// of the estimated effort to develop the code base, and warns if the
-// estimated debt is more than 20% of the estimated effort to develop
-// the code base
-// ]]>
-
-failif value > 50 man-days
-warnif value > 30 man-days
-Issues.Sum(i => i.Debt).ToManDay()
-
-//
-// This Quality Gate is disabled per default because the fail and warn
-// thresholds of unacceptable Debt in man-days can only depend on the
-// project size, number of developers and overall context.
-//
-// However you can refer to the default Quality Gate **Percentage Debt**.
-//
-// The Debt is defined as the sum of estimated effort to fix all issues.
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-//]]>
-
-failif value > 2 man-days
-warnif value > 0 man-days
-let debt = Issues.Sum(i => i.Debt)
-let debtInBaseline = IssuesInBaseline.Sum(i => i.Debt)
-select (debt - debtInBaseline).ToManDay()
-
-
-//
-// This Quality Gate fails if the estimated effort to fix new or worsened
-// issues (what is called the *New Debt since Baseline*) is higher
-// than 2 man-days.
-//
-// This Quality Gate warns if this estimated effort is positive.
-//
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-//]]>
-
-failif count > 0 namespaces
-
-from n in Application.Namespaces
-where n.DebtRating() != null &&
- n.DebtRating().Value.EqualsAny(DebtRating.E, DebtRating.D)
-select new {
- n,
- debtRating = n.DebtRating(),
- debtRatio = n.DebtRatio(), // % of debt from which DebtRating is inferred
- devTimeInManDay = n.EffortToDevelop().ToDebt(),
- debtInManDay = n.AllDebt(),
- issues = n.AllIssues()
-}
-
-//
-// Forbid namespaces with a poor Debt Rating equals to **E** or **D**.
-//
-// The **Debt Rating** for a code element is estimated by the value of the **Debt Ratio**
-// and from the various rating thresholds defined in this project *Debt Settings*.
-//
-// The **Debt Ratio** of a code element is a percentage of **Debt Amount** (in floating man-days)
-// compared to the **estimated effort to develop the code element** (also in floating man-days).
-//
-// The **estimated effort to develop the code element** is inferred from the code elements
-// number of lines of code, and from the project *Debt Settings* parameters
-// *estimated number of man-days to develop 1000* **logical lines of code**.
-//
-// The **logical lines of code** corresponds to the number of debug breakpoints in a method
-// and doesn't depend on code formatting nor comments.
-//
-// The Quality Gate can be modified to match assemblies, types or methods
-// with a poor Debt Rating, instead of matching namespaces.
-// ]]>
-
-failif value > 50 man-days
-warnif value > 30 man-days
-Issues.Sum(i => i.AnnualInterest).ToManDay()
-
-
-//
-// This Quality Gate is disabled per default because the fail and warn
-// thresholds of unacceptable Annual-Interest in man-days can only depend
-// on the project size, number of developers and overall context.
-//
-// However you can refer to the default Quality Gate
-// **New Annual Interest since Baseline**.
-//
-// The Annual-Interest is defined as the sum of estimated annual cost
-// in man-days, to leave all issues unfixed.
-//
-// Each rule can either provide a formula to compute the Annual-Interest
-// per issue, or assign a **Severity** level for each issue. Some thresholds
-// defined in *Project Properties > Issue and Debt > Annual Interest* are
-// used to infer an Annual-Interest value from a Severity level.
-// Annual Interest documentation: https://www.ndepend.com/docs/technical-debt#AnnualInterest
-//]]>
-
-failif value > 2 man-days
-warnif value > 0 man-days
-let ai = Issues.Sum(i => i.AnnualInterest)
-let aiInBaseline = IssuesInBaseline.Sum(i => i.AnnualInterest)
-select (ai - aiInBaseline).ToManDay()
-
-//
-// This Quality Gate fails if the estimated annual cost to leave all issues
-// unfixed, increased from more than 2 man-days since the baseline.
-//
-// This Quality Gate warns if this estimated annual cost is positive.
-//
-// This estimated annual cost is named the **Annual-Interest**.
-//
-// Each rule can either provide a formula to compute the Annual-Interest
-// per issue, or assign a **Severity** level for each issue. Some thresholds
-// defined in *Project Properties > Issue and Debt > Annual Interest* are
-// used to infer an Annual-Interest value from a Severity level.
-// Annual Interest documentation: https://www.ndepend.com/docs/technical-debt#AnnualInterest
-//]]>
-
-
- Types Hot Spots
-from t in JustMyCode.Types
-where t.AllDebt() > Debt.Zero &&
- t.AllAnnualInterest() > AnnualInterest.Zero
-orderby t.AllDebt().Value.TotalMinutes descending
-select new { t,
- Debt = t.AllDebt(),
- Issues = t.AllIssues(), // AllIssues = {types issues} union {members issues}
- AnnualInterest = t.AllAnnualInterest(),
- BreakingPoint = t.AllBreakingPoint(),
- t.NbLinesOfCode,
- // t.PercentageCoverage, to uncomment if coverage data is imported
- DebtRating = t.DebtRating(),
- DebtRatio = t.DebtRatio()
-}
-
-//
-// This query lists **types with most Debt**,
-// or in other words, types with issues that would need
-// the largest effort to get fixed.
-//
-// Both issues on the type and its members are
-// taken account.
-//
-// Since untested code often generates a lot of
-// Debt, the type size and percentage coverage is shown
-// (just uncomment *t.PercentageCoverage* in the query
-// source code once you've imported the coverage data).
-//
-// The *Debt Rating* and *Debt Ratio* are also shown
-// for informational purpose.
-//
-// --
-//
-// The amount of *Debt* is not a measure to prioritize
-// the effort to fix issues, it is an estimation of how far
-// the team is from clean code that abides by the rules set.
-//
-// For each issue the *Annual Interest* estimates the annual
-// cost to leave the issues unfixed. The *Severity* of an issue
-// is estimated through thresholds from the *Annual Interest*.
-//
-// The **Debt Breaking Point** represents the duration
-// from now when the estimated cost to leave the issue unfixed
-// costs as much as the estimated effort to fix it.
-//
-// Hence the shorter the **Debt Breaking Point**
-// the largest the **Return on Investment** for fixing
-// the issue. The **Breaking Point is the right metric
-// to prioritize issues fix**.
-//]]>
- Types to Fix Priority
-from t in JustMyCode.Types
-where t.AllBreakingPoint() > TimeSpan.Zero &&
- t.AllDebt().Value > 30.ToMinutes()
-orderby t.AllBreakingPoint().TotalMinutes ascending
-select new { t,
- BreakingPoint = t.AllBreakingPoint(),
- Debt = t.AllDebt(),
- AnnualInterest = t.AllAnnualInterest(),
- Issues = t.AllIssues(),
- t.NbLinesOfCode,
- // t.PercentageCoverage, to uncomment if coverage data is imported
- DebtRating = t.DebtRating(),
- DebtRatio = t.DebtRatio()
-}
-
-//
-// This query lists types per increasing
-// **Debt Breaking Point**.
-//
-// For each issue the *Debt* estimates the
-// effort to fix the issue, and the *Annual Interest*
-// estimates the annual cost to leave the issue unfixed.
-// The *Severity* of an issue is estimated through
-// thresholds from the *Annual Interest* of the issue.
-//
-// The **Debt Breaking Point** represents the duration
-// from now when the estimated cost to leave the issue unfixed
-// costs as much as the estimated effort to fix it.
-//
-// Hence the shorter the **Debt Breaking Point**
-// the largest the **Return on Investment** for fixing
-// the issues.
-//
-// Often new and refactored types since baseline will be
-// listed first, because issues on these types get a
-// higher *Annual Interest* because it is important to
-// focus first on new issues.
-//
-//
-// --
-//
-// Both issues on the type and its members are
-// taken account.
-//
-// Only types with at least 30 minutes of Debt are listed
-// to avoid parasiting the list with the numerous
-// types with small *Debt*, on which the *Breaking Point*
-// value makes less sense.
-//
-// The *Annual Interest* estimates the cost per year
-// in man-days to leave these issues unfixed.
-//
-// Since untested code often generates a lot of
-// Debt, the type size and percentage coverage is shown
-// (just uncomment *t.PercentageCoverage* in the query
-// source code once you've imported the coverage data).
-//
-// The *Debt Rating* and *Debt Ratio* are also shown
-// for informational purpose.
-//]]>
- Issues to Fix Priority
-from i in Issues
-// Don't show first issues with BreakingPoint equals to zero.
-orderby i.BreakingPoint != TimeSpan.Zero ? i.BreakingPoint : TimeSpan.MaxValue
-select new { i,
- Debt = i.Debt,
- AnnualInterest = i.AnnualInterest,
- BreakingPoint = i.BreakingPoint,
- CodeElement = i.CodeElement
-}
-
-//
-// This query lists issues per increasing
-// **Debt Breaking Point**.
-//
-// Double-click an issue to edit its rule and
-// select the issue in the rule result. This way
-// you can view all information concerning the issue.
-//
-// For each issue the *Debt* estimates the
-// effort to fix the issue, and the *Annual Interest*
-// estimates the annual cost to leave the issue unfixed.
-// The *Severity* of an issue is estimated through
-// thresholds from the *Annual Interest* of the issue.
-//
-// The **Debt Breaking Point** represents the duration
-// from now when the estimated cost to leave the issue unfixed
-// costs as much as the estimated effort to fix it.
-//
-// Hence the shorter the **Debt Breaking Point**
-// the largest the **Return on Investment** for fixing
-// the issue.
-//
-// Often issues on new and refactored code elements since
-// baseline will be listed first, because such issues get a
-// higher *Annual Interest* because it is important to
-// focus first on new issues on recent code.
-//
-// More documentation: https://www.ndepend.com/docs/technical-debt
-//]]>
- Debt and Issues per Rule
-from r in Rules
-where r.IsViolated()
-orderby r.Debt().Value descending
-select new {
- r,
- Issues = r.Issues(),
- Debt = r.Debt(),
- AnnualInterest = r.AnnualInterest(),
- BreakingPoint = r.BreakingPoint(),
- Category = r.Category
-}
-
-//
-// This query lists violated rules with most *Debt* first.
-//
-// A rule violated has issues. For each issue the *Debt*
-// estimates the effort to fix the issue.
-//
-// --
-//
-// The amount of *Debt* is not a measure to prioritize
-// the effort to fix issues, it is an estimation of how far
-// the team is from clean code that abides by the rules set.
-//
-// For each issue the *Annual Interest* estimates the annual
-// cost to leave the issues unfixed. The *Severity* of an issue
-// is estimated through thresholds from the *Annual Interest*.
-//
-// The **Debt Breaking Point** represents the duration
-// from now when the estimated cost to leave the issue unfixed
-// costs as much as the estimated effort to fix it.
-//
-// Hence the shorter the **Debt Breaking Point**
-// the largest the **Return on Investment** for fixing
-// the issue. The **Breaking Point is the right metric
-// to prioritize issues fix**.
-//
-// --
-//
-// Notice that rules can be grouped in *Rule Category*. This
-// way you'll see categories that generate most *Debt*.
-//
-// Typically the rules that generate most *Debt* are the
-// ones related to *Code Coverage by Tests*, *Architecture*
-// and *Code Smells*.
-//
-// More documentation: https://www.ndepend.com/docs/technical-debt
-//]]>
- New Debt and Issues per Rule
-from r in Rules
-where r.IsViolated() && r.IssuesAdded().Count() > 0
-orderby r.DebtDiff().Value descending
-select new {
- r,
- IssuesAdded = r.IssuesAdded(),
- IssuesFixed = r.IssuesFixed(),
- Issues = r.Issues(),
- Debt = r.Debt(),
- DebtDiff = r.DebtDiff(),
- Category = r.Category
-}
-
-//
-// This query lists violated rules that have new issues
-// since baseline, with most **new Debt** first.
-//
-// A rule violated has issues. For each issue the *Debt*
-// estimates the effort to fix the issue.
-//
-// --
-//
-// New issues since the baseline are consequence of recent code
-// refactoring sessions. They represent good opportunities
-// of fix because the code recently refactored is fresh in
-// the developers mind, which means fixing now costs less
-// than fixing later.
-//
-// Fixing issues on recently touched code is also a good way
-// to foster practices that will lead to higher code quality
-// and maintainability, including writing unit-tests
-// and avoiding unnecessary complex code.
-//
-// --
-//
-// Notice that rules can be grouped in *Rule Category*. This
-// way you'll see categories that generate most *Debt*.
-//
-// Typically the rules that generate most *Debt* are the
-// ones related to *Code Coverage by Tests*, *Architecture*
-// and *Code Smells*.
-//
-// More documentation: https://www.ndepend.com/docs/technical-debt
-//]]>
- Debt and Issues per Code Element
-from elem in CodeElements
-where elem.HasIssue()
-orderby elem.Debt().Value descending
-select new {
- elem,
- Issues = elem.Issues(),
- Debt = elem.Debt(),
- AnnualInterest = elem.AnnualInterest(),
- BreakingPoint = elem.BreakingPoint()
-}
-
-//
-// This query lists code elements that have issues,
-// with most *Debt* first.
-//
-// For each code element the *Debt* estimates
-// the effort to fix the element issues.
-//
-// The amount of *Debt* is not a measure to prioritize
-// the effort to fix issues, it is an estimation of how far
-// the team is from clean code that abides by the rules set.
-//
-// For each element the *Annual Interest* estimates the annual
-// cost to leave the elements issues unfixed. The *Severity* of an
-// issue is estimated through thresholds from the *Annual Interest*
-// of the issue.
-//
-// The **Debt Breaking Point** represents the duration
-// from now when the estimated cost to leave the issues unfixed
-// costs as much as the estimated effort to fix it.
-//
-// Hence the shorter the **Debt Breaking Point**
-// the largest the **Return on Investment** for fixing
-// the issue. The **Breaking Point is the right metric
-// to prioritize issues fix**.
-//]]>
- New Debt and Issues per Code Element
-from elem in CodeElements
-where elem.HasIssue() && elem.IssuesAdded().Count() > 0
-orderby elem.DebtDiff().Value descending
-select new {
- elem,
- IssuesAdded = elem.IssuesAdded(),
- IssuesFixed = elem.IssuesFixed(),
- Issues = elem.Issues(),
- Debt = elem.Debt(),
- DebtDiff = elem.DebtDiff()
-}
- //
-// This query lists code elements that have new issues
-// since baseline, with most **new Debt** first.
-//
-// For each code element the *Debt* estimates
-// the effort to fix the element issues.
-//
-// New issues since the baseline are consequence of recent code
-// refactoring sessions. They represent good opportunities
-// of fix because the code recently refactored is fresh in
-// the developers mind, which means fixing now costs less
-// than fixing later.
-//
-// Fixing issues on recently touched code is also a good way
-// to foster practices that will lead to higher code quality
-// and maintainability, including writing unit-tests
-// and avoiding unnecessary complex code.
-//
-]]>
-
-
- Avoid types too big
-// ND1000:AvoidTypesTooBig
-warnif count > 0 from t in JustMyCode.Types where
-
- // First filter on type to optimize
- t.NbLinesOfCode > 200
- // # IL Instructions is commented, because with LINQ syntax, a few lines of code can compile to hundreds of IL instructions.
- // || t.NbILInstructions > 3000
-
- // What matters is the # lines of code in JustMyCode
- let locJustMyCode = t.MethodsAndConstructors.Where(m => JustMyCode.Contains(m)).Sum(m => m.NbLinesOfCode)
- where locJustMyCode > 200
-
- let isStaticWithNoMutableState = (t.IsStatic && t.Fields.Any(f => !f.IsImmutable))
- let staticFactor = (isStaticWithNoMutableState ? 0.2 : 1)
-
- orderby locJustMyCode descending
-select new {
- t,
- locJustMyCode,
- t.NbILInstructions,
- t.Methods,
- t.Fields,
-
- Debt = (staticFactor*locJustMyCode.Linear(200, 1, 2000, 10)).ToHours().ToDebt(),
-
- // The annual interest varies linearly from interest for severity major for 300 loc
- // to interest for severity critical for 2000 loc
- AnnualInterest = staticFactor*(locJustMyCode.Linear(
- 200, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 2000, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule matches types with more than 200 lines of code.
-// **Only lines of code in JustMyCode methods are taken account.**
-//
-// Types where *NbLinesOfCode > 200* are extremely complex
-// to develop and maintain.
-// See the definition of the NbLinesOfCode metric here
-// https://www.ndepend.com/docs/code-metrics#NbLinesOfCode
-//
-// Maybe you are facing the **God Class** phenomenon:
-// A **God Class** is a class that controls way too many other classes
-// in the system and has grown beyond all logic to become
-// *The Class That Does Everything*.
-//
-
-//
-// Types with many lines of code
-// should be split in a group of smaller types.
-//
-// To refactor a *God Class* you'll need patience,
-// and you might even need to recreate everything from scratch.
-// Here are a few refactoring advices:
-//
-// • The logic in the *God Class* must be splitted in smaller classes.
-// These smaller classes can eventually become private classes nested
-// in the original *God Class*, whose instances objects become
-// composed of instances of smaller nested classes.
-//
-// • Smaller classes partitioning should be driven by the multiple
-// responsibilities handled by the *God Class*. To identify these
-// responsibilities it often helps to look for subsets of methods
-// strongly coupled with subsets of fields.
-//
-// • If the *God Class* contains way more logic than states, a good
-// option can be to define one or several static classes that
-// contains no static field but only pure static methods. A pure static
-// method is a function that computes a result only from inputs
-// parameters, it doesn't read nor assign any static or instance field.
-// The main advantage of pure static methods is that they are easily
-// testable.
-//
-// • Try to maintain the interface of the *God Class* at first
-// and delegate calls to the new extracted classes.
-// In the end the *God Class* should be a pure facade without its own logic.
-// Then you can keep it for convenience or throw it away and
-// start to use the new classes only.
-//
-// • Unit Tests can help: write tests for each method before extracting it
-// to ensure you don't break functionality.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 1 hour for a 200 lines of code type,
-// up to 10 hours for a type with 2.000 or more lines of code.
-//
-// In Debt and Interest computation, this rule takes account of the fact
-// that static types with no mutable fields are just a collection of
-// static methods that can be easily splitted and moved from one type
-// to another.
-//]]>
- Avoid types with too many methods
-// ND1001:AvoidTypesWithTooManyMethods
-warnif count > 0 from t in JustMyCode.Types
-
- // Optimization: Fast discard of non-relevant types
- where t.Methods.Count() > 20
-
- // Don't match these methods
- let methods = t.Methods.Where(
- m => !(m.IsGeneratedByCompiler ||
- // m.IsConstructor || m.IsClassConstructor || // ctor/cctor not enumerated through IType.Methods
- m.IsPropertyGetter || m.IsPropertySetter ||
- m.IsEventAdder || m.IsEventRemover))
-
- where methods.Count() > 20
- orderby methods.Count() descending
-
- let isStaticWithNoMutableState = (t.IsStatic && t.Fields.Any(f => !f.IsImmutable))
- let staticFactor = (isStaticWithNoMutableState ? 0.2 : 1)
-
-select new {
- t,
- nbMethods = methods.Count(),
- instanceMethods = methods.Where(m => !m.IsStatic),
- staticMethods = methods.Where(m => m.IsStatic),
-
- t.NbLinesOfCode,
-
- Debt = (staticFactor*methods.Count().Linear(20, 1, 200, 10)).ToHours().ToDebt(),
-
- // The annual interest varies linearly from interest for severity major for 30 methods
- // to interest for severity critical for 200 methods
- AnnualInterest = (staticFactor*methods.Count().Linear(
- 20, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 200, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule matches types with more than 20 methods.
-// Such type might be hard to understand and maintain.
-//
-// Notice that methods like constructors or property
-// and event accessors are not taken account.
-//
-// Having many methods for a type might be a symptom
-// of too many responsibilities implemented.
-//
-// Maybe you are facing the **God Class** phenomenon:
-// A **God Class** is a class that controls way too many other classes
-// in the system and has grown beyond all logic to become
-// *The Class That Does Everything*.
-//
-
-//
-// To refactor properly a *God Class* please read *HowToFix advices*
-// from the default rule **Types to Big**.
-////
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 1 hour for a type with 20 methods,
-// up to 10 hours for a type with 200 or more methods.
-//
-// In Debt and Interest computation, this rule takes account of the fact
-// that static types with no mutable fields are just a collection of
-// static methods that can be easily splitted and moved from one type
-// to another.
-//]]>
- Avoid types with too many fields
-// ND1002:AvoidTypesWithTooManyFields
-warnif count > 0 from t in JustMyCode.Types
-
- // Optimization: Fast discard of non-relevant types
- where !t.IsEnumeration &&
- t.Fields.Count() > 15
-
- // Count instance fields and non-constant static fields
- let fields = t.Fields.Where(f =>
- !f.IsGeneratedByCompiler &&
- !f.IsLiteral &&
- !(f.IsStatic && f.IsInitOnly) &&
- JustMyCode.Contains(f) )
-
- where fields.Count() > 15
-
- let methodsAssigningFields = fields.SelectMany(f => f.MethodsAssigningMe)
-
- orderby fields.Count() descending
-select new {
- t,
- instanceFields = fields.Where(f => !f.IsStatic),
- staticFields = fields.Where(f => f.IsStatic),
-methodsAssigningFields ,
-
- // See definition of Size of Instances metric here:
- // https://www.ndepend.com/docs/code-metrics#SizeOfInst
- t.SizeOfInst,
-
- Debt = fields.Count().Linear(15, 1, 200, 10).ToHours().ToDebt(),
-
- // The annual interest varies linearly from interest for severity major for 30 methods
- // to interest for severity critical for 200 methods
- AnnualInterest = fields.Count().Linear(15, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 200, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule matches types with more than 15 fields.
-// Such type might be hard to understand and maintain.
-//
-// Notice that constant fields and static-readonly fields are not counted.
-// Enumerations types are not counted also.
-//
-// Having many fields for a type might be a symptom
-// of too many responsibilities implemented.
-//
-
-//
-// To refactor such type and increase code quality and maintainability,
-// certainly you'll have to group subsets of fields into smaller types
-// and dispatch the logic implemented into the methods
-// into these smaller types.
-//
-// More refactoring advices can be found in the default rule
-// **Types to Big**, *HowToFix* section.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 1 hour for a type with 15 fields,
-// to up to 10 hours for a type with 200 or more fields.
-//]]>
- Avoid methods too big, too complex
-// ND1003:AvoidMethodsTooBigTooComplex
-warnif count > 0 from m in JustMyCode.Methods where
-
- // Don't match async methods here to avoid
- // false positives because of special compiler tricks.
- !m.IsAsync &&
-
- m.ILNestingDepth > 2 &&
- (m.NbLinesOfCode > 35 ||
- m.CyclomaticComplexity > 20 ||
- m.ILCyclomaticComplexity > 60)
-
- let complexityScore = m.NbLinesOfCode/2 + m.CyclomaticComplexity + m.ILCyclomaticComplexity/3 + 3*m.ILNestingDepth
-
- orderby complexityScore descending,
- m.CyclomaticComplexity descending,
- m.ILCyclomaticComplexity descending,
- m.ILNestingDepth descending
-select new {
- m,
- m.NbLinesOfCode,
- m.CyclomaticComplexity,
- m.ILCyclomaticComplexity,
- m.ILNestingDepth,
- complexityScore,
-
- Debt = complexityScore.Linear(30, 40, 400, 8*60).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interest for severity minor
- // to interest for severity major
- AnnualInterest = complexityScore .Linear(30, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 200, 2*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// This rule matches methods where *ILNestingDepth* > 2
-// and (*NbLinesOfCode* > 35
-// or *CyclomaticComplexity* > 20
-// or *ILCyclomaticComplexity* > 60)
-// Such method is typically hard to understand and maintain.
-//
-// Maybe you are facing the **God Method** phenomenon.
-// A "God Method" is a method that does way too many processes in the system
-// and has grown beyond all logic to become *The Method That Does Everything*.
-// When need for new processes increases suddenly some programmers realize:
-// why should I create a new method for each processe if I can only add an *if*.
-//
-// See the definition of the *CyclomaticComplexity* metric here:
-// https://www.ndepend.com/docs/code-metrics#CC
-//
-// See the definition of the *ILCyclomaticComplexity* metric here:
-// https://www.ndepend.com/docs/code-metrics#ILCC
-//
-// See the definition of the *ILNestingDepth* metric here:
-// https://www.ndepend.com/docs/code-metrics#ILNestingDepth
-//
-
-//
-// A large and complex method should be split in smaller methods,
-// or even one or several classes can be created for that.
-//
-// During this process it is important to question the scope of each
-// variable local to the method. This can be an indication if
-// such local variable will become an instance field of the newly created class(es).
-//
-// Large *switch…case* structures might be refactored through the help
-// of a set of types that implement a common interface, the interface polymorphism
-// playing the role of the *switch cases tests*.
-//
-// Unit Tests can help: write tests for each method before extracting it
-// to ensure you don't break functionality.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies from 40 minutes to 8 hours, linearly from a weighted complexity score.
-//]]>
- Avoid methods with too many parameters
-// ND1004:AvoidMethodsWithTooManyParameters
-warnif count > 0 from m in JustMyCode.Methods where
- m.NbParameters >= 7 &&
-
- // Don't match a method that overrides a third-party method with many parameters
- !m.OverriddensBase.Any(mo => mo.IsThirdParty) &&
-
- // Don't match a constructor that calls a base constructor with many parameters
- !(m.IsConstructor && m.MethodsCalled.Any(
- mc => mc.IsConstructor &&
- mc.NbParameters >= 7 &&
- m.ParentType.DeriveFrom(mc.ParentType))) &&
-
- // Don't match DllImport P/invoke methods with many parameters
- !m.HasAttribute("System.Runtime.InteropServices.DllImportAttribute".AllowNoMatch())
-
- orderby m.NbParameters descending
-select new {
- m,
- m.NbParameters,
- Debt = m.NbParameters.Linear(7, 1, 40, 6).ToHours().ToDebt(),
-
- // The annual interest varies linearly from interest for severity Medium for 7 parameters
- // to interest for severity Critical for 40 parameters
- AnnualInterest = m.NbParameters.Linear(7, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 40, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule matches methods with 7 or more parameters.
-// Such method is painful to call and might degrade performance.
-// See the definition of the *NbParameters* metric here:
-// https://www.ndepend.com/docs/code-metrics#NbParameters
-//
-// This rule doesn't match a method that overrides a third-party method
-// with 7 or more parameters because such situation is the consequence
-// of a lower-level problem.
-//
-// For the same reason, this rule doesn't match a constructor that calls a
-// base constructor with 7 or more parameters.
-//
-
-//
-// More properties/fields can be added to the declaring type to
-// handle numerous states. An alternative is to provide
-// a class or a structure dedicated to handle arguments passing.
-// For example see the class *System.Diagnostics.ProcessStartInfo*
-// and the method *System.Diagnostics.Process.Start(ProcessStartInfo)*.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 1 hour for a method with 7 parameters,
-// up to 6 hours for a methods with 40 or more parameters.
-//]]>
- Avoid methods with too many overloads
-// ND1005:AvoidMethodsWithTooManyOverloads
-warnif count > 0
-let max = 6
-let lookup = JustMyCode.Methods.Where(m =>
- m.NbOverloads >= max &&
- !m.IsOperator && // Don't report operator overload
-
- // Don't match overloads due tu the visitor pattern, based on a naming convention.
- !m.SimpleName.ToLower().StartsWithAny("visit", "dispatch")
-).ToLookup(m => m.ParentType.FullName + "."+ m.SimpleName)
-
-from @group in lookup
-let overloads = @group.ToArray()
-
-// Prune not fixable situations.
-let overloadsPruned = overloads.Where(
- m =>
- // Don't match a method that overrides a third-party methods
- !m.OverriddensBase.Any(mo => mo.IsThirdParty) &&
-
- // Don't match a constructor that calls a base constructor.
- !(m.IsConstructor && m.MethodsCalled.Any(
- mc => mc.IsConstructor &&
- m.ParentType.DeriveFrom(mc.ParentType)))
-).ToArray()
-
-where overloadsPruned.Length > max
-
-orderby overloads.Length descending
-
-select new {
- m = @group.First(),
- overloadsPruned,
- Debt = (3*overloads.Length).ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Method overloading is the ability to create multiple methods of the same name
-// with different implementations, and various set of parameters.
-//
-// This rule matches sets of methods with 6 overloads or more.
-//
-// Such method set might be a problem to maintain
-// and provokes coupling higher than necessary.
-//
-// See the definition of the *NbOverloads* metric here
-// https://www.ndepend.com/docs/code-metrics#NbOverloads
-//
-// Notice that this rule doesn't include in the overloads list
-// methods that override a third-party method
-// nor constructors that call a base constructor.
-// Such situations are consequences of lower-level problems.
-//
-
-//
-// Typically the *too many overloads* phenomenon appears when an algorithm
-// takes a various set of in-parameters. Each overload is presented as
-// a facility to provide a various set of in-parameters.
-// In such situation, the C# and VB.NET language feature named
-// *Named and Optional arguments* should be used.
-//
-// The *too many overloads* phenomenon can also be a consequence of the usage
-// of the **visitor design pattern** http://en.wikipedia.org/wiki/Visitor_pattern
-// since a method named *Visit()* must be provided for each sub type.
-// For this reason, the default version of this rule doesn't match overloads whose name
-// start with "visit" or "dispatch" (case-unsensitive) to avoid match
-// overload visitors, and you can adapt this rule to your own naming convention.
-//
-// Sometime *too many overloads* phenomenon is not the symptom of a problem,
-// for example when a *numeric to something conversion* method applies to
-// all numeric and nullable numeric types.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is of 3 minutes per method overload.
-//]]>
- Avoid methods potentially poorly commented
-// ND1006:AvoidMethodsPotentiallyPoorlyCommented
-warnif count > 0 from t in JustMyCode.Types where
- // Entity Framework ModelSnapshot and DbContext and Migration have large uncommented methods.
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot".AllowNoMatch()) &&
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.DbContext".AllowNoMatch()) &&
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.Migrations.Migration".AllowNoMatch())
-
-
-from m in t.Methods where
- m.PercentageComment < 10 &&
- m.NbLinesOfCode > 20 &&
- JustMyCode.Contains(t)
-
- let nbLinesOfCodeNotCommented = m.NbLinesOfCode - m.NbLinesOfComment
-
- orderby nbLinesOfCodeNotCommented descending
-
-select new {
- m,
- m.PercentageComment,
- m.NbLinesOfCode,
- m.NbLinesOfComment,
- nbLinesOfCodeNotCommented,
-
- Debt = nbLinesOfCodeNotCommented .Linear(20, 2, 200, 20).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interest for severity major for 300 loc
- // to interest for severity critical for 2000 loc
- AnnualInterest = m.PercentageComment.Linear(
- 0, 8 *(Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes),
- 20, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule matches methods with less than 10% of comment lines and that have
-// at least 20 lines of code. Such method might need to be more commented.
-//
-// See the definitions of the *Comments metric* here:
-// https://www.ndepend.com/docs/code-metrics#PercentageComment
-// https://www.ndepend.com/docs/code-metrics#NbLinesOfComment
-//
-// Notice that only comments about the method implementation
-// (comments in method body) are taken account.
-//
-
-//
-// Typically add more comment. But code commenting is subject to controversy.
-// While poorly written and designed code would needs a lot of comment
-// to be understood, clean code doesn't need that much comment, especially
-// if variables and methods are properly named and convey enough information.
-// Unit-Test code can also play the role of code commenting.
-//
-// However, even when writing clean and well-tested code, one will have
-// to write **hacks** at a point, usually to circumvent some API limitations or bugs.
-// A hack is a non-trivial piece of code, that doesn't make sense at first glance,
-// and that took time and web research to be found.
-// In such situation comments must absolutely be used to express the intention,
-// the need for the hacks and the source where the solution has been found.
-//
-// The estimated Debt, which means the effort to comment such method,
-// varies linearly from 2 minutes for 10 lines of code not commented,
-// up to 20 minutes for 200 or more, lines of code not commented.
-//]]>
- Avoid types with poor cohesion
-// ND1007:AvoidTypesWithPoorCohesion
-warnif count > 0 from t in JustMyCode.Types where
- t.LCOM > 0.8 &&
- t.NbFields > 10 &&
- t.NbMethods >10
-
- let poorCohesionScore = 1/(1.01 - t.LCOM)
- orderby poorCohesionScore descending
-
- select new {
- t,
- t.LCOM,
- t.NbMethods,
- t.NbFields,
- poorCohesionScore,
-
- Debt = poorCohesionScore.Linear(5, 5, 50, 4*60).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interest for severity Medium for low poorCohesionScore
- // to 4 times interest for severity High for high poorCohesionScore
- AnnualInterest = poorCohesionScore.Linear(5, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 50, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// This rule is based on the *LCOM code metric*,
-// LCOM stands for **Lack Of Cohesion of Methods**.
-// See the definition of the LCOM metric here
-// https://www.ndepend.com/docs/code-metrics#LCOM
-//
-// The LCOM metric measures the fact that most methods are using most fields.
-// A class is considered utterly cohesive (which is good)
-// if all its methods use all its instance fields.
-//
-// Only types with enough methods and fields are taken account to avoid bias.
-// The LCOM takes its values in the range [0-1].
-//
-// This rule matches types with LCOM higher than 0.8.
-// Such value generally pinpoints a **poorly cohesive class**.
-//
-
-//
-// To refactor a poorly cohesive type and increase code quality and maintainability,
-// certainly you'll have to split the type into several smaller and more cohesive types
-// that together, implement the same logic.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 5 minutes for a type with a low poorCohesionScore,
-// up to 4 hours for a type with high poorCohesionScore.
-//]]>
- Avoid methods with too many local variables
-// ND1008:AvoidMethodsWithTooManyLocalVariables
-warnif count > 0 from m in JustMyCode.Methods where
- m.NbVariables > 15
- orderby m.NbVariables descending
-select new {
- m,
- m.NbVariables,
-
- Debt = m.NbVariables.Linear(15, 1, 80, 6).ToHours().ToDebt(),
-
- // The annual interest varies linearly from interest for severity Medium for 15 variables
- // to interest for severity Critical for 80 variables
- AnnualInterest = m.NbVariables.Linear(15, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 80, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes).ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// This rule matches methods with more than 15 variables.
-//
-// Methods where *NbVariables > 8* are hard to understand and maintain.
-// Methods where *NbVariables > 15* are extremely complex and must be refactored.
-//
-// The number of variables is infered from the compiled IL code of the method.
-// The C# and VB.NET compiler might introduce some hidden variables
-// for language constructs like lambdas, so the default threshold of
-// this rule is set to 15 to avoid matching false positives.
-//
-
-//
-// To refactor such method and increase code quality and maintainability,
-// certainly you'll have to split the method into several smaller methods
-// or even create one or several classes to implement the logic.
-//
-// During this process it is important to question the scope of each
-// variable local to the method. This can be an indication if
-// such local variable will become an instance field of the newly created class(es).
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 10 minutes for a method with 15 variables,
-// up to 2 hours for a methods with 80 or more variables.
-//]]>
-
-
- From now, all types added should respect basic quality principles
-// ND1100:FromNowAllTypesAddedShouldRespectBasicQualityPrinciples
-warnif count > 0 from t in JustMyCode.Types where
-
-// Only match types added since Baseline.
-// Uncomment this line to match also refactored types since Baseline.
-// (t.WasAdded() || t.CodeWasChanged()) &&
- t.WasAdded() &&
-
-// Eliminate interfaces, enumerations or types only with constant fields
-// by making sure we are matching type with code.
-t.NbLinesOfCode > 10 &&
-
-// Optimization: Fast discard of non-relevant types
-(t.Fields.Count() > 20 || t.Methods.Count() > 20)
-
-// Count instance fields and non-constant static fields
-let fields = t.Fields.Where(f =>
- !f.IsLiteral &&
- !(f.IsStatic && f.IsInitOnly))
-
-// Don't match these methods
-let methods = t.Methods.Where(
- m => !(// m.IsConstructor || m.IsClassConstructor || // ctor/cctor not enumerated through IType.Methods
- m.IsGeneratedByCompiler ||
- m.IsPropertyGetter || m.IsPropertySetter ||
- m.IsEventAdder || m.IsEventRemover))
-
-where
-
-// Low Quality types Metrics' definitions are available here:
-// https://www.ndepend.com/docs/code-metrics#MetricsOnTypes
-( // Types with too many methods
- fields.Count() > 20 ||
-
- methods.Count() > 20 ||
-
- // Complex Types that use more than 50 other types
- t.NbTypesUsed > 50
-)
-select new {
- t,
- t.NbLinesOfCode,
-
- instanceMethods = methods.Where(m => !m.IsStatic),
- staticMethods = methods.Where(m => m.IsStatic),
-
- instanceFields = fields.Where(f => !f.IsStatic),
- staticFields = fields.Where(f => f.IsStatic),
-
- t.TypesUsed,
-
- // Constant Debt estimation, since for such type rules in category "Code Smells"
- // accurately estimate the Debt.
- Debt = 10.ToMinutes().ToDebt(),
-
- // The Severity is higher for new types than for refactored types
- AnnualInterest= (t.WasAdded() ? 3 : 1) *
- Severity.High.AnnualInterestThreshold()
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-// This rule operates only on types added since baseline.
-//
-// This rule can be easily modified to also match types refactored since baseline,
-// that don't satisfy all quality criterions.
-//
-// Types matched by this rule not only have been recently added or refactored,
-// but also somehow violate one or several basic quality principles,
-// whether it has too many methods,
-// it has too many fields,
-// or is using too many types.
-// Any of these criterions is often a symptom of a type with too many responsibilities.
-//
-// Notice that to count methods and fields, methods like constructors
-// or property and event accessors are not taken account.
-// Notice that constants fields and static-readonly fields are not counted.
-// Enumerations types are not counted also.
-//
-
-//
-// To refactor such type and increase code quality and maintainability,
-// certainly you'll have to split the type into several smaller types
-// that together, implement the same logic.
-//
-// Issues of this rule have a constant 10 minutes Debt, because the Debt,
-// which means the effort to fix such issue, is already estimated for issues
-// of rules in the category **Code Smells**.
-//
-// However issues of this rule have a **High** severity, with even more
-// interests for issues on new types since baseline, because the proper time
-// to increase the quality of these types is **now**, before they get commited
-// in the next production release.
-//]]>
- From now, all types added should be 100% covered by tests
-// ND1101:FromNowAllTypesAddedShouldBe100PercentCoveredByTests
-warnif count > 0 from t in JustMyCode.Types where
-
-// Only match types added since Baseline.
-// Uncomment this line to match also refactored types since Baseline.
-// (t.WasAdded() || t.CodeWasChanged()) &&
- t.WasAdded() &&
-
- // …that are not 100% covered by tests
- t.PercentageCoverage < 100
-
- let methodsCulprit = t.Methods.Where(m => m.PercentageCoverage < 100)
-
-select new {
- t,
- t.PercentageCoverage,
- methodsCulprit,
- t.NbLinesOfCode,
-
- // Constant Debt estimation, since for such type rules in category "Coverage"
- // accurately estimate the untested code Debt.
- Debt = 10.ToMinutes().ToDebt(),
-
- // The Severity is higher for new types than for refactored types
- AnnualInterest= (t.WasAdded() ? 3 : 1) *
- Severity.High.AnnualInterestThreshold()
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-// This rule operates only on types added since baseline.
-//
-// This rule can be easily modified to also match types refactored since baseline,
-// that are not 100% covered by tests.
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// Often covering 10% of remaining uncovered code of a class,
-// requires as much work as covering the first 90%.
-// For this reason, typically teams estimate that 90% coverage is enough.
-// However *untestable code* usually means *poorly written code*
-// which usually leads to *error prone code*.
-// So it might be worth refactoring and making sure to cover the 10% remaining code
-// because **most tricky bugs might come from this small portion of hard-to-test code**.
-//
-// Not all classes should be 100% covered by tests (like UI code can be hard to test)
-// but you should make sure that most of the logic of your application
-// is defined in some *easy-to-test classes*, 100% covered by tests.
-//
-// In this context, this rule warns when a type added or refactored since the baseline,
-// is not fully covered by tests.
-//
-
-//
-// Write more unit-tests dedicated to cover code not covered yet.
-// If you find some *hard-to-test code*, it is certainly a sign that this code
-// is not *well designed* and hence, needs refactoring.
-//
-// You'll find code impossible to cover by unit-tests, like calls to *MessageBox.Show()*.
-// An infrastructure must be defined to be able to *mock* such code at test-time.
-//
-// Issues of this rule have a constant 10 minutes Debt, because the Debt,
-// which means the effort to write tests for the culprit type, is already
-// estimated for issues in the category **Code Coverage**.
-//
-// However issues of this rule have a **High** severity, with even more
-// interests for issues on new types since baseline, because the proper time
-// to write tests for these types is **now**, before they get commited
-// in the next production release.
-//]]>
- From now, all methods added should respect basic quality principles
-// ND1102:FromNowAllMethodsAddedShouldRespectBasicQualityPrinciples
-warnif count > 0 from m in JustMyCode.Methods where
-
- // Only match methods added since Baseline.
- // Uncomment this line to match also refactored methods since Baseline.
- // (m.WasAdded() || m.CodeWasChanged()) &&
- m.WasAdded() &&
-
- // Don't match async methods here to avoid
- // false positives because of special compiler tricks.
- !m.IsAsync &&
-
-// Low Quality methods// Metrics' definitions
-( m.NbLinesOfCode > 30 || // https://www.ndepend.com/docs/code-metrics#NbLinesOfCode
- m.NbILInstructions > 200 || // https://www.ndepend.com/docs/code-metrics#NbILInstructions
- m.CyclomaticComplexity > 20 || // https://www.ndepend.com/docs/code-metrics#CC
- m.ILCyclomaticComplexity > 50 || // https://www.ndepend.com/docs/code-metrics#ILCC
- m.ILNestingDepth > 4 || // https://www.ndepend.com/docs/code-metrics#ILNestingDepth
- m.NbParameters > 5 || // https://www.ndepend.com/docs/code-metrics#NbParameters
- m.NbVariables > 8 || // https://www.ndepend.com/docs/code-metrics#NbVariables
- m.NbOverloads > 6 )
-select new {
- m,
- m.NbLinesOfCode,
- m.NbILInstructions,
- m.CyclomaticComplexity,
- m.ILCyclomaticComplexity,
- m.ILNestingDepth,
- m.NbParameters,
- m.NbVariables,
- m.NbOverloads, // https://www.ndepend.com/docs/code-metrics#NbOverloads
-
- // Constant Debt estimation, since for such method rules in category "Code Smells"
- // accurately estimate the Debt.
- Debt = 5.ToMinutes().ToDebt(),
-
- // The Severity is higher for new methods than for refactored methods
- AnnualInterest= (m.WasAdded() ? 3 : 1) *
- Severity.High.AnnualInterestThreshold()
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-// This rule operates only on methods added or refactored since the baseline.
-//
-// This rule can be easily modified to also match methods refactored since baseline,
-// that don't satisfy all quality criterions.
-//
-// Methods matched by this rule not only have been recently added or refactored,
-// but also somehow violate one or several basic quality principles,
-// whether it is too large (too many *lines of code*),
-// too complex (too many *if*, *switch case*, loops…)
-// has too many variables, too many parameters
-// or has too many overloads.
-//
-
-//
-// To refactor such method and increase code quality and maintainability,
-// certainly you'll have to split the method into several smaller methods
-// or even create one or several classes to implement the logic.
-//
-// During this process it is important to question the scope of each
-// variable local to the method. This can be an indication if
-// such local variable will become an instance field of the newly created class(es).
-//
-// Large *switch…case* structures might be refactored through the help
-// of a set of types that implement a common interface, the interface polymorphism
-// playing the role of the *switch cases tests*.
-//
-// Unit Tests can help: write tests for each method before extracting it
-// to ensure you don't break functionality.
-//
-// Issues of this rule have a constant 5 minutes Debt, because the Debt,
-// which means the effort to fix such issue, is already estimated for issues
-// of rules in the category **Code Smells**.
-//
-// However issues of this rule have a **High** severity, with even more
-// interests for issues on new methods since baseline, because the proper time
-// to increase the quality of these methods is **now**, before they get commited
-// in the next production release.
-//]]>
- Avoid decreasing code coverage by tests of types
-// ND1103:AvoidDecreasingCodeCoverageByTestsOfTypes
-warnif count > 0
-from t in JustMyCode.Types where
- t.IsPresentInBothBuilds() && t.CoverageDataAvailable && t.OlderVersion().CoverageDataAvailable
-let locDiff = (int)t.NbLinesOfCode.Value - (int)t.OlderVersion().NbLinesOfCode.Value
-where locDiff >= 0
-let uncoveredLoc = (int)t.NbLinesOfCodeNotCovered.Value - ((int)t.OlderVersion().NbLinesOfCodeNotCovered.Value + locDiff)
-where uncoveredLoc > 0
-
-orderby uncoveredLoc descending
-
-select new {
- t,
- OldCoveragePercent = t.OlderVersion().PercentageCoverage,
- NewCoveragePercent = t.PercentageCoverage,
- OldLoc = t.OlderVersion().NbLinesOfCode,
- NewLoc = t.NbLinesOfCode,
- uncoveredLoc,
-
- Debt = uncoveredLoc.Linear(1, 15, 100, 3*60).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interest for severity High for one line of code that is not covered by tests anymore
- // to interest for severity Critical for 50 lines of code that are not covered by tests anymore
- AnnualInterest = uncoveredLoc.Linear(1, Severity.High.AnnualInterestThreshold().Value.TotalMinutes,
- 50, 2*Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes).ToMinutes().ToAnnualInterest()
-
-
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// This rule warns when the number of lines of a type covered by tests
-// decreased since the baseline. In case the type faced some refactoring
-// since the baseline, this loss in coverage is estimated only for types
-// with more lines of code, where # lines of code covered now is lower
-// than # lines of code covered in baseline + the extra number of
-// lines of code.
-//
-// Such situation can mean that some tests have been removed
-// but more often, this means that the type has been modified,
-// and that changes haven't been covered properly by tests.
-//
-// To visualize changes in code, right-click a matched type and select:
-//
-// • Compare older and newer versions of source file
-//
-// • or Compare older and newer versions disassembled with Reflector
-//
-
-//
-// Write more unit-tests dedicated to cover changes in matched types
-// not covered yet.
-// If you find some *hard-to-test code*, it is certainly a sign that this code
-// is not *well designed* and hence, needs refactoring.
-//
-// The estimated Debt, which means the effort to cover by test
-// code that used to be covered, varies linearly 15 minutes to 3 hours,
-// depending on the number of lines of code that are not covered by tests anymore.
-//
-// Severity of issues of this rule varies from **High** to **Critical**
-// depending on the number of lines of code that are not covered by tests anymore.
-// Because the loss in code coverage happened since the baseline,
-// the severity is high because it is important to focus on these issues
-// **now**, before such code gets released in production.
-//]]>
- Avoid making complex methods even more complex
-// ND1104:AvoidMakingComplexMethodsEvenMoreComplex
-warnif count > 0
-
-let complexityScoreProc = new Func(m =>
- (m.CyclomaticComplexity + m.ILCyclomaticComplexity/3 + 5*m.ILNestingDepth).Value)
-
-from m in JustMyCode.Methods where
-
- // Don't match async methods here to avoid
- // false positives because of special compiler tricks.
- !m.IsAsync &&
-
- !m.IsAbstract &&
- m.IsPresentInBothBuilds() &&
- m.CodeWasChanged() &&
- m.OlderVersion().CyclomaticComplexity > 6
-
-let complexityScore = complexityScoreProc(m)
-let oldComplexityScore = complexityScoreProc(m.OlderVersion())
-where complexityScore > oldComplexityScore
-
-let complexityScoreDiff = complexityScoreProc(m) - complexityScoreProc(m.OlderVersion())
-orderby complexityScoreDiff descending
-
-select new {
- m,
- oldComplexityScore ,
- complexityScore ,
- diff= complexityScoreDiff,
-
- Debt = complexityScoreDiff.Linear(1, 15, 50, 60).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interest for severity Medium for a tiny complexity increment
- // to interest for severity critical for 2000 loc
- AnnualInterest = complexityScoreDiff.Linear(1, Severity.High.AnnualInterestThreshold().Value.TotalMinutes,
- 50, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// The method complexity is measured through the code metric
-// *Cyclomatic Complexity* defined here:
-// https://www.ndepend.com/docs/code-metrics#CC
-//
-// This rule warns when a method already complex
-// (i.e with *Cyclomatic Complexity* higher than 6)
-// become even more complex since the baseline.
-//
-// This rule needs assemblies PDB files and source code
-// to be available at analysis time, because the *Cyclomatic Complexity*
-// is inferred from the source code and source code location
-// is inferred from PDB files. See:
-// https://www.ndepend.com/docs/ndepend-analysis-inputs-explanation
-//
-// To visualize changes in code, right-click a matched method and select:
-//
-// • Compare older and newer versions of source file
-//
-// • or Compare older and newer versions disassembled with Reflector
-//
-
-//
-// A large and complex method should be split in smaller methods,
-// or even one or several classes can be created for that.
-//
-// During this process it is important to question the scope of each
-// variable local to the method. This can be an indication if
-// such local variable will become an instance field of the newly created class(es).
-//
-// Large *switch…case* structures might be refactored through the help
-// of a set of types that implement a common interface, the interface polymorphism
-// playing the role of the *switch cases tests*.
-//
-// Unit Tests can help: write tests for each method before extracting it
-// to ensure you don't break functionality.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 15 to 60 minutes depending on the extra complexity added.
-//
-// Issues of this rule have a **High** severity, because it is important to focus
-// on these issues **now**, before such code gets released in production.
-//]]>
- Avoid making large methods even larger
-// ND1105:AvoidMakingLargeMethodsEvenLarger
-warnif count > 0
-from m in JustMyCode.Methods where
- !m.IsAbstract &&
-
- // Eliminate constructors from match, since they get larger
- // as soons as some fields initialization are added.
- !m.IsConstructor &&
- !m.IsClassConstructor &&
-
- // Filter just here for optimization
- m.NbLinesOfCode > 15 &&
-
- m.IsPresentInBothBuilds() &&
- m.CodeWasChanged()
-
-let oldLoc = m.OlderVersion().NbLinesOfCode
-where oldLoc > 15 && m.NbLinesOfCode > oldLoc
-
-let diff = m.NbLinesOfCode - oldLoc
-where diff > 0
-orderby diff descending
-
-select new {
- m,
- oldLoc,
- newLoc = m.NbLinesOfCode,
- diff,
-
- Debt = diff.Linear(1, 10, 100, 60).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interest for severity Medium for a tiny complexity increment
- // to interest for severity critical for 2000 loc
- AnnualInterest = diff .Linear(1, Severity.High.AnnualInterestThreshold().Value.TotalMinutes,
- 100, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule warns when a method already large
-// (i.e with more than 15 lines of code)
-// become even larger since the baseline.
-//
-// The method size is measured through the code metric
-// *# Lines of Code* defined here:
-// https://www.ndepend.com/docs/code-metrics#NbLinesOfCode
-//
-// This rule needs assemblies PDB files
-// to be available at analysis time, because the *# Lines of Code*
-// is inferred from PDB files. See:
-// https://www.ndepend.com/docs/ndepend-analysis-inputs-explanation
-//
-// To visualize changes in code, right-click a matched method and select:
-//
-// • Compare older and newer versions of source file
-//
-// • or Compare older and newer versions disassembled with Reflector
-//
-
-//
-// Usually too big methods should be split in smaller methods.
-//
-// But long methods with no branch conditions, that typically initialize some data,
-// are not necessarily a problem to maintain, and might not need refactoring.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 5 to 20 minutes depending
-// on the number of lines of code added.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 10 to 60 minutes depending on the extra complexity added.
-//
-// Issues of this rule have a **High** severity, because it is important to focus
-// on these issues **now**, before such code gets released in production.
-//]]>
- Avoid adding methods to a type that already had many methods
-// ND1106:AvoidAddingMethodsToATypeThatAlreadyHadManyMethods
-warnif count > 0
-
-// Don't count constructors and methods generated by the compiler!
-let getMethodsProc = new Func>(
- t => t.Methods.Where(m =>
- //!m.IsConstructor && !m.IsClassConstructor && // ctor/cctor not enumerated through IType.Methods
- !m.IsGeneratedByCompiler).ToArray())
-
-
-from t in JustMyCode.Types where
-
- t.NbMethods > 30 && // Just here for optimization
-
- t.IsPresentInBothBuilds()
-
- // Optimization: fast discard of non-relevant types
- where t.OlderVersion().NbMethods > 30
-
- let oldMethods = getMethodsProc(t.OlderVersion())
- where oldMethods.Count > 30
-
- let newMethods = getMethodsProc(t)
- where newMethods.Count > oldMethods.Count
-
- let addedMethods = newMethods.Where(m => m.WasAdded())
- let removedMethods = oldMethods.Where(m => m.WasRemoved())
-
- orderby addedMethods.Count() descending
-
-select new {
- t,
- nbOldMethods = oldMethods.Count,
- nbNewMethods = newMethods.Count,
- addedMethods,
- removedMethods,
-
- Debt = (10*addedMethods.Count()).ToMinutes().ToDebt(),
- AnnualInterest = addedMethods.Count().Linear(
- 1, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 100, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// Types where number of methods is greater than 15
-// might be hard to understand and maintain.
-//
-// This rule lists types that already had more than 15 methods
-// at the baseline time, and for which new methods have been added.
-//
-// Having many methods for a type might be a symptom
-// of too many responsibilities implemented.
-//
-// Notice that constructors and methods generated by the compiler
-// are not taken account.
-//
-
-//
-// To refactor such type and increase code quality and maintainability,
-// certainly you'll have to split the type into several smaller types
-// that together, implement the same logic.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 10 minutes per method added.
-//
-// Issues of this rule have a **High** severity, because it is important to focus
-// on these issues **now**, before such code gets released in production.
-//]]>
- Avoid adding instance fields to a type that already had many instance fields
-// ND1107:AvoidAddingInstanceFieldsToATypeThatAlreadyHadManyInstanceFields
-warnif count > 0
-
-let getFieldsProc = new Func>(
- t => t.Fields.Where(f =>
- !f.IsLiteral &&
- !f.IsGeneratedByCompiler &&
- !f.IsStatic).ToArray())
-
-
-from t in JustMyCode.Types where
-
- !t.IsEnumeration &&
- t.IsPresentInBothBuilds()
-
- // Optimization: fast discard of non-relevant types
- where t.OlderVersion().NbFields > 15
-
- let oldFields = getFieldsProc(t.OlderVersion())
- where oldFields.Count > 15
-
- let newFields = getFieldsProc(t)
- where newFields.Count > oldFields.Count
-
- let addedFields = newFields.Where(f => f.WasAdded())
- let removedFields = oldFields.Where(f => f.WasRemoved())
-
- orderby addedFields.Count() descending
-
-select new {
- t,
- nbOldFields = oldFields.Count,
- nbNewFields = newFields.Count,
- addedFields,
- removedFields,
-
- Debt = (10*addedFields.Count()).ToMinutes().ToDebt(),
- AnnualInterest = addedFields.Count().Linear(
- 1, Severity.High.AnnualInterestThreshold().Value.TotalMinutes,
- 100, 4*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes)).ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// Types where number of fields is greater than 15
-// might be hard to understand and maintain.
-//
-// This rule lists types that already had more than 15 fields
-// at the baseline time, and for which new fields have been added.
-//
-// Having many fields for a type might be a symptom
-// of too many responsibilities implemented.
-//
-// Notice that *constants* fields and *static-readonly* fields are not taken account.
-// Enumerations types are not taken account also.
-//
-
-//
-// To refactor such type and increase code quality and maintainability,
-// certainly you'll have to group subsets of fields into smaller types
-// and dispatch the logic implemented into the methods
-// into these smaller types.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 10 minutes per field added.
-//
-// Issues of this rule have a **High** severity, because it is important to focus
-// on these issues **now**, before such code gets released in production.
-//]]>
- Avoid transforming an immutable type into a mutable one
-// ND1108:AvoidTransformingAnImmutableTypeIntoAMutableOne
-warnif count > 0
-from t in Application.Types where
- t.CodeWasChanged() &&
- t.OlderVersion().IsImmutable &&
- !t.IsImmutable &&
- // Don't take account of immutable types transformed into static types (not deemed as immutable)
- !t.IsStatic
-
-let culpritFields = t.InstanceFields.Where(f => !f.IsImmutable)
-select new {
- t,
- culpritFields,
- Debt = (10 + 10*culpritFields.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// A type is considered as *immutable* if its instance fields
-// cannot be modified once an instance has been built by a constructor.
-//
-// Being immutable has several fortunate consequences for a type.
-// For example its instance objects can be used concurrently
-// from several threads without the need to synchronize accesses.
-//
-// Hence users of such type often rely on the fact that the type is immutable.
-// If an immutable type becomes mutable, there are chances that this will break
-// users code.
-//
-// This is why this rule warns about such immutable type that become mutable.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 2 minutes per instance field that became mutable.
-//
-
-//
-// If being immutable is an important property for a matched type,
-// then the code must be refactored to preserve immutability.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 10 minutes plus 10 minutes per instance fields of
-// the matched type that is now mutable.
-//
-// Issues of this rule have a **High** severity, because it is important to focus
-// on these issues **now**, before such code gets released in production.
-//]]>
-
-
- Avoid interfaces too big
-// ND1200:AvoidInterfacesTooBig
-warnif count > 0
-
-from i in JustMyCode.Types
-where i.IsInterface && i.NbMethods >= 10 // Optimization First threshold
-
-// A get;set; property count as one method
-let properties = i.Methods.Where(m => m.SimpleName.Length > 4 && (m.IsPropertyGetter || m.IsPropertySetter))
- .Distinct(m => m.SimpleName.Substring(4, m.SimpleName.Length -4))
-
-// An event count as one method
-let events = i.Methods.Where(m => (m.IsEventAdder|| m.IsEventRemover))
- .Distinct(m => m.SimpleName.Replace("add_","").Replace("remove_",""))
-
-let methods = i.Methods.Where(m => !m.IsPropertyGetter && !m.IsPropertySetter && !m.IsEventAdder && !m.IsEventRemover)
-let methodsCount = methods.Count() + properties.Count() + events.Count()
-where methodsCount >= 10
-let publicFactor = i.IsPubliclyVisible ? 1 : 0.5
-orderby methodsCount descending
-select new {
- i,
- Methods= methods,
- Properties = properties,
- Events = events,
- Debt = (publicFactor*methodsCount.Linear(10, 20, 100, 7*60)).ToMinutes().ToDebt(),
- // The annual interest varies linearly from interest for severity Medium for an interface with 10 methods
- // to interest for severity Critical for an interface with 100 methods and more
- AnnualInterest = (publicFactor*methodsCount.Linear(
- 10, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 100, Severity.Critical.AnnualInterestThreshold().Value.TotalMinutes))
- .ToMinutes().ToAnnualInterest()
-}
-
-
-//
-// This rule matches interfaces with more than 10 methods.
-// Interfaces are abstractions and are meant to simplify the code structure.
-// An interface should represent a single responsibility.
-// Making an interface too large, too complex, necessarily means
-// that the interface has too many responsibilities.
-//
-// A property with getter or setter or both count as one method.
-// An event count as one method.
-//
-
-//
-// Typically to fix such issue, the interface must be refactored
-// in a grape of smaller *single-responsibility* interfaces.
-//
-// A classic example is a *ISession* large interface, responsible
-// for holding states, run commands and offer various accesses
-// and facilities.
-//
-// The classic problem for a large public interface is that it has
-// many clients that consume it. As a consequence splitting it in
-// smaller interfaces has an important impact and it is not always
-// feasible.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from 20 minutes for an interface with 10 methods,
-// up to 7 hours for an interface with 100 or more methods.
-// The Debt is divided by two if the interface is not publicly
-// visible, because in such situation only the current project is impacted
-// by the refactoring.
-//
-]]>
- Base class should not use derivatives
-// ND1201:BaseClassShouldNotUseDerivatives
-warnif count > 0
-from baseClass in JustMyCode.Types
-where baseClass.IsClass && baseClass.NbChildren > 0 // <-- for optimization!
-let derivedClassesUsed = baseClass.DerivedTypes.UsedBy(baseClass)
- // Don't warn when a base class is using nested private derived class
- .Where(derivedClass =>
- !(derivedClass.IsNested &&
- derivedClass.Visibility == Visibility.Private &&
- derivedClass.ParentType == baseClass))
-where derivedClassesUsed.Count() > 0
-
-let derivedClassesMemberUsed = derivedClassesUsed.SelectMany(c => c.Members).UsedBy(baseClass)
-orderby derivedClassesMemberUsed.Count() descending
-
-select new {
- baseClass,
- derivedClassesUsed,
- derivedClassesMemberUsed,
-
- Debt = 3*(derivedClassesUsed.Count()+derivedClassesMemberUsed.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// In *Object-Oriented Programming*, the **open/closed principle** states:
-// *software entities (components, classes, methods, etc.) should be open
-// for extension, but closed for modification*.
-// http://en.wikipedia.org/wiki/Open/closed_principle
-//
-// Hence a base class should be designed properly to make it easy to derive from,
-// this is *extension*. But creating a new derived class, or modifying an
-// existing one, shouldn't provoke any *modification* in the base class.
-// And if a base class is using some derivative classes somehow, there
-// are good chances that such *modification* will be needed.
-//
-// Extending the base class is not anymore a simple operation,
-// this is not good design.
-//
-// Note that this rule doesn't warn when a base class is using a derived class
-// that is nested in the base class and declared as private. In such situation
-// we consider that the derived class is an encapsulated implementation
-// detail of the base class.
-//
-
-//
-// Understand the need for using derivatives,
-// then imagine a new design, and then refactor.
-//
-// Typically an algorithm in the base class needs to access something
-// from derived classes. You can try to encapsulate this access behind
-// an abstract or a virtual method.
-//
-// If you see in the base class some conditions on *typeof(DerivedClass)*
-// not only *urgent refactoring* is needed. Such condition can easily
-// be replaced through an abstract or a virtual method.
-//
-// Sometime you'll see a base class that creates instance of some derived classes.
-// In such situation, certainly using the *factory method pattern*
-// http://en.wikipedia.org/wiki/Factory_method_pattern
-// or the *abstract factory pattern*
-// http://en.wikipedia.org/wiki/Abstract_factory_pattern
-// will improve the design.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 3 minutes per derived class used by the base class +
-// 3 minutes per member of a derived class used by the base class.
-//]]>
- Class shouldn't be too deep in inheritance tree
-// ND1202:ClassShouldntBeTooDeepInInheritanceTree
-warnif count > 0 from t in JustMyCode.Types
-where t.IsClass
-let baseClasses = t.BaseClasses.ExceptThirdParty()
-where baseClasses.Count() >= 3
-orderby baseClasses.Count() descending
-
-select new {
- t,
- baseClasses,
- // The metric value DepthOfInheritance takes account
- // of third-party base classessee its definition here:
- // https://www.ndepend.com/docs/code-metrics#DIT
- t.DepthOfInheritance,
- Debt = (baseClasses.Count() -2)*3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about classes having 3 or more base classes.
-// Notice that third-party base classes are not counted
-// because this rule is about your code design, not
-// third-party libraries consumed design.
-//
-// *In theory*, there is nothing wrong having a *long inheritance chain*,
-// if the modelization has been well thought out,
-// if each base class is a well-designed refinement of the domain.
-//
-// *In practice*, modeling properly a domain demands a lot of effort
-// and experience and more often than not, a *long inheritance chain*
-// is a sign of confused design, that will be hard to work with and maintain.
-//
-
-//
-// In *Object-Oriented Programming*, a well-known motto is
-// **Favor Composition over Inheritance**.
-//
-// This is because *inheritance* comes with pitfalls.
-// In general, the implementation of a derived class is very bound up with
-// the base class implementation. Also a base class exposes implementation
-// details to its derived classes, that's why it's often said that
-// inheritance breaks encapsulation.
-//
-// On the other hands, *Composition* favors binding with interfaces
-// over binding with implementations. Hence, not only the encapsulation
-// is preserved, but the design is clearer, because interfaces make it explicit
-// and less coupled.
-//
-// Hence, to break a *long inheritance chain*, *Composition* is often
-// a powerful way to enhance the design of the refactored underlying logic.
-//
-// You can also read:
-// http://en.wikipedia.org/wiki/Composition_over_inheritance and
-// http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance
-//
-// The estimated Debt, which means the effort to fix such issue,
-// depends linearly upon the depth of inheritance.
-//]]>
- Class with no descendant should be sealed if possible
-// ND1203:ClassWithNoDescendantShouldBeSealedIfPossible
-warnif count > 0 from t in JustMyCode.Types where
- t.IsClass &&
- t.NbChildren ==0 &&
- !t.IsSealed &&
- !t.IsStatic &&
- !t.IsPubliclyVisible // You might want to comment this condition
- // if you are developing an application,
- // instead of developing a library
- // with public classes that are intended to be
- // sub-classed by your clients.
- orderby t.NbLinesOfCode descending
-select new {
- t,
- t.NbLinesOfCode,
- Debt = 30.ToSeconds().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// If a *non-static* class isn't declared with the keyword *sealed*,
-// it means that it can be subclassed everywhere the *non-sealed*
-// class is visible.
-//
-// Making a class a *base class* requires significant design effort.
-// Subclassing a *non-sealed* class, not initially designed
-// to be subclassed, will lead to unanticipated design issue.
-//
-// Most classes are *non-sealed* because developers don't care about
-// the keyword *sealed*, not because the primary intention was to write
-// a class that can be subclassed.
-//
-// There are minor performance gain in declaring a class as *sealed*.
-// But the real benefit of doing so, is actually to **express the
-// intention**: *this class has not be designed to be a base class,
-// hence it is not allowed to subclass it*.
-//
-// Notice that by default this rule doesn't match *public* class
-// to avoid matching classes that are intended to be sub-classed by
-// third-party code using your library.
-// If you are developing an application and not a library,
-// just uncomment the clause *!t.IsPubliclyVisible*.
-//
-
-//
-// For each matched class, take the time to assess if it is really
-// meant to be subclassed. Certainly most matched class will end up
-// being declared as *sealed*.
-//]]>
- Overrides of Method() should call base.Method()
-// ND1204:OverridesOfMethodShouldCallBaseMethod
-warnif count > 0
-from t in Types // Take account of third-party base classes also
-
-// Bother only classes with descendant
-where t.IsClass && t.NbChildren > 0
-
-from mBase in t.InstanceMethods
-where mBase.IsVirtual &&
- !mBase.IsThirdParty &&
- !mBase.IsAbstract &&
- !mBase.IsExplicitInterfaceImpl &&
- !mBase.IsPropertyGetter &&
- !mBase.IsPropertySetter &&
- !mBase.IsIndexerGetter &&
- !mBase.IsIndexerSetter &&
- // Don't take account of virtual methods of the Object type.
- !mBase.Name.EqualsAny("Equals(Object)","ToString()", "GetHashCode()","Finalize()")
-
-from mOverride in mBase.OverridesDirectDerived
-where !mOverride.IsUsing(mBase) &&
- JustMyCode.Contains(mOverride) // Don't warn on generated code
-select new {
- mOverride,
- shouldCall = mBase,
- definedInBaseClass = mBase.ParentType,
-
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Typically overrides of a base method, should **refine** or **complete**
-// the behavior of the base method. If the base method is not called,
-// the base behavior is not refined but it is *replaced*.
-//
-// Violations of this rule are a sign of *design flaw*,
-// especially if the actual design provides valid reasons
-// that advocates that the base behavior must be replaced and not refined.
-//
-
-//
-// You should investigate if *inheritance* is the right choice
-// to bind the base class implementation with the derived classes
-// implementations. Does presenting the method with polymorphic
-// behavior through an interface, would be a better design choice?
-//
-// In such situation, often using the design pattern **template method**
-// http://en.wikipedia.org/wiki/Template_method_pattern might help
-// improving the design.
-//]]>
- Do not hide base class methods
-// ND1205:DoNotHideBaseClassMethods
-warnif count > 0
-
-// Define a lookup table indexing methods by their name including parameters signature.
-let lookup = Methods.Where(m => !m.IsConstructor && !m.IsStatic && !m.IsGeneratedByCompiler)
- .ToLookup(m1 => m1.Name)
-
-from t in Application.Types
-where !t.IsStatic && t.IsClass &&
- // Discard classes deriving directly from System.Object
- t.DepthOfInheritance > 1
-where t.BaseClasses.Any()
-
-// For each methods not overriding any methods (new slot),
-// let's check if it hides by name some methods defined in base classes.
-from m in t.InstanceMethods
-where m.IsNewSlot && !m.IsExplicitInterfaceImpl && !m.IsGeneratedByCompiler
-
-// Notice how lookup is used to quickly retrieve methods with same name as m.
-// This makes the query 10 times faster than iterating each base methods to check their name.
-let baseMethodsHidden = lookup[m.Name].Where(m1 => m1 != m && t.DeriveFrom(m1.ParentType))
-
-where baseMethodsHidden.Count() > 0
-select new {
- m,
- baseMethodsHidden,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// Method hiding is when a base class has a non-virtual method *M()*,
-// and a derived class has also a method *M()* with the same signature.
-// In such situation, calling *base.M()* does something different
-// than calling *derived.M()*.
-//
-// Notice that this is not *polymorphic* behavior. With *polymorphic*
-// behavior, calling both *base.M()* and *derived.M()* on an instance
-// object of *derived*, invoke the same implementation.
-//
-// This situation should be avoided because it obviously leads to confusion.
-// This rule warns about all method hiding cases in the code base.
-//
-
-//
-// To fix a violation of this rule, remove or rename the method,
-// or change the parameter signature so that the method does
-// not hide the base method.
-//
-// However *method hiding is for those times when you need to have two
-// things to have the same name but different behavior*. This is a very
-// rare situations, described here:
-// http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx
-//]]>
- A stateless class or structure might be turned into a static type
-// ND1206:AStatelessClassOrStructureMightBeTurnedIntoAStaticType
-warnif count > 0
-
-let testAttributes = ThirdParty.Types
- .Where(t => t.IsAttributeClass && t.SimpleName.Contains("Test")).ToArray()
-
-from t in JustMyCode.Types where
- !t.IsStatic &&
- !t.IsGeneric &&
- t.InstanceFields.Count() == 0 &&
- t.SimpleName != "Program" && // Don't warn on Program classes generated by designers
-
- // Don't match:
- // --> types that implement some interfaces.
- t.NbInterfacesImplemented == 0 &&
-
- // --> or classes that have sub-classes children.
- t.NbChildren == 0 &&
-
- // --> or classes that have a base class
- ((t.IsClass && t.DepthOfDeriveFrom("System.Object".AllowNoMatch()) == 1) ||
- t.IsStructure) &&
-
- // Don't match test classes
- !testAttributes.Any(tAttr => t.HasAttribute(tAttr))
-
-let methodsUsingMe = t.TypesUsingMe.ChildMethods().Where(m => m.IsUsing(t))
-
-select new {
- t,
- methodsUsingMe,
- Debt = (1 + methodsUsingMe.Count()).ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule matches classes and structures that are not static, nor generic,
-// that doesn't have any instance fields, that doesn't implement any interface
-// nor has a base class (different than *System.Object*).
-//
-// Such class or structure is a *stateless* collection of *pure* functions,
-// that doesn't act on any *this* object data. Such collection of *pure* functions
-// is better hosted in a **static class**. Doing so simplifies the client code
-// that doesn't have to create an object anymore to invoke the *pure* functions.
-//
-
-//
-// Declare all methods as *static* and transform the class or structure
-// into a *static* class.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Non-static classes should be instantiated or turned to static
-// ND1207:NonStaticClassesShouldBeInstantiatedOrTurnedToStatic
-warnif count > 0
-
-let testAttributes = Types
- .Where(t => t.IsAttributeClass && t.SimpleName.Contains("Test")).ToArray()
-
-from t in JustMyCode.Types
-where t.IsClass &&
- //!t.IsPublic && // if you are developing a framework,
- // you might not want to match public classes
- !t.IsStatic &&
- !t.IsAbstract &&
- !t.IsAttributeClass && // Attributes class are never seen as instantiated
-
- // Don't suggest to turn to static, classes that implement interfaces
- t.InterfacesImplemented.Count() == 0 &&
-
- // Find the first constructor of t called
- // match t if none of its constructors is called.
- t.Constructors.FirstOrDefault(ctor => ctor.NbMethodsCallingMe > 0) == null &&
-
- // Don't warn on Program classes generated by designers
- t.SimpleName != "Program" &&
-
- // Types instantiated through remoting infrastructure
- !t.DeriveFrom("System.MarshalByRefObject".AllowNoMatch()) &&
-
- // JSON and XML serialized types might not be seen as instantiated.
- !t.IsUsing("Newtonsoft.Json".MatchNamespace().AllowNoMatch()) &&
- !t.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Xml.Serialization.XmlElementAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()) &&
-
- // Serialized type might never be seen as instantiated.
- !t.HasAttribute("System.Runtime.Serialization.DataContractAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Runtime.Serialization.DataMemberAttribute".AllowNoMatch()) &&
-
- // ASP.NET Core ViewModel and Repository
- !t.SimpleName.EndsWithAny("Model","Repository") &&
- !t.IsUsing("System.ComponentModel.DataAnnotations".AllowNoMatch().MatchNamespace()) &&
-
- // ASP.NET Classes that are instantiated by the ASP.NET infrastructure.
- !t.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWithAny("System.Web", "Microsoft.AspNetCore")) &&
- !(t.Constructors.Count() == 1 && t.Constructors.Single().Name.Contains("(IHostingEnvironment)")) &&
-
- // Entity Framework ModelSnapshot and DbContext and Migration
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot".AllowNoMatch()) &&
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.DbContext".AllowNoMatch()) &&
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.Migrations.Migration".AllowNoMatch()) &&
-
- // Don't match test classes
- !testAttributes.Any(tAttr => t.HasAttribute(tAttr)) &&
-
- // Validtor classes might not be instantiated
- !t.SimpleName.EndsWith("Validator") &&
-
- // Don't warn about classes instantiated by Dependency Injection frameworks
- !t.TypesUsingMe.Any(t1 => t1.TypesUsed.ParentNamespaces().Any(n => n.Name.StartsWithAny(
- "Microsoft.Extensions.DependencyInjection",
- "Autofac", "Microsoft.Practices.Unity", "Ninject",
- "StructureMap", "SimpleInjector", "Castle.Windsor",
- "LightInject", "Spring", "Lamar"
- )))
-
-select new {
- t,
- t.Visibility,
- Debt = 2.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-// Notice that classes only instantiated through reflection, like plug-in root classes
-// are matched by this rules.
-
-//
-// If the constructors of a class are never called, the class is
-// never instantiated, and should be defined as a *static class*.
-//
-// However this rule doesn't match instantiation through reflection.
-// As a consequence, plug-in root classes, instantiated through reflection
-// via *IoC frameworks*, can be *false positives* for this rule.
-//
-// This rule doesn't match also classes instantiated by the ASP.NET
-// infrastructure, ASP.NET view model classes
-// and Entity Framework ModelSnapshot, DbContext and Migration classes.
-//
-// Notice that by default this rule matches also *public* class.
-// If you are developing a framework with classes that are intended
-// to be instantiated by your clients, just uncomment the line
-// *!t.IsPublic*.
-//
-
-//
-// First it is important to investigate why the class is never instantiated.
-// If the reason is *the class hosts only static methods* then the class
-// can be safely declared as *static*.
-//
-// Others reasons like, *the class is meant to be instantiated via reflection*,
-// or *is meant to be instantiated only by client code* should lead to
-// adapt this rule code to avoid these matches.
-//
-]]>
- Methods should be declared static if possible
-// ND1208:MethodsShouldBeDeclaredStaticIfPossible
-warnif count > 0
-
-let testAttributes = ThirdParty.Types
- .Where(t => t.IsAttributeClass &&
- ( t.SimpleName.Contains("Test") ||
- t.SimpleName.Contains("Fact") ||
- t.SimpleName.Contains("SetUp") ||
- t.SimpleName.Contains("TearDown") )
- ).ToArray()
-
-from t in JustMyCode.Types.Where(t =>
- !t.IsStatic && !t.IsInterface &&
- !t.IsEnumeration && !t.IsDelegate &&
- !t.IsGeneratedByCompiler &&
-
- // Don't advise to declare Global ASP.NET or ApiController methods as static
- !t.DeriveFrom("System.Web.HttpApplication".AllowNoMatch()) &&
- !t.DeriveFrom("System.Web.Http.ApiController".AllowNoMatch()) &&
- !t.DeriveFrom("Microsoft.AspNetCore.Mvc.Controller".AllowNoMatch()) &&
-
- // Don't set as static methods of JSON serialized type
- !t.TypesUsed.Any(t1 => t1.IsAttributeClass && t1.ParentNamespace.Name == "Newtonsoft.Json") &&
-
- // Don't set as static methods of XML serialized type
- !t.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Xml.Serialization.XmlElementAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()))
-
-let methodsThatCanBeMadeStatic =
- from m in t.InstanceMethods
-
- // An instance method can be turned to static if it is not virtual,
- // not using the this reference and also, not using
- // any of its class or base classes instance fields or instance methods.
- where !m.IsAbstract && !m.IsVirtual &&
- !m.AccessThis && !m.IsExplicitInterfaceImpl &&
- !m.IsProtected && // Protected method access doesn't match well with static methods
-
- // Don't warn about not yet implemented methods.
- !m.CreateA("System.NotImplementedException".AllowNoMatch()) &&
-
- // Optimization: Using FirstOrDefault() avoid to check all members,
- // as soon as one member is found
- // we know the method m cannot be made static.
- m.MembersUsed.FirstOrDefault(
- mUsed => !mUsed.IsStatic &&
- (mUsed.ParentType == t ||
- t.DeriveFrom(mUsed.ParentType))
- ) == null
-
- // Don't match test methods
- && !testAttributes.Any(tAttr => m.HasAttribute(tAttr))
- select m
-
-from m in methodsThatCanBeMadeStatic
-let staticFieldsUsed = m.ParentType.StaticFields.UsedBy(m).Where(f => !f.IsGeneratedByCompiler)
-let methodsCallingMe = m.MethodsCallingMe
-
-// All callers of the method must be in JustMyCode,
-// else having a method declared as static would break the call from the code generated
-// like when a WPF Connect() method is binding a method to an event.
-where methodsCallingMe.All(m1 => JustMyCode.Contains(m1))
-
-select new {
- m,
- staticFieldsUsed,
- methodsCallingMe,
- Debt = (1 + methodsCallingMe.Count())*30.ToSeconds().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// When an instance method can be *safely* declared as static you should declare it as static.
-//
-// Whenever you write a method, you fulfill a contract in a given scope.
-// The narrower the scope is, the smaller the chance is that you write a bug.
-//
-// When a method is static, you can't access non-static members; hence, your scope is
-// narrower. So, if you don't need and will never need (even in subclasses) instance
-// fields to fulfill your contract, why give access to these fields to your method?
-// Declaring the method static in this case will let the compiler check that you
-// don't use members that you do not intend to use.
-//
-// Declaring a method as static if possible is also good practice because clients can
-// tell from the method signature that calling the method can't alter the object's state.
-//
-// Doing so, is also a micro performance optimization, since a static method is a
-// bit cheaper to invoke than an instance method, because the *this* reference*
-// doesn't need anymore to be passed.
-//
-// Notice that if a matched method is a handler, bound to an event through code
-// generated by a designer, declaring it as static might break the designer
-// generated code, if the generated code use the *this* invocation syntax,
-// (like *this.Method()*).
-//
-
-//
-// Declare matched methods as static.
-//
-// Since such method doesn't use any instance fields and methods of its type and
-// base-types, you should consider if it makes sense, to move such a method
-// to a static utility class.
-//]]>
- Constructor should not call a virtual method
-// ND1209:ConstructorShouldNotCallAVirtualMethod
-warnif count > 0
-
-from t in JustMyCode.Types where
- t.IsClass &&
- !t.IsGeneratedByCompiler &&
- !t.IsSealed
-
-from ctor in t.Constructors
-let virtualMethodsCalled =
- from mCalled in ctor.MethodsCalled
- where mCalled.IsVirtual && !mCalled.IsFinal &&
- // Only take care of just-my-code virtual methods called
- JustMyCode.Contains(mCalled) &&
- ( mCalled.ParentType == t ||
- (t.DeriveFrom(mCalled.ParentType) &&
- // Don't accept Object methods since they can be called
- // from another reference than the 'this' reference.
- mCalled.ParentType.FullName != "System.Object")
- )
- select mCalled
-where virtualMethodsCalled.Count() > 0
-
-select new {
- ctor ,
- virtualMethodsCalled,
- // If there is no derived type, it might be
- // an opportunity to mark t as sealed.
- t.DerivedTypes,
- Debt = ((virtualMethodsCalled.Count())*6).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule matches constructors of a non-sealed class that call one or
-// several virtual methods.
-//
-// When an object written in C# is constructed, what happens is that constructors
-// run in order from the base class to the most derived class.
-//
-// Also objects do not change type as they are constructed, but start out as
-// the most derived type, with the method table being for the most derived type.
-// This means that virtual method calls always run on the most derived type,
-// even when calls are made from the constructor.
-//
-// When you combine these two facts you are left with the problem that if you
-// make a virtual method call in a constructor, and it is not the most derived
-// type in its inheritance hierarchy, then it will be called on a class whose
-// constructor has not been run, and therefore may not be in a suitable state
-// to have that method called.
-//
-// Hence this situation makes the class *fragile to derive from*.
-//
-
-//
-// Violations reported can be solved by re-designing object initialisation
-// or by declaring the parent class as *sealed*, if possible.
-//
-]]>
- Avoid the Singleton pattern
-// ND1210:AvoidTheSingletonPattern
-warnif count > 0
-from t in Application.Types
-where !t.IsStatic && !t.IsAbstract && (t.IsClass || t.IsStructure)
-
-// All ctors of a singleton are private
-where t.Constructors.Where(ctor => !ctor.IsPrivate).Count() == 0
-
-// Require mutable instance fields to be shared across the several clients of the single object.
-let mutableInstanceFields = t.InstanceFields.Where(f => !f.IsImmutable)
-where mutableInstanceFields.Any()
-
-// A singleton contains one or several static fields of its parent type,
-// or of an interface implented by its parent type,
-// to reference the unique instance
-let staticFieldInstances = t.StaticFields.WithFieldTypeIn(t.InterfacesImplemented.Concat(t))
-where staticFieldInstances.Count() == 1
-
-let staticFieldInstance = staticFieldInstances.Single()
-let methodsUsingField = staticFieldInstance.MethodsUsingMe
-let methodsUsingField2 = methodsUsingField.Concat(methodsUsingField.SelectMany(m => m.MethodsCallingMe))
-
-select new {
- t,
- staticFieldInstance,
- methodsUsingField2,
- mutableInstanceFields ,
- Debt = (3*methodsUsingField2.Count()).ToMinutes().ToDebt(),
- AnnualInterest = (10+methodsUsingField2.Count()).ToMinutes().ToAnnualInterest()
-}
-
-//
-// The *singleton pattern* consists in enforcing that a class has just
-// a single instance: http://en.wikipedia.org/wiki/Singleton_pattern
-// At first glance, this pattern looks appealing, it is simple to implement,
-// it adresses a common situation, and as a consequence it is widely used.
-//
-// However, we discourage you from using singleton classes because experience
-// shows that **singleton often results in less testable and less maintainable code**.
-// Singleton is *by-design*, not testable. Each unit test should use their own objects
-// while singleton forces multiple unit-tests to use the same instance object.
-//
-// Also the singleton static *GetInstance()* method allows *magic* access to that
-// single object and its state from wherever developers want! This potentially
-// attractive facility unfortunatly ends up into *unorganized*/*messy* code that
-// will require effort to be refactored.
-//
-// Notice that this rule matches only singleton types with **mutable** instance fields
-// because singleton pitfalls result from anarchical access and modification
-// of instance data.
-//
-// More details available in these discussions:
-// http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members/
-// http://adamschepis.com/blog/2011/05/02/im-adam-and-im-a-recovering-singleton-addict/
-//
-
-//
-// This rule matches *the classic syntax of singletons*, where one
-// static field hold the single instance of the parent class. We underline that
-// *the problem is this particular syntax*, that plays against testability.
-// The problem is not the fact that a single instance of the class lives
-// at runtime.
-//
-// Hence to fix matches fo this rule, creates the single instance
-// at the startup of the program, and pass it to all classes and methods
-// that need to access it.
-//
-// If multiple singletons are identified, they actually form together a
-// *program execution context*. Such context can be unified in a unique
-// singleton context. Doing so will make it easier to propagate the
-// context across the various program units.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 3 minutes per method relying on the singleton.
-// It is not rare that hundreds of methods rely on the singleton
-// and that it takes hours to get rid of a singleton, refactoring
-// the way just explained above.
-//
-// The severity of each singleton issue is **Critical** because as
-// explained, using a the singleton pattern can really prevent the
-// whole program to be testable.
-//]]>
- Don't assign static fields from instance methods
-// ND1211:DontAssignStaticFieldsFromInstanceMethods
-warnif count > 0
-from f in Application.Fields where
- f.IsStatic &&
- !f.IsLiteral &&
- !f.IsInitOnly &&
- !f.IsGeneratedByCompiler &&
- // Contract API define such a insideContractEvaluation static field
- f.Name != "insideContractEvaluation"
-let assignedBy = f.MethodsAssigningMe.Where(m => !m.IsStatic)
-where assignedBy .Count() > 0
-select new {
- f,
- assignedBy,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Assigning static fields from instance methods leads to
-// poorly maintainable and non-thread-safe code.
-//
-// More discussion on the topic can be found here:
-// http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members/
-//
-
-//
-// If the *static* field is just assigned once in the program
-// lifetime, make sure to declare it as *readonly* and assign
-// it inline, or from the static constructor.
-//
-// In *Object-Oriented-Programming* the natural artifact
-// to hold states that can be modified is **instance fields**.
-//
-// Hence to fix violations of this rule, make sure to
-// hold assignable states through *instance* fields, not
-// through *static* fields.
-//]]>
- Avoid empty interfaces
-// ND1212:AvoidEmptyInterfaces
-warnif count > 0 from t in JustMyCode.Types where
- t.IsInterface &&
- t.NbMethods == 0 &&
- !t.InterfacesImplemented.Any()
-select new {
- t,
- t.TypesThatImplementMe,
- Debt = (10 + 3*t.TypesThatImplementMe.Count()).ToMinutes().ToDebt(),
- Severity = t.TypesThatImplementMe.Any() ? Severity.Medium : Severity.Low
-}
-
-//
-// Interfaces define members that provide a behavior or usage contract.
-// The functionality that is described by the interface
-// can be adopted by any type, regardless of where the type
-// appears in the inheritance hierarchy.
-// A type implements an interface by providing implementations
-// for the members of the interface.
-// An empty interface does not define any members.
-// Therefore, it does not define a contract that can be implemented.
-//
-// If your design includes empty interfaces that types
-// are expected to implement, you are probably using an interface
-// as a marker or a way to identify a group of types.
-// If this identification will occur at run time,
-// the correct way to accomplish this is to use a custom attribute.
-// Use the presence or absence of the attribute,
-// or the properties of the attribute, to identify the target types.
-// If the identification must occur at compile time,
-// then it is acceptable to use an empty interface.
-//
-// Note that if an interface is empty but implements at least one
-// other interface, it won't be matched by this rule.
-// Such interface can be considered as not empty,
-// since implementing it means that sub-interfaces members
-// must be implemented.
-//
-
-//
-// Remove the interface or add members to it.
-// If the empty interface is being used to label a set of types,
-// replace the interface with a custom attribute.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 10 minutes to discard an empty interface plus
-// 3 minutes per type implementing an empty interface.
-//]]>
- Avoid types initialization cycles
-// ND1213:AvoidTypesInitializationCycles
-warnif count > 0
-
-// Types initialization cycle can only happen between types of an assembly.
-from assembly in Application.Assemblies
-
-let cctorSuspects = assembly.ChildMethods.Where(
- m => m.IsClassConstructor &&
- // Optimization: types involved in a type cycle necessarily don't have type level.
- m.ParentType.Level == null)
-
-where cctorSuspects.Count() > 1
-let typesSuspects = cctorSuspects.ParentTypes().ToHashSetEx()
-
-//
-// dicoTmp associates to each type suspect T, a set of types from typesSuspects
-// that contains at least a method or a field used directly or indirectly by the cctor of T.
-//
-let dicoTmp = cctorSuspects.ToDictionary(
- cctor => cctor.ParentType,
- cctor => ((IMember)cctor).ToEnumerable().FillIterative(
- members => from m in members
- from mUsed in (m is IMethod) ? (m as IMethod).MembersUsed : new IMember[0]
- where mUsed.ParentAssembly == assembly
- select mUsed)
- .DefinitionDomain
- .Select(m => m.ParentType) // Don't need .Distinct() here, because of ToHashSetEx() below.
- .Except(cctor.ParentType)
- .Intersect(typesSuspects)
- .ToHashSetEx()
-)
-
-//
-// dico associates to each type suspect T, the set of types initialized (directly or indirectly)
-// by the initialization of T. This second step is needed, because if a cctor of a type T1
-// calls a member of a type T2, not only the cctor of T1 triggers the initialization of T2,
-// but also it triggers the initialization of all types that are initialized by T2 initialization.
-//
-let dico = typesSuspects.Where(t => dicoTmp[t].Count() > 0).ToDictionary(
- typeSuspect => typeSuspect,
- typeSuspect => typeSuspect.ToEnumerable().FillIterative(
- types => from t in types
- from tUsed in dicoTmp[t]
- select tUsed)
- .DefinitionDomain
- .Except(typeSuspect)
- .ToHashSetEx()
-)
-
-
-//
-// Now that dico is prepared, detect the cctor cycles
-//
-from t in dico.Keys
-
- // Thanks to the work done to build dico, it is now pretty easy
- // to spot types involved in an initialization cyle with t!
- let usersAndUseds = from tTmp in dico[t]
- where dico.ContainsKey(tTmp) && dico[tTmp].Contains(t)
- select tTmp
- where usersAndUseds.Count() > 0
-
- // Here we've found type(s) both using and used by the suspect type.
- // A cycle involving the type t is found!
- // v2017.3.2: don't call Append() as an extension method else ambiguous syntax error
- // with the new extension method in .NET Fx v4.7.1 / .NET Standard 2.0: System.Linq.Enumerable.Append()
- let typeInitCycle = ExtensionMethodsEnumerable.Append(usersAndUseds,t)
-
-
- // Compute methodsCalled and fieldsUsed, useful to explore
- // how a cctor involved in a type initialization cycle, triggers other type initialization.
- let methodsCalledDepth = assembly.ChildMethods.DepthOfIsUsedBy(t.ClassConstructor)
- let fieldsUsedDepth = assembly.ChildFields.DepthOfIsUsedBy(t.ClassConstructor)
-
- let methodsCalled = methodsCalledDepth.DefinitionDomain.OrderBy(m => methodsCalledDepth[m]).ToArray()
- let fieldsUsed = fieldsUsedDepth.DefinitionDomain.OrderBy(f => fieldsUsedDepth[f]).ToArray()
-
-// Use the tick box to: Group cctors methods By parent types
-select new {
- t.ClassConstructor,
- cctorsCycle= typeInitCycle.Select(tTmp => tTmp.ClassConstructor),
-
- // methodsCalled and fieldsUsed are members used directly and indirectly by the cctor.
- // Export these members to the dependency graph (right click the cell Export/Append … to the Graph)
- // and see how the cctor trigger the initialization of other types
- methodsCalled,
- fieldsUsed,
- Debt = (20+10*typeInitCycle.Count()).ToMinutes().ToDebt(),
- Severity = Severity.Critical
-}
-
-//
-// The *class constructor* (also called *static constructor*, and named *cctor* in IL code)
-// of a type, if any, is executed by the CLR at runtime, the first time the type is used.
-// A *cctor* doesn't need to be explicitly declared in C# or VB.NET, to exist in compiled IL code.
-// Having a static field inline initialization is enough to have
-// the *cctor* implicitly declared in the parent class or structure.
-//
-// If the *cctor* of a type *t1* is using the type *t2* and if the *cctor* of *t2* is using *t1*,
-// some type initialization unexpected and hard-to-diagnose buggy behavior can occur.
-// Such a cyclic chain of initialization is not necessarily limited to two types
-// and can embrace *N* types in the general case.
-// More information on types initialization cycles can be found here:
-// http://codeblog.jonskeet.uk/2012/04/07/type-initializer-circular-dependencies/
-//
-// The present code rule enumerates types initialization cycles.
-// Some *false positives* can appear if some lambda expressions are defined
-// in *cctors* or in methods called by *cctors*. In such situation, this rule
-// considers these lambda expressions as executed at type initialization time,
-// while it is not necessarily the case.
-//
-
-//
-// Types initialization cycles create confusion and unexpected behaviors.
-// If several states hold by several classes must be initialized during the first
-// access of any of those classes, a better design option is to create a dedicated
-// class whose responsibility is to initialize and hold all these states.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 20 minutes per cycle plus 10 minutes per type class constructor
-// involved in the cycle.
-//]]>
-
-
- Avoid custom delegates
-// ND1300:AvoidCustomDelegates
-
-warnif count > 0
-from t in JustMyCode.Types where t.IsDelegate
-
-let invokeMethod = (from m in t.Methods where m.SimpleName == "Invoke" select m).Single()
-let signature1 = invokeMethod.Name.Substring(
- invokeMethod.SimpleName.Length,
- invokeMethod.Name.Length - invokeMethod.SimpleName.Length)
-
-// 'ref' and 'out' parameters cannot be supported
-where !signature1.Contains("&")
-
-let signature2 = signature1.Replace("(","<").Replace(")",">")
-let signature3 = signature2 == "<>" ? "" : signature2
-let resultTypeName = invokeMethod.ReturnType == null ? "????" :
- invokeMethod.ReturnType.FullName == "System.Void" ? "" :
- invokeMethod.ReturnType.Name
-let replaceWith =
- resultTypeName == "Boolean" && invokeMethod.NbParameters == 1 ?
- "Predicate" + signature3 : resultTypeName == "" ?
- "Action" + signature3 : invokeMethod.NbParameters ==0 ?
- "Func<" + resultTypeName + ">" :
- "Func" + signature3.Replace(">", "," + resultTypeName + ">")
-
-let methodsUser = t.TypesUsingMe.ChildMethods().Where(m => m.IsUsing(t))
-
-select new {
- t,
- replaceWith,
- methodsUser,
- Debt = (5 + 3*methodsUser.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// Generic delegates sould be preferred over custom delegates.
-// Generic delegates are:
-//
-// • *Action<…>* to represent any method with *void* return type.
-//
-// • *Func<…>* to represent any method with a return type. The last
-// generic argument is the return type of the prototyped methods.
-//
-// • *Predicate* to represent any method that takes an instance
-// of *T* and that returns a *boolean*.
-//
-// • Expression<…> that represents function definitions that can be
-// compiled and subsequently invoked at runtime but can also be
-// serialized and passed to remote processes.
-//
-// Thanks to generic delegates, not only the code using these custom
-// delegates will become clearer, but you'll be relieved from the
-// maintenance of these delegate types.
-//
-// Notice that delegates that are consumed by *DllImport* extern methods
-// must not be converted, else this could provoke marshalling issues.
-//
-
-//
-// Remove custom delegates and replace them with generic
-// delegates shown in the **replaceWith** column.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is 5 minutes per custom delegates plus 3 minutes per method
-// using such custom delegate.
-//]]>
- Types with disposable instance fields must be disposable
-// ND1301:TypesWithDisposableInstanceFieldsMustBeDisposable
-warnif count > 0
-
-// Several IDisposable types can be found if several .NET profiles are referenced.
-let iDisposables = ThirdParty.Types.WithFullName("System.IDisposable")
-where iDisposables.Any() // in case the code base doesn't use at all System.IDisposable
-
-from t in Application.Types.Except(
- Application.Types.ThatImplementAny(iDisposables)
- // Don't match ASP.NET types like Page, MasterPage or Control
- .Union(Application.Types.Where(t => t.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWith("System.Web.UI")))))
-where !t.IsGeneratedByCompiler
-
-let instanceFieldsDisposable =
- t.InstanceFields.Where(f => f.FieldType != null &&
- f.FieldType.InterfacesImplemented.Intersect(iDisposables).Any())
-
-where instanceFieldsDisposable.Any()
-
-// Don't warn for types that implement the dispose pattern with a Dispose(bool) method.
-where t.Methods.FirstOrDefault(m => m.Name == "Dispose(Boolean)") == null
-
-select new {
- t,
- instanceFieldsDisposable,
- Debt = (5 + 2*instanceFieldsDisposable.Count()).ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns when a class declares and implements an instance field that
-// is a *System.IDisposable* type and the class does not implement *IDisposable*.
-//
-// A class implements the *IDisposable* interface to dispose of unmanaged resources
-// that it owns. An instance field that is an *IDisposable* type indicates that
-// the field owns an unmanaged resource. A class that declares an *IDisposable*
-// field indirectly owns an unmanaged resource and should implement the
-// *IDisposable* interface. If the class does not directly own any unmanaged
-// resources, it should not implement a finalizer.
-//
-// This rules might report false positive in case the lifetime of the disposable
-// objects referenced, is longer than the lifetime of the object that hold the
-// disposable references.
-//
-
-//
-// To fix a violation of this rule, implement *IDisposable* and from the
-// *IDisposable.Dispose()* method call the *Dispose()* method of the field(s).
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is 5 minutes per type matched plus 3 minutes per disposable instance field.
-//]]>
- Disposable types with unmanaged resources should declare finalizer
-// ND1302:DisposableTypesWithUnmanagedResourcesShouldDeclareFinalizer
-
-// This default rule is disabled by default,
-// see in the rule description (below) why.
-// warnif count > 0
-
-// Several IDisposable type can be found if several .NET Fx are referenced.
-let iDisposables = ThirdParty.Types.WithFullName("System.IDisposable")
-where iDisposables.Any() // in case the code base doesn't use at all System.IDisposable
-
-let disposableTypes = Application.Types.ThatImplementAny(iDisposables)
-let unmanagedResourcesFields = disposableTypes.ChildFields().Where(f =>
- !f.IsStatic &&
- f.FieldType != null &&
- f.FieldType.FullName.EqualsAny(
- "System.IntPtr",
- "System.UIntPtr",
- "System.Runtime.InteropServices.HandleRef")).ToHashSetEx()
-let disposableTypesWithUnmanagedResource = unmanagedResourcesFields.ParentTypes()
-
-from t in disposableTypesWithUnmanagedResource
-where !t.HasFinalizer
-let unmanagedResourcesTypeFields = unmanagedResourcesFields.Intersect(t.InstanceFields)
-select new {
- t,
- unmanagedResourcesTypeFields,
- //Debt = 10.ToMinutes().ToDebt(),
- //Severity = Severity.Critical
-}
-
-//
-//A type that implements *System.IDisposable*,
-//and has fields that suggest the use of unmanaged resources,
-//does not implement a finalizer as described by *Object.Finalize()*.
-//A violation of this rule is reported
-//if the disposable type contains fields of the following types:
-//
-// • *System.IntPtr*
-//
-// • *System.UIntPtr*
-//
-// • *System.Runtime.InteropServices.HandleRef*
-//
-// Notice that this default rule is disabled by default,
-// because it typically reports *false positive* for classes
-// that just hold some references to managed resources,
-// without the responsibility to dispose them.
-//
-// To enable this rule just uncomment *warnif count > 0*.
-//
-
-//
-//To fix a violation of this rule,
-//implement a finalizer that calls your *Dispose()* method.
-//]]>
- Methods that create disposable object(s) and that don't call Dispose()
-// ND1303:MethodsThatCreateDisposableObjectAndThatDontCallDispose
-
-// Uncomment this to transform this code query into a code rule.
-// warnif count > 0
-
-// Several IDisposable types can be found if several .NET Fx are referenced.
-let iDisposables = ThirdParty.Types.WithFullName("System.IDisposable")
-where iDisposables.Any() // in case the code base doesn't use at all System.IDisposable
-
-// Build sequences of disposableTypes and disposeMethods
-let disposableTypes = Types.ThatImplementAny(iDisposables).Concat(iDisposables)
-let disposeMethods = disposableTypes.ChildMethods().WithName("Dispose()").ToHashSetEx()
-
-
-// -> You can refine this code query by assigning to disposableTypesToLookAfter something like:
-// disposableTypes.WithFullNameIn("Namespace.TypeName1", "Namespace.TypeName2", ...)
-let disposableTypesToLookAfter = disposableTypes
-
-
-// -> You can refine this code query by assigning to methodsToLookAfter something like:
-// Application.Assemblies.WithNameLike("Asm").ChildMethods()
-let methodsToLookAfter = Application.Methods
-
-
-// Enumerate methods that create any disposable type, without calling Dispose()
-from m in methodsToLookAfter.ThatCreateAny(disposableTypesToLookAfter )
-
-where !m.MethodsCalled.Intersect(disposeMethods).Any()
-select new {
- m,
- disposableObjectsCreated = disposableTypes.Where(t => m.CreateA(t)),
- m.MethodsCalled,
- //Debt = 10.ToMinutes().ToDebt(),
- //Severity = Severity.Low
-}
-
-//
-// This code query enumerates methods that create one or several disposable object(s),
-// without calling any Dispose() method.
-//
-// This code query is not a code rule because it is acceptable to do so,
-// as long as disposable objects are disposed somewhere else.
-//
-// This code query is designed to be be easily refactored
-// to look after only specific disposable types, or specific caller methods.
-//
-// You can then refactor this code query to adapt it to your needs and transform it into a code rule.
-//]]>
- Classes that are candidate to be turned into structures
-// ND1304:ClassesThatAreCandidateToBeTurnedIntoStructures
-
-warnif count > 0
-from t in JustMyCode.Types where
- t.IsClass &&
- !t.IsGeneratedByCompiler &&
- !t.IsStatic &&
- !t.IsGeneric &&
-
- t.NbChildren == 0 && // Must not have children
-
- t.Constructors.All(c => c.NbParameters > 0) && // Must not have parameterless ctor, struct cannot have custom parameterless ctor
-
- t.IsImmutable && // Structures should be immutable type.
-
- // Must have fields and all fields must be of value-type
- t.InstanceFields.Count() > 0 &&
- t.InstanceFields.All(f => f.FieldType != null) &&
- t.InstanceFields.All(f => f.FieldType.IsStructure || f.FieldType.IsEnumeration) &&
-
- // Must not implement interfaces to avoid boxing mismatch
- // when structures implements interfaces.
- t.InterfacesImplemented.Count() == 0 &&
-
- // Must derive directly from System.Object
- t.DepthOfDeriveFrom("System.Object".AllowNoMatch()) == 1 &&
-
- // Must not be a serializable class because a structure should be immutable
- // and serialized types are mutable.
- !t.TypesUsed.Any(t1 => t1.IsAttributeClass && t1.ParentNamespace.Name == "Newtonsoft.Json") &&
- !t.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Xml.Serialization.XmlElementAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()) &&
- !t.HasAttribute("System.Runtime.Serialization.DataContractAttribute".AllowNoMatch()) &&
- !t.IsUsing("System.Runtime.Serialization.DataMemberAttribute".AllowNoMatch()) &&
-
- // ASP.NET Core ViewModel and Repository
- !t.SimpleName.EndsWithAny("Model","Repository") &&
- !t.IsUsing("System.ComponentModel.DataAnnotations".AllowNoMatch().MatchNamespace()) &&
-
- // Must not be an entry point class like 'Program'
- !t.Methods.Any(m => m.IsEntryPoint)
-
- // && t.IsSealed <-- You might want to add this condition
- // to restraint the set.
- // && !t.IsPubliclyVisible <-- You might want to add this condition if
- // you are developping a framework with classes
- // that are intended to be sub-classed by
- // your clients.
- let methodsUser = t.TypesUsingMe.ChildMethods().Where(m => m.IsUsing(t))
-
-select new {
- t,
- t.SizeOfInst,
- t.InstanceFields,
- methodsUser,
- Debt = (5 + 1*methodsUser.Count()).ToMinutes().ToDebt(),
- Severity = Severity.Info
-}
-
-//
-// *Int32*, *Double*, *Char* or *Boolean* are structures and not classes.
-// Structures are particularly suited to implement **lightweight values**.
-// Hence a class is candidate to be turned into a structure
-// when its instances are *lightweight values*.
-//
-// This is a matter of *performance*. It is expected that a program
-// works with plenty of *short lived lightweight values*.
-// In such situation, the advantage of using *struct* instead of
-// *class*, (in other words, the advantage of using *values* instead
-// of *objects*), is that *values* are not managed by the garbage collector.
-// This means that values are cheaper to deal with.
-//
-// This rule matches classes that looks like being *lightweight values*.
-// The characterization of such class is:
-//
-// • It has instance fields.
-//
-// • All instance fields are typed with value-types (primitive, structure or enumeration)
-//
-// • It is immutable (the value of its instance fields cannot be modified once the constructor ended).
-//
-// • It implements no interfaces.
-//
-// • It has no parameterless construtor.
-//
-// • It is not generic.
-//
-// • It has no derived classes.
-//
-// • It derives directly from *System.Object*.
-//
-// • ASP.NETCore ViewModel (its name ends with *Model*) and Repository
-//
-// This rule doesn't take account if instances of matched
-// classes are numerous *short-lived* objects.
-// These criterions are just indications. Only you can decide if it is
-// *performance wise* to transform a class into a structure.
-//
-// A related case-study of using *class* or *struct* for *Tuple<…>* generic
-// types can be found here:
-// http://stackoverflow.com/questions/2410710/why-is-the-new-tuple-type-in-net-4-0-a-reference-type-class-and-not-a-value-t
-//
-
-//
-// Just use the keyword *struct* instead of the keyword *class*.
-//
-// **CAUTION:** Before applying this rule, make sure to understand
-// the **deep implications** of transforming a class into a structure.
-// http://msdn.microsoft.com/en-us/library/aa664471(v=vs.71).aspx
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is 5 minutes per class matched plus one minute per method
-// using such class transformed into a structure.
-//]]>
- Avoid namespaces with few types
-// ND1305:AvoidNamespacesWithFewTypes
-
-warnif count > 0
-
-// Common infrastructure namespace names not matched by the rule.
-// Complete this list to your need.
-let infraNamespaceNames = new HashSet() {
- "Services","Exceptions","Logging", "Domain",
- "Identity", "Migrations", "Controllers",
- "Specifications", "Interfaces", "Components",
- "Bus", "Models", "EventHandlers", "Mappings",
- "ViewModels", "ViewComponents", "Notifications",
- "Configurations", "Extensions", "Events",
- "Context", "Data", "EventSourcing", "Repository",
- "IoC", "Manage", "Commands", "CommandHandlers",
- "Validations", "EventStoreSQL", "Authorization",
- "Formatters", "Xml", "Json", "Enums",
- "Abstractions", "BaseClasses", "Settings",
- "Helpers", "Validators", "Entities"
-}
-
-from n in JustMyCode.Namespaces
-where n.Name.Length > 0 // Don't match anonymous namespaces
- && !infraNamespaceNames.Contains(n.SimpleName) // Don't match common infrastructure namespaces
- && n.Name != n.ParentAssembly.Name // Don't warn on namespace named as assembly to avoid warning on new VS projects
-let types = n.ChildTypes.Where(t => !t.IsGeneratedByCompiler).ToArray()
-where
- types.Length > 0 && // Don't match namespaces that contain only types GeneratedByCompiler
- types.Length < 5 &&
- // Only match namespaces that have all types in JustMyCode
- types.All(t => JustMyCode.Contains(t))
- orderby types.Length ascending
-select new {
- n,
- types,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule warns about namespaces other than the global namespace
-// that contain less than five types.
-//
-// Make sure that each of your namespaces has a logical organization
-// and that a valid reason exists to put types in a sparsely
-// populated namespace.
-//
-// Namespaces should contain types that are used together in most
-// scenarios. When their applications are mutually exclusive,
-// types should be located in separate namespaces. For example,
-// the *System.Web.UI* namespace contains types that are used
-// in Web applications, and the *System.Windows.Forms* namespace
-// contains types that are used in Windows-based applications.
-// Even though both namespaces have types that control aspects
-// of the user interface, these types are not designed for
-// use in the same application. Therefore, they are located in
-// separate namespaces.
-//
-// Careful namespace organization can also be helpful because
-// it increases the discoverability of a feature. By examining the
-// namespace hierarchy, library consumers should be able to locate
-// the types that implement a feature.
-//
-// Notice that this rule source code contains a list of common
-// infrastructure namespace names that you can complete.
-// Namespaces with ending name component in this list are not matched.
-//
-
-//
-// To fix a violation of this rule, try to combine namespaces
-// that contain just a few types into a single namespace.
-//
-]]>
- Nested types should not be visible
-// ND1306:NestedTypesShouldNotBeVisible
-
-warnif count > 0 from t in JustMyCode.Types where
- t.IsNested &&
- !t.IsGeneratedByCompiler &&
- !t.IsPrivate
-let typesUser = t.TypesUsingMe.Where(t1 => t1 != t.ParentType && t1.ParentType != t.ParentType)
-select new {
- t,
- t.Visibility,
- typesUser,
- Debt = (2 + 4*typesUser.Count()).ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about nested types not declared as private.
-//
-// A nested type is a type declared within the scope of another
-// type. Nested types are useful for encapsulating private
-// implementation details of the containing type. Used
-// for this purpose, nested types should not be externally visible.
-//
-// Do not use externally visible nested types for logical
-// grouping or to avoid name collisions; instead use namespaces.
-//
-// Nested types include the notion of member accessibility,
-// which some programmers do not understand clearly.
-//
-// Protected types can be used in subclasses and nested types
-// in advanced customization scenarios.
-//
-
-//
-// If you do not intend the nested type to be externally visible,
-// change the type's accessibility.
-//
-// Otherwise, remove the nested type from its parent and make it
-// *non-nested*.
-//
-// If the purpose of the nesting is to group some nested types,
-// use a namespace to create the hierarchy instead.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is 2 minutes per nested type plus 4 minutes per outter type
-// using such nesting type.
-//]]>
- Declare types in namespaces
-// ND1307:DeclareTypesInNamespaces
-
-warnif count > 0 from n in Application.Namespaces where
- // If an anonymous namespace can be found,
- // it means that it contains types outside of namespaces.
- n.Name == ""
-
- // Eliminate anonymous namespaces that contains
- // only notmycode types (like generated types).
- let childTypes = n.ChildTypes.Where(t => JustMyCode.Contains(t))
- where childTypes.Count() > 0
-select new {
- n,
- childTypes,
- n.NbLinesOfCode,
- Debt = 2*childTypes.Count().ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Types are declared within namespaces to prevent name collisions,
-// and as a way of organizing related types in an object hierarchy.
-//
-// Types outside any named namespace are in a *global
-// namespace* that cannot be referenced in code.
-//
-// The *global namespace* has no name, hence it is qualified as
-// being the *anonymous namespace*.
-//
-// This rule warns about *anonymous namespaces*.
-//
-
-//
-// To fix a violation of this rule,
-// declare all types of all anonymous
-// namespaces in some named namespaces.
-//]]>
- Empty static constructor can be discarded
-// ND1308:EmptyStaticConstructorCanBeDiscarded
-
-warnif count > 0 from m in JustMyCode.Methods where
- m.IsClassConstructor &&
- m.NbLinesOfCode == 0
-select new {
- m,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// The *class constructor* (also called *static constructor*, and named *cctor* in IL code)
-// of a type, if any, is executed by the CLR at runtime, just before the first time the type is used.
-//
-// This rule warns about the declarations of *static constructors*
-// that don't contain any lines of code. Such *cctors* are useless
-// and can be safely removed.
-//
-
-//
-// Remove matched empty *static constructors*.
-//]]>
- Instances size shouldn't be too big
-// ND1309:InstancesSizeShouldntBeTooBig
-
-warnif count > 0 from t in JustMyCode.Types where
- t.SizeOfInst > 128 &&
-
- // You might want to restrict this rule only on structure, since the cost of copying instance data at each method call might be prohibitive
- // t.IsStructure &&
-
- // Discard types that represent WPF, WindowsForm and ASP.NET forms and controls and EntityFramwork classes.
- t.BaseClasses.All(bc => !bc.ParentNamespace.Name.StartsWithAny(
- "System.Windows", "System.Web.UI", "System.Web", "Microsoft.EntityFramework",
- // Discard types related to these namespaces that typically require large instances size
- "System.ComponentModel", "System.Xml",
- // Just add more component vendors here if needed
- "DevExpress"))
-
- orderby t.SizeOfInst descending
-select new {
- t,
- t.SizeOfInst,
- t.InstanceFields,
- t.BaseClasses,
- Debt = t.SizeOfInst.Linear(128,10, 2048, 120).ToMinutes().ToDebt(),
-
- // The annual interest varies linearly from interests for severity Medium for 64 bytes per instance
- // to twice interests for severity High for 2048 bytes per instance
- AnnualInterest = (t.SizeOfInst.Linear(128, Severity.Medium.AnnualInterestThreshold().Value.TotalMinutes,
- 2048, 2*(Severity.High.AnnualInterestThreshold().Value.TotalMinutes))
- )*(t.IsStructure ? 10 : 1) // Multiply interest by 10 for structures
- .ToMinutes().ToAnnualInterest()
-
-}
-
-//
-// Types where *SizeOfInst > 128* might degrade performance
-// if many instances are created at runtime.
-// They can also be hard to maintain.
-//
-// Notice that a class with a large *SizeOfInst* value
-// doesn't necessarily have a lot of instance fields.
-// It might derive from a class with a large *SizeOfInst* value.
-//
-// This query doesn't match types that represent WPF
-// and WindowsForm forms and controls nor Entity Framework
-// special classes.
-//
-// Some other namespaces like *System.ComponentModel* or *System.Xml*
-// have base classes that typically imply large instances size
-// so this rule doesn't match these situations.
-//
-// This rule doesn't match custom *DevExpress* component
-// and it is easy to modify this rule ro append other component vendors
-// to avoid false positives.
-//
-// See the definition of the *SizeOfInst* metric here
-// https://www.ndepend.com/docs/code-metrics#SizeOfInst
-//
-
-//
-// A type with a large *SizeOfInst* value hold *directly*
-// a lot of data. Typically, you can group this data into
-// smaller types that can then be composed.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// varies linearly from severity **Medium** for 128 bytes per instance
-// to twice interests for severity **High** for 2048 bytes per instance.
-//
-// The estimated annual interest of issues of this rule is 10 times higher
-// for structures, because large structures have a significant performance cost.
-// Indeed, each time such structure *value* is passed as a method parameter
-// it gets copied to a new local variable
-// (note that the word *value* is more appropriate than the word *instance* for structures).
-// For this reason, such structure should be declared as class.
-//]]>
- Attribute classes should be sealed
-// ND1310:AttributeClassesShouldBeSealed
-
-warnif count > 0 from t in Application.Types where
- t.IsAttributeClass &&
- !t.IsSealed &&
- !t.IsAbstract &&
- t.IsPublic
-select new {
- t,
- t.NbLinesOfCode,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// The .NET Framework class library provides methods
-// for retrieving custom attributes. By default,
-// these methods search the attribute inheritance
-// hierarchy; for example
-// *System.Attribute.GetCustomAttribute()*
-// searches for the specified attribute type, or any
-// attribute type that extends the specified attribute
-// type.
-//
-// Sealing the attribute eliminates the search
-// through the inheritance hierarchy, and can improve
-// performance.
-//
-
-//
-// To fix a violation of this rule, seal the attribute
-// type or make it abstract.
-//]]>
- Don't use obsolete types, methods or fields
-// ND1311:DontUseObsoleteTypesMethodsOrFields
-
-warnif count > 0
-let obsoleteTypes = Types.Where(t => t.IsObsolete)
-let obsoleteMethods = Methods.Where(m => m.IsObsolete).ToHashSetEx()
-let obsoleteFields = Fields.Where(f => f.IsObsolete)
-
-from m in JustMyCode.Methods.UsingAny(obsoleteTypes).Union(
- JustMyCode.Methods.UsingAny(obsoleteMethods)).Union(
- JustMyCode.Methods.UsingAny(obsoleteFields))
-let obsoleteTypesUsed = obsoleteTypes.UsedBy(m)
-
-// Optimization: MethodsCalled + Intersect() is faster than using obsoleteMethods.UsedBy()
-let obsoleteMethodsUsed = m.MethodsCalled.Intersect(obsoleteMethods)
-let obsoleteFieldsUsed = obsoleteFields.UsedBy(m)
-
-let obsoleteUsage = obsoleteTypesUsed.Cast().Concat(obsoleteMethodsUsed).Concat(obsoleteFieldsUsed)
-
-select new {
- m,
- obsoleteUsage,
- Debt = (5*obsoleteUsage.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// The attribute *System.ObsoleteAttribute* is used to tag
-// types, methods or fields of an API that clients shouldn't
-// use because these code elements will be removed sooner
-// or later.
-//
-// This rule warns about methods that use a type, a method
-// or a field, tagged with *System.ObsoleteAttribute*.
-//
-
-//
-// Typically when a code element is tagged with
-// *System.ObsoleteAttribute*, a *workaround message*
-// is provided to clients.
-//
-// This *workaround message* will tell you what to do
-// to avoid using the obsolete code element.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is 5 minutes per type, method or field used.
-//
-// Issues of this rule have a severity **High**
-// because it is important to not rely anymore on obsolete code.
-//]]>
- Do implement methods that throw NotImplementedException
-// ND1312:DoImplementMethodsThatThrowNotImplementedException
-
-warnif count > 0
-from m in Application.Methods
-where m.CreateA("System.NotImplementedException".AllowNoMatch())
-select new {
- m,
- m.NbLinesOfCode,
- Debt = (m.NbLinesOfCode == 1 ? 10 : 3).ToMinutes().ToDebt(),
- Severity = m.NbLinesOfCode == 1 ? Severity.High : Severity.Medium
-}
-
-//
-// The exception *NotImplementedException* is used to declare
-// a method *stub* that can be invoked, and defer the
-// development of the method implementation.
-//
-// This exception is especially useful when doing **TDD**
-// (*Test Driven Development*) when tests are written first.
-// This way tests fail until the implementation is written.
-//
-// Hence using *NotImplementedException* is a *temporary*
-// facility, and before releasing, will come a time when
-// this exception shouldn't be used anywhere in code.
-//
-// *NotImplementedException* should not be used permanently
-// to mean something like *this method should be overriden*
-// or *this implementation doesn't support this facility*.
-// Artefact like *abstract method* or *abstract class* should
-// be used instead, to favor a *compile time* error over a
-// *run-time* error.
-//
-// This rule warns about method still using
-// *NotImplementedException*.
-//
-
-//
-// Investigate why *NotImplementedException* is still
-// thrown.
-//
-// Such issue has a **High** severity if the method code
-// consists only in throwing *NotImplementedException*.
-// Such situation means either that the method should be
-// implemented, either that what should be a *compile time*
-// error is a *run-time* error *by-design*,
-// and this is not good design. Sometime this situation
-// also pinpoints a method stub that can be safely removed.
-//
-// If *NotImplementedException* is thrown from a method
-// with significant logic, the severity is considered as
-// **Medium**, because often the fix consists in throwing
-// another exception type, like **InvalidOperationException**.
-//]]>
- Override equals and operator equals on value types
-// ND1313:OverrideEqualsAndOperatorEqualsOnValueTypes
-
-warnif count > 0
-from t in JustMyCode.Types where
- t.IsStructure &&
- t.InstanceFields.Count() > 0
-let equalsMethod = t.InstanceMethods.Where(m0 => m0.Name == "Equals(Object)").SingleOrDefault()
-where equalsMethod == null
-select new {
- t,
- t.InstanceFields,
- Debt = (15 + 2*t.InstanceFields.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// For value types, the inherited implementation of *Equals()* uses
-// the Reflection library, and compares the contents of all instances
-// fields. Reflection is computationally expensive, and comparing
-// every field for equality might be unnecessary.
-//
-// If you expect users to compare or sort instances, or use them
-// as hash table keys, your value type should implement *Equals()*.
-// In C# and VB.NET, you should also provide an implementation of
-// *GetHashCode()* and of the equality and inequality operators.
-//
-
-//
-// To fix a violation of this rule, provide an implementation
-// of *Equals()* and *GetHashCode()* and implement the equality
-// and inequality operators.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 15 minutes plus 2 minutes per instance field.
-//]]>
- Boxing/unboxing should be avoided
-// ND1314:BoxingUnboxingShouldBeAvoided
-warnif count > 0 from m in JustMyCode.Methods where
- m.IsUsingBoxing ||
- m.IsUsingUnboxing
-select new {
- m,
- m.NbLinesOfCode,
- m.IsUsingBoxing,
- m.IsUsingUnboxing,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// *Boxing* is the process of converting a value type to the type
-// *object* or to any interface type implemented by this value
-// type. When the CLR boxes a value type, it wraps the value
-// inside a *System.Object* and stores it on the managed heap.
-//
-// *Unboxing* extracts the value type from the object. Boxing
-// is implicit; unboxing is explicit.
-//
-// The concept of boxing and unboxing underlies the C# unified
-// view of the type system in which a value of any type can
-// be treated as an object. More about *boxing* and *unboxing*
-// here: https://msdn.microsoft.com/en-us/library/yz2be5wk.aspx
-//
-// **This rule has been disabled by default** to avoid noise in
-// issues found by the NDepend default rule set. If boxing/unboxing
-// is important to your team, just re-activate this rule.
-//
-
-//
-// Thanks to .NET generic, and especially thanks to
-// generic collections, *boxing* and *unboxing* should
-// be rarely used. Hence in most situations the code can
-// be refactored to avoid relying on *boxing* and *unboxing*.
-// See for example:
-// http://stackoverflow.com/questions/4403055/boxing-unboxing-and-generics
-//
-// With a performance profiler, indentify methods that consume
-// a lot of CPU time. If such method uses *boxing* or
-// *unboxing*, especially in a **loop**, make sure to refactor it.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
-
-
- Avoid namespaces mutually dependent
-// ND1400:AvoidNamespacesMutuallyDependent
-
-warnif count > 0
-
-// Optimization: restraint application assemblies set
-// If some namespaces are mutually dependent
-// - They must be declared in the same assembly
-// - The parent assembly must ContainsNamespaceDependencyCycle
-from assembly in Application.Assemblies.Where(a => a.ContainsNamespaceDependencyCycle != null && a.ContainsNamespaceDependencyCycle.Value)
-
-// hashset is used to avoid reporting both A <-> B and B <-> A
-let hashset = new HashSet()
-
-// Optimization: restraint namespaces set
-let namespacesSuspect = assembly.ChildNamespaces.Where(
- // If a namespace doesn't have a Level value, it must be in a dependency cycle
- // or it must be using directly or indirectly a dependency cycle.
- n => n.Level == null &&
- // Also require the namespace to be JustMyCode to avoid generated namespaces like My / My.Resources in VB.NET
- JustMyCode.Contains(n))
-
-from nA in namespacesSuspect
-
-// Select namespaces mutually dependent with nA
-let unused = hashset.Add(nA) // Populate hashset
-let namespacesMutuallyDependentWith_nA = nA.NamespacesUsed.Using(nA)
- .Except(hashset) // <-- avoid reporting both A <-> B and B <-> A
-where namespacesMutuallyDependentWith_nA.Count() > 0
-
-from nB in namespacesMutuallyDependentWith_nA
-
-// nA and nB are mutually dependent
-// Infer which one is low level and which one is high level,
-// for that we need to compute the coupling from A to B
-// and from B to A in terms of number of types and methods
-// usages involved in the coupling.
-let typesOfBUsedByA = nB.ChildTypes.UsedBy(nA).ToArray() // Enumerate once
-let couplingA2B =
- typesOfBUsedByA.Sum(t => t.TypesUsingMe.Count(t1 => t1.ParentNamespace == nA)) +
- typesOfBUsedByA.ChildMethods().Sum(m => m.MethodsCallingMe.Count(m1 => m1.ParentNamespace == nA))
-
-let typesOfAUsedByB = nA.ChildTypes.UsedBy(nB).ToArray() // Enumerate once
-let couplingB2A =
- typesOfAUsedByB.Sum(t => t.TypesUsingMe.Count(t1 => t1.ParentNamespace == nB)) +
- typesOfAUsedByB.ChildMethods().Sum(m => m.MethodsCallingMe.Count(m1 => m1.ParentNamespace == nB))
-
-// The lowLevelNamespace is inferred from the fact that
-// [coupling lowLevel -> highLevel] is lower than [coupling highLevel -> lowLevel]
-let lowLevelNamespace = (couplingA2B < couplingB2A) ? nA : nB
-let highLevelNamespace = (lowLevelNamespace == nA) ? nB : nA
-
-let highLevelTypesUsed = (lowLevelNamespace == nA) ? typesOfBUsedByA : typesOfAUsedByB
-let lowLevelTypesUser = lowLevelNamespace.ChildTypes.UsingAny(highLevelTypesUsed)
-
-let lowLevelTypesMethodsUser = lowLevelTypesUser.Cast()
- .Concat(lowLevelTypesUser.ChildMethods().Using(highLevelNamespace))
- .ToArray() // Enumerate once
-
-// Make the rule works also when lines of code is not available
-let lowLevelNamespaceLoc = lowLevelNamespace.NbLinesOfCode ?? (lowLevelNamespace.NbILInstructions / 7)
-let highLevelNamespaceLoc = highLevelNamespace.NbLinesOfCode ?? (highLevelNamespace.NbILInstructions / 7)
-
-let annualInterestPerIssue =
- // Such issue has at least a Severity.Medium, never a Severity.Low
- Math.Max(Severity.Medium.AnnualInterestThreshold().Value.TotalSeconds,
- ((3600 + lowLevelNamespaceLoc + highLevelNamespaceLoc) / Math.Max(1,lowLevelTypesMethodsUser.Length)).Value)
- .ToSeconds().ToAnnualInterest()
-
-// Select in details types and methods involved in the coupling lowLevelNamespace using highLevelNamespace
-from tmCulprit in lowLevelTypesMethodsUser
-let used = (tmCulprit.IsType ? tmCulprit.AsType.TypesUsed.Where(t => t.ParentNamespace == highLevelNamespace) :
- tmCulprit.AsMethod.MembersUsed.Where(m => m.ParentNamespace == highLevelNamespace))
- .ToArray() // Enumerate once
-
-select new {
- tmCulprit,
- shouldntUse = used,
- becauseNamespace = lowLevelNamespace,
- shouldntUseNamespace = highLevelNamespace,
- Debt = used.Length.Linear(1, 15, 10, 60).ToMinutes().ToDebt(),
- AnnualInterest = annualInterestPerIssue
-
-}
-//
-// This rule lists types and methods from a low-level namespace
-// that use types and methods from higher-level namespace.
-//
-// The pair of low and high level namespaces is made of two
-// namespaces that use each other.
-//
-// For each pair of namespaces, to infer which one is low-level
-// and which one is high-level, the rule computes the two coupling
-// [from A to B] and [from B to A] in terms of number of types,
-// methods and fields involved in the coupling. Typically
-// the coupling from low-level to high-level namespace is significantly
-// lower than the other legitimate coupling.
-//
-// Following this rule is useful to avoid **namespaces dependency
-// cycles**. This will get the code architecture close to a
-// *layered architecture*, where *low-level* code is not allowed
-// to use *high-level* code.
-//
-// In other words, abiding by this rule will help significantly
-// getting rid of what is often called **spaghetti code:
-// Entangled code that is not properly layered and structured**.
-//
-// More on this in our white books relative to partitioning code.
-// https://www.ndepend.com/docs/white-books
-//
-
-//
-// Refactor the code to make sure that **the low-level namespace
-// doesn't use the high-level namespace**.
-//
-// The rule lists in detail which low-level types and methods
-// shouldn't use which high-level types and methods. The refactoring
-// patterns that help getting rid of each listed dependency include:
-//
-// • Moving one or several types from the *low-level* namespaces
-// to the *high-level* one, or do the opposite.
-//
-// • Use *Inversion of Control (IoC)*:
-// http://en.wikipedia.org/wiki/Inversion_of_control
-// This consists in creating new interfaces in the
-// *low-level* namespace, implemented by classes
-// in the *high-level* namespace. This way *low-level*
-// code can consume *high-level* code through interfaces,
-// without using directly *high-level* implementations.
-// Interfaces can be passed to *low-level* code through
-// the *high-level* namespace code, or through even
-// higher-level code. In related documentations
-// you can see these interfaces named as *callbacks*,
-// and the overall pattern is also known as
-// *Dependency Injection (DI)*:
-// http://en.wikipedia.org/wiki/Dependency_injection
-//
-// That rule might not be applicable for frameworks
-// that present public namespaces mutually dependent.
-// In such situation the cost to break the API can be
-// higher than the cost to let the code entangled.
-//
-// -
-//
-// The estimated **Debt**, which means the effort to fix such issue
-// to make sure that the first namespace doesn't rely anymore
-// on the second one, depends on the number of types and methods used.
-//
-// Because both namespace are now forming a *super-component*
-// that cannot be partitioned in smaller components, the cost to
-// unfix each issue is proportional to the size of this super-component.
-// As a consequence, the estimated **Annual Interest**, which means
-// the annual cost to let both namespaces mutually dependend, is equal
-// to an hour plus a number of minutes proportional to the size
-// (in lines of code) of both namespaces. The obtained *Annual Interest*
-// value is then divided by the number of detailled issues listed.
-//
-// Often the estimated *Annual Interest* for each listed issue
-// is higher than the *Debt*, which means that leaving such issue
-// unfixed for a year costs more than taking the time to fix issue once.
-//
-// --
-//
-// To explore the coupling between the two namespaces mutually
-// dependent:
-//
-// 1) from the *becauseNamespace right-click menu* choose
-// *Copy to Matrix Columns* to export this low-level namespace
-// to the horizontal header of the dependency matrix.
-//
-// 2) from the *shouldntUseNamespace right-click menu* choose
-// *Copy to Matrix Rows* to export this high-level namespace to
-// the vertical header of the dependency matrix.
-//
-// 3) double-click the black matrix cell (it is black because of
-// the mutual dependency).
-//
-// 4) in the matrix command bar, click the button:
-// *Remove empty Row(s) and Column(s)*.
-//
-// At this point, the dependency matrix shows types involved
-// into the coupling.
-//
-// • Blue cells represent types from low-level namespace using types
-// from high-level namespace
-//
-// • Green cells represent types from high-level namespace using
-// types from low-level namespace
-//
-// • Black cells represent types from low-level and high-level
-// namespaces that use each other.
-//
-// There are more green cells than blue and black cells because
-// green cell represents correct coupling from high-level to low-level.
-// **The goal is to eliminate incorrect dependencies represented by
-// blue and black cells.**
-//
- ]]>
- Avoid namespaces dependency cycles
-// ND1401:AvoidNamespacesDependencyCycles
-
-warnif count > 0
-
-// Optimization: restraint application assemblies set
-// If some namespaces are mutually dependent
-// - They must be declared in the same assembly
-// - The parent assembly must ContainsNamespaceDependencyCycle
-from assembly in Application.Assemblies
- .Where(a => a.ContainsNamespaceDependencyCycle != null &&
- a.ContainsNamespaceDependencyCycle.Value)
-
-// Optimization: restraint namespaces set
-let namespacesSuspect = assembly.ChildNamespaces.Where(n =>
- // A namespace involved in a cycle necessarily have a null Level.
- n.Level == null &&
- // Also require the namespace to be JustMyCode to avoid generated namespaces like My / My.Resources in VB.NET
- JustMyCode.Contains(n))
-
-// hashset is used to avoid iterating again on namespaces already caught in a cycle.
-let hashset = new HashSet()
-
-
-from suspect in namespacesSuspect
- // By commenting in this line, the query matches all namespaces involved in a cycle.
- where !hashset.Contains(suspect)
-
- // Define 2 code metrics
- // • Namespaces depth of is using indirectly the suspect namespace.
- // • Namespaces depth of is used by the suspect namespace indirectly.
- // Note: for direct usage the depth is equal to 1.
- let namespacesUserDepth = namespacesSuspect.DepthOfIsUsing(suspect)
- let namespacesUsedDepth = namespacesSuspect.DepthOfIsUsedBy(suspect)
-
- // Select namespaces that are both using and used by namespaceSuspect
- let usersAndUsed = from n in namespacesSuspect where
- namespacesUserDepth[n] > 0 &&
- namespacesUsedDepth[n] > 0
- select n
-
- where usersAndUsed.Count() > 0
-
- // Here we've found namespace(s) both using and used by the suspect namespace.
- // A cycle involving the suspect namespace is found!
- // v2017.3.2: don't call Append() as an extension method else ambiguous syntax error
- // with the new extension method in .NET Fx v4.7.1 / .NET Standard 2.0: System.Linq.Enumerable.Append()
- let cycle = ExtensionMethodsEnumerable.Append(usersAndUsed,suspect)
-
- // Fill hashset with namespaces in the cycle.
- // .ToArray() is needed to force the iterating process.
- let unused1 = (from n in cycle let unused2 = hashset.Add(n) select n).ToArray()
-
-select new {
- suspect,
- cycle,
- Debt = 120.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule lists all *application namespace dependency cycles*.
-// Each row shows a different cycle, indexed with one of the namespace entangled
-// in the cycle.
-//
-// To browse a cycle on the dependency graph or the dependency matrix, right click
-// a cycle cell and export the matched namespaces to the dependency graph or matrix.
-//
-// In the matrix, dependency cycles are represented with red squares and black cells.
-// To easily browse dependency cycles, the dependency matrix comes with an option:
-// *Display Direct and Indirect Dependencies*
-//
-// Read our white books relative to partitioning code,
-// to know more about namespaces dependency cycles, and why avoiding them
-// is a *simple yet efficient* solution to clean the architecture of a code base.
-// https://www.ndepend.com/docs/white-books
-//
-
-//
-// Removing first pairs of *mutually dependent namespaces* will eliminate
-// most *namespaces dependency cycles*. This is why it is recommended
-// focusing on matches of the default rule
-// **Avoid namespaces mutually dependent** before dealing
-// with the present rule.
-//
-// Once solving all *mutually dependent namespaces*, remaining cycles
-// matched by the present rule necessarily involve 3 or more namespaces
-// like in: *A is using B is using C is using A*.
-// Such cycle can be broken by identifying which namespace should
-// be at the *lower-level*. For example if B should be at the
-// *lower-level*, then it means C should be at the *higher-level*
-// and to break the cycle, you just have to remove the dependency
-// from B to C, with a pattern described in the *HowToFix* section
-// of the rule *Avoid namespaces mutually dependent*.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// doesn't depend on the cycle length. First because fixing the rule
-// **Avoid namespaces mutually dependent** will fix most cycle reported
-// here, second because even a long cycle can be broken by removing
-// a few dependency.
-//]]>
- Avoid partitioning the code base through many small library Assemblies
-// ND1402:AvoidPartitioningTheCodeBaseThroughManySmallLibraryAssemblies
-
-warnif count > 10
-from a in Application.Assemblies where
- ( a.NbLinesOfCode < 1000 ||
- a.NbILInstructions < 7000 ) &&
- a.FilePath.FileExtension.ToLower() == ".dll"
-select new {
- a,
- a.NbLinesOfCode,
- a.NbILInstructions,
- Debt = 40.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Each .NET Assembly compiled represents one or several physical file(s).
-// Having too many library .NET Assemblies is a symptom of
-// considering **physical** .NET Assemblies as **logical** components.
-//
-// We advise having less, and bigger, .NET Assemblies
-// and using the concept of namespaces to define logical components.
-// Benefits are:
-//
-// • Faster compilation time.
-//
-// • Faster startup time for your program.
-//
-// • Easier deployment thanks to less files to manage.
-//
-// • If you are developing a Framework,
-// less .NET assemblies to reference and manage for your clients.
-//
-
-//
-// Consider using the *physical* concept of assemblies for physical needs
-// only.
-//
-// Our white book about **Partitioning code base through .NET assemblies
-// and Visual Studio projects** explains in details valid and invalid
-// reasons to use assemblies.
-// Download it here:
-// https://www.ndepend.com/Res/NDependWhiteBook_Assembly.pdf
-//]]>
- UI layer shouldn't use directly DB types
-// ND1403:UILayerShouldntUseDirectlyDBTypes
-
-warnif count > 0
-
-// UI layer is made of types using a UI framework
-let uiTypes = Application.Types.UsingAny(Assemblies.WithNameIn("PresentationFramework", "System.Windows", "System.Windows.Forms", "System.Web"))
-
-// You can easily customize this part to define what are DB types.
-let dbTypes = ThirdParty.Assemblies.WithNameIn("System.Data", "EntityFramework", "NHibernate").ChildTypes()
- // Ideally even DataSet and associated, usage should be forbidden from UI layer:
- // http://stackoverflow.com/questions/1708690/is-list-better-than-dataset-for-ui-layer-in-asp-net
- .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))
-
-from uiType in uiTypes.UsingAny(dbTypes)
-let dbTypesUsed = dbTypes.Intersect(uiType.TypesUsed)
-
-let dbTypesAndMembersUsed = dbTypesUsed.Union(dbTypesUsed.ChildMembers().UsedBy(uiType))
-
-// Per defaut this rule estimates a technical debt
-// proportional to the coupling between the UI and DB types.
-let couplingPerUIType = 2 +
- uiType.Methods.UsingAny(dbTypesUsed).Count() +
- dbTypesAndMembersUsed.Count()
-
-select new {
- uiType,
- dbTypesAndMembersUsed,
- Debt = (4 * couplingPerUIType).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is more a *sample rule to adapt to your need*,
-// than a rigid rule you should abide by. It shows how to
-// define code layers in a rule and how to be warned about
-// layers dependencies violations.
-//
-// This rule first defines the UI layer and the DB framework
-// layer. Second it checks if any UI layer type is using
-// directly any DB framework layer type.
-//
-// • The **DB framework layer** is defined as the set of *third-party*
-// types in the framework *ADO.NET*, *EntityFramework*,
-// *NHibernate* types, that the application is consuming.
-// It is easy to append and suppress any DB framework.
-//
-// • The UI layer (**User Interface Layer**) is defined as the
-// set of types that use *WPF*, *Windows Form*, *ASP.NET*.
-//
-// *UI using directly DB frameworks* is generally considered
-// as *poor design* because DB frameworks accesses should be
-// a concept hidden to UI, encapsulated into a **dedicated
-// Data Access Layer (DAL)**.
-//
-// Notice that per defaut this rule estimates a technical debt
-// proportional to the coupling between the UI and DB types.
-//
-
-//
-// This rule lists precisely which UI type uses which
-// DB framework type. Instead of fixing matches one by one,
-// first imagine how DB framework accesses could be
-// encapsulated into a dedicated layer.
-//
-]]>
- UI layer shouldn't use directly DAL layer
-// ND1404:UILayerShouldntUseDirectlyDALLayer
-
-warnif count > 0
-
-// UI layer is made of types using a UI framework
-let uiTypes = Application.Types.UsingAny(Assemblies.WithNameIn("PresentationFramework", "System.Windows", "System.Windows.Forms", "System.Web"))
-
-// Exclude commonly used DataSet and associated, from ADO.Net types
-// You can easily customize this part to define what are DB types.
-let dbTypes = ThirdParty.Assemblies.WithNameIn("System.Data", "EntityFramework", "NHibernate").ChildTypes()
- .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))
-
-// DAL layer is made of types using a DB framework
-// .ToHashSetEx() results to faster execution of dalTypes.Intersect(uiType.TypesIUse).
-let dalTypes = Application.Types.UsingAny(dbTypes).ToHashSetEx()
-
-from uiType in uiTypes.UsingAny(dalTypes)
-let dalTypesUsed = dalTypes.Intersect(uiType.TypesUsed)
-
-let dalTypesAndMembersUsed = dalTypesUsed.Union(dalTypesUsed.ChildMembers().UsedBy(uiType))
-
-// Per defaut this rule estimates a technical debt
-// proportional to the coupling between the UI with the DAL layer.
-let couplingPerUIType = 2 +
- uiType.Methods.UsingAny(dalTypesUsed).Count() +
- dalTypesAndMembersUsed.Count()
-
-select new {
- uiType,
- // if dalTypesUsed is empty, it means that the uiType is part of the DAL
- dalTypesAndMembersUsed,
- Debt = (4 * couplingPerUIType).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is more a *sample rule to adapt to your need*,
-// than a rigid rule you should abide by. It shows how to
-// define code layers in a rule and how to be warned about
-// layers dependencies violations.
-//
-// This rule first defines the UI layer and the DAL layer.
-// Second it checks if any UI layer type is using directly
-// any DAL layer type.
-//
-// • The DB layer (the DAL, **Data Access Layer**) is defined as
-// the set of types of the application that use *ADO.NET*,
-// *EntityFramework*, *NHibernate* types. It is easy to append
-// and suppress any DB framework.
-//
-// • The UI layer (**User Interface Layer**) is defined as the
-// set of types that use *WPF*, *Windows Form*, *ASP.NET*.
-//
-// *UI using directly DAL* is generally considered as *poor
-// design* because DAL accesses should be a concept
-// hidden to UI, encapsulated into an **intermediary domain
-// logic**.
-//
-// Notice that per defaut this rule estimates a technical debt
-// proportional to the coupling between the UI with the DAL layer.
-//
-
-//
-// This rule lists precisely which UI type uses which DAL type.
-//
-// More about this particular design topic here:
-// http://www.kenneth-truyers.net/2013/05/12/the-n-layer-myth-and-basic-dependency-injection/
-//
-]]>
- Assemblies with poor cohesion (RelationalCohesion)
-// ND1405:AssembliesWithPoorRelationalCohesion
-
-warnif count > 0 from a in Application.Assemblies
-
-// Build the types list on which we want to check cohesion
-// This is the assembly 'a' type, minus enumeration
-// and types generated by the compiler.
-let types = a.ChildTypes.Where(
- t => !t.IsGeneratedByCompiler &&
- !t.IsEnumeration &&
- JustMyCode.Contains(t))
- // Absolutly need ToHashet() to have fast Intersect() calls below.
- .ToHashSetEx()
-
-// Relational Cohesion metrics is relevant only if there are enough types
-where types.LongCount()> 20
-
-// R is the total number of relationship between types of the assemblies.
-let R = types.Sum(t => t.TypesUsed.Intersect(types).Count())
-
-// Relational Cohesion formula
-let relationalCohesion = (double)R / types.Count
-where
-
- (relationalCohesion < 1.5 ||
- relationalCohesion > 4.0)
-select new {
- a,
- a.ChildTypes,
- relationalCohesion,
- a.RelationalCohesion,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule computes the *Relational Cohesion* metric for
-// the application assemblies, and warns about wrong values.
-//
-// The *Relational Cohesion* for an assembly, is the total number
-// of relationship between types of the assemblies, divided
-// by the number of types. In other words it is the average
-// number of types in the assembly used by a type in the assembly.
-//
-// As classes inside an assembly should be strongly related,
-// the cohesion should be high. On the other hand, a value
-// which is too high may indicate over-coupling. A good range
-// for *Relational Cohesion* is **1.5 to 4.0**.
-//
-// Notice that assemblies with less than 20 types are ignored.
-//
-
-//
-// Matches of this present rule might reveal either assemblies
-// with specific coding constraints (like code generated that
-// have particular structure) either issues in design.
-//
-// In the second case, large refactoring can be planned
-// not to respect this rule in particular, but to increase
-// the overall design and code maintainability.
-//
-// The severity of issues of this rule is **Low** because
-// the code metric *Relational Cohesion* is an information
-// about the code structure state but **is not actionable**,
-// it doesn't tell precisely what to do obtain a better score.
-//
-// Fixing actionable issues of others **Architecture** and
-// **Code Smells** default rules will necessarily increase
-// the *Relational Cohesion* scores.
-//]]>
- Namespaces with poor cohesion (RelationalCohesion)
-// ND1406:NamespacesWithPoorRelationalCohesion
-
-warnif count > 0 from n in Application.Namespaces
-
-// Build the types list on which we want to check cohesion
-// This is the namespace children types, minus enumerations
-// and types generated by the compiler.
-let types = n.ChildTypes.Where(
- t => JustMyCode.Contains(t) && !t.IsEnumeration)
- // Absolutly need ToHashet() to have fast Intersect() calls below.
- .ToHashSetEx()
-
-// Relational Cohesion metrics is relevant only if there are enough types
-where types.LongCount() > 20
-
-// R is the total number of relationship between types of the namespaces.
-let R = types.Sum(t => t.TypesUsed.Intersect(types).Count())
-
-// Relational Cohesion formula
-let relationalCohesion = (double)R / types.Count
-where
- (relationalCohesion < 1.5 ||
- relationalCohesion > 4.0)
-select new {
- n,
- n.ChildTypes,
- relationalCohesion,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule computes the *Relational Cohesion* metric for
-// the application namespaces, and warns about wrong values.
-//
-// The *Relational Cohesion* for a namespace, is the total number
-// of relationship between types of the namespaces, divided
-// by the number of types. In other words it is the average
-// number of types in the namespace used by a type in the namespace.
-//
-// As classes inside a namespace should be strongly related,
-// the cohesion should be high. On the other hand, a value
-// which is too high may indicate over-coupling. A good range
-// for *Relational Cohesion* is **1.5 to 4.0**.
-//
-// Notice that namespaces with less than 20 types are ignored.
-//
-
-//
-// Matches of this present rule might reveal either namespaces
-// with specific coding constraints (like code generated that
-// have particular structure) either issues in design.
-//
-// In the second case, refactoring sessions can be planned
-// to increase the overall design and code maintainability.
-//
-// You can get an overview of class coupling for a
-// matched namespace by exporting the *ChildTypes* to the graph.
-// (Right click the *ChildTypes* cells)
-//
-// The severity of issues of this rule is **Low** because
-// the code metric *Relational Cohesion* is an information
-// about the code structure state but **is not actionable**,
-// it doesn't tell precisely what to do obtain a better score.
-//
-// Fixing actionable issues of others **Architecture** and
-// **Code Smells** default rules will necessarily increase
-// the *Relational Cohesion* scores.
-//]]>
- Assemblies that don't satisfy the Abstractness/Instability principle
-// ND1407:AssembliesThatDontSatisfyTheAbstractnessInstabilityPrinciple
-
-warnif count > 0 from a in Application.Assemblies
- where a.NormDistFromMainSeq > 0.7
- orderby a.NormDistFromMainSeq descending
-select new {
- a,
- a.NormDistFromMainSeq,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// The **Abstractness versus Instability Diagram** that is shown in the NDepend
-// report helps to assess which assemblies are **potentially painful to maintain**
-// (i.e concrete and stable) and which assemblies are **potentially useless**
-// (i.e abstract and instable).
-//
-// • **Abstractness**: If an assembly contains many abstract types
-// (i.e interfaces and abstract classes) and few concrete types,
-// it is considered as abstract.
-//
-// • **Stability**: An assembly is considered stable if its types
-// are used by a lot of types from other assemblies. In this context
-// stable means *painful to modify*.
-//
-// From these metrics, we define the *perpendicular normalized distance of
-// an assembly from the idealized line* **A + I = 1** (called *main sequence*).
-// This metric is an indicator of the assembly's balance between abstractness
-// and stability. We precise that the word *normalized* means that the range
-// of values is [0.0 … 1.0].
-//
-// This rule warns about assemblies with a *normalized distance* greater than
-// than 0.7.
-//
-// This rules use the default code metric on assembly
-// *Normalized Distance from the Main Sequence* explained here:
-// https://www.ndepend.com/docs/code-metrics#DitFromMainSeq
-//
-// These concepts have been originally introduced by *Robert C. Martin*
-// in 1994 in this paper: http://www.objectmentor.com/resources/articles/oodmetrc.pdf
-//
-
-//
-// Violations of this rule indicate assemblies with an improper
-// *abstractness / stability* balance.
-//
-// • Either the assembly is *potentially painful to maintain* (i.e is massively
-// used and contains mostly concrete types). This can be fixed by creating
-// abstractions to avoid too high coupling with concrete implementations.
-//
-// • Either the assembly is *potentially useless* (i.e contains mostly
-// abstractions and is not used enough). In such situation, the design
-// must be reviewed to see if it can be enhanced.
-//
-// The severity of issues of this rule is **Low** because
-// the *Abstractness/Instability principle* is an information
-// about the code structure state but **is not actionable**,
-// it doesn't tell precisely what to do obtain a better score.
-//
-// Fixing actionable issues of others **Architecture** and
-// **Code Smells** default rules will necessarily push
-// the *Abstractness/Instability principle* scores in the
-// right direction.
-//]]>
- Higher cohesion - lower coupling
-// ND1408:HigherCohesionLowerCoupling
-
-// warnif count > 0
-let abstractNamespaces = JustMyCode.Namespaces.Where(
- n => n.ChildTypes.Where(t => !t.IsInterface && !t.IsEnumeration && !t.IsDelegate).Count() == 0
-).ToHashSetEx()
-
-let concreteNamespaces = JustMyCode.Namespaces.Except(abstractNamespaces).ToHashSetEx()
-
-from n in concreteNamespaces
-let namespacesUsed = n.NamespacesUsed.ExceptThirdParty()
-let concreteNamespacesUsed = namespacesUsed.Except(abstractNamespaces)
-let abstractNamespacesUsed = namespacesUsed.Except(concreteNamespaces)
-orderby concreteNamespacesUsed.Count() descending
-select new {
- n,
- concreteNamespacesUsed ,
- abstractNamespacesUsed,
- // Debt = 50.ToMinutes().ToDebt(),
- // Severity = Severity.High
-}
-
-//
-// It is deemed as a good software architecture practice to clearly separate
-// *abstract* namespaces that contain only abstractions (interfaces, enumerations, delegates)
-// from *concrete* namespaces, that contain classes and structures.
-//
-// Typically, the more concrete namespaces rely on abstract namespaces *only*,
-// the more **Decoupled** is the architecture, and the more **Cohesive** are
-// classes inside concrete namespaces.
-//
-// The present code query defines sets of abstract and concrete namespaces
-// and show for each concrete namespaces, which concrete and abstract namespaces
-// are used.
-//
-
-//
-// This query can be transformed into a code rule, depending if you wish to
-// constraint your code structure *coupling / cohesion* ratio.
-//]]>
- Avoid mutually-dependent types
-// ND1409:AvoidMutuallyDependentTypes
-
-warnif count > 0
-from t1 in Application.Types
-where t1.NbLinesOfCode > 10 &&
- (t1.IsClass || t1.IsStructure)
-
-from t2 in t1.TypesUsingMe
-where t2.NbLinesOfCode > 10 &&
- (t2.IsClass || t2.IsStructure) &&
- t1.IsUsing(t2)
-
-// To avoid reporting twice the same pair
-// use lexicographically sort of full names of types
-// to only take the first one.
-where new string[] {t1.FullName, t2.FullName}.OrderBy(x => x).First() == t1.FullName
-
-// So far we only keep dependencies that involve method call.
-// It is possible to comment the two 'where' clauses below to get also
-// others kind of dependencies, like usage of typeof(Class).
-let t2MethodsUsingT1 = t2.Methods.Where(m => m.IsUsing(t1)).ToArray()
-where t2MethodsUsingT1.Length > 0
-
-let t1MethodsUsingT2 = t1.Methods.Where(m => m.IsUsing(t2)).ToArray()
-where t1MethodsUsingT2.Length > 0
-
-select new {
- t1, t2,
- t2MethodsUsingT1,
- t1MethodsUsingT2,
- Debt = 20.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule matches pairs of classes or structures that use each others.
-//
-// In this situation both types are not isolated: each type cannot be
-// reviewed, refactored or tested without the other one.
-//
-// This rule is disabled by default because there are some common
-// situations, like when implementing recursive data structures,
-// complex serialization or using the visitor pattern, where having
-// mutually dependent types is legitimate.
-// Just enable this rule if you wish to fix most of its issues.
-//
-
-//
-// Fixing mutually-dependent types means identifying the unwanted dependency
-// (*t1* using *t2*, or *t2* using *t1*) and then removing this dependency.
-//
-// Often you'll have to use the **dependency inversion principle** by creating
-// one or several interfaces dedicated to abstract one implementation
-// from the other one: https://en.wikipedia.org/wiki/Dependency_inversion_principle
-//]]>
- Example of custom rule to check for dependency
-// ND9900:ExplicitId9900
-
-warnif count > 0 from a in Assemblies
-where
-a.IsUsing("Foo1.Foo2".AllowNoMatch().MatchNamespace()) &&
-(a.Name == @"Foo3")
-select new {
- a,
- a.NbLinesOfCode,
- // Debt and Severity / Annual Interest can be modified to estimate well the
- // effort to fix the issue and the annual cost to leave the issue unfixed.
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-// the assembly Foo3
-// shouldn't use directly
-// the namespace Foo3.Foo4
-// because (TODO insert your reason)
-
-//
-// This rule is a **sample rule** that shows how to
-// check if a particular dependency exists or not,
-// from a code element **A** to a code element **B**,
-// **A** and **B** being an *Assembly*, a *Namespace*, a *Type*,
-// a *Method* or a *Field*, **A** and **B** being not
-// necessarily of same kind (i.e two Assemblies or
-// two Namespaces…).
-//
-// Such rule can be generated:
-//
-// • by right clicking the cell in the *Dependency Matrix*
-// with **B** in row and **A** in column,
-//
-// • or by right-clicking the concerned arrow in the *Dependency
-// Graph* from **A** to **B**,
-//
-// and in both cases, click the menu
-// **Generate a code rule that warns if this dependency exists**
-//
-// The generated rule will look like this one.
-// It is now up to you to adapt this rule to check exactly
-// your needs.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
-
-
- API Breaking Changes: Types
-// ND1500:APIBreakingChangesTypes
-
-warnif count > 0 from t in codeBase.OlderVersion().Application.Types
-where t.IsPubliclyVisible &&
-
- // The type has been removed, it was not tagged as obsolete
- // and its parent assembly hasn't been removed …
- ( ( t.WasRemoved() &&
- !t.ParentAssembly.WasRemoved() &&
- !t.IsObsolete) ||
-
- // … or the type is not publicly visible anymore
- !t.WasRemoved() && !t.NewerVersion().IsPubliclyVisible)
-
-select new {
- t,
- NewVisibility =
- (t.WasRemoved() ? " " :
- t.NewerVersion().Visibility.ToString()),
- Debt = 20.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule warns if a type publicly visible in the *baseline*,
-// is not publicly visible anymore or if it has been removed.
-// Clients code using such type will be broken.
-//
-
-//
-// Make sure that public types that used to be presented to
-// clients, still remain public now, and in the future.
-//
-// If a public type must really be removed, you can tag it
-// with *System.ObsoleteAttribute* with a *workaround message*
-// during a few public releases, until it gets removed definitely.
-// Notice that this rule doesn't match types removed that were
-// tagged as obsolete.
-//
-// Issues of this rule have a severity equal to **High**
-// because an API Breaking change can provoque significant
-// friction with consumers of the API.
-//]]>
- API Breaking Changes: Methods
-// ND1501:APIBreakingChangesMethods
-
-warnif count > 0 from m in codeBase.OlderVersion().Application.Methods
-where m.IsPubliclyVisible &&
-
- // The method has been removed, it was not tagged as obsolete
- // and its parent type hasn't been removed …
- ( ( m.WasRemoved() &&
- !m.ParentType.WasRemoved() &&
- !m.IsObsolete )
-
- // … or the method is not publicly visible anymore
- || (!m.WasRemoved() && !m.NewerVersion().IsPubliclyVisible)
-
- // … or the method return type has changed
- || (!m.WasRemoved() && m.ReturnType != null && m.NewerVersion().ReturnType != null
- && m.ReturnType.FullName != m.NewerVersion().ReturnType.FullName)
- )
-
-//--------------------------------------
-// Handle special case: if between two versions a regular property becomes
-// an auto-property (or vice-versa) the property getter/setter method have
-// a different value for IMethod.IsGeneratedByCompiler
-// since auto-property getter/setter are marked as generated by the compiler.
-//
-// If a method IsGeneratedByCompiler value changes between two versions,
-// NDepend doesn't pair the newer/older occurences of the method.
-//
-// Hence in such situation, a public method is seen as added
-// and a public method is seen as removed, but the API is not broken!
-// The equivalentMethod-check below avoids reporting such
-// API Breaking Change false-positive.
-let equivalentMethod = m.WasRemoved() && m.ParentType.IsPresentInBothBuilds() ?
- m.ParentType.NewerVersion().Methods
- .FirstOrDefault(m1 =>
- m1.IsPubliclyVisible &&
- m1.Name == m.Name &&
- m1.IsGeneratedByCompiler != m.IsGeneratedByCompiler &&
- (m1.ReturnType == null || m.ReturnType == null || m1.ReturnType.FullName == m.ReturnType.FullName)
- )
- : null
-where equivalentMethod == null
-//--------------------------------------
-
-
-select new {
- m,
- NewVisibility =
- (m.WasRemoved() ? " " :
- m.NewerVersion().Visibility.ToString()),
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule warns if a method publicly visible in the *baseline*,
-// is not publicly visible anymore or if it has been removed.
-// Clients code using such method will be broken.
-//
-
-//
-// Make sure that public methods that used to be presented to
-// clients, still remain public now, and in the future.
-//
-// If a public method must really be removed, you can tag it
-// with *System.ObsoleteAttribute* with a *workaround message*
-// during a few public releases, until it gets removed definitely.
-// Notice that this rule doesn't match methods removed that were
-// tagged as obsolete.
-//
-// Issues of this rule have a severity equal to **High**
-// because an API Breaking change can provoque significant
-// friction with consumers of the API.
-//
-]]>
- API Breaking Changes: Fields
-// ND1502:APIBreakingChangesFields
-
-warnif count > 0 from f in codeBase.OlderVersion().Application.Fields
-where f.IsPubliclyVisible &&
-
- // The field has been removed, it was not tagged as obsolete
- // and its parent type hasn't been removed …
- ( ( f.WasRemoved() &&
- !f.ParentType.WasRemoved() &&
- !f.IsObsolete)
-
- // … or the field is not publicly visible anymore
- || !f.WasRemoved() && !f.NewerVersion().IsPubliclyVisible)
-
- // … or the field type has changed
- || (!f.WasRemoved() && f.FieldType != null && f.NewerVersion().FieldType != null
- && f.FieldType.FullName != f.NewerVersion().FieldType.FullName)
-
-select new {
- f,
- NewVisibility =
- (f.WasRemoved() ? " " :
- f.NewerVersion().Visibility.ToString()),
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule warns if a field publicly visible in the *baseline*,
-// is not publicly visible anymore or if it has been removed.
-// Clients code using such field will be broken.
-//
-
-//
-// Make sure that public fields that used to be presented to
-// clients, still remain public now, and in the future.
-//
-// If a public field must really be removed, you can tag it
-// with *System.ObsoleteAttribute* with a *workaround message*
-// during a few public releases, until it gets removed definitely.
-// Notice that this rule doesn't match fields removed that were
-// tagged as obsolete.
-//
-// Issues of this rule have a severity equal to **High**
-// because an API Breaking change can provoque significant
-// friction with consumers of the API.
-//]]>
- API Breaking Changes: Interfaces and Abstract Classes
-// ND1503:APIBreakingChangesInterfacesAndAbstractClasses
-
-warnif count > 0 from tNewer in Application.Types where
- (tNewer.IsInterface || tNewer.IsClass && tNewer.IsAbstract) &&
- tNewer.IsPubliclyVisible &&
- tNewer.IsPresentInBothBuilds()
-
-let tOlder = tNewer.OlderVersion() where tOlder.IsPubliclyVisible
-
-let methodsRemoved = tOlder.Methods.Where(m => m.IsAbstract && m.WasRemoved())
-let methodsAdded = tNewer.Methods.Where(m => m.IsAbstract && m.WasAdded())
-
-where methodsAdded.Count() > 0 || methodsRemoved.Count() > 0
-select new {
- tNewer,
- methodsAdded,
- methodsRemoved,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule warns if a publicly visible interface or abstract class
-// has been changed and contains new abstract methods or
-// if some abstract methods have been removed.
-//
-// Clients code that implement such interface or derive from
-// such abstract class will be broken.
-//
-
-//
-// Make sure that the public contracts of interfaces and abstract classes
-// that used to be presented to clients, remain stable now, and in the future.
-//
-// If a public contract must really be changed, you can tag
-// abstract methods that will be removed with *System.ObsoleteAttribute*
-// with a *workaround message* during a few public releases, until it gets
-// removed definitely.
-//
-// Issues of this rule have a severity equal to **High**
-// because an API Breaking change can provoque significant
-// friction with consummers of the API.
-// The severity is not set to **Critical** because an interface
-// is not necessarily meant to be implemented by the consummer
-// of the API.
-//]]>
- Broken serializable types
-// ND1504:BrokenSerializableTypes
-
-warnif count > 0
-
-from t in Application.Types where
-
- // Collect types tagged with SerializableAttribute
- t.HasAttribute("System.SerializableAttribute".AllowNoMatch()) &&
- !t.IsDelegate &&
- t.IsPresentInBothBuilds() &&
- t.HasAttribute(t)
-
- // Find newer and older versions of NonSerializedAttribute
- let newNonSerializedAttribute = ThirdParty.Types.WithFullName("System.NonSerializedAttribute").SingleOrDefault()
- let oldNonSerializedAttribute = newNonSerializedAttribute == null ? null : newNonSerializedAttribute.OlderVersion()
-
- // Find added or removed fields not marked with NonSerializedAttribute
- let addedInstanceField = from f in t.InstanceFields where
- f.WasAdded() &&
- (newNonSerializedAttribute == null || !f.HasAttribute(newNonSerializedAttribute))
- select f
- let removedInstanceField = from f in t.OlderVersion().InstanceFields where
- f.WasRemoved() &&
- (oldNonSerializedAttribute == null || !f.HasAttribute(oldNonSerializedAttribute))
- select f
- where addedInstanceField.Count() > 0 || removedInstanceField.Count() > 0
-
-select new {
- t,
- addedInstanceField,
- removedInstanceField,
- Debt = 20.ToMinutes().ToDebt(),
- Severity = Severity.Critical
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule warns about breaking changes in types tagged with
-// *SerializableAttribute*.
-//
-// To do so, this rule searches for serializable type with serializable
-// instance fields added or removed. Notice that it doesn't take account
-// of fields tagged with *NonSerializedAttribute*.
-//
-// From http://msdn.microsoft.com/library/system.serializableattribute.aspx :
-// "All the public and private fields in a type that are marked by the
-// *SerializableAttribute* are serialized by default, unless the type
-// implements the *ISerializable* interface to override the serialization process.
-// The default serialization process excludes fields that are marked
-// with the *NonSerializedAttribute* attribute."
-//
-
-//
-// Make sure that the serialization process of serializable types remains
-// stable now, and in the future.
-//
-// Else you'll have to deal with **Version Tolerant Serialization**
-// that is explained here:
-// https://msdn.microsoft.com/en-us/library/ms229752(v=vs.110).aspx
-//
-// Issues of this rule have a severity equal to **High**
-// because an API Breaking change can provoque significant
-// friction with consummers of the API.
-//]]>
- Avoid changing enumerations Flags status
-// ND1505:AvoidChangingEnumerationsFlagsStatus
-
-warnif count > 0
-
-let oldFlags = codeBase.OlderVersion().ThirdParty.Types.WithFullName("System.FlagsAttribute").FirstOrDefault()
-let newFlags = ThirdParty.Types.WithFullName("System.FlagsAttribute").FirstOrDefault()
-where oldFlags != null && newFlags != null
-
-from t in Application.Types where
- t.IsEnumeration &&
- t.IsPresentInBothBuilds()
-let hasFlagsAttributeNow = t.HasAttribute(newFlags)
-let usedToHaveFlagsAttribute = t.OlderVersion().HasAttribute(oldFlags)
-where hasFlagsAttributeNow != usedToHaveFlagsAttribute
-select new {
- t,
- hasFlagsAttributeNow,
- usedToHaveFlagsAttribute,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule matches enumeration types that used to be tagged
-// with *FlagsAttribute* in the *baseline*, and not anymore.
-// It also matches the opposite, enumeration types that are now
-// tagged with *FlagsAttribute*, and were not tagged in the *baseline*.
-//
-// Being tagged with *FlagsAttribute* is a strong property for an enumeration.
-// Not so much in terms of *behavior* (only the *enum.ToString()* method
-// behavior changes when an enumeration is tagged with *FlagsAttribute*)
-// but in terms of *meaning*: is the enumeration a **range of values**
-// or a **range of flags**?
-//
-// As a consequence, changing the *FlagsAttribute*s status of an enumeration can
-// have significant impact for its clients.
-//
-
-//
-// Make sure the *FlagsAttribute* status of each enumeration remains stable
-// now, and in the future.
-//]]>
- API: New publicly visible types
-from t in Application.Types
-where t.IsPubliclyVisible &&
-
- // The type has been removed and its parent assembly hasn't been removed …
- ( (t.WasAdded() && !t.ParentAssembly.WasAdded()) ||
-
- // … or the type existed but was not publicly visible
- !t.WasAdded() && !t.OlderVersion().IsPubliclyVisible)
-
-select new {
- t,
- OldVisibility =
- (t.WasAdded() ? " " :
- t.OlderVersion().Visibility.ToString()),
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists types that are new in the public
-// surface of the analyzed assemblies.
-//]]>
- API: New publicly visible methods
-from m in Application.Methods
-where m.IsPubliclyVisible &&
-
- // The method has been removed and its parent assembly hasn't been removed …
- ( (m.WasAdded() && !m.ParentType.WasAdded()) ||
-
- // … or the method existed but was not publicly visible
- !m.WasAdded() && !m.OlderVersion().IsPubliclyVisible)
-
-//--------------------------------------
-// Handle special case: if between two versions a regular property becomes
-// an auto-property (or vice-versa) the property getter/setter method have
-// a different value for IMethod.IsGeneratedByCompiler
-// since auto-property getter/setter are marked as generated by the compiler.
-//
-// If a method IsGeneratedByCompiler value changes between two versions,
-// NDepend doesn't pair the newer/older occurences of the method.
-//
-// Hence in such situation, a public method is seen as added
-// and a public method is seen as removed, but the API is not broken!
-// The equivalentMethod-check below avoids reporting such
-// API Breaking Change false-positive.
-let equivalentMethod = m.WasAdded() && m.ParentType.IsPresentInBothBuilds() ?
- m.ParentType.OlderVersion().Methods
- .FirstOrDefault(m1 =>
- m1.IsPubliclyVisible &&
- m1.Name == m.Name &&
- m1.IsGeneratedByCompiler != m.IsGeneratedByCompiler)
- : null
-where equivalentMethod == null
-//--------------------------------------
-
-select new {
- m,
- OldVisibility =
- (m.WasAdded() ? " " :
- m.OlderVersion().Visibility.ToString())
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists methods that are new in the public
-// surface of the analyzed assemblies.
-//
-]]>
- API: New publicly visible fields
-from f in Application.Fields
-where f.IsPubliclyVisible &&
-
- // The method has been removed and its parent assembly hasn'f been removed …
- ( (f.WasAdded() && !f.ParentType.WasAdded()) ||
-
- // … or the t existed but was not publicly visible
- !f.WasAdded() && !f.OlderVersion().IsPubliclyVisible)
-
-select new {
- f,
- OldVisibility =
- (f.WasAdded() ? " " :
- f.OlderVersion().Visibility.ToString())
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists fields that are new in the public
-// surface of the analyzed assemblies.
-//]]>
-
-
- Code should be tested
-// ND1600:CodeShouldBeTested
-
-warnif count > 0
-
-// This lambda infers a factor in the range [0,1] from a sequence of distinct types used,
-// based on how many of these types are actually concrete (i.e are not interfaces or enumeration).
-// Primitive types (int, bool...) are eliminated from the sequence of types used
-// by filtering types declared in the namespace System.
-let abstractionUsageFactorFormula = new Func,double>(typesUsed =>
- typesUsed.Count(t => t.ParentNamespace.Name != "System" && !t.IsInterface && !t.IsEnumeration)
- / (1 + typesUsed.Count(t => t.ParentNamespace.Name != "System")))
-
-
-from method in Application.Methods
- where !method.IsExcludedFromCoverage && method.NbLinesOfCode >= 0 && method.PercentageCoverage < 100
-
- // Factor in case method is partially covered
- let uncoverageFactor = ((100 - method.PercentageCoverage) / 100).Value
-
- // Complexity factor
- let complexityFactor = ((method.CyclomaticComplexity ?? method.ILCyclomaticComplexity) + method.ILNestingDepth).Linear(0, 0.1, 10, 1).Value
-
- // Not my code is often generated code and is in general easier to get tested since test can be generated as well.
- let justMyCodeFactor = (JustMyCode.Contains(method) ? 1 : 0.4)
-
- // abstractionUsageFactor reflects the fact that code that relies on interfaces
- // is easier to test that code that relies on concrete classes.
- let abstractionUsageFactor = 0.7 + 0.3 *abstractionUsageFactorFormula(method.MembersUsed.Select(m => m.ParentType).Distinct())
-
- // The usageFactor depends on the method 'rank' that is a value
- // indicating if the method is often used or not
- let usageFactor = (method.Rank / (method.Rank + 4)).Value
-
- // It is more complicated to write tests for non publicly visible methods
- let visibilityFactor = method.Visibility.EqualsAny(Visibility.Public, Visibility.Internal) ? 1 :
- method.Visibility != Visibility.Private ? 1.1 : 1.2
-
- // Is is more complicated to write tests for methods that read mutable static fields
- // whose changing state is shared across tests executions.
- let staticFieldUsageFactor = method.ReadsMutableTypeState ? 1.3 : 1.0
-
-
- // Both "effort to write tests" and "annual cost to not test" for a method
- // is determined by several factors in the range [0,1] that multiplies the effortToDevelop
- let effortToDevelopInMinutes = method.EffortToDevelop().Value.TotalMinutes
-
- let effortToWriteTests = Math.Max(2, // Minimum 2 minutes per method not tested
- effortToDevelopInMinutes *
- uncoverageFactor *
- complexityFactor *
- justMyCodeFactor *
- abstractionUsageFactor *
- visibilityFactor *
- staticFieldUsageFactor).ToMinutes().ToDebt()
-
- let annualCostToNotFix = Math.Max(2, // Minimum 2 minutes per method not tested
- effortToDevelopInMinutes *
- usageFactor *
- uncoverageFactor *
- justMyCodeFactor).ToMinutes().ToAnnualInterest()
-
- orderby annualCostToNotFix.Value descending
-
-select new {
- method,
- method.PercentageCoverage,
- method.NbLinesOfCode,
- method.NbLinesOfCodeNotCovered,
- method.CyclomaticComplexity,
- Debt = effortToWriteTests,
- AnnualInterest = annualCostToNotFix,
-
- // BreakingPoint = effortToWriteTests.BreakingPoint(annualCostToNotFix),
-
- // Uncomment the line below to tinker with various factors
- // uncoverageFactor, complexityFactor , justMyCodeFactor , abstractionUsageFactor, visibilityFactor, staticFieldUsageFactor
-}
-
-
-//
-// This rule lists methods not covered at all by test
-// or partially covered by tests.
-//
-// For each match, the rules estimates the **technical debt**, i.e
-// the effort to write unit and integration tests for the method.
-// The estimation is based on the effort to develop the code element
-// multiplied by factors in the range ]0,1.3] based on
-//
-// • the method code size and complexity
-//
-// • the actual percentage coverage
-//
-// • the abstractness of types used, because relying on classes instead of
-// interfaces makes the code more difficult to test
-//
-// • the method visibility because testing private or protected
-// methods is more difficult than testing public and internal ones
-//
-// • the fields used by the method, because is is more complicated to
-// write tests for methods that read mutable static fields whose changing
-// state is shared across tests executions.
-//
-// • whether the method is considered *JustMyCode* or not because *NotMyCode*
-// is often generated easier to get tested since tests can be generated as well.
-//
-// This rule is necessarily a large source of technical debt, since
-// the code left untested is by definition part of the technical debt.
-//
-// This rule also estimates the **annual interest**, i.e the annual cost
-// to let the code uncovered, based on the effort to develop the
-// code element, multiplied by factors based on usage of the code element.
-//
-
-//
-// Write unit tests to test and cover the methods and their parent classes
-// matched by this rule.
-//]]>
- New Methods should be tested
-// ND1601:NewMethodsShouldBeTested
-
-warnif count > 0
-from m in Application.Methods where
- m.NbLinesOfCode > 0 &&
- m.PercentageCoverage < 30 &&
- m.WasAdded()
- orderby m.NbLinesOfCode descending,
- m.NbLinesOfCodeNotCovered ,
- m.PercentageCoverage
-select new {
- m,
- m.PercentageCoverage,
- m.NbLinesOfCode,
- m.NbLinesOfCodeNotCovered,
-
- // Simplistic Debt estimation, because the effort to write tests for a method not 100% tested
- // is already estimated properly with the rule "Code should be tested".
- Debt = m.NbLinesOfCodeNotCovered.Linear(1,2, 10,10).ToMinutes().ToDebt(),
-
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-// This rule operates only on methods added or refactored since the baseline.
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// It is important to write code mostly covered by tests
-// to achieve *maintainable* and *non-error-prone* code.
-//
-// In real-world, many code bases are poorly covered by tests.
-// However it is not practicable to stop the development for months
-// to refactor and write tests to achieve high code coverage ratio.
-//
-// Hence it is recommended that each time a method (or a type) gets added,
-// the developer takes the time to write associated unit-tests to cover it.
-//
-// Doing so will help to increase significantly the maintainability of the code base.
-// You'll notice that quickly, refactoring will also be driven by testability,
-// and as a consequence, the overall code structure and design will increase as well.
-//
-// Issues of this rule have a **High** severity because they reflect
-// an actual trend to not care about writing tests on refactored code.
-//
-
-//
-// Write unit-tests to cover the code of most methods and classes added.
-//]]>
- Methods refactored should be tested
-// ND1602:MethodsRefactoredShouldBeTested
-
-warnif count > 0
-from m in Application.Methods where
- m.PercentageCoverage < 30 &&
- m.CodeWasChanged()
- orderby m.NbLinesOfCode descending,
- m.NbLinesOfCodeNotCovered ,
- m.PercentageCoverage
-select new {
- m,
- m.PercentageCoverage,
- m.NbLinesOfCode,
- m.NbLinesOfCodeNotCovered,
-
- // Simplistic Debt estimation, because the effort to write tests for a method not 100% tested
- // is already estimated properly with the rule "Code should be tested".
- Debt = m.NbLinesOfCodeNotCovered.Linear(1,2, 10,10).ToMinutes().ToDebt(),
-
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-// This rule operates only on methods added or refactored since the baseline.
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// It is important to write code mostly covered by tests
-// to achieve *maintainable* and *non-error-prone* code.
-//
-// In real-world, many code bases are poorly covered by tests.
-// However it is not practicable to stop the development for months
-// to refactor and write tests to achieve high code coverage ratio.
-//
-// Hence it is recommended that each time a method (or a type) gets refactored,
-// the developer takes the time to write associated unit-tests to cover it.
-//
-// Doing so will help to increase significantly the maintainability of the code base.
-// You'll notice that quickly, refactoring will also be driven by testability,
-// and as a consequence, the overall code structure and design will increase as well.
-//
-// Issues of this rule have a **High** severity because they reflect
-// an actual trend to not care about writing tests on refactored code.
-//
-
-//
-// Write unit-tests to cover the code of most methods and classes refactored.
-//]]>
- Assemblies Namespaces and Types should be tested
-// ND1603:AssembliesNamespacesAndTypesShouldBeTested
-
-warnif count > 0
-from elem in CodeElementParents
-where elem.NbLinesOfCode > 0 &&
- elem.PercentageCoverage == 0 &&
- elem.Parent.PercentageCoverage != 0
-orderby elem.NbLinesOfCode descending
-select new {
- elem,
- elem.NbLinesOfCodeNotCovered,
- Debt = 4.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule lists assemblies, namespaces and types that are not
-// covered at all by unit tests.
-//
-// If a parent is matched its children are not matched. For example
-// if a namespace is matched, its child types are not matched.
-//
-// This rule goal is not to collide with the **Code should be tested**
-// rule that lists uncovered code for each method and infer the effort
-// to write unit tests (the *Debt*) and the annual cost to let the code
-// untested (the Annual Interest).
-//
-// This rule goal is to inform of large code elements left untested.
-// As a consequence the *Debt* per issue is only 4 minutes and the
-// severity of the issues is *Low*.
-//
-//
-//
-// Write unit and integration tests to cover, even partially,
-// code elements matched by this rule.
-//
-// Then use issues of the rules **Code should be tested**,
-// **New Methods should be tested** and
-// **Methods refactored should be tested**
-// to write more tests where it matters most, and eventually
-// refactor some code to make it more testable.
-//]]>
- Types almost 100% tested should be 100% tested
-// ND1604:TypesAlmost100PercentTestedShouldBe100PercentTested
-
-warnif count > 0
-from t in Application.Types where
- t.PercentageCoverage >= 95 &&
- t.PercentageCoverage <= 99 &&
- !t.IsGeneratedByCompiler
-
- let methodsCulprit = t.Methods.Where(m => m.PercentageCoverage < 100)
-
- orderby t.NbLinesOfCode descending ,
- t.NbLinesOfCodeNotCovered ,
- t.PercentageCoverage
-select new {
- t,
- t.PercentageCoverage,
- t.NbLinesOfCode,
- t.NbLinesOfCodeNotCovered,
- methodsCulprit,
-
- // Simplistic Debt estimation, because the effort to write tests for a type not 100% tested
- // is already estimated properly with the rule "Code should be tested".
- Debt = t.NbLinesOfCodeNotCovered.Linear(1,2, 20,20).ToMinutes().ToDebt(),
-
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// Often covering the few percents of remaining uncovered code of a class,
-// requires as much work as covering the first 90%.
-// For this reason, often teams estimate that 90% coverage is enough.
-// However *untestable code* usually means *poorly written code*
-// which usually leads to *error prone code*.
-// So it might be worth refactoring and making sure to cover the few uncovered lines of code
-// **because most tricky bugs might come from this small portion of hard-to-test code**.
-//
-// Not all classes should be 100% covered by tests (like UI code can be hard to test)
-// but you should make sure that most of the logic of your application
-// is defined in some *easy-to-test classes*, 100% covered by tests.
-//
-// Issues of this rule have a **High** severity because as explained,
-// such situation is *bug-prone*.
-//
-
-//
-// Write more unit-tests dedicated to cover code not covered yet.
-// If you find some *hard-to-test code*, it is certainly a sign that this code
-// is not *well designed* and hence, needs refactoring.
-//]]>
- Namespaces almost 100% tested should be 100% tested
-// ND1605:NamespacesAlmost100PercentTestedShouldBe100PercentTested
-
-warnif count > 0
-from n in Application.Namespaces where
- n.PercentageCoverage >= 95 &&
- n.PercentageCoverage <= 99
-
- let methodsCulprit = n.ChildMethods.Where(m => m.PercentageCoverage < 100)
-
- orderby n.NbLinesOfCode descending ,
- n.NbLinesOfCodeNotCovered ,
- n.PercentageCoverage
-select new {
- n,
- n.PercentageCoverage,
- n.NbLinesOfCode,
- n.NbLinesOfCodeNotCovered,
- methodsCulprit,
-
- // Simplistic Debt estimation, because the effort to write tests for a type not 100% tested
- // is already estimated properly with the rule "Code should be tested".
- Debt = n.NbLinesOfCodeNotCovered.Linear(1,2, 50,60).ToMinutes().ToDebt(),
-
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// Often covering the few percents of remaining uncovered code of
-// one or several classes in a namespace
-// requires as much work as covering the first 90%.
-// For this reason, often teams estimate that 90% coverage is enough.
-// However *untestable code* usually means *poorly written code*
-// which usually leads to *error prone code*.
-// So it might be worth refactoring and making sure to cover the few uncovered lines of code
-// **because most tricky bugs might come from this small portion of hard-to-test code**.
-//
-// Not all classes should be 100% covered by tests (like UI code can be hard to test)
-// but you should make sure that most of the logic of your application
-// is defined in some *easy-to-test classes*, 100% covered by tests.
-//
-// Issues of this rule have a **High** severity because as explained,
-// such situation is *bug-prone*.
-//
-
-//
-// Write more unit-tests dedicated to cover code not covered yet in the namespace.
-// If you find some *hard-to-test code*, it is certainly a sign that this code
-// is not *well designed* and hence, needs refactoring.
-//]]>
- Types that used to be 100% covered by tests should still be 100% covered
-// ND1606:TypesThatUsedToBe100PercentCoveredByTestsShouldStillBe100PercentCovered
-
-warnif count > 0
-from t in JustMyCode.Types where
- t.IsPresentInBothBuilds() &&
- t.OlderVersion().PercentageCoverage == 100 &&
- t.PercentageCoverage < 100
-
-from m in t .MethodsAndConstructors where
- m.NbLinesOfCode> 0 &&
- m.PercentageCoverage < 100 &&
- !m.IsExcludedFromCoverage
-
-select new {
- m,
- m.PercentageCoverage,
-
- // Simplistic Debt estimation, because the effort to write tests for a method not 100% tested
- // is already estimated properly with the rule "Code should be tested".
- Debt = t.NbLinesOfCodeNotCovered.Linear(1,2, 10,10).ToMinutes().ToDebt(),
-
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// Often covering 10% of remaining uncovered code of a class,
-// requires as much work as covering the first 90%.
-// For this reason, typically teams estimate that 90% coverage is enough.
-// However *untestable code* usually means *poorly written code*
-// which usually leads to *error prone code*.
-// So it might be worth refactoring and making sure to cover the 10% remaining code
-// **because most tricky bugs might come from this small portion of hard-to-test code**.
-//
-// Not all classes should be 100% covered by tests (like UI code can be hard to test)
-// but you should make sure that most of the logic of your application
-// is defined in some *easy-to-test classes*, 100% covered by tests.
-//
-// In this context, this rule warns when a type fully covered by tests is now only partially covered.
-//
-// Issues of this rule have a **High** severity because often,
-// a type that used to be 100% and is not covered anymore
-// is a bug-prone situation that should be carefully handled.
-//
-
-//
-// Write more unit-tests dedicated to cover code not covered anymore.
-// If you find some *hard-to-test code*, it is certainly a sign that this code
-// is not *well designed* and hence, needs refactoring.
-//
-// You'll find code impossible to cover by unit-tests, like calls to *MessageBox.Show()*.
-// An infrastructure must be defined to be able to *mock* such code at test-time.
-//]]>
- Types tagged with FullCoveredAttribute should be 100% covered
-// ND1607:TypesTaggedWithFullCoveredAttributeShouldBe100PercentCovered
-
-warnif count > 0
-from t in Application.Types where
- t.HasAttribute ("NDepend.Attributes.FullCoveredAttribute".AllowNoMatch()) &&
- t.PercentageCoverage < 100
-
-from m in t .MethodsAndConstructors where
- m.NbLinesOfCode> 0 &&
- m.PercentageCoverage < 100 &&
- !m.IsExcludedFromCoverage
-
-select new {
- m,
- m.PercentageCoverage,
- m.NbLinesOfCodeNotCovered,
- m.NbLinesOfCode,
-
- // Simplistic Debt estimation, because the effort to write tests for a method not 100% tested
- // is already estimated properly with the rule "Code should be tested".
- Debt = m.NbLinesOfCodeNotCovered.Linear(1,2, 10,10).ToMinutes().ToDebt(),
-
- Severity = Severity.High
-}
-
-//
-// This rule lists methods partially covered by tests, of types tagged with
-// **FullCoveredAttribute**.
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// By using a **FullCoveredAttribute**, you can express in source code the intention
-// that a class is 100% covered by tests, and should remain 100% covered in the future.
-// If you don't want to link *NDepend.API.dll*,
-// you can use your own attribute and adapt the source code of this rule.
-//
-// Benefits of using a **FullCoveredAttribute** are twofold:
-// Not only the intention is expressed in source code,
-// but it is also continuously checked by the present rule.
-//
-// Often covering 10% of remaining uncovered code of a class,
-// requires as much work as covering the first 90%.
-// For this reason, often teams estimate that 90% coverage is enough.
-// However *untestable code* usually means *poorly written code* which usually means *error prone code*.
-// So it might be worth refactoring and making sure to cover the 10% remaining code
-// **because most tricky bugs might come from this small portion of hard-to-test code**.
-//
-// Not all classes should be 100% covered by tests (like UI code can be hard to test)
-// but you should make sure that most of the logic of your application
-// is defined in some *easy-to-test classes*, 100% covered by tests.
-//
-// Issues of this rule have a **High** severity because often,
-// a type that used to be 100% and is not covered anymore
-// is a bug-prone situation that should be carefully handled.
-//
-
-//
-// Write more unit-tests dedicated to cover code of matched classes not covered yet.
-// If you find some *hard-to-test code*, it is certainly a sign that this code
-// is not *well designed* and hence, needs refactoring.
-//]]>
- Types 100% covered should be tagged with FullCoveredAttribute
-// ND1608:Types100PercentCoveredShouldBeTaggedWithFullCoveredAttribute
-
-warnif count > 0 from t in JustMyCode.Types where
- !t.HasAttribute ("NDepend.Attributes.FullCoveredAttribute".AllowNoMatch()) &&
- t.PercentageCoverage == 100 &&
- !t.IsGeneratedByCompiler
-select new {
- t,
- t.NbLinesOfCode,
- Debt = 3.ToMinutes().ToDebt(), // It is fast to add such attribute to a type.
- Severity = Severity.Low
-}
-
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// By using a **FullCoveredAttribute**, you can express in source code the intention
-// that a class is 100% covered by tests, and should remain 100% covered in the future.
-//
-// Benefits of using a **FullCoveredAttribute** are twofold:
-// Not only the intention is expressed in source code,
-// but it is also continuously checked by the present rule.
-//
-// Issues of this rule have an **Low** severity because they don't reflect
-// a problem, but provide an advice for potential improvement.
-//
-
-//
-// Just tag types 100% covered by tests with the **FullCoveredAttribute**
-// that can be found in *NDepend.API.dll*,
-// or by an attribute of yours defined in your own code
-// (in which case this rule must be adapted).
-//]]>
- Methods should have a low C.R.A.P score
-// ND1609:MethodsShouldHaveALowCRAPScore
-
-warnif count > 0
-from m in JustMyCode.Methods
-
-// Don't match too short methods
-where m.NbLinesOfCode > 10 && m.CoverageDataAvailable
-
-let CC = m.CyclomaticComplexity
-let uncov = (100 - m.PercentageCoverage) / 100f
-let CRAP = (double)(CC * CC * uncov * uncov * uncov) + CC
-where CRAP != null && CRAP > 30
-orderby CRAP descending, m.NbLinesOfCode descending
-select new {
- m,
- CRAP,
- CC,
- m.PercentageCoverage, m.NbLinesOfCode,
-
- // CRAP score equals 30 => 10 minutes debt
- // CRAP score equals 3000 => 3 hours to write tests
- Debt = CRAP.Linear(30,10, 3000, 3*60).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is executed only if some code coverage data is imported
-// from some code coverage files.
-//
-// So far this rule is disabled because other code coverage rules
-// assess properly code coverage issues.
-//
-// **Change Risk Analyzer and Predictor** (i.e. CRAP) is a code metric
-// that helps in pinpointing overly both complex and untested code.
-// Is has been first defined here:
-// http://www.artima.com/weblogs/viewpost.jsp?thread=215899
-//
-// The Formula is: **CRAP(m) = CC(m)^2 * (1 – cov(m)/100)^3 + CC(m)**
-//
-// • where *CC(m)* is the *cyclomatic complexity* of the method *m*
-//
-// • and *cov(m)* is the *percentage coverage* by tests of the method *m*
-//
-// Matched methods cumulates two highly *error prone* code smells:
-//
-// • A complex method, difficult to develop and maintain.
-//
-// • Non 100% covered code, difficult to refactor without introducing any regression bug.
-//
-// The higher the CRAP score, the more painful to maintain and error prone is the method.
-//
-// An arbitrary threshold of 30 is fixed for this code rule as suggested by inventors.
-//
-// Notice that no amount of testing will keep methods with a Cyclomatic Complexity
-// higher than 30, out of CRAP territory.
-//
-// Notice that this rule doesn't match too short method
-// with less than 10 lines of code.
-//
-
-//
-// In such situation, it is recommended to both refactor the complex method logic
-// into several smaller and less complex methods
-// (that might belong to some new types especially created),
-// and also write unit-tests to full cover the refactored logic.
-//
-// You'll find code impossible to cover by unit-tests, like calls to *MessageBox.Show()*.
-// An infrastructure must be defined to be able to *mock* such code at test-time.
-//]]>
- Test Methods
-
-let testAttr = ThirdParty.Types.WithNameIn("FactAttribute", "TestAttribute", "TestCaseAttribute")
-let testMethods = Methods.TaggedWithAnyAttributes(testAttr)
-from m in testMethods
-select m
-
-//
-// We advise to not include test assemblies in code analyzed by NDepend.
-// We estimate that it is acceptable and practical to lower the quality gate of test code,
-// because the important measures for tests are:
-//
-// • The coverage ratio,
-//
-// • And the amount of logic results asserted: This includes both
-// assertions in test code, and assertions in code covered by tests,
-// like *Code Contract* assertions and *Debug.Assert(…)* assertions.
-//
-// But if you wish to enforce the quality of test code, you'll need to
-// consider test assemblies in your list of application assemblies
-// analyzed by NDepend.
-//
-// In such situation, this code query lists tests methods and you can
-// reuse this code in custom rules.
-//]]>
- Methods directly called by test Methods
-
-let testAttr = ThirdParty.Types.WithNameIn("FactAttribute", "TestAttribute", "TestCaseAttribute")
-let testMethods = Methods.TaggedWithAnyAttributes(testAttr).ToHashSetEx()
-
-// --- Uncomment this line if your test methods are in dedicated test assemblies ---
-//let testAssemblies = testMethods.ParentAssemblies().ToHashSetEx()
-
-from m in Application.Methods.UsedByAny(testMethods)
-
-// --- Uncomment this line if your test methods are in dedicated test assemblies ---
-//where !testAssemblies.Contains(m.ParentAssembly)
-
-select new { m ,
- calledByTests = m.MethodsCallingMe.Intersect(testMethods ),
- // --- Uncomment this line if your project import some coverage data ---
- // m.PercentageCoverage
-}
-
-
-//
-// This query lists all methods directly called by tests methods.
-// Overrides of virtual and abstract methods, called through polymorphism, are not listed.
-// Methods solely invoked through a delegate are not listed.
-// Methods solely invoked through reflection are not listed.
-//
-// We advise to not include test assemblies in code analyzed by NDepend.
-// We estimate that it is acceptable and practical to lower the quality gate of test code,
-// because the important measures for tests are:
-//
-// • The coverage ratio,
-//
-// • And the amount of logic results asserted: This includes both
-// assertions in test code, and assertions in code covered by tests,
-// like *Code Contract* assertions and *Debug.Assert(…)* assertions.
-//
-// But if you wish to run this code query,
-// you'll need to consider test assemblies in your list of
-// application assemblies analyzed by NDepend.
-//]]>
- Methods directly and indirectly called by test Methods
-
-let testAttr = from t in ThirdParty.Types.WithNameIn("FactAttribute", "TestAttribute", "TestCaseAttribute") select t
-let testMethods = Methods.TaggedWithAnyAttributes(testAttr)
-
-// --- Uncomment this line if your test methods are in dedicated test assemblies ---
-// let testAssemblies = testMethods.ParentAssemblies().ToHashSetEx()
-
-let depthOfCalledByTest = Application.Methods.DepthOfIsUsedByAny(testMethods)
-from pair in depthOfCalledByTest
-where pair.Value > 0
-orderby pair.Value ascending
-// --- Uncomment this line if your test methods are in dedicated test assemblies ---
-//&& !testAssemblies.Contains(pair.CodeElement.ParentAssembly)
-
-select new {
- method = pair.CodeElement,
- // (depthOfCalledByTests == 1) means that the method is directly called by tests
- // (depthOfCalledByTests == 2) means that the method is directly called by a method directly called by tests
- // …
- depthOfCalledByTests = pair.Value,
- nbLinesOfCode = pair.CodeElement.NbLinesOfCode,
- // --- Uncomment this line if your project import some coverage data ---
- // m.PercentageCoverage
-}
-
-//
-// This query lists all methods *directly or indirectly* called by tests methods.
-// *Indirectly* called by a test means that a test method calls a method, that calls a method…
-// From this recursion, a code metric named *depthOfCalledByTests* is inferred,
-// The value *1* means directly called by test,
-// the value *2* means called by a method that is called by a test…
-//
-// Overrides of virtual and abstract methods, called through polymorphism, are not listed.
-// Methods solely invoked through a delegate are not listed.
-// Methods solely invoked through reflection are not listed.
-//
-// We advise to not include test assemblies in code analyzed by NDepend.
-// We estimate that it is acceptable and practical to lower the quality gate of test code,
-// because the important measures for tests are:
-//
-// • The coverage ratio,
-//
-// • And the amount of logic results asserted: This includes both
-// assertions in test code, and assertions in code covered by tests,
-// like *Code Contract* assertions and *Debug.Assert(…)* assertions.
-//
-// But if you wish to run this code query,
-// you'll need to consider test assemblies in your list of
-// application assemblies analyzed by NDepend.
-//]]>
-
-
- Potentially Dead Types
-// ND1700:PotentiallyDeadTypes
-
-warnif count > 0
-// Filter procedure for types that should'nt be considered as dead
-let canTypeBeConsideredAsDeadProc = new Func(
- t => !t.IsPublic && // Public types might be used by client applications of your assemblies.
- t.Name != "Program" &&
- !t.IsGeneratedByCompiler &&
-
- // If you don't want to link NDepend.API.dll, you can use your own
- // IsNotDeadCodeAttribute or UsedImplicitlyAttribute
- // and adapt the source code of this rule.
- !t.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- !t.HasAttribute("JetBrains.Annotations.UsedImplicitlyAttribute".AllowNoMatch()) &&
-
- // Exclude static types that define only const fields
- // because they cannot be seen as used in IL code.
- !(t.IsStatic && t.NbMethods == 0 && !t.Fields.Where(f => !f.IsLiteral).Any()) &&
-
- // Entity Framework ModelSnapshot classes are used ony by the EF infrastructure.
- !t.DeriveFrom("Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot".AllowNoMatch()))
-
-// Select types unused
-let typesUnused =
- from t in JustMyCode.Types where
- t.NbTypesUsingMe == 0 && canTypeBeConsideredAsDeadProc(t)
- select t
-
-// Dead types = types used only by unused types (recursive)
-let deadTypesMetric = typesUnused.FillIterative(
-types => from t in codeBase.Application.Types.UsedByAny(types).Except(types)
- where canTypeBeConsideredAsDeadProc(t) &&
- t.TypesUsingMe.Intersect(types).Count() == t.NbTypesUsingMe
- select t)
-
-from t in deadTypesMetric.DefinitionDomain
-select new {
- t,
- depth = deadTypesMetric[t],
- t.TypesUsingMe,
- Debt = 15.ToMinutes().ToDebt(),
- AnnualInterest = (10 + (t.NbLinesOfCode ?? 1)).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule lists *potentially* **dead types**.
-// A dead type is a type that can be removed
-// because it is never used by the program.
-//
-// This rule lists not only types not used anywhere in code,
-// but also types used only by types not used anywhere in code.
-// This is why this rule comes with a column *TypesusingMe* and
-// this is why there is a code metric named *depth*:
-//
-// • A *depth* value of *0* means the type is not used.
-//
-// • A *depth* value of *1* means the type is used only by types not used.
-//
-// • etc…
-//
-// By reading the source code of this rule, you'll see that by default,
-// *public* types are not matched, because such type might not be used
-// by the analyzed code, but still be used by client code, not analyzed by NDepend.
-// This default behavior can be easily changed.
-//
-// Note that this rule doesn't match Entity Framework ModelSnapshot classes
-// that are used ony by the EF infrastructure.
-//
-
-//
-// *Static analysis* cannot provide an *exact* list of dead types,
-// because there are several ways to use a type *dynamically* (like through reflection).
-//
-// For each type matched by this query, first investigate if the type is used somehow
-// (like through reflection).
-// If the type is really never used, it is important to remove it
-// to avoid maintaining useless code.
-// If you estimate the code of the type might be used in the future,
-// at least comment it, and provide an explanatory comment about the future intentions.
-//
-// If a type is used somehow,
-// but still is matched by this rule, you can tag it with the attribute
-// **IsNotDeadCodeAttribute** found in *NDepend.API.dll* to avoid matching the type again.
-// You can also provide your own attribute for this need,
-// but then you'll need to adapt this code rule.
-//
-// Issues of this rule have a **Debt** equal to 15 minutes because it only
-// takes a short while to investigate if a type can be safely discarded.
-// The **Annual Interest** of issues of this rule, the annual cost to not
-// fix such issue, is proportional to the type #lines of code, because
-// the bigger the type is, the more it slows down maintenance.
-//]]>
- Potentially Dead Methods
-// ND1701:PotentiallyDeadMethods
-
-warnif count > 0
-// Filter procedure for methods that should'nt be considered as dead
-let canMethodBeConsideredAsDeadProc = new Func(
- m => !m.IsPubliclyVisible && // Public methods might be used by client applications of your assemblies.
- !m.IsEntryPoint && // Main() method is not used by-design.
- !m.IsExplicitInterfaceImpl && // The IL code never explicitly calls explicit interface methods implementation.
- !m.IsClassConstructor && // The IL code never explicitly calls class constructors.
- !m.IsFinalizer && // The IL code never explicitly calls finalizers.
- !m.IsVirtual && // Only check for non virtual method that are not seen as used in IL.
- !(m.IsConstructor && // Don't take account of protected ctor that might be call by a derived ctors.
- m.IsProtected) &&
- !m.IsEventAdder && // The IL code never explicitly calls events adder/remover.
- !m.IsEventRemover &&
- !m.IsGeneratedByCompiler &&
- !m.ParentType.IsDelegate &&
-
- // Don't consider Global ASP.NET methods as unused
- !m.ParentType.DeriveFrom("System.Web.HttpApplication".AllowNoMatch()) &&
-
- // Methods tagged with these attributes are called by the serialization infrastructure.
- !m.HasAttribute("System.Runtime.Serialization.OnSerializingAttribute".AllowNoMatch()) &&
- !m.HasAttribute("System.Runtime.Serialization.OnDeserializingAttribute".AllowNoMatch()) &&
- !m.HasAttribute("System.Runtime.Serialization.OnSerializedAttribute".AllowNoMatch()) &&
- !m.HasAttribute("System.Runtime.Serialization.OnDeserializedAttribute".AllowNoMatch()) &&
-
- // If you don't want to link NDepend.API.dll, you can use your own
- // IsNotDeadCodeAttribute or UsedImplicitlyAttribute
- // and adapt the source code of this rule.
- !m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- !m.HasAttribute("JetBrains.Annotations.UsedImplicitlyAttribute".AllowNoMatch()) &&
-
- // Don't consider public getters/setters
- // of classes that implement INotifyPropertyChanged
- // as dead code.
- !(m.IsPublic && (m.IsPropertyGetter || m.IsPropertySetter) &&
- m.ParentType.Implement("System.ComponentModel.INotifyPropertyChanged".AllowNoMatch()))
- )
-
-// Get methods unused
-let methodsUnused =
- from m in JustMyCode.Methods where
- m.NbMethodsCallingMe == 0 &&
- canMethodBeConsideredAsDeadProc(m)
- select m
-
-// Dead methods = methods used only by unused methods (recursive)
-let deadMethodsMetric = methodsUnused.FillIterative(
- methods => // Unique loop, just to let a chance to build the hashset.
- from o in (new object()).ToEnumerable()
- // Use a hashet to make Intersect calls much faster!
- let hashset = methods.ToHashSetEx()
- from m in codeBase.Application.Methods.UsedByAny(methods).Except(methods)
- where canMethodBeConsideredAsDeadProc(m) &&
- // Select methods called only by methods already considered as dead
- hashset.Intersect(m.MethodsCallingMe).Count() == m.NbMethodsCallingMe
- select m)
-
-from m in JustMyCode.Methods.Intersect(deadMethodsMetric.DefinitionDomain)
-let depth = deadMethodsMetric[m]
-select new {
- m,
- depth,
- m.MethodsCallingMe,
- Debt = (10 + 3*depth).ToMinutes().ToDebt(),
- AnnualInterest = (8 + (m.NbLinesOfCode ?? 1)).ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule lists *potentially* **dead methods**.
-// A dead method is a method that can be removed
-// because it is never called by the program.
-//
-// This rule lists not only methods not called anywhere in code,
-// but also methods called only by methods not called anywhere in code.
-// This is why this rule comes with a column *MethodsCallingMe* and
-// this is why there is a code metric named *depth*:
-//
-// • A *depth* value of *0* means the method is not called.
-//
-// • A *depth* value of *1* means the method is called only by methods not called.
-//
-// • etc…
-//
-// By reading the source code of this rule, you'll see that by default,
-// *public* methods are not matched, because such method might not be called
-// by the analyzed code, but still be called by client code, not analyzed by NDepend.
-// This default behavior can be easily changed.
-//
-
-//
-// *Static analysis* cannot provide an *exact* list of dead methods,
-// because there are several ways to invoke a method *dynamically* (like through reflection).
-//
-// For each method matched by this query, first investigate if the method is invoked somehow
-// (like through reflection).
-// If the method is really never invoked, it is important to remove it
-// to avoid maintaining useless code.
-// If you estimate the code of the method might be used in the future,
-// at least comment it, and provide an explanatory comment about the future intentions.
-//
-// If a method is invoked somehow,
-// but still is matched by this rule, you can tag it with the attribute
-// **IsNotDeadCodeAttribute** found in *NDepend.API.dll* to avoid matching the method again.
-// You can also provide your own attribute for this need,
-// but then you'll need to adapt this code rule.
-//
-// Issues of this rule have a **Debt** equal to 10 minutes because it only
-// takes a short while to investigate if a method can be safely discarded.
-// On top of these 10 minutes, the depth of usage of such method adds up
-// 3 minutes per unity because dead method only called by dead code
-// takes a bit more time to be investigated.
-//
-// The **Annual Interest** of issues of this rule, the annual cost to not
-// fix such issue, is proportional to the type #lines of code, because
-// the bigger the method is, the more it slows down maintenance.
-//]]>
- Potentially Dead Fields
-// ND1702:PotentiallyDeadFields
-
-warnif count > 0
-from f in JustMyCode.Fields where
- f.NbMethodsUsingMe == 0 &&
- !f.IsPublic && // Although not recommended, public fields might be used by client applications of your assemblies.
- !f.IsLiteral && // The IL code never explicitly uses literal fields.
- !f.IsEnumValue && // The IL code never explicitly uses enumeration value.
- f.Name != "value__" && // Field named 'value__' are relative to enumerations and the IL code never explicitly uses them.
- !f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- !f.HasAttribute("JetBrains.Annotations.UsedImplicitlyAttribute".AllowNoMatch()) &&
- !f.IsGeneratedByCompiler
- // If you don't want to link NDepend.API.dll, you can use your own IsNotDeadCodeAttribute
- // and adapt the source code of this rule.
-select new {
- f,
- Debt = 10.ToMinutes().ToDebt(),
- AnnualInterest = 8.ToMinutes().ToAnnualInterest()
-}
-
-//
-// This rule lists *potentially* **dead fields**.
-// A dead field is a field that can be removed
-// because it is never used by the program.
-//
-// By reading the source code of this rule, you'll see that by default,
-// *public* fields are not matched, because such field might not be used
-// by the analyzed code, but still be used by client code, not analyzed by NDepend.
-// This default behavior can be easily changed.
-// Some others default rules in the *Visibility* group, warn about public fields.
-//
-// More restrictions are applied by this rule because of some *by-design* limitations.
-// NDepend mostly analyzes compiled IL code, and the information that
-// an enumeration value or a literal constant (which are fields) is used
-// is lost in IL code. Hence by default this rule won't match such field.
-//
-
-//
-// *Static analysis* cannot provide an *exact* list of dead fields,
-// because there are several ways to assign or read a field *dynamically*
-// (like through reflection).
-//
-// For each field matched by this query, first investigate
-// if the field is used somehow (like through reflection).
-// If the field is really never used, it is important to remove it
-// to avoid maintaining a useless code element.
-//
-// If a field is used somehow,
-// but still is matched by this rule, you can tag it with the attribute
-// **IsNotDeadCodeAttribute** found in *NDepend.API.dll*
-// to avoid matching the field again.
-// You can also provide your own attribute for this need,
-// but then you'll need to adapt this code rule.
-//
-// Issues of this rule have a **Debt** equal to 10 minutes because it only
-// takes a short while to investigate if a method can be safely discarded.
-// The **Annual Interest** of issues of this rule, the annual cost to not
-// fix such issue, is set by default to 8 minutes per unused field matched.
-//]]>
- Wrong usage of IsNotDeadCodeAttribute
-// ND1703:WrongUsageOfIsNotDeadCodeAttribute
-
-warnif count > 0
-
-let tAttr = Types.WithFullName("NDepend.Attributes.IsNotDeadCodeAttribute").FirstOrDefault()
-where tAttr != null
-
-// Get types that do a wrong usage of IsNotDeadCodeAttribute
-let types = from t in Application.Types where
- t.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
-
- ( // types used don't need to be tagged with IsNotDeadCodeAttribute!
- t.TypesUsingMe.Count(t1 =>
- !t.NestedTypes.Contains(t1) &&
- !t1.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) ) > 0 ||
-
- // Static types that define only const fields cannot be seen as used in IL code.
- // They don't need to be tagged with IsNotDeadCodeAttribute.
- (t.IsStatic && t.NbMethods == 0 && !t.Fields.Where(f => !f.IsLiteral).Any())
- )
- select t
-
-// Get methods that do a wrong usage of IsNotDeadCodeAttribute
-let methods = from m in Application.Methods where
- m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- m.MethodsCallingMe.Count(m1 => !m1.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch())) > 0
- select m
-
-// Get fields that do a wrong usage of IsNotDeadCodeAttribute
-let fields = from f in Application.Fields where
- f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- f.MethodsUsingMe.Count(m1 => !m1.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch())) > 0
- select f
-
-from member in types.Cast().Concat(methods).Concat(fields)
-select new {
- member,
- Debt = 4.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// The attribute **NDepend.Attributes.IsNotDeadCodeAttribute**
-// is defined in *NDepend.API.dll*. This attribute is used
-// to mean that a code element is not used directly, but is used
-// somehow, like through reflection.
-//
-// This attribute is used in the dead code rules,
-// *Potentially dead Types*, *Potentially dead Methods*
-// and *Potentially dead Fields*.
-// If you don't want to link *NDepend.API.dll*, you can use
-// your own *IsNotDeadCodeAttribute* and adapt the source code of
-// this rule, and the source code of the *dead code* rules.
-//
-// In this context, this code rule matches code elements
-// (types, methods, fields) that are tagged with this attribute,
-// but still used directly somewhere in the code.
-//
-
-//
-// Just remove *IsNotDeadCodeAttribute* tagging of
-// types, methods and fields matched by this rule
-// because this tag is not useful anymore.
-//]]>
-
-
- Don't use CoSetProxyBlanket and CoInitializeSecurity
-// ND3100:DontUseCoSetProxyBlanketAndCoInitializeSecurity
-warnif count > 0
-
-from m in Application.Methods
-where (m.HasAttribute ("System.Runtime.InteropServices.DllImportAttribute".AllowNoMatch()))
- && m.SimpleName.EqualsAny("CoSetProxyBlanket","CoInitializeSecurity")
-
-select new {
- m,
- Debt = 1.ToHours().ToDebt(),
- AnnualInterest = 2.ToHours().ToAnnualInterest()
-}
-
-//
-// As soon as some managed code starts being JIT’ed and executed by the CLR,
-// it is too late to call *CoInitializeSecurity()* or *CoSetProxyBlanket()*.
-// By this point in time, the CLR has already initialized the
-// COM security environment for the entire Windows process.
-//
-
-//
-// Don't call CoSetProxyBlanket() or CoInitializeSecurity() from managed code.
-//
-// Instead write an unmanaged "shim" in C++ that will call
-// one or both methods before loading the CLR within the process.
-//
-// More information about writing such unmanaged "shim"
-// can be found in this StackOverflow answer:
-// https://stackoverflow.com/a/48545055/27194
-//]]>
- Don't use System.Random for security purposes
-// ND3101:DontUseSystemRandomForSecurityPurposes
-warnif count > 0
-
-from m in Application.Methods
-where m.CreateA("System.Random".AllowNoMatch())
-select new {
- m,
- Debt = 15.ToMinutes().ToDebt(),
- AnnualInterest = 1.ToHours().ToAnnualInterest()
-}
-
-//
-// The algorithm used by the implementation of **System.Random** is weak
-// because random numbers generated can be predicted.
-//
-// Using predictable random values in a security critical context
-// can lead to vulnerabilities.
-//
-
-//
-// If the matched method is meant to be executed in a security
-// critical context use **System.Security.Cryptography.RandomNumberGenerator**
-// or **System.Security.Cryptography.RNGCryptoServiceProvider** instead.
-// These random implementations are slower to execute but the random numbers
-// generated cannot be predicted.
-//
-// Find more on using *RNGCryptoServiceProvider* to generate random values here:
-// https://stackoverflow.com/questions/32932679/using-rngcryptoserviceprovider-to-generate-random-string
-//
-// Otherwise you can use the faster **System.Random** implementation and
-// suppress corresponding issues.
-//
-// More information about the weakness of *System.Random* implementation
-// can be found here: https://stackoverflow.com/a/6842191/27194
-//]]>
- Don't use DES/3DES weak cipher algorithms
-// ND3102:DontUseDES3DESWeakCipherAlgorithms
-warnif count > 0
-
-from m in Application.Methods
-where
- m.CreateA("System.Security.Cryptography.TripleDESCryptoServiceProvider".AllowNoMatch()) ||
- m.CreateA("System.Security.Cryptography.DESCryptoServiceProvider".AllowNoMatch()) ||
- m.IsUsing("System.Security.Cryptography.DES.Create()".AllowNoMatch()) ||
- m.IsUsing("System.Security.Cryptography.DES.Create(String)".AllowNoMatch())
-select new {
- m,
- Debt = 1.ToHours().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// Since 2005 the NIST, the US National Institute of Standards and Technology,
-// doesn't consider DES and 3DES cypher algorithms as secure. Source:
-// https://www.nist.gov/news-events/news/2005/06/nist-withdraws-outdated-data-encryption-standard
-//
-
-//
-// Use the AES (Advanced Encryption Standard) algorithms instead
-// with the .NET Framework implementation:
-// *System.Security.Cryptography.AesCryptoServiceProvider*.
-//
-// You can still suppress issues of this rule when using
-// DES/3DES algorithms for compatibility reasons with legacy applications and data.
-//]]>
- Don't disable certificate validation
-// ND3103:DontDisableCertificateValidation
-warnif count > 0
-
-from m in Application.Methods
-where
- m.IsUsing("System.Net.ServicePointManager.set_ServerCertificateValidationCallback(RemoteCertificateValidationCallback)".AllowNoMatch())
-select new {
- m,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// Matched methods are subscribing a custom certificate validation
-// procedure through the delegate: *ServicePointManager.ServerCertificateValidationCallback*.
-//
-// Doing so is often used to disable certificate validation
-// to connect easily to a host that is not signed by a **root certificate authority**.
-// https://en.wikipedia.org/wiki/Root_certificate
-//
-// This creates a **vulnerability to man-in-the-middle attacks** since the client will trust any certificate.
-// https://en.wikipedia.org/wiki/Man-in-the-middle_attack
-//
-
-//
-// Don't rely on a weak custom certificate validation.
-//
-// If a legitimate custom certificate validation procedure must be subscribed,
-// you can chose to suppress related issue(s).
-//]]>
- Review publicly visible event handlers
-// ND3104:ReviewPubliclyVisibleEventHandlers
-warnif count > 0
-from m in Application.Methods
-where
- m.IsPubliclyVisible
- && m.Name.EndsWith("(Object,EventArgs)")
-select new {
- m,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-
-//
-// Review publicly visible event handlers to check those that are
-// running security critical actions.
-//
-// An event handler is any method with the standard signature *(Object,EventArgs)*.
-// An event handler can be registered to any event matching this standard signature.
-//
-// As a consequence, such event handler can be subscribed
-// by malicious code to an event to provoke execution of the
-// security critical action on event firing.
-//
-// Even if such event handler does a security check,
-// it can be executed from a chain of trusted callers on the call stack,
-// and cannot detect about malicious registration.
-//
-
-//
-// Change matched event handlers to make them non-public.
-// Preferably don't run a security critical action from an event handler.
-//
-// If after a careful check no security critical action is involved
-// from a matched event-handler, you can suppress the issue.
-//]]>
- Pointers should not be publicly visible
-// ND3105:PointersShouldNotBePubliclyVisible
-
-warnif count > 0
-from f in Application.Fields
-where
- f.FieldType != null &&
- f.FieldType.FullName.EqualsAny("System.IntPtr","System.UIntPtr") &&
- (f.IsPubliclyVisible || f.IsProtected)
-let methodsUserOutsideMyAssembly = f.MethodsUsingMe.Where(m => m.ParentAssembly != m.ParentAssembly)
-select new {
- f,
- f.FieldType,
- methodsUserOutsideMyAssembly,
- Debt = (15 + 10*methodsUserOutsideMyAssembly.Count()).ToMinutes().ToDebt(),
- Severity = f.IsInitOnly ? Severity.Medium : Severity.High
-}
-
-//
-// Pointers should not be exposed publicly.
-//
-// This rule detects fields with type *System.IntPtr* or *System.UIntPtr*
-// that are public or protected.
-//
-// Pointers are used to access unmanaged memory from managed code.
-// Exposing a pointer publicly makes it easy for malicious code
-// to read and write unmanaged data used by the application.
-//
-// The situation is even worse if the field is not read-only
-// since malicious code can change it and force the application
-// to rely on arbitrary data.
-//
-
-//
-// Pointers should have the visibility - private or internal.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is 15 minutes and 10 additional minutes per method using the field outside its assembly.
-//
-// The estimated Severity of such issue is *Medium*, and *High*
-// if the field is non read-only.
-//]]>
- Seal methods that satisfy non-public interfaces
-// ND3106:SealMethodsThatSatisfyNonPublicInterfaces
-
-warnif count > 0
-from m in Application.Methods
-where
- !m.IsFinal && // If the method is not marked as virtual the flag final is set
- m.IsPubliclyVisible &&
- !m.ParentType.IsSealed &&
- m.ParentType.IsClass
-let overridenInterface =
- m.OverriddensBase.FirstOrDefault(mb => mb.ParentType.IsInterface && !mb.ParentType.IsPubliclyVisible)
-where overridenInterface != null
-select new {
- m,
- overridenInterface = overridenInterface.ParentType,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
- }
-
-//
-// A match of this rule represents a virtual method, publicly visible,
-// defined in a non-sealed public class, that overrides a method of an
-// internal interface.
-//
-// The interface not being public indicates a process that
-// should remain private.
-//
-// Hence this situation represents a security vulnerability because
-// it is now possible to create a malicious class, that derives from
-// the parent class and that overrides the method behavior.
-// This malicious behavior will be then invoked by private implementation.
-//
-
-//
-// You can:
-//
-// - seal the parent class,
-//
-// - or change the accessibility of the parent class to non-public,
-//
-// - or implement the method without using the *virtual* modifier,
-//
-// - or change the accessibility of the method to non-public.
-//
-// If after a careful check such situation doesn't represent
-// a security threat, you can suppress the issue.
-//]]>
- Review commands vulnerable to SQL injection
-// ND3107:ReviewCommandsVulnerableToSQLInjection
-
-warnif count > 0
-
-let commands = ThirdParty.Types.WithFullNameIn(
- "System.Data.Common.DbCommand",
- "System.Data.SqlClient.SqlCommand",
- "System.Data.OleDb.OleDbCommand",
- "System.Data.Odbc.OdbcCommand",
- "System.Data.OracleClient.OracleCommand")
-where commands.Any()
-let commandCtors = commands.ChildMethods().Where(m => m.IsConstructor).ToHashSetEx()
-let commandExecutes = commands.ChildMethods().Where(m => m.SimpleName.Contains("Execute")).ToHashSetEx()
-let commandParameters = commands.ChildMethods().Where(m => m.IsPropertyGetter && m.SimpleName == "get_Parameters").ToHashSetEx()
-
-
-from m in Application.Methods.UsingAny(commandCtors)
- .UsingAny(commandExecutes)
-where !m.MethodsCalled.Intersect(commandParameters).Any() &&
- // Check also that non of the method call rely on command parameters to get less false positives:
- !m.MethodsCalled.SelectMany(mc => mc.MethodsCalled).Intersect(commandParameters).Any()
-
-select new { m,
- createA = m.MethodsCalled.Intersect(commandCtors).First().ParentType,
- calls = m.MethodsCalled.Intersect(commandExecutes).First(),
- Debt = 15.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule matches methods that create a DB command
-// (like an *SqlCommand* or an *OleDbCommand*)
-// that call an *Execute* command method (like *ExecuteScalar()*)
-// and that don't use command parameters.
-//
-// This situation is prone to **SQL Injection** https://en.wikipedia.org/wiki/SQL_injection
-// since malicious SQL code might be injected in string parameters values.
-//
-// However there might be false positives.
-// So review carefully matched methods
-// and use suppress issues when needed.
-//
-// To limit the false positives, this rule also checks whether
-// command parameters are accessed from any sub method call.
-// This is a solid indication of non-vulnerability.
-//
-
-//
-// If after a careful check it appears that the method is indeed
-// using some strings to inject parameters values in the SQL query string,
-// **command.Parameters.Add(...)** must be used instead.
-//
-// You can get more information on adding parameters explicitely here:
-// https://stackoverflow.com/questions/4892166/how-does-sqlparameter-prevent-sql-injection
-// ]]>
- Review data adapters vulnerable to SQL injection
-// ND3108:ReviewDataAdaptersVulnerableToSQLInjection
-
-warnif count > 0
-
-let adapters = ThirdParty.Types.WithFullNameIn(
- "System.Data.Common.DataAdapter",
- "System.Data.Common.DbDataAdapter",
- "System.Data.SqlClient.SqlDataAdapter",
- "System.Data.OleDb.OleDbDataAdapter",
- "System.Data.Odbc.OdbcDataAdapter",
- "System.Data.OracleClient.OracleDataAdapter")
-
-where adapters.Any()
-let adapterCtors = adapters.ChildMethods().Where(m => m.IsConstructor).ToHashSetEx()
-let adapterFill = adapters.ChildMethods().Where(m => m.SimpleName.Contains("Fill")).ToHashSetEx()
-
-
-let commands = ThirdParty.Types.WithFullNameIn(
- "System.Data.Common.DbCommand",
- "System.Data.SqlClient.SqlCommand",
- "System.Data.OleDb.OleDbCommand",
- "System.Data.Odbc.OdbcCommand",
- "System.Data.OracleClient.OracleCommand")
-where commands.Any()
-let commandParameters = commands.ChildMethods().Where(m => m.IsPropertyGetter && m.SimpleName == "get_Parameters").ToHashSetEx()
-
-
-from m in Application.Methods.UsingAny(adapterCtors)
- .UsingAny(adapterFill)
-where !m.MethodsCalled.Intersect(commandParameters).Any() &&
- // Check also that non of the method call rely on command parameters to get less false positives:
- !m.MethodsCalled.SelectMany(mc => mc.MethodsCalled).Intersect(commandParameters).Any()
-
-select new { m,
- createA = m.MethodsCalled.Intersect(adapterCtors).First().ParentType,
- calls = m.MethodsCalled.Intersect(adapterFill).First(),
- Debt = 15.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule matches methods that create a DB adapter
-// (like an *SqlDataAdapter* or an *OleDbDataAdapter*)
-// that call the method *Fill()*
-// and that don't use DB command parameters.
-//
-// This situation is prone to **SQL Injection** https://en.wikipedia.org/wiki/SQL_injection
-// since malicious SQL code might be injected in string parameters values.
-//
-// However there might be false positives.
-// So review carefully matched methods
-// and use suppress issues when needed.
-//
-// To limit the false positives, this rule also checks whether
-// command parameters are accessed from any sub method call.
-// This is a solid indication of non-vulnerability.
-//
-
-//
-// If after a careful check it appears that the method is indeed
-// using some strings to inject parameters values in the SQL query string,
-// **adapter.SelectCommand.Parameters.Add(...)** must be used instead
-// (or *adapter.UpdateCommand* or *adapter.InsertCommand*, depending on the context).
-//
-// You can get more information on adding parameters explicitely here:
-// https://stackoverflow.com/questions/4892166/how-does-sqlparameter-prevent-sql-injection
-// ]]>
-
-
- Methods that could have a lower visibility
-// ND1800:MethodsThatCouldHaveALowerVisibility
-
-warnif count > 0 from m in JustMyCode.Methods where
- m.Visibility != m.OptimalVisibility &&
-
- !m.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
- !m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- !m.HasAttribute("JetBrains.Annotations.UsedImplicitlyAttribute".AllowNoMatch()) &&
- // If you don't want to link NDepend.API.dll, you can use your own attributes
- // and adapt the source code of this rule.
-
- // methods of serialized type must remain public.
- !m.ParentType.TypesUsed.Any(t1 => t1.IsAttributeClass && t1.ParentNamespace.Name == "Newtonsoft.Json") &&
- !m.ParentType.HasAttribute("System.Runtime.Serialization.DataContractAttribute".AllowNoMatch()) &&
- !m.ParentType.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch()) &&
-
- // Eliminate public methods visible outside of their assembly
- // because the rule cannot know if the developer left the method public
- // intentionally or not.
- !m.IsPubliclyVisible &&
-
- // Avoid matching public methods declared in a non-public type,
- // that could have the visibility internal, because
- // such situation is caught by the rule 'Avoid public methods not publicly visible'.
- !(m.Visibility == Visibility.Public &&
- m.ParentType.Visibility != Visibility.Public &&
- m.OptimalVisibility == Visibility.Internal) &&
-
- // Eliminate default constructor from the result.
- // Whatever the visibility of the declaring class,
- // default constructors are public and introduce noise
- // in the current rule.
- !( m.IsConstructor && m.IsPublic && m.NbParameters == 0) &&
-
- // Don't advise to reduce visibility of property getters/setters
- // of classes that implement INotifyPropertyChanged
- !((m.IsPropertyGetter || m.IsPropertySetter) &&
- m.ParentType.Implement("System.ComponentModel.INotifyPropertyChanged".AllowNoMatch())) &&
-
- // Don't decrease the visibility of Main() methods.
- !m.IsEntryPoint
-
-select new {
- m,
- m.Visibility ,
- CouldBeDeclared = m.OptimalVisibility,
- m.MethodsCallingMe,
-
- Debt = 30.ToSeconds().ToDebt(), // It is fast to change the method visibility
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about methods that can be declared with a lower visibility
-// without provoking any compilation error.
-// For example *private* is a visibility lower than *internal*
-// which is lower than *public*.
-//
-// **Narrowing visibility** is a good practice because doing so **promotes encapsulation**.
-// The scope from which methods can be called is then reduced to a minimum.
-//
-// By default, this rule doesn't match publicly visible methods that could have a
-// lower visibility because it cannot know if the developer left the method public
-// intentionally or not. Public methods matched are declared in non-public types.
-//
-// By default this rule doesn't match methods with the visibility *public*
-// that could be *internal*, declared in a type that is not *public*
-// (internal, or nested private for example) because
-// this situation is caught by the rule *Avoid public methods not publicly visible*.
-//
-// Notice that methods tagged with one of the attribute
-// *NDepend.Attributes.CannotDecreaseVisibilityAttribute* or
-// *NDepend.Attributes.IsNotDeadCodeAttribute*, found in *NDepend.API.dll*
-// are not matched. If you don't want to link *NDepend.API.dll* but still
-// wish to rely on this facility, you can declare these attributes in your code.
-//
-
-//
-// Declare each matched method with the specified *optimal visibility*
-// in the *CouldBeDeclared* rule result column.
-//
-// By default, this rule matches *public methods*. If you are publishing an API
-// many public methods matched should remain public. In such situation,
-// you can opt for the *coarse solution* to this problem by adding in the
-// rule source code *&& !m.IsPubliclyVisible* or you can prefer the
-// *finer solution* by tagging each concerned method with
-// *CannotDecreaseVisibilityAttribute*.
-//]]>
- Types that could have a lower visibility
-// ND1801:TypesThatCouldHaveALowerVisibility
-
-warnif count > 0 from t in JustMyCode.Types where
-
- t.Visibility != t.OptimalVisibility &&
-
- // If you don't want to link NDepend.API.dll, you can use your own attributes
- // and adapt the source code of this rule.
- !t.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
- !t.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- !t.HasAttribute("JetBrains.Annotations.UsedImplicitlyAttribute".AllowNoMatch()) &&
-
- // JSON and XML serialized type must remain public.
- !t.IsUsing("Newtonsoft.Json".MatchNamespace().AllowNoMatch()) &&
- !t.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch()) &&
-
- // Eliminate public types visible outside of their assembly
- // because the rule cannot know if the developer left the type public
- // intentionally or not.
- !t.IsPubliclyVisible &&
-
- // Static types that define only const fields cannot be seen as used in IL code.
- // They don't have to be tagged with CannotDecreaseVisibilityAttribute.
- !( t.IsStatic &&
- !t.Methods.Any(m => !m.IsClassConstructor) &&
- !t.Fields.Any(f => !f.IsLiteral && !(f.IsStatic && f.IsInitOnly))) &&
-
- // A type used by an interface that has the same visibility
- // cannot have its visibility decreased, else a compilation error occurs!
- !t.TypesUsingMe.Any(tUser =>
- tUser.IsInterface &&
- tUser.Visibility == t.Visibility) &&
-
- // Don't change the visibility of a type that contain an entry point method.
- !t.Methods.Any(m =>m.IsEntryPoint)
-
-select new {
- t,
- t.Visibility ,
- CouldBeDeclared = t.OptimalVisibility,
- t.TypesUsingMe,
-
- Debt = 30.ToSeconds().ToDebt(), // It is fast to change the method visibility
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about types that can be declared with a lower visibility
-// without provoking any compilation error.
-// For example *private* is a visibility lower than *internal*
-// which is lower than *public*.
-//
-// **Narrowing visibility** is a good practice because doing so **promotes encapsulation**.
-// The scope from which types can be consumed is then reduced to a minimum.
-//
-// By default, this rule doesn't match publicly visible types that could have
-// a lower visibility because it cannot know if the developer left the type public
-// intentionally or not. Public types matched are nested in non-public types.
-//
-// Notice that types tagged with one of the attribute
-// *NDepend.Attributes.CannotDecreaseVisibilityAttribute* or
-// *NDepend.Attributes.IsNotDeadCodeAttribute*, found in *NDepend.API.dll*
-// are not matched. If you don't want to link *NDepend.API.dll* but still
-// wish to rely on this facility, you can declare these attributes in your code.
-//
-
-//
-// Declare each matched type with the specified *optimal visibility*
-// in the *CouldBeDeclared* rule result column.
-//
-// By default, this rule matches *public types*. If you are publishing an API
-// many public types matched should remain public. In such situation,
-// you can opt for the *coarse solution* to this problem by adding in the
-// rule source code *&& !m.IsPubliclyVisible* or you can prefer the
-// *finer solution* by tagging each concerned type with
-// *CannotDecreaseVisibilityAttribute*.
-//]]>
- Fields that could have a lower visibility
-// ND1802:FieldsThatCouldHaveALowerVisibility
-
-warnif count > 0 from f in JustMyCode.Fields where
- f.Visibility != f.OptimalVisibility &&
- !f.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
- !f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
- !f.HasAttribute("JetBrains.Annotations.UsedImplicitlyAttribute".AllowNoMatch()) &&
- // If you don't want to link NDepend.API.dll, you can use your own attributes
- // and adapt the source code of this rule.
-
- // JSON and XML serialized fields must remain public.
- !f.ParentType.TypesUsed.Any(t1 => t1.IsAttributeClass && t1.ParentNamespace.Name == "Newtonsoft.Json") &&
- !f.HasAttribute("System.Xml.Serialization.XmlElementAttribute".AllowNoMatch()) &&
- !f.HasAttribute("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()) &&
- !f.HasAttribute("System.Xml.Serialization.XmlArrayAttribute".AllowNoMatch()) &&
- !f.HasAttribute("System.Xml.Serialization.XmlArrayItemAttribute".AllowNoMatch()) &&
-
- // Don't check for serialized fields visibility
- !f.HasAttribute("System.Runtime.Serialization.DataMemberAttribute".AllowNoMatch()) &&
-
- // Eliminate public fields visible outside of their assembly
- // because the rule cannot know if the developer left the field public
- // intentionally or not.
- !f.IsPubliclyVisible
-
-select new {
- f,
- f.Visibility ,
- CouldBeDeclared = f.OptimalVisibility,
- f.MethodsUsingMe,
-
- Debt = 30.ToSeconds().ToDebt(), // It is fast to change the field visibility
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about fields that can be declared with a lower visibility
-// without provoking any compilation error.
-// For example *private* is a visibility lower than *internal*
-// which is lower than *public*.
-//
-// **Narrowing visibility** is a good practice because doing so **promotes encapsulation**.
-// The scope from which fields can be consumed is then reduced to a minimum.
-//
-// By default, this rule doesn't match publicly visible fields that could have a
-// lower visibility because it cannot know if the developer left the field public
-// intentionally or not. Public fields matched are declared in non-public types.
-//
-// Notice that fields tagged with one of the attribute
-// *NDepend.Attributes.CannotDecreaseVisibilityAttribute* or
-// *NDepend.Attributes.IsNotDeadCodeAttribute*, found in *NDepend.API.dll*
-// are not matched. If you don't want to link *NDepend.API.dll* but still
-// wish to rely on this facility, you can declare these attributes in your code.
-//
-
-//
-// Declare each matched field with the specified *optimal visibility*
-// in the *CouldBeDeclared* rule result column.
-//
-// By default, this rule matches *public fields*. If you are publishing an API
-// some public fields matched should remain public. In such situation,
-// you can opt for the *coarse solution* to this problem by adding in the
-// rule source code *&& !m.IsPubliclyVisible* or you can prefer the
-// *finer solution* by tagging eah concerned field with
-// *CannotDecreaseVisibilityAttribute*.
-//]]>
- Types that could be declared as private, nested in a parent type
-// ND1803:TypesThatCouldBeDeclaredAsPrivateNestedInAParentType
-
-warnif count > 0
-from t in JustMyCode.Types
-where !t.IsGeneratedByCompiler &&
- !t.IsNested &&
- !t.IsPubliclyVisible &&
- !t.IsEnumeration &&
- // Only one type user…
- t.TypesUsingMe.Count() == 1
-
-let couldBeNestedIn = t.TypesUsingMe.Single()
-where !couldBeNestedIn.IsGeneratedByCompiler &&
- !couldBeNestedIn.IsInterface && // Cannot nest a type in an interface
- // …declared in the same namespace
- couldBeNestedIn.ParentNamespace == t.ParentNamespace &&
-
- // Don't advise to move a base class
- // or an interface into one of its child type.
- !couldBeNestedIn.DeriveFrom(t) &&
- !couldBeNestedIn.Implement(t)
-
- // Require that t doesn't contain any extension method.
- // Types with extension methods cannot be nested.
-where t.Methods.All(m => !m.IsExtensionMethod)
-
-select new {
- t,
- couldBeNestedIn,
- Debt = 3.ToMinutes().ToDebt(), // It is fast to nest a type into another one
- Severity = Severity.Low // This rule proposes advices, not potential problems
-}
-
-//
-// This rule matches types that can be potentially
-// *nested* and declared *private* into another type.
-//
-// The conditions for a type to be potentially nested
-// into a *parent type* are:
-//
-// • the *parent type* is the only type consuming it,
-//
-// • the type and the *parent type* are declared in the same namespace.
-//
-// Declaring a type as private into a parent type **promotes encapsulation**.
-// The scope from which the type can be consumed is then reduced to a minimum.
-//
-// This rule doesn't match classes with extension methods
-// because such class cannot be nested in another type.
-//
-
-//
-// Nest each matched *type* into the specified *parent type* and
-// declare it as private.
-//
-// However *nested private types* are hardly testable. Hence this rule
-// might not be applied to types consumed directly by tests.
-//]]>
- Avoid publicly visible constant fields
-// ND1804:AvoidPubliclyVisibleConstantFields
-
-warnif count > 0
-from f in JustMyCode.Fields
-where f.IsLiteral &&
- f.IsPubliclyVisible &&
- !f.IsEnumValue
-select new {
- f,
-
- Debt = 30.ToSeconds().ToDebt(), // It is fast to update field declaration
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about constant fields that are visible outside their
-// parent assembly. Such field, when used from outside its parent assembly,
-// has its constant value *hard-coded* into the client assembly.
-// Hence, when changing the field's value, it is *mandatory* to recompile
-// all assemblies that consume the field, else the program will run
-// with different constant values in-memory. Certainly in such situation
-// bugs are lurking.
-//
-
-//
-// Declare matched fields as **static readonly** instead of **constant**.
-// This way, the field value is *safely changeable* without the need to
-// recompile client assemblies.
-//
-// Notice that enumeration value fields suffer from the same *potential
-// pitfall*. But enumeration values cannot be declared as
-// *static readonly* hence the rule comes with the condition
-// **&& !f.IsEnumValue** to avoid matching these. Unless you decide
-// to banish public enumerations, just let the rule *as is*.
-//]]>
- Fields should be declared as private
-// ND1805:FieldsShouldBeDeclaredAsPrivate
-
-warnif count > 0 from f in JustMyCode.Fields where
- !f.IsPrivate &&
-
- // These conditions filter cases where fields
- // doesn't represent state that should be encapsulated.
- !f.IsGeneratedByCompiler &&
- !f.IsSpecialName &&
- !f.IsInitOnly &&
- !f.IsLiteral &&
- !f.IsEnumValue &&
- !f.HasAttribute("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()) &&
- !f.HasAttribute("System.Runtime.Serialization.DataMemberAttribute".AllowNoMatch())
-
-// A non-private field assigned from outside its class,
-// usually leads to complicated field state management.
-let outsideMethodsAssigningMe =
- f.MethodsAssigningMe.Where(m => m.ParentType != f.ParentType)
-
-select new {
- f,
- f.Visibility,
- outsideMethodsAssigningMe,
-
- Debt = (60+20*outsideMethodsAssigningMe.Count()).ToSeconds().ToDebt(),
- // The cost to leave such issue unfixed is higher if the field is publicly visible!
- AnnualInterest = Severity.Medium.AnnualInterestThreshold() * (f.IsPubliclyVisible ? 3 : 1)
-}
-
-//
-// This rule matches **non-private and mutable fields**.
-// *Mutable* means that the field value can be modified.
-// Typically mutable fields are *non-constant*,
-// *non-readonly* fields.
-//
-// Fields should be considered as **implementation details**
-// and as a consequence they should be declared as private.
-//
-// If something goes wrong with a *non-private field*,
-// the culprit can be anywhere, and so in order to track down
-// the bug, you may have to look at quite a lot of code.
-//
-// A private field, by contrast, can only be assigned from
-// inside the same class, so if something goes wrong with that,
-// there is usually only one source file to look at.
-//
-// Issues of this rule are fast to get fixed, and they have
-// a debt proportional to the number of methods assigning
-// the field.
-//
-
-//
-// Declare a matched mutable field as *private*, or declare it
-// as *readonly*.
-//
-// If code outside the type needs to access the field
-// you can encapsulate the field accesses in a read-write property.
-// At least with a read-write property you can set a debug breakpoint
-// on the property setter, which makes easier to track write-accesses
-// in case of problem.
-//
-]]>
- Constructors of abstract classes should be declared as protected or private
-// ND1806:ConstructorsOfAbstractClassesShouldBeDeclaredAsProtectedOrPrivate
-
-warnif count > 0
-from t in Application.Types where
- t.IsClass &&
- t.IsAbstract
-let ctors = t.Constructors.Where(c => !c.IsProtected && !c.IsPrivate)
-where ctors.Count() > 0
-select new {
- t,
- ctors,
-
- Debt = 30.ToSeconds().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Constructors of abstract classes can only be called from derived
-// classes.
-//
-// Because a public constructor is creating instances of its class,
-// and because it is forbidden to create instances of an *abstract* class,
-// an abstract class with a public constructor is wrong design.
-//
-// Notice that when the constructor of an abstract class is private,
-// it means that derived classes must be nested in the abstract class.
-//
-
-//
-// To fix a violation of this rule,
-// either declare the constructor as *protected*,
-// or do not declare the type as *abstract*.
-//]]>
- Avoid public methods not publicly visible
-// ND1807:AvoidPublicMethodsNotPubliclyVisible
-
-warnif count > 0
-from m in JustMyCode.Methods where
- !m.IsPubliclyVisible && m.IsPublic &&
-
- // Eliminate virtual methods
- !m.IsVirtual &&
- // Eliminate interface and delegate types
- !m.ParentType.IsInterface &&
- !m.ParentType.IsDelegate &&
- // Eliminate default constructors
- !(m.IsConstructor && m.NbParameters == 0) &&
- // Eliminate operators that must be declared public
- !m.IsOperator &&
- // Eliminate methods generated by compiler, except auto-property getter/setter
- (!m.IsGeneratedByCompiler || m.IsPropertyGetter || m.IsPropertySetter) &&
-
- // Don't advise to reduce visibility of property getters/setters
- // of classes that implement INotifyPropertyChanged
- !((m.IsPropertyGetter || m.IsPropertySetter) &&
- m.ParentType.Implement("System.ComponentModel.INotifyPropertyChanged".AllowNoMatch()))
-
-let calledOutsideParentType =
- m.MethodsCallingMe.FirstOrDefault(mCaller => mCaller.ParentType != m.ParentType) != null
-
-select new {
- m,
- parentTypeVisibility = m.ParentType.Visibility,
- declareMethodAs = (Visibility) (calledOutsideParentType ? Visibility.Internal : Visibility.Private),
- methodsCaller = m.MethodsCallingMe,
-
- Debt = 30.ToSeconds().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule warns about methods declared as *public*
-// whose parent type is not declared as *public*.
-//
-// In such situation *public* means, *can be accessed
-// from anywhere my parent type is visible*. Some
-// developers think this is an elegant language construct,
-// some others find it misleading.
-//
-// This rule can be deactivated if you don't agree with it.
-// Read the whole debate here:
-// http://ericlippert.com/2014/09/15/internal-or-public/
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//
-
-//
-// Declare the method as *internal* if it is used outside of
-// its type, else declare it as *private*.
-//]]>
- Event handler methods should be declared as private or protected
-// ND1808:EventHandlerMethodsShouldBeDeclaredAsPrivateOrProtected
-
-warnif count > 0
-from m in Application.Methods where
- !(m.IsPrivate || m.IsProtected) &&
- !m.IsGeneratedByCompiler &&
-
- // A method is considered as an event handler if…
- m.NbParameters == 2 && // … it has two parameters …
- m.Name.Contains("Object") && // … of types Object …
- m.Name.Contains("EventArgs") && // … and EventArgs
-
- // Discard special cases
- !m.ParentType.IsDelegate &&
- !m.IsGeneratedByCompiler
-
-select new {
- m,
- m.Visibility,
- Debt = 2.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Think of a event handler like for example *OnClickButton()*.
-// Typically such method must be declared as *private*
-// and shouldn't be called in other context than event firing.
-//
-// Such method can also be declared as *protected* because
-// some designers such as the ASP.NET designer, generates such method
-// as *protected* to let a chance to sub-classes to call it.
-//
-
-//
-// If you have the need that event handler method should be called
-// from another class, then find a code structure that more
-// closely matches the concept of what you're trying to do.
-// Certainly you don't want the other class to click a button; you
-// want the other class to do something that clicking a button
-// also do.
-//]]>
- Wrong usage of CannotDecreaseVisibilityAttribute
-// ND1809:WrongUsageOfCannotDecreaseVisibilityAttribute
-
-warnif count > 0
-
-let tAttr = Types.WithFullName("NDepend.Attributes.CannotDecreaseVisibilityAttribute").FirstOrDefault()
-where tAttr != null
-
-// Get types that do a wrong usage of CannotDecreaseVisibilityAttribute
-let types = from t in Application.Types where
- t.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
- ( t.Visibility == t.OptimalVisibility ||
-
- // Static types that define only const fields cannot be seen as used in IL code.
- // They don't need to be tagged with CannotDecreaseVisibilityAttribute.
- (t.IsStatic && t.NbMethods == 0 && !t.Fields.Any(f => !f.IsLiteral))
- )
- select t
-
-// Get methods that do a wrong usage of CannotDecreaseVisibilityAttribute
-let methods = from m in Application.Methods where
- m.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
- m.Visibility == m.OptimalVisibility
- select m
-
-// Get fields that do a wrong usage of CannotDecreaseVisibilityAttribute
-let fields = from f in Application.Fields where
- f.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
- f.Visibility == f.OptimalVisibility
- select f
-
-from member in types.Cast().Concat(methods).Concat(fields)
-select new {
- member,
- Debt = 30.ToSeconds().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// The attribute **NDepend.Attributes.CannotDecreaseVisibilityAttribute**
-// is defined in *NDepend.API.dll*. If you don't want to reference
-// *NDepend.API.dll* you can declare it in your code.
-//
-// Usage of this attribute means that a code element visibility is not
-// optimal (it can be lowered like for example from *public* to *internal*)
-// but shouldn’t be modified anyway. Typical reasons to do so include:
-//
-// • Public code elements consumed through reflection, through a mocking
-// framework, through XML or binary serialization, through designer,
-// COM interfaces…
-//
-// • Non-private code element invoked by test code, that would be difficult
-// to reach from test if it was declared as *private*.
-//
-// In such situation *CannotDecreaseVisibilityAttribute* is used to avoid
-// that default rules about not-optimal visibility warn. Using this
-// attribute can be seen as an extra burden, but it can also be seen as
-// an opportunity to express in code: **Don't change the visibility else
-// something will be broken**
-//
-// In this context, this code rule matches code elements
-// (types, methods, fields) that are tagged with this attribute,
-// but still already have an optimal visibility.
-//
-
-//
-// Just remove *CannotDecreaseVisibilityAttribute* tagging of
-// types, methods and fields matched by this rule
-// because this tag is not useful anymore.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Methods that should be declared as 'public' in C#, 'Public' in VB.NET
-
-from m in Application.Methods where
- m.ShouldBePublic
-let usedInAssemblies = m.MethodsCallingMe.ParentAssemblies().Except(m.ParentAssembly)
-select new {
- m,
- m.ParentAssembly,
- usedInAssemblies,
- m.MethodsCallingMe
-}
-
-//
-// This code query lists methods that *should* be declared
-// as *public*. Such method is actually declared as *internal*
-// and is consumed from outside its parent assembly
-// thanks to the attribute
-// *System.Runtime.CompilerServices.InternalsVisibleToAttribute*.
-//
-// This query relies on the property
-// *NDepend.CodeModel.IMember.ShouldBePublic*
-// https://www.ndepend.com/api/webframe.html?NDepend.API~NDepend.CodeModel.IMember~ShouldBePublic.html
-//
-// This is just a code query, it is not intended to advise
-// you to declare the method as *public*, but to inform you
-// that the code actually relies on the peculiar behavior
-// of the attribute *InternalsVisibleToAttribute*.
-//]]>
-
-
- Fields should be marked as ReadOnly when possible
-// ND1900:FieldsShouldBeMarkedAsReadOnlyWhenPossible
-
-warnif count > 0
-from f in JustMyCode.Fields where
- f.IsImmutable &&
- !f.IsInitOnly && // The condition IsInitOnly matches fields that
- // are marked with the C# readonly keyword
- // (ReadOnly in VB.NET).
- !f.IsGeneratedByCompiler &&
- !f.IsEventDelegateObject &&
- !f.ParentType.IsEnumeration &&
- !f.IsLiteral &&
-
- // Don't warn if a method using the field is also calling a method that has 'ref' and 'out' parameters.
- // This could lead to false positive. A field used in a 'ref' or 'out' parameter cannot be set as read-only.
- f.MethodsUsingMe.SelectMany(m => m.MethodsCalled).FirstOrDefault(m => m.Name.Contains("&")) == null
-
-select new {
- f,
- f.MethodsReadingMeButNotAssigningMe,
- f.MethodsAssigningMe,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about instance and static fields that
-// can be declared as **readonly**.
-//
-// This source code of this rule is based on the conditon
-// *IField.IsImmutable*.
-// https://www.ndepend.com/api/webframe.html?NDepend.API~NDepend.CodeModel.IField~IsImmutable.html
-//
-// A field that matches the condition *IsImmutable*
-// is a field that is assigned only by constructors
-// of its class.
-//
-// For an *instance field*, this means its value
-// will remain constant through the lifetime
-// of the object.
-//
-// For a *static field*, this means its value will
-// remain constant through the lifetime of the
-// program.
-//
-
-//
-// Declare the field with the C# *readonly* keyword
-// (*ReadOnly* in VB.NET). This way the intention
-// that the field value shouldn't change is made
-// explicit.
-//]]>
- Avoid non-readonly static fields
-// ND1901:AvoidNonReadOnlyStaticFields
-
-warnif count > 0
-from f in Application.Fields
-where f.IsStatic &&
- !f.IsEnumValue &&
- !f.IsGeneratedByCompiler &&
- !f.IsLiteral &&
- !f.IsInitOnly
-
-let methodAssigningField = f.MethodsAssigningMe
-
-select new {
- f,
- methodAssigningField,
- Debt = (2+8*methodAssigningField.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns about static fields that are not
-// declared as read-only.
-//
-// In *Object-Oriented-Programming* the natural artifact
-// to hold states that can be modified is **instance fields**.
-// Such mutable static fields create *confusion* about
-// the expected state at runtime and impairs the code
-// testability since the same mutable state is re-used for
-// each test.
-//
-// More discussion on the topic can be found here:
-// http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members/
-//
-
-//
-// If the *static* field is just assigned once in the program
-// lifetime, make sure to declare it as *readonly* and assign
-// it inline, or from the static constructor.
-//
-// Else if methods other than the static constructor need to
-// assign the state hold by the static field, refactoring must
-// occur to ensure that this state is hold through an instance
-// field.
-//]]>
- Avoid static fields with a mutable field type
-// ND1902:AvoidStaticFieldsWithAMutableFieldType
-
-warnif count > 0
-from f in Application.Fields
-where f.IsStatic &&
- !f.IsEnumValue &&
- !f.IsGeneratedByCompiler &&
- !f.IsLiteral
-
-let fieldType = f.FieldType
-where fieldType != null &&
- !fieldType.IsThirdParty &&
- !fieldType.IsInterface &&
- !fieldType.IsImmutable
-
-select new {
- f,
- mutableFieldType = fieldType ,
- isFieldImmutable = f.IsImmutable ? "Immutable" : "Mutable",
- isFieldReadOnly = f.IsInitOnly ? "ReadOnly" : "Not ReadOnly",
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about static fields whose field type
-// is mutable. In such case the static field is
-// holding a state that can be modified.
-//
-// In *Object-Oriented-Programming* the natural artifact
-// to hold states that can be modified is **instance fields**.
-// Hence such static fields create *confusion* about
-// the expected state at runtime.
-//
-// More discussion on the topic can be found here:
-// http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members/
-//
-
-//
-// To fix violations of this rule, make sure to
-// hold mutable states through objects that are passed
-// **explicitly** everywhere they need to be consumed, in
-// opposition to mutable object hold by a static field that
-// makes it modifiable from a bit everywhere in the program.
-//]]>
- Structures should be immutable
-// ND1903:StructuresShouldBeImmutable
-
-warnif count > 0 from t in JustMyCode.Types where
- t.IsStructure &&
- !t.IsImmutable
-
-let mutableFields = t.Fields.Where(f => !f.IsImmutable)
-
-select new {
- t,
- t.NbLinesOfCode,
- mutableFields,
- Debt = (3+2*mutableFields.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// An object is immutable if its state doesn’t change once the
-// object has been created. Consequently, a structure or a class
-// is immutable if its instances fields are only assigned inline
-// or from constructor(s).
-//
-// But for structure it is a bit different. **Structures are value
-// types** which means instances of structures are copied when they are
-// passed around (like through a method argument).
-//
-// So if you change a copy you are changing only that copy, not the
-// original and not any other copies which might be around. Such
-// situation is very different than what happen with instances of
-// classes. Hence developers are not used to work with modified values
-// and doing so introduces *confusion* and is *error-prone*.
-//
-
-//
-// Make sure matched structures are immutable. This way, all
-// automatic copies of an original instance, resulting from being
-// *passed by value* will hold the same values and there will be
-// no surprises.
-//
-// If your structure is immutable then if you want to change
-// a value, you have to consciously do it by creating a new instance
-// of the structure with the modified data.
-//]]>
- Property Getters should be immutable
-// ND1904:PropertyGettersShouldBeImmutable
-
-warnif count > 0 from m in Application.Methods where
- !m.IsGeneratedByCompiler &&
- m.IsPropertyGetter &&
- ( ( !m.IsStatic && m.ChangesObjectState) ||
- ( m.IsStatic && m.ChangesTypeState) )
-
-let propertyName = m.SimpleName.Substring(4,m.SimpleName.Length-4)
-let setterSimpleName = "set_" + propertyName
-
-
-let fieldsAssigned = m.FieldsAssigned.Where(f =>
-
- // Don't count field that have a name similar to the property name
- // to avoid matching lazy initialization situations.
- !(propertyName.Length >= 4 &&
- f.SimpleName.Length >= 4 &&
- // Don't count the first 3 characters of the field name,
- // to avoid special field name formatting like 'm_X' or '_x'
- propertyName.EndsWith(f.SimpleName.Substring(3, f.SimpleName.Length -3)))
- &&
-
- // Don't count field that are assigned only by the property getter and the related property setter.
- f.MethodsAssigningMe.Any(m1 => m1 != m &&
- !(m1.IsPropertySetter && m1.SimpleName == setterSimpleName)))
-where fieldsAssigned.Any()
-let otherMethodsAssigningSameFields = fieldsAssigned.SelectMany(f => f.MethodsAssigningMe.Where(m1 => m1 != m))
-
-select new {
- m,
- m.NbLinesOfCode,
- fieldsAssigned,
- otherMethodsAssigningSameFields,
- Debt = (2 + 5*fieldsAssigned.Count() + 5*otherMethodsAssigningSameFields.Count() ).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// It is not expected that a state gets modified when
-// accessing a property getter. Hence doing so create
-// confusion and property getters should be pure methods,
-// they shouldn't assign any field.
-//
-// This rule doesn't match property getters that assign a field
-// not assigned by any other methods than the getter itself
-// and the corresponding property setter. Hence this rule avoids
-// matching *lazy initialization at first access* of a state.
-// In such situation the getter assigns a field at first access
-// and from the client point of view, lazy initialization
-// is an invisible implementation detail.
-//
-// A field assigned by a property with a name similar to the
-// property name are not count either, also to avoid matching
-// *lazy initialization at first access* situations.
-//
-
-//
-// Make sure that matched property getters don't assign any
-// field.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 2 minutes plus 5 minutes per field assigned and
-// 5 minutes per other method assigning such field.
-//]]>
- A field must not be assigned from outside its parent hierarchy types
-// ND1905:AFieldMustNotBeAssignedFromOutsideItsParentHierarchyTypes
-
-warnif count > 0
-from f in JustMyCode.Fields.Where(f =>
- (f.IsInternal || f.IsPublic) &&
- !f.IsGeneratedByCompiler &&
- !f.IsImmutable &&
- !f.IsEnumValue)
-
-let methodsAssignerOutsideOfMyType = f.MethodsAssigningMe.Where(
- m =>!m.IsGeneratedByCompiler &&
- m.ParentType != f.ParentType &&
- !m.ParentType.DeriveFrom(f.ParentType) )
-
-where methodsAssignerOutsideOfMyType.Any()
-
-select new {
- f,
- methodsAssignerOutsideOfMyType,
- Debt = (5*methodsAssignerOutsideOfMyType.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is related to the rule *Fields should be declared as
-// private*. It matches any **public or internal, mutable field**
-// that is assigned from outside its parent class and subclasses.
-//
-// Fields should be considered as **implementation details**
-// and as a consequence they should be declared as private.
-//
-// If something goes wrong with a *non-private field*,
-// the culprit can be anywhere, and so in order to track down
-// the bug, you may have to look at quite a lot of code.
-//
-// A private field, by contrast, can only be assigned from
-// inside the same class, so if something goes wrong with that,
-// there is usually only one source file to look at.
-//
-
-//
-// Matched fields must be declared as *protected* and even better
-// as *private*.
-//
-// Alternatively, if the field can reference immutable states,
-// it can remain visible from the outside, but then must be
-// declared as *readonly*.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 5 minutes per method outside the parent hierarchy
-// that assigns the matched field.
-//]]>
- Don't assign a field from many methods
-// ND1906:DontAssignAFieldFromManyMethods
-
-warnif count > 0
-from f in JustMyCode.Fields where
- !f.IsEnumValue &&
- !f.IsImmutable &&
- !f.IsInitOnly &&
- !f.IsGeneratedByCompiler &&
- !f.IsEventDelegateObject
-
-let methodsAssigningMe = f.MethodsAssigningMe.Where(m => !m.IsConstructor)
-
-// The threshold 4 is arbitrary and it should avoid matching too many fields.
-// Threshold is even lower for static fields because this reveals situations even more complex.
-where methodsAssigningMe.Count() >= (!f.IsStatic ? 4 : 2)
-
-select new {
- f,
- methodsAssigningMe,
- f.MethodsReadingMeButNotAssigningMe,
- f.MethodsUsingMe,
- Debt = (4+(f.IsStatic ? 10 : 5)).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// A field assigned from many methods is a symptom of **bug-prone code**.
-// Notice that:
-//
-// • For an instance field, constructor(s) of its class that assign the field are not counted.
-//
-// • For a static field, the class constructor that assigns the field is not counted.
-//
-// The default threshold for *instance fields* is equal to *4 or more than 4 methods
-// assigning the instance field*. Such situation makes harder to anticipate the
-// field state at runtime. The code is then complicated to read, hard to debug
-// and hard to maintain. Hard-to-solve bugs due to corrupted state are often the
-// consequence of fields *anarchically assigned*.
-//
-// The situation is even more complicated if the field is *static*.
-// Indeed, such situation potentially involves global random accesses from
-// various parts of the application. This is why this rule provides a lower
-// threshold equals to *2 or more than 2 methods assigning the static field*.
-//
-// If the object containing such field is meant to be used from multiple threads,
-// there are **alarming chances** that the code is unmaintainable and bugged.
-// When multiple threads are involved, the rule of thumb is to use immutable objects.
-//
-// If the field type is a reference type (interfaces, classes, strings, delegates)
-// corrupted state might result in a *NullReferenceException*.
-// If the field type is a value type (number, boolean, structure)
-// corrupted state might result in wrong result not even signaled by an exception
-// thrown.
-//
-
-//
-// There is no straight advice to refactor the number of methods responsible
-// for assigning a field. Sometime the situation is simple enough, like when
-// a field that hold an indentation state is assigned by many writer methods.
-// Such situation only requires to define two methods *IndentPlus()/IndentMinus()*
-// that assign the field, called from all writers methods.
-//
-// Sometime the solution involves rethinking and then rewriting
-// a complex algorithm. Such field can sometime become just a variable accessed
-// locally by a method or a *closure*. Sometime, just rethinking the life-time
-// and the role of the parent object allows the field to become immutable
-// (i.e assigned only by the constructor).
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 4 minutes plus 5 minutes per method assigning the instance field
-// or 10 minutes per method assigning the static field.
-//]]>
- Do not declare read only mutable reference types
-// ND1907:DoNotDeclareReadOnlyMutableReferenceTypes
-
-warnif count > 0
-from f in JustMyCode.Fields where
- f.IsInitOnly &&
- !f.ParentType.IsPrivate &&
- !f.IsPrivate &&
- f.FieldType != null &&
- f.FieldType.IsClass &&
- !f.FieldType.IsThirdParty &&
- !f.FieldType.IsImmutable
-select new {
- f,
- f.FieldType,
- FieldVisibility = f.Visibility,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule is violated when a *public* or *internal*
-// type contains a *public* or *internal* read-only field
-// whose field type is a mutable reference type.
-//
-// This situation gives the false impression that the
-// value can't change, when actually it's only the field
-// value that can't change, but the object state
-// can still change.
-//
-
-//
-// To fix a violation of this rule,
-// replace the field type with an immutable type,
-// or declare the field as *private*.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Array fields should not be read only
-// ND1908:ArrayFieldsShouldNotBeReadOnly
-
-warnif count > 0
-from f in Application.Fields where
- f.IsInitOnly &&
- f.IsPubliclyVisible &&
- f.FieldType != null &&
- f.FieldType.FullName == "System.Array"
-select new {
- f,
- FieldVisibility = f.Visibility,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This rule is violated when a publicly visible field
-// that holds an array, is declared read-only.
-//
-// This situation represents a *security vulnerability*.
-// Because the field is read-only it cannot be changed to refer
-// to a different array. However, the elements of the array
-// that are stored in a read-only field can be changed.
-// Code that makes decisions or performs operations that are
-// based on the elements of a read-only array that can be publicly
-// accessed might contain an exploitable security vulnerability.
-//
-
-//
-// To fix the security vulnerability that is identified by
-// this rule do not rely on the contents of a read-only array
-// that can be publicly accessed. It is strongly recommended
-// that you use one of the following procedures:
-//
-// • Replace the array with a strongly typed collection
-// that cannot be changed. See for example:
-// *System.Collections.Generic.IReadOnlyList* ;
-// *System.Collections.Generic.IReadOnlyCollection* ;
-// *System.Collections.ReadOnlyCollectionBase*
-//
-// • Or replace the public field with a method that returns a clone
-// of a private array. Because your code does not rely on
-// the clone, there is no danger if the elements are modified.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Types tagged with ImmutableAttribute must be immutable
-// ND1909:TypesTaggedWithImmutableAttributeMustBeImmutable
-
-warnif count > 0
-from t in Application.Types where
- t.HasAttribute ("NDepend.Attributes.ImmutableAttribute".AllowNoMatch()) &&
- !t.IsImmutable
-let culpritFields = t.Fields.Where(f => !f.IsStatic && !f.IsImmutable)
-select new {
- t,
- culpritFields,
- Debt = (5+10*culpritFields.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// An object is immutable if its state doesn’t change once the
-// object has been created. Consequently, a structure or a class
-// is immutable if its instances fields are only assigned inline
-// or from constructor(s).
-//
-// An attribute **NDepend.Attributes.ImmutableAttribute** can be
-// used to express in code that a type is immutable. In such
-// situation, the present code rule checks continuously that the
-// type remains immutable whatever the modification done.
-//
-// This rule warns when a type that is tagged with
-// *ImmutableAttribute* is actually not immutable anymore.
-//
-// Notice that *FullCoveredAttribute* is defined in *NDepend.API.dll*
-// and if you don't want to link this assembly, you can create your
-// own *FullCoveredAttribute* and adapt the rule.
-//
-
-//
-// First understand which modification broke the type immutability.
-// The list of *culpritFields* provided in this rule result can help.
-// Then try to refactor the type to bring it back to immutability.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 5 minutes plus 10 minutes per culprit field.
-//]]>
- Types immutable should be tagged with ImmutableAttribute
-// ND1910:TypesImmutableShouldBeTaggedWithImmutableAttribute
-
-// warnif count > 0 <-- not a code rule per default
-
-from t in Application.Types where
- !t.HasAttribute ("NDepend.Attributes.ImmutableAttribute".AllowNoMatch()) &&
- t.IsImmutable
-select new {
- t,
- t.NbLinesOfCode,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// An object is immutable if its state doesn’t change once the
-// object has been created. Consequently, a structure or a class
-// is immutable if its instances fields are only assigned inline
-// or from constructor(s).
-//
-// This code query lists immutable type that are not tagged with
-// an **ImmutableAttribute**. By using such attribute, you can express
-// in source code the intention that a class is immutable, and
-// should remain immutable in the future. Benefits of using
-// an **ImmutableAttribute** are twofold:
-//
-// • Not only the intention is expressed in source code,
-//
-// • but it is also continuously checked by the rule
-// *Types tagged with ImmutableAttribute must be immutable*.
-//
-
-//
-// Just tag types matched by this code query with **ImmutableAttribute**
-// that can be found in *NDepend.API.dll*,
-// or by an attribute of yours defined in your own code
-// (in which case this code query must be adapted).
-//]]>
- Methods tagged with PureAttribute must be pure
-// ND1911:MethodsTaggedWithPureAttributeMustBePure
-
-warnif count > 0
-from m in Application.Methods where
- ( m.HasAttribute ("NDepend.Attributes.PureAttribute".AllowNoMatch()) ||
- m.HasAttribute ("System.Diagnostics.Contract.PureAttribute".AllowNoMatch()) ) &&
- ( m.ChangesObjectState || m.ChangesTypeState ) &&
- m.NbLinesOfCode > 0
-
-let fieldsAssigned = m.FieldsAssigned
-
-select new {
- m,
- m.NbLinesOfCode,
- fieldsAssigned,
- Debt = 15.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// A method is pure if its execution doesn’t change
-// the value of any instance or static field.
-// A pure method is just a **function** that output
-// a result from inputs.
-// Pure methods naturally simplify code by **limiting
-// side-effects**.
-//
-// An attribute **PureAttribute** can be
-// used to express in code that a method is pure. In such
-// situation, the present code rule checks continuously that the
-// method remains pure whatever the modification done.
-//
-// This rule warns when a method that is tagged with
-// *PureAttribute* is actually not pure anymore.
-//
-// Notice that *NDepend.Attributes.PureAttribute* is defined
-// in *NDepend.API.dll* and if you don't want to link this
-// assembly, you can also use
-// *System.Diagnostics.Contract.PureAttribute*
-// or create your own *PureAttribute* and adapt the rule.
-//
-// Notice that *System.Diagnostics.Contract.PureAttribute* is
-// taken account by the compiler only when the VS project has
-// Microsoft Code Contract enabled.
-//
-
-//
-// First understand which modification broke the method purity.
-// Then refactor the method to bring it back to purity.
-//]]>
- Pure methods should be tagged with PureAttribute
-// ND1912:PureMethodsShouldBeTaggedWithPureAttribute
-
-// warnif count > 0 <-- not a code rule per default
-
-from m in Application.Methods where
- !m.IsGeneratedByCompiler &&
- !m.HasAttribute ("NDepend.Attributes.PureAttribute".AllowNoMatch()) &&
- !m.HasAttribute ("System.Diagnostics.Contract.PureAttribute".AllowNoMatch()) &&
- !m.ChangesObjectState && !m.ChangesTypeState &&
- m.NbLinesOfCode > 0
-select new {
- m,
- m.NbLinesOfCode,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// A method is pure if its execution doesn’t change
-// the value of any instance or static field.
-// Pure methods naturally simplify code by **limiting
-// side-effects**.
-//
-// This code query lists pure methods that are not tagged with
-// a **PureAttribute**. By using such attribute, you can express
-// in source code the intention that a method is pure, and
-// should remain pure in the future. Benefits of using
-// a **PureAttribute** are twofold:
-//
-// • Not only the intention is expressed in source code,
-//
-// • but it is also continuously checked by the rule
-// *Methods tagged with PureAttribute must be pure*.
-//
-// This code query is not by default defined as a code rule
-// because certainly many of the methods of the code base
-// are matched. Hence fixing all matches and then
-// maintaining the rule unviolated might require a lot of
-// work. This may *counter-balance* such rule benefits.
-//
-
-//
-// Just tag methods matched by this code query with
-// *NDepend.Attributes.PureAttribute*
-// that can be found in *NDepend.API.dll*,
-// or with *System.Diagnostics.Contract.PureAttribute*,
-// or with an attribute of yours defined in your own code
-// (in which case this code query must be adapted).
-//
-// Notice that *System.Diagnostics.Contract.PureAttribute* is
-// taken account by the compiler only when the VS project has
-// Microsoft Code Contract enabled.
-//]]>
-
-
- Instance fields naming convention
-// ND2000:InstanceFieldsNamingConvention
-
-warnif count > 0 from f in JustMyCode.Fields where
- !(
- // Instance field name starting with a lower-case letter
- (f.Name.Length >= 1 && char.IsLetter(f.Name[0]) && char.IsLower(f.Name[0])) ||
-
- // Instance field name starting with "_" followed with a lower-case letter
- (f.Name.Length >= 2 && f.Name.StartsWith("_") && char.IsLetter(f.Name[1]) && char.IsLower(f.Name[1])) ||
-
- // Instance field name starting with "m_" followed with an upper-case letter
- (f.Name.Length >= 3 && f.Name.StartsWith("m_") && char.IsLetter(f.Name[2]) && char.IsUpper(f.Name[2]))
-
- ) &&
- !f.IsStatic &&
- !f.IsLiteral &&
- !f.IsGeneratedByCompiler &&
- !f.IsSpecialName &&
- !f.IsEventDelegateObject &&
-
- // Don't check naming convention on serializable fields
- !f.HasAttribute("System.Xml.Serialization.XmlAttributeAttribute".AllowNoMatch()) &&
- !f.HasAttribute("System.Runtime.Serialization.DataMemberAttribute".AllowNoMatch()) &&
-
- // Don't warn if a method using the field is also calling a method that has 'ref' and 'out' parameters.
- // This could lead to false positive. A field used in a 'ref' or 'out' parameter cannot be set as read-only.
- f.MethodsUsingMe.SelectMany(m => m.MethodsCalled).FirstOrDefault(m => m.Name.Contains("&")) == null
-
-select new {
- f,
- f.SizeOfInst,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// By default the presents rule supports the 3 most used naming
-// conventions for instance fields:
-//
-// • Instance field name starting with a lower-case letter
-//
-// • Instance field name starting with "_" followed with a lower-case letter
-//
-// • Instance field name starting with "m_" followed with an upper-case letter
-//
-// The rule can be easily adapted to your own company naming convention.
-//
-// In terms of behavior, a *static field* is something completely different
-// than an *instance field*, so it is interesting to differentiate them at
-// a glance through a naming convetion.
-//
-// This is why it is advised to use a specific naming convention for instance
-// field like name that starts with **m_**.
-//
-// Related discussion:
-// http://codebetter.com/patricksmacchia/2013/09/04/on-hungarian-notation-for-instance-vs-static-fields-naming/
-//
-
-//
-// Once the rule has been adapted to your own naming convention
-// make sure to name all matched instance fields adequately.
-//]]>
- Static fields naming convention
-// ND2001:StaticFieldsNamingConvention
-
-warnif count > 0 from f in JustMyCode.Fields where
- !(
- // Static field name starting with an upper-case letter
- (f.Name.Length >= 1 && char.IsLetter(f.Name[0]) && char.IsUpper(f.Name[0])) ||
-
- // Static field name starting with "_" followed with an upper-case letter
- (f.Name.Length >= 2 && f.Name.StartsWith("_") && char.IsLetter(f.Name[1]) && char.IsUpper(f.Name[1])) ||
-
- // Static field name starting with "s_" followed with an upper-case letter
- (f.Name.Length >= 3 && f.Name.StartsWith("s_") && char.IsLetter(f.Name[2]) && char.IsUpper(f.Name[2]))
-
- ) &&
- f.IsStatic &&
- !f.IsLiteral &&
- !f.IsGeneratedByCompiler &&
- !f.IsSpecialName &&
- !f.IsEventDelegateObject
-select new {
- f,
- f.SizeOfInst,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// By default the presents rule supports the 3 most used naming
-// conventions for static fields:
-//
-// • Static field name starting with an upper-case letter
-//
-// • Static field name starting with "_" followed with an upper-case letter
-//
-// • Static field name starting with "s_" followed with an upper-case letter
-//
-// The rule can be easily adapted to your own company naming convention.
-//
-// In terms of behavior, a *static field* is something completely different
-// than an *instance field*, so it is interesting to differentiate them at
-// a glance through a naming convetion.
-//
-// This is why it is advised to use a specific naming convention for static
-// field like name that starts with **s_**.
-//
-// Related discussion:
-// http://codebetter.com/patricksmacchia/2013/09/04/on-hungarian-notation-for-instance-vs-static-fields-naming/
-//
-
-//
-// Once the rule has been adapted to your own naming convention
-// make sure to name all matched static fields adequately.
-//]]>
- Interface name should begin with a 'I'
-// ND2002:InterfaceNameShouldBeginWithAI
-
-// Don't query all Application.Types because some interface generated might not start with an 'I'
-// like for example when adding a WSDL reference to a project.
-warnif count > 0 from t in JustMyCode.Types where
- t.IsInterface &&
- // Don't apply this rule for COM interfaces.
- !t.HasAttribute("System.Runtime.InteropServices.ComVisibleAttribute".AllowNoMatch())
-
-// Discard outter type(s) name prefix for nested types
-let name = !t.IsNested ?
- t.Name :
- t.Name.Substring(t.Name.LastIndexOf('+') + 1, t.Name.Length - t.Name.LastIndexOf('+') - 1)
-
-where name[0] != 'I'
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// In the .NET world, interfaces names are commonly prefixed
-// with an upper case **I**. This rule warns about interfaces
-// whose names don't follow this convention. Because this
-// naming convention is widely used and accepted, we
-// recommend abiding by this rule.
-//
-// Typically COM interfaces names don't follow this rule.
-// Hence this code rule doesn't take care of interfaces tagged
-// with *ComVisibleAttribute*.
-//
-
-//
-// Make sure that matched interfaces names are prefixed with
-// an upper **I**.
-//]]>
- Abstract base class should be suffixed with 'Base'
-// ND2003:AbstractBaseClassShouldBeSuffixedWithBase
-
-warnif count > 0 from t in Application.Types where
- t.IsAbstract &&
- t.IsClass &&
-
- t.BaseClass != null &&
- t.BaseClass.FullName == "System.Object" &&
-
- ((!t.IsGeneric && !t.NameLike (@"Base$")) ||
- ( t.IsGeneric && !t.NameLike (@"Base<")))
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about *abstract classes* whose names are not
-// suffixed with **Base**. It is a common practice in the .NET
-// world to suffix base classes names with **Base**.
-//
-// Notice that this rule doesn't match abstract classes that
-// are in a middle of a hierarchy chain.
-// In other words, only base classes that derive directly
-// from *System.Object* are matched.
-//
-
-//
-// Suffix the names of matched base classes with **Base**.
-//]]>
- Exception class name should be suffixed with 'Exception'
-// ND2004:ExceptionClassNameShouldBeSuffixedWithException
-
-warnif count > 0 from t in Application.Types where
- t.IsExceptionClass &&
-
- // We use SimpleName, because in case of generic Exception type
- // SimpleName suppresses the generic suffix (like ).
- !t.SimpleNameLike(@"Exception$") &&
- !t.SimpleNameLike(@"ExceptionBase$") // Allow the second suffix Base
- // for base exception classes.
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns about *exception classes* whose names are not
-// suffixed with **Exception**. It is a common practice in the .NET
-// world to suffix exception classes names with **Exception**.
-//
-// For exception base classes, the suffix **ExceptionBase**
-// is also accepted.
-//
-
-//
-// Suffix the names of matched exception classes with **Exception**.
-//]]>
- Attribute class name should be suffixed with 'Attribute'
-// ND2005:AttributeClassNameShouldBeSuffixedWithAttribute
-
-warnif count > 0 from t in Application.Types where
- t.IsAttributeClass &&
- !t.NameLike (@"Attribute$")
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns about *attribute classes* whose names are not
-// suffixed with **Attribute**. It is a common practice in the .NET
-// world to suffix attribute classes names with **Attribute**.
-//
-
-//
-// Suffix the names of matched attribute classes with **Attribute**.
-//]]>
- Types name should begin with an Upper character
-// ND2006:TypesNameShouldBeginWithAnUpperCharacter
-
-warnif count > 0
-let isAspNetApp = ThirdParty.Assemblies.WithName("System.Web").Any()
-from t in JustMyCode.Types where
- // The name of a type should begin with an Upper letter.
- !t.SimpleNameLike (@"^[A-Z]") &&
-
- // Except if it is generated by compiler.
- !t.IsSpecialName &&
- !t.IsGeneratedByCompiler &&
-
- // Special default ASP.NET type named "_Default"
- !(isAspNetApp && t.SimpleName == "_Default")
-
-select new {
- t,
- // We show the type simple name
- // that doesn't include the parent type name
- // for nested types.
- t.SimpleName,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about *types* whose names don't start
-// with an Upper character. It is a common practice in the .NET
-// world to use **Pascal Casing Style** to name types.
-//
-// **Pascal Casing Style** : The first letter in the identifier
-// and the first letter of each subsequent concatenated word
-// are capitalized. For example: *BackColor*
-//
-
-//
-// *Pascal Case* the names of matched types.
-//]]>
- Methods name should begin with an Upper character
-// ND2007:MethodsNameShouldBeginWithAnUpperCharacter
-
-warnif count > 0
-from m in JustMyCode.Methods where
- !m.NameLike (@"^[A-Z]") &&
- !m.IsSpecialName &&
- !m.IsGeneratedByCompiler &&
- !m.IsExplicitInterfaceImpl // This can generate unexpected method name.
-select new {
- m,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about *methods* whose names don't start
-// with an Upper character. It is a common practice in the .NET
-// world to use **Pascal Casing Style** to name methods.
-//
-// **Pascal Casing Style** : The first letter in the identifier
-// and the first letter of each subsequent concatenated word
-// are capitalized. For example: *ComputeSize*
-//
-
-//
-// *Pascal Case* the names of matched methods.
-//]]>
- Do not name enum values 'Reserved'
-// ND2008:DoNotNameEnumValuesReserved
-
-warnif count > 0
-from f in Application.Fields where
- f.IsEnumValue &&
- f.NameLike (@"Reserved")
-select new {
- f,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule assumes that an enumeration member
-// with a name that contains **"Reserved"**
-// is not currently used but is a placeholder to
-// be renamed or removed in a future version.
-// Renaming or removing a member is a breaking
-// change. You should not expect users to ignore
-// a member just because its name contains
-// **"Reserved"** nor can you rely on users to read or
-// abide by documentation. Furthermore, because
-// reserved members appear in object browsers
-// and smart integrated development environments,
-// they can cause confusion as to which members
-// are actually being used.
-//
-// Instead of using a reserved member, add a
-// new member to the enumeration in the future
-// version.
-//
-// In most cases, the addition of the new
-// member is not a breaking change, as long as the
-// addition does not cause the values of the
-// original members to change.
-//
-
-//
-// To fix a violation of this rule, remove or
-// rename the member.
-//]]>
- Avoid types with name too long
-// ND2009:AvoidTypesWithNameTooLong
-
-warnif count > 0
-from t in JustMyCode.Types
-where !t.IsGeneratedByCompiler
-
-where t.SimpleName.Length > 40
-orderby t.SimpleName.Length descending
-select new {
- t,
- t.SimpleName,
- NameLength = t.SimpleName.Length,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Types with a name too long tend to decrease code readability.
-// This might also be an indication that a type is doing too much.
-//
-// This rule matches types with names with more than 40 characters.
-//
-
-//
-// To fix a violation of this rule, rename the type with a shortest name
-// or eventually split the type in several more fine-grained types.
-//]]>
- Avoid methods with name too long
-// ND2010:AvoidMethodsWithNameTooLong
-
-warnif count > 0
-
-// First get test method for which we allow long names
-let testAttr = ThirdParty.Types.WithNameIn("FactAttribute", "TestAttribute", "TestCaseAttribute")
-let testMethods = Methods.TaggedWithAnyAttributes(testAttr).ToHashSetEx()
-
-from m in JustMyCode.Methods where
-
- // Explicit Interface Implementation methods are
- // discarded because their names are prefixed
- // with the interface name.
- !m.IsExplicitInterfaceImpl &&
- !m.IsGeneratedByCompiler &&
- ((!m.IsSpecialName && m.SimpleName.Length > 40) ||
- // Property getter/setter are prefixed with "get_" "set_" of length 4.
- ( m.IsSpecialName && m.SimpleName.Length - 4 > 40)) &&
-
- // Don't match test methods
- !testMethods.Contains(m) &&
- !m.SimpleName.Contains("Test") &&
- !m.ParentType.SimpleName.Contains("Test") &&
- !m.ParentNamespace.Name.Contains("Test")
-
-orderby m.SimpleName.Length descending
-
-select new {
- m,
- m.SimpleName,
- NameLength = m.SimpleName.Length - (m.IsSpecialName ? 4 : 0),
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Methods with a name too long tend to decrease code readability.
-// This might also be an indication that a method is doing too much.
-//
-// This rule matches methods with names with more than 40 characters.
-//
-// However it is considered as a good practice to name unit tests
-// in such a way with a very expressive name, hence this rule doens't match
-// methods tagged with *FactAttribute*, *TestAttribute* and *TestCaseAttribute*.
-//
-
-//
-// To fix a violation of this rule, rename the method with a shortest name
-// that equally conveys the behavior of the method.
-// Or eventually split the method into several smaller methods.
-//]]>
- Avoid fields with name too long
-// ND2011:AvoidFieldsWithNameTooLong
-
-warnif count > 0 from f in JustMyCode.Fields where
- !f.IsGeneratedByCompiler &&
- f.Name.Length > 40
-orderby f.Name descending
-select new {
- f,
- NameLength = f.Name.Length,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// Fields with a name too long tend to decrease code readability.
-//
-// This rule matches fields with names with more than 40 characters.
-//
-
-//
-// To fix a violation of this rule, rename the field with a shortest name
-// that equally conveys the same information.
-//]]>
- Avoid having different types with same name
-// ND2012:AvoidHavingDifferentTypesWithSameName
-
-warnif count > 0
-
-// Special type names for which multiple types with such name are allowed.
-let nonReportedTypeName = new [] {
- "Program", "NamespaceDoc", "Initial", "Startup", "SwaggerConfig", "Constants" }
-
-// Special type name suffixes for which multiple types with such suffix are allowed.
-let nonReportedTypeNameSuffix = new [] {
- "Service", "Model", "Controller", "Page", "Pages" }
-
-// This rule matches also collisions between
-// application and third-party types sharing a same name.
-let groups = JustMyCode.Types.Union(ThirdParty.Types)
- // Discard nested types, whose name is
- // prefixed with the parent type name.
- .Where(t => !t.IsNested &&
- !nonReportedTypeName.Contains(t.Name) &&
- !t.Name.EndsWithAny(nonReportedTypeNameSuffix))
-
- // Group types by name.
- .GroupBy(t => t.Name)
-
-from @group in groups
- where @group.Count() > 1
-
- // Let's see if types with the same name are declared
- // in different namespaces.
- // (t.FullName is {namespaceName}.{typeName} )
- let groupsFullName = @group.GroupBy(t => t.FullName)
- where groupsFullName.Count() > 1
-
- // If several types with same name are declared in different namespaces
- // eliminate the case where all types are declared in third-party assemblies.
- let types= groupsFullName.SelectMany(g => g)
- where types.Any(t => !t.IsThirdParty)
- // Uncomment this line, to only gets naming collision involving
- // both application and third-party types.
- // && types.Any(t => t.IsThirdParty)
-
-orderby types.Count() descending
-
-select new {
- // Order types by parent namespace and assembly name,this way we always get the same type across sessions.
- // Without this astute, the same issue would be seen as added/removed when the first type choosen in the group
- // was not always the same, a situation that actually happens.
- // Also make sure that the chosen type is not a third-party one.
- t = types.OrderBy(t => (t.IsThirdParty ? "1" : "0") + t.ParentNamespace.Name + t.ParentAssembly.Name).First(),
-
- // In the 'types' column, make sure to group matched types
- // by parent assemblies and parent namespaces, to get a result
- // more readable.
- types,
-
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns about multiple types with same name,
-// that are defined in different *application* or
-// *third-party* namespaces or assemblies.
-//
-// Such practice create confusion and also naming collision
-// in source files that use different types with same name.
-//
-
-//
-// To fix a violation of this rule, rename concerned types.
-//]]>
- Avoid prefixing type name with parent namespace name
-// ND2013:AvoidPrefixingTypeNameWithParentNamespaceName
-
-warnif count > 0
-
-from n in JustMyCode.Namespaces
-where n.Name.Length > 0
-
-from t in n.ChildTypes
-where
- JustMyCode.Contains(t) && // Don't warn about generated code
- !t.IsGeneratedByCompiler &&
- !t.IsNested &&
- t.Name.IndexOf(n.SimpleName) == 0 &&
-
- // The type name is equal to namespace name or the type name contains another
- // word that starts with an upper-case letter after the namespace name.
- // This way we avoid matching false-positive where namespace name is "Stat" and type name is "Statistic".
- (t.Name.Length == n.SimpleName.Length || char.IsUpper(t.Name[n.SimpleName.Length]))
-select new {
- t,
- namespaceName = n.SimpleName,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about situations where the parent namespace name
-// is used as the prefix of a contained type.
-//
-// For example a type named "RuntimeEnvironment"
-// declared in a namespace named "Foo.Runtime"
-// should be named "Environment".
-//
-// Such situation creates naming redundancy with no readability gain.
-//
-
-//
-// To fix a violation of this rule, remove the prefix from the type name.
-//]]>
- Avoid naming types and namespaces with the same identifier
-// ND2014:AvoidNamingTypesAndNamespacesWithTheSameIdentifier
-
-warnif count > 0
-let hashsetShortNames = Namespaces.Where(n => n.Name.Length > 0).Select(n => n.SimpleName).ToHashSetEx()
-
-from t in JustMyCode.Types
-where hashsetShortNames.Contains(t.Name)
-select new {
- t,
- namespaces = Namespaces.Where(n => n.SimpleName == t.Name),
- Debt = 12.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns when a type and a namespace have the same name.
-//
-// For example when a type is named *Environment*
-// and a namespace is named *Foo.Environment*.
-//
-// Such situation provokes tedious compiler resolution collision,
-// and makes the code less readable because concepts are not
-// concisely identified.
-//
-
-//
-// To fix a violation of this rule, renamed the concerned type or namespace.
-//]]>
- Don't call your method Dispose
-// ND2015:DontCallYourMethodDispose
-
-warnif count > 0
-
-// Activate this rule only when IDisposable is resolved in third-party code
-// else this rule might produce false positives.
-let thirdPartyDisposable = ThirdParty.Types.WithFullName("System.IDisposable").FirstOrDefault()
-where thirdPartyDisposable != null
-
-from m in JustMyCode.Methods.WithSimpleName("Dispose")
-where !m.ParentType.Implement("System.IDisposable".AllowNoMatch())
- && m.OverriddensBase.Count() == 0 // Can't change the name of an override
- && !m.IsNewSlot // new slot also means override of an intreface method
-select new {
- m,
- Debt = 15.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// In .NET programming, the identifier *Dispose* should be kept
-// only for implementations of *System.IDisposable*.
-//
-// This rule warns when a method is named *Dispose()*,
-// but the parent type doesn't implement *System.IDisposable*.
-//
-
-//
-// To fix a violation of this rule,
-// either make the parent type implements *System.IDisposable*,
-// or rename the *Dispose()* method with another identifier like:
-// *Close() Terminate() Finish() Quit() Exit() Unlock() ShutDown()*…
-//]]>
- Methods prefixed with 'Try' should return a boolean
-// ND2016:MethodsPrefixedWithTryShouldReturnABoolean
-
-warnif count > 0
-from m in Application.Methods where
- m.SimpleNameLike("^Try") &&
- m.ReturnType != null &&
- m.ReturnType.FullName != "System.Boolean"
-select new {
- m,
- m.ReturnType,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// When a method has a name prefixed with **Try**, it is expected that
-// it returns a *boolean*, that reflects the method execution status,
-// *success* or *failure*.
-//
-// Such method usually returns a result through an *out parameter*.
-// For example: *System.Int32.TryParse(int,out string):bool*
-//
-
-//
-// To fix a violation of this rule,
-// Rename the method, or transform it into an operation that can fail.
-//]]>
- Properties and fields that represent a collection of items should be named Items.
-// ND2017:PropertiesAndFieldsThatRepresentACollectionOfItemsShouldBeNamedItems
-
-warnif count > 0
-
-let collectionTypes = Types.Where(t =>
- t.Implement("System.Collections.Generic.IEnumerable".AllowNoMatch()) &&
- t.IsGeneric &&
- t.FullName != "System.Collections.Generic.IDictionary" &&
- !t.Implement("System.Collections.Generic.IDictionary".AllowNoMatch()) &&
- t.FullName != "System.Collections.Generic.IReadOnlyDictionary" &&
- !t.Implement("System.Collections.Generic.IReadOnlyDictionary".AllowNoMatch())).ToHashSetEx()
-
-let properties = from m in JustMyCode.Methods
-where (m.IsPropertyGetter || m.IsPropertySetter) &&
- collectionTypes.Contains(m.ReturnType)
-select new { Member = (IMember)m, Type = m.ReturnType }
-
-let fields = from f in JustMyCode.Fields
-where collectionTypes.Contains(f.FieldType)
-select new { Member = (IMember)f, Type = f.FieldType }
-
-from pair in properties.Concat(fields)
-let identifier = pair.Member.SimpleName
-where !identifier.EndsWith("s") &&
- !identifier.Contains('<') // Remove potential generated fields like backing fields, and also potential generated properties accessors
-
-let identifierRefined = identifier.Replace("get_", "").Replace("set_", "")
-let words = identifierRefined.GetWords()
-where !words.Any(word =>
- word.EndsWith("s") || // Don't warn if any word ends with an s
- word == "Empty") // Don't warn if any word in the identifier is Empty
-
-select new { pair.Member, pair.Type }
-
-//
-// A good practice to make the code more readable and more predictable
-// is to name properties and fields typed with a collection of *items*
-// with the plural form of *Items*.
-//
-// Depending on the domain of your application, a proper identifier could be
-// *NewDirectories*, *Words*, *Values*, *UpdatedDates*.
-//
-// Also this rule doesn't warn when any word in the identifier ends with an *s*.
-// This way identifiers like **TasksToRun**, **KeysDisabled**, **VersionsSupported**,
-// **ChildrenFilesPath**, **DatedValuesDescending**, **ApplicationNodesChanged**
-// or **ListOfElementsInResult** are valid and won't be seen as violations.
-//
-// Moreover this rule won't warn for a field or property with an identifier
-// that contain the word **Empty**.
-// This is a common pattern to define an immutable and empty collection instance
-// shared.
-//
-// Before inspecting properties and fields, this rule gathers
-// application and third-party collection types that might be returned
-// by a property or a field. To do so this rule searches types that implement
-// *IEnumerable* except:
-//
-// - Non generic types: Often a non generic type is not seen as a collection.
-// For example *System.String* implements *IEnumerable*, but a string
-// is rarely named as a collection of characters. In others words,
-// we have much more strings in our program named like *FirstName*
-// than named like *EndingCharacters*.
-//
-// - Dictionaries types: A dictionary is more than a collection of pairs,
-// it is a mapping from one domain to another. A common practice is to suffix
-// the name of a dictionary with *Map* *Table* or *Dictionary*,
-// although often dictionaries names satify this rule with names like
-// *GuidsToPersons* or *PersonsByNames*.
-//
-
-//
-// Just rename the fields and properties accordingly,
-// by making plural the word in the identifier
-// that describes best the *items* in the collection.
-//
-// For example:
-//
-// - **ListOfDir** can be renamed **Directories**.
-//
-// - **Children** can be renamed **ChildrenItems**
-//
-// - **QueueForCache** can be renamed **QueueOfItemsForCache**
-//]]>
- DDD ubiquitous language check
-// ND2018:DDDUbiquitousLanguageCheck
-
-warnif count > 0
-
-// Update to your core domain namespace(s)
-let coreDomainNamespaces = Application.Namespaces.WithNameLike("TrainTrain.Domain")
-
-// Update your vocabulary list
-let vocabulary = new [] {
-"Train", "Coach", "Coaches", "Seat", "Seats",
-"Reservation", "Fulfilled", "Booking", "Book", "Reserve", "Confirm"
-}.ToHashSetEx()
-
-let technicalWords = new [] { "get", "set", "Get", "Set", "Add" }.ToHashSetEx()
-let multiWordsVocabulary = vocabulary.Where(w => w.GetWords().Length >= 2)
-
-// Append multi-words words in vocabulary
-let multiWordsWords = multiWordsVocabulary.SelectMany(w => w.GetWords())
-let vocabulary2 = vocabulary.Concat(multiWordsWords).ToHashSetEx()
-let vocabulary3 = vocabulary2.Concat(technicalWords).ToHashSetEx()
-
-from ce in coreDomainNamespaces.ChildTypesAndMembers()
-let tokens = ce.SimpleName.GetWords().Select(w => w.FirstCharToUpper()).ToArray()
-
-where !(ce.IsMethod && ce.AsMethod.IsConstructor) && // No vocabulary in ctor
- !(ce.IsField && ce.AsField.IsGeneratedByCompiler) && // Remove compiler generated backing fields, their vocabulary is in property
- !(vocabulary3.Any(vocable => tokens.Contains(vocable)))
-
-let wordsNotInVocabulary = tokens.Where(w => !(vocabulary2.Contains(w) && string.IsNullOrEmpty(w))).ToArray()
-
-select new { ce,
- wordsNotInVocabulary = string.Join(", ",wordsNotInVocabulary)
-}
-
-//
-// The language used in identifiers of classes, methods and fields of the **core domain**,
-// should be based on the **Domain Model**.
-// This constraint is known as **ubiquitous language** in **Domain Driven Design (DDD)**
-// and it reflects the need to be rigorous with naming,
-// since software doesn't cope well with ambiguity.
-//
-// This rule is disabled per default
-// because its source code needs to be customized to work,
-// both with the **core domain** namespace name
-// (that contains classes and types to be checked),
-// and with the list of domain language terms.
-//
-// If a term needs to be used both with singular and plural forms,
-// both forms need to be mentioned,
-// like **Seat** and **Seats** for example.
-// Notice that this default rule is related with the other default rule
-// *Properties and fields that represent a collection of items should be named Items*
-// defined in the *Naming Convention* group.
-//
-// This rule implementation relies on the NDepend API
-// **ExtensionMethodsString.GetWords(this string identifier)**
-// extension method that extracts terms
-// from classes, methods and fields identifiers in a smart way.
-//
-
-//
-// For each violation, this rule provides the list of **words not in vocabulary**.
-//
-// To fix a violation of this rule, either rename the concerned code element
-// or update the domain language terms list defined in this rule source code,
-// with the missing term(s).
-//]]>
- Avoid fields with same name in class hierarchy
-// ND2019:AvoidFieldsWithSameNameInClassHierarchy
-
-warnif count > 0
-
-// Optimization: only consider fields of derived classes
-let derivedClasses = Application.Types.Where(t =>
- t.IsClass &&
- !t.IsStatic &&
- t.DepthOfInheritance > 1 &&
- t.BaseClasses.ChildFields().Any())
-
-from f in derivedClasses.ChildFields()
-where JustMyCode.Contains(f) // Make sure it is fixable by targeting only JustMyCode fields
-let fieldsOfBaseClassesWithSameName =
- f.ParentType
- .BaseClasses
- .ChildFields()
- .Where(cf => cf.Name == f.Name && JustMyCode.Contains(cf))
-where fieldsOfBaseClassesWithSameName.Any()
-
-select new {
- f,
- fieldsOfBaseClassesWithSameName,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule matches a field whose name is already used by
-// another field in the base class hierarchy.
-//
-// The C# and VB.NET compilers allow this situation even
-// if the base class field is visible to derived classes
-// with a visibility different than *private*.
-//
-// However this situation is certainly a sign of
-// an erroneous attempt to redefine a field in a derived class.
-//
-
-//
-// Check if the field in the derived class is indeed a redefinition
-// of the base class field. Check also that both fields types
-// corresponds. If fields are static, double check that only a single
-// instance of the referenced object is needed. If all checks are positive
-// delete the derived class field and make sure that the base class
-// field is visible to derived classes with the *protected* visibility.
-//
-// If no, rename the field in the derived class and be very careful
-// in renaming all usages of this field, they might be related
-// with the base class field.
-//]]>
- Avoid various capitalizations for method name
-// ND2020:AvoidVariousCapitalizationsForMethodName
-
-warnif count > 0
-
-let lookup = JustMyCode.Methods.ToLookup(m => m.SimpleName.ToLower())
-from grouping in lookup
-where grouping.Count() > 1
-let name = grouping.First().SimpleName
-let method = grouping.FirstOrDefault(m => m.SimpleName != name)
-where method != null
-let nbCapitalizations = grouping.ToLookup(m => m.SimpleName).Count
-
-// Increase the severity if various capitalizations are found in same class
-let differentCapitalizationInSameType =
- grouping.ToLookup(m => m.ParentType)
- .Any(groupingPerType => groupingPerType.ToLookup(m => m.SimpleName).Count > 1)
-
-select new {
- method,
- methods = grouping.ToArray(),
- nbCapitalizations,
- Debt = (nbCapitalizations * 6).ToMinutes().ToDebt(),
- Severity = differentCapitalizationInSameType ? Severity.Critical : Severity.Medium
-}
-
-//
-// This rule matches application methods whose names differ
-// only in capitalization.
-//
-// With this rule you'll discover various names like
-// *ProcessOrderId* and *ProcessOrderID*. It is important to
-// choose a single capitalization used accross the whole application.
-//
-// Matched methods are not necessarily declared in the same type.
-// However if various capitalizations of a method name are found
-// within the same type, the issue severity goes from *Medium*
-// to *Critical*. Indeed, this situation is not just a matter
-// of convention, it is error-prone. It forces type's clients
-// to investigate which version of the method to call.
-//
-
-//
-// Choose a single capitalization for the method name
-// used accross the whole application.
-//
-// Or alternatively make the distinction clear by having
-// different method names that don't only differ by
-// capitalization.
-//
-// The technical-debt for each issue, the estimated cost
-// to fix an issue, is proportional to the number
-// of capitalizations found (2 minimum).
-//]]>
-
-
- Avoid referencing source file out of Visual Studio project directory
-// ND2100:AvoidReferencingSourceFileOutOfVisualStudioProjectDirectory
-
-warnif count > 0
-
-from a in Application.Assemblies
-where a.VisualStudioProjectFilePath != null
-let vsProjDirPathLower = a.VisualStudioProjectFilePath.ParentDirectoryPath.ToString().ToLower()
-
-from t in a.ChildTypes
-where JustMyCode.Contains(t) && t.SourceFileDeclAvailable
-
-from decl in t.SourceDecls
-let sourceFilePathLower = decl.SourceFile.FilePath.ToString().ToLower()
-where sourceFilePathLower.IndexOf(vsProjDirPathLower) != 0
-select new {
- t,
- sourceFilePathLower,
- projectFilePath = a.VisualStudioProjectFilePath.ToString(),
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// A source file located outside of the VS project directory can be added through:
-// *> Add > Existing Items… > Add As Link*
-//
-// Doing so can be used to share types definitions across several assemblies.
-// This provokes type duplication at binary level.
-// Hence maintainability is degraded and subtle versioning bug can appear.
-//
-// This rule matches types whose source files are not declared under the
-// directory that contains the related Visual Studio project file, or under
-// any sub-directory of this directory.
-//
-// This practice can be tolerated for certain types shared across executable assemblies.
-// Such type can be responsible for startup related concerns,
-// such as registering custom assembly resolving handlers or
-// checking the .NET Framework version before loading any custom library.
-//
-
-//
-// To fix a violation of this rule, prefer referencing from a VS project
-// only source files defined in sub-directories of the VS project file location.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Avoid duplicating a type definition across assemblies
-// ND2101:AvoidDuplicatingATypeDefinitionAcrossAssemblies
-
-warnif count > 0
-
-let groups = Application.Types
- .Where(t => !t.IsGeneratedByCompiler &&
- // Types created by the test infrastructure
- t.FullName != "AutoGeneratedProgram")
- .GroupBy(t => t.FullName)
-from @group in groups
-where @group.Count() > 1
-
-// Tricky: This rule is executed on both current snapshot and baseline snapshot (if any).
-// Taking t as @group.First() could return any type in the group, and potentially
-// it can return different types for current and baseline snapshot.
-// As a result issues wouldn't corresponds (since types are different) and the user
-// would see issues of this rule as a couple of issues added and removed.
-// Ordering types by parent assembly name and then taking the first type, discards this risk.
-let types = @group.OrderBy(t => t.ParentAssembly.Name)
-
-select new {
- t = types.First(),
- // In the 'types' column, make sure to group matched types by parent assemblies.
- typesDefs = types.ToArray(),
- Debt = 15.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// A source file located outside of the VS project directory can be added through:
-// *> Add > Existing Items… > Add As Link*
-//
-// This rule warns about using this feature to share code across several assemblies.
-// This provokes type duplication at binary level.
-// Hence maintainability is degraded and subtle versioning bug can appear.
-//
-// Each match represents a type duplicated. Unfolding the types in the column
-// **typesDefs** will show the multiple definitions across multiple assemblies.
-//
-// This practice can be tolerated for certain types shared across executable assemblies.
-// Such type can be responsible for startup related concerns,
-// such as registering custom assembly resolving handlers or
-// checking the .NET Framework version before loading any custom library.
-//
-
-//
-// To fix a violation of this rule, prefer sharing types through DLLs.
-//]]>
- Avoid defining multiple types in a source file
-// ND2102:AvoidDefiningMultipleTypesInASourceFile
-
-warnif count > 0
-
-// Build a lookup indexed by source files, values being a sequence of types defined in the source file.
-let lookup = JustMyCode.Types
- // When a source file is referenced by several assemblies,
- // type(s) contained in the source file are seen as distinct types, both by the CLR and by NDepend.
- // This Distinct clause based on type full-name (type name prefixed with namespace)
- // avoids matching the multiple versions of such type.
- .Distinct(t => t.FullName)
- .Where(t => t.SourceFileDeclAvailable &&
- // except enumerations, nested types and types generated by compilers!
- !t.IsEnumeration &&
- !t.IsNested &&
- !t.IsGeneratedByCompiler)
- // We use multi-key, since a type can be declared in multiple source files.
- .ToMultiKeyLookup(t => t.SourceDecls.Select(d => d.SourceFile))
-
-from @group in lookup where @group.Count() > 1
- let sourceFile = @group.Key
-
- // CQLinq doesn't let indexing result with sourceFile
- // so we choose a typeIndex in types,
- // preferably the type that has the file name.
- let typeWithSourceFileName = @group.FirstOrDefault(t => t.SimpleName == sourceFile.FileNameWithoutExtension)
- let typeIndex = typeWithSourceFileName ?? @group.First()
-
-select new {
- typeIndex,
- TypesInSourceFile = @group as IEnumerable,
- SourceFilePathString = sourceFile.FilePathString,
- Debt = 3.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// Defining multiple types in a single source file decreases code readability,
-// because developers are used to see all types in a namespace,
-// when expanding a folder in the *Visual Studio Solution Explorer*.
-// Also doing so, leads to source files with too many lines.
-//
-// Each match of this rule is a source file that contains several types
-// definitions, indexed by one of those types, preferably the one with
-// the same name than the source file name without file extension, if any.
-//
-
-//
-// To fix a violation of this rule, create a source file for each type.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Namespace name should correspond to file location
-// ND2103:NamespaceNameShouldCorrespondToFileLocation
-
-warnif count > 0
-
-from a in Application.Assemblies
-let assemblyName = a.Name
-
-from n in a.ChildNamespaces
-let namespaceName = n.Name
-
-// Build the dirShouldContain string
-// and then we check which source file path contains dirShouldContain or not
-let dirShouldContain = (
- // namespaceName starts with assembly name => gets only components after the assembly name
- namespaceName.StartsWith(assemblyName)
- ? namespaceName.Substring(assemblyName.Length)
-
- // namespaceName contains assembly name => gets only components after the assembly name
- : namespaceName.Contains("." + assemblyName)
- ? namespaceName.Substring(n.Name.IndexOf("." + assemblyName))
-
- // namespaceName has more than one part => gets only components after the first part
- : namespaceName.Contains(".")
- ? namespaceName.Substring(n.Name.IndexOf("."))
- : namespaceName)
-
- // Replace dots by spaces in namespace name
- .Replace('.', ' ')
-
-where dirShouldContain.Length > 0
-
-// Look at source file decl of JustMyCode type's declared in the namespace 'n'
-from t in n.ChildTypes
-where JustMyCode.Contains(t) && t.SourceFileDeclAvailable
-
-let sourceDeclConcerned = (from decl in t.SourceDecls
- let sourceFilePath = decl.SourceFile.FilePath.ToString()
- // Replace dots and path separators by spaces in source files names
- where !sourceFilePath.Replace('.',' ').Replace('\\',' ').Contains(dirShouldContain)
- select sourceFilePath).ToArray()
-where sourceDeclConcerned.Length > 0
-
-let justACaseSensitiveIssue = sourceDeclConcerned[0].ToLower().Replace('.',' ').Replace('\\',' ').Contains(dirShouldContain.ToLower())
-
-select new {
- t,
- dirShouldContain,
- sourceFilePath = sourceDeclConcerned[0],
- nbSourceDeclConcerned = sourceDeclConcerned.Length,
- justACaseSensitiveIssue ,
- Debt = (justACaseSensitiveIssue ?
- 1f + sourceDeclConcerned.Length/2f :
- 2f + sourceDeclConcerned.Length).ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// For a solid code structure and organization,
-// do mirror the namespaces hierarchy and the directories hierarchy containing source files.
-//
-// Doing so is a widely accepted convention, and not respecting this convention
-// will lead to less maintainable and less browsable source code.
-//
-// This rule matches all types in such source file, whose location doesn't correspond
-// to the type parent namespace. If a source file contains several such types (that
-// are not necessarily in the same namespace) each type will result in a violation.
-//
-// If a type is declared in several such source files, the value for the column
-// *nbSourceDeclConcerned* in the result, is greater than 1.
-// The technical-debt per issue is proportional to *nbSourceDeclConcerned*.
-//
-// Notice that namespaces and directories names comparison is **case-sensitive**.
-// A boolean *justACaseSensitiveIssue* indicates if it is just a case-sensitive issue,
-// in which case the technical-debt is divided by two.
-//
-
-//
-// To fix a violation of this rule, make sure that the type parent namespace and
-// the directory sub-paths that contains the type source file, are mirrored.
-//
-// Make sure to first check the boolean *justACaseSensitiveIssue*, in which case
-// the issue is easier to fix.
-//
-]]>
- Types with source files stored in the same directory, should be declared in the same namespace
-// ND2104:TypesWithSourceFilesStoredInTheSameDirectoryShouldBeDeclaredInTheSameNamespace
-
-warnif count > 0
-
-// Group JustMyCode types in a lookup
-// where groups are keyed with directories that contain the types' source file(s).
-// Note that a type can be contained in several groups
-// if it is declared in several source files stored in different directories.
-let lookup = JustMyCode.Types.Where(t => t.SourceFileDeclAvailable)
- .ToMultiKeyLookup(
- t => t.SourceDecls.Select(
- decl => decl.SourceFile.FilePath.ParentDirectoryPath).Distinct()
- )
-
-from groupOfTypes in lookup
-let parentNamespaces = groupOfTypes.ParentNamespaces()
-
-// Select group of types (with source files stored in the same directory) …
-// … but contained in several namespaces
-where parentNamespaces.Count() > 1
-
-// mainNamespaces is the namespace that contains many types
-// declared in the directory groupOfTypes .key
-let mainNamespace = groupOfTypes
- .ToLookup(t => t.ParentNamespace)
- .OrderByDescending(g => g.Count()).First().Key
-
-// Select types with source files stored in the same directory,
-// but contained in namespaces different than mainNamespace.
-let typesOutOfMainNamespace = groupOfTypes
- .Where(t => t.ParentNamespace != mainNamespace &&
- t.ParentAssembly == mainNamespace.ParentAssembly)
-
- // Filter types declared on several source files that contain generated methods
- // because typically such type contains one or several partial definitions generated.
- // These partially generated types would be false positive for the present rule.
- .Where(t => t.SourceDecls.Count() == 1 ||
- t.Methods.Count(m => JustMyCode.Contains(m)) == 0)
-where typesOutOfMainNamespace.Count() > 0
-
-let typesInMainNamespace = groupOfTypes.Where(t => t.ParentNamespace == mainNamespace)
-
-select new {
- mainNamespace,
- typesOutOfMainNamespace,
- typesInMainNamespace,
- Debt = (2+5*typesOutOfMainNamespace.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// For a solid code structure and organization, do mirror the namespaces
-// hierarchy and the directories hierarchy containing source files.
-//
-// Doing so is a widely accepted convention, and not respecting this convention
-// will lead to less maintainable and less browsable code.
-//
-// Respecting this convention means that types with source files stored in the same directory,
-// should be declared in the same namespace.
-//
-// For each directory that contains several source files, where most types are declared
-// in a namespace (what we call the **main namespace**) and a few types are declared
-// out of the *main namespace*, this code rule matches:
-//
-// • The *main namespace*
-//
-// • **typesOutOfMainNamespace**: Types declared in source files in the *main namespace*'s directory
-// but that are not in the *main namespace*.
-//
-// • *typesInMainNamespace*: And for informational purposes, types declared in source files in the
-// *main namespace*'s directory, and that are in the *main namespace*.
-//
-
-//
-// Violations of this rule are types in the *typesOutOfMainNamespace* column.
-// Typically such type …
-//
-// • … is contained in the wrong namespace but its source file is stored in the right directory.
-// In such situation the type should be contained in *main namespace*.
-//
-// • … is contained in the right namespace but its source file is stored in the wrong directory
-// In such situation the source file of the type must be moved to the proper parent namespace directory.
-//
-// • … is declared in multiple source files, stored in different directories.
-// In such situation it is preferable that all source files are stored in a single directory.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 2 minutes plus 5 minutes per type in *typesOutOfMainNamespace*.
-//]]>
- Types declared in the same namespace, should have their source files stored in the same directory
-// ND2105:TypesDeclaredInTheSameNamespaceShouldHaveTheirSourceFilesStoredInTheSameDirectory
-
-warnif count > 0
-from @namespace in Application.Namespaces
-
-// Group types of @namespace in a lookup
-// where groups are keyed with directories that contain the types' source file(s).
-// Note that a type can be contained in several groups
-// if it is declared in several source files stored in different directories.
-let lookup = @namespace.ChildTypes.Where(
- t => t.SourceFileDeclAvailable &&
- JustMyCode.Contains(t) &&
- // Don't match ASP.NET application types declared in Global.asax file
- // that typically are in the root directory of the VS project.
- t.SourceDecls.First().SourceFile.FileNameWithoutExtension.ToLower() != "global.asax")
- .ToMultiKeyLookup(
- t => t.SourceDecls.Select(
- decl => decl.SourceFile.FilePath.ParentDirectoryPath).Distinct()
- )
-
-// Are types of @namespaces declared in more than one directory?
-where lookup.Count > 1
-
-// Infer the main folder, preferably the one that has the same name as the namespace.
-let dirs = lookup.Select(types => types.Key)
-let mainDirNullable = dirs.Where(d => d.DirectoryName == @namespace.SimpleName).FirstOrDefault()
-let mainDir = mainDirNullable ?? dirs.First()
-
-// Types declared out of mainDir, are types in group of types declared in a directory different than mainDir!
-let typesDeclaredOutOfMainDir =
- lookup.Where(types => types.Key != mainDir)
- .SelectMany(types => types)
-
- // Filter types declared on several source files that contain generated methods
- // because typically such type contains one or several partial definitions generated.
- // These partially generated types would be false positive for the present rule.
- .Where(t => t.SourceDecls.Count() == 1 ||
- t.Methods.Count(m => JustMyCode.Contains(m)) == 0)
-
-where typesDeclaredOutOfMainDir.Count() > 0
-
-let typesDeclaredInMainDir =
- lookup.Where(types => types.Key == mainDir)
- .SelectMany(types => types)
-
-select new {
- @namespace,
- typesDeclaredOutOfMainDir,
- mainDir = mainDir.ToString(),
- typesDeclaredInMainDir,
- Debt = (2+5*typesDeclaredOutOfMainDir.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// For a solid code structure and organization,
-// do mirror the namespaces hierarchy and the directories hierarchy containing source files.
-//
-// Doing so is a widely accepted convention, and not respecting this convention
-// will lead to less maintainable and less browsable code.
-//
-// Respecting this convention means that types declared in the same namespace,
-// should have their source files stored in the same directory.
-//
-// For each namespace that contains types whose source files
-// are declared in several directories, infer the **main directory**,
-// the directory that naturally hosts source files of types,
-// preferably the directory whose name corresponds with the namespace
-// name. In this context, this code rule matches:
-//
-// • The namespace
-//
-// • **typesDeclaredOutOfMainDir**: types in the namespace whose source files
-// are stored out of the *main directory*.
-//
-// • The *main directory*
-//
-// • *typesDeclaredInMainDir*: for informational purposes, types declared
-// in the namespace, whose source files are stored in the *main directory*.
-//
-
-//
-// Violations of this rule are types in the **typesDeclaredOutOfMainDir** column.
-// Typically such type…
-//
-// • … is contained in the wrong namespace but its source file is stored in the right directory.
-// In such situation the type should be contained in the namespace corresponding to
-// the parent directory.
-//
-// • … is contained in the right namespace but its source file is stored in the wrong directory.
-// In such situation the source file of the type must be moved to the *main directory*.
-//
-// • … is declared in multiple source files, stored in different directories.
-// In such situation it is preferable that all source files are stored in a single directory.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 2 minutes plus 5 minutes per type in *typesDeclaredOutOfMainDir*.
-//]]>
-
-
-
- Mark ISerializable types with SerializableAttribute
-// ND2200:MarkISerializableTypesWithSerializableAttribute
-
-warnif count > 0
-
-from t in Application.Types where
- t.IsPublic &&
- !t.IsDelegate &&
- !t.IsExceptionClass && // Don't match exceptions, since the Exception class
- // implements ISerializable, this would generate
- // too many false positives.
- t.Implement ("System.Runtime.Serialization.ISerializable".AllowNoMatch()) &&
- !t.HasAttribute ("System.SerializableAttribute".AllowNoMatch())
-
-select new {
- t,
- t.NbLinesOfCode,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// To be recognized by the CLR as serializable,
-// types must be marked with the *SerializableAttribute*
-// attribute even if the type uses a custom
-// serialization routine through implementation of
-// the *ISerializable* interface.
-//
-// This rule matches types that implement *ISerializable* and
-// that are not tagged with *SerializableAttribute*.
-//
-
-//
-// To fix a violation of this rule, tag the matched type
-// with *SerializableAttribute* .
-//]]>
- Mark assemblies with CLSCompliant (deprecated)
-// ND2201:MarkAssembliesWithCLSCompliant
-
-warnif count > 0 from a in Application.Assemblies where
- !a.HasAttribute ("System.CLSCompliantAttribute".AllowNoMatch())
-select new {
- a,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule has been deprecated and, as a consequence, it is disabled by default.
-// Feel free to re-enable it if it makes sense in your dev environment.
-//
-// The *Common Language Specification* (CLS) defines naming restrictions,
-// data types, and rules to which assemblies must conform if they are to
-// be used across programming languages. Good design dictates that all
-// assemblies explicitly indicate CLS compliance with **CLSCompliantAttribute**.
-// If the attribute is not present on an assembly, the assembly is not compliant.
-//
-// Notice that it is possible for a CLS-compliant assembly to contain types or
-// type members that are not compliant.
-//
-// This rule matches assemblies that are not tagged with
-// **System.CLSCompliantAttribute**.
-//
-
-//
-// To fix a violation of this rule, tag the assembly with *CLSCompliantAttribute*.
-//
-// Instead of marking the whole assembly as non-compliant, you should determine
-// which type or type members are not compliant and mark these elements as such.
-// If possible, you should provide a CLS-compliant alternative for non-compliant
-// members so that the widest possible audience can access all the functionality
-// of your assembly.
-//]]>
- Mark assemblies with ComVisible (deprecated)
-// ND2202:MarkAssembliesWithComVisible
-
-warnif count > 0 from a in Application.Assemblies where
- !a.HasAttribute ("System.Runtime.InteropServices.ComVisibleAttribute".AllowNoMatch())
-select new {
- a,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule has been deprecated and, as a consequence, it is disabled by default.
-// Feel free to re-enable it if it makes sense in your dev environment.
-//
-// The **ComVisibleAttribute** attribute determines how COM clients access
-// managed code. Good design dictates that assemblies explicitly indicate
-// COM visibility. COM visibility can be set for a whole assembly and then
-// overridden for individual types and type members. If the attribute is not
-// present, the contents of the assembly are visible to COM clients.
-//
-// This rule matches assemblies that are not tagged with
-// **System.Runtime.InteropServices.ComVisibleAttribute**.
-//
-
-//
-// To fix a violation of this rule, tag the assembly with *ComVisibleAttribute*.
-//
-// If you do not want the assembly to be visible to COM clients, set the
-// attribute value to **false**.
-//]]>
- Mark attributes with AttributeUsageAttribute
-// ND2203:MarkAttributesWithAttributeUsageAttribute
-
-warnif count > 0
-from t in JustMyCode.Types where
-
- t.DeriveFrom ("System.Attribute".AllowNoMatch())
-&& !t.HasAttribute ("System.AttributeUsageAttribute".AllowNoMatch())
-
-// AttributeUsageAttribute can be deferred to classes that derive from an abstract attribute class
-&& !t.IsAbstract
-
-// AttributeUsageAttribute can de inherited from a base attribute class (that is not System.Attribute)
-&& !t.BaseClasses.Any(c =>
- c.FullName != "System.Attribute" &&
- c.HasAttribute ("System.AttributeUsageAttribute".AllowNoMatch()))
-
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// When you define a custom attribute, mark it by using **AttributeUsageAttribute**
-// to indicate where in the source code the custom attribute can be applied. The
-// meaning and intended usage of an attribute will determine its valid locations
-// in code. For example, you might define an attribute that identifies the person
-// who is responsible for maintaining and enhancing each type in a library, and
-// that responsibility is always assigned at the type level. In this case, compilers
-// should enable the attribute on classes, enumerations, and interfaces, but should
-// not enable it on methods, events, or properties. Organizational policies and
-// procedures would dictate whether the attribute should be enabled on assemblies.
-//
-// The **System.AttributeTargets** enumeration defines the targets that you can
-// specify for a custom attribute. If you omit *AttributeUsageAttribute*, your
-// custom attribute will be valid for all targets, as defined by the **All** value of
-// *AttributeTargets* enumeration.
-//
-// This rule matches attribute classes that are not tagged with
-// **System.AttributeUsageAttribute**.
-//
-// Abstract attribute classes are not matched since AttributeUsageAttribute
-// can be deferred to derived classes.
-//
-// Attribute classes that have a base class tagged with AttributeUsageAttribute
-// are not matched since in this case attribute usage is inherited.
-//
-
-//
-// To fix a violation of this rule, specify targets for the attribute by using
-// *AttributeUsageAttribute* with the proper *AttributeTargets* values.
-//]]>
- Remove calls to GC.Collect()
-// ND2204:RemoveCallsToGCCollect
-
-warnif count > 0
-
-let gcCollectMethods = ThirdParty.Methods.WithFullNameWildcardMatch(
- "System.GC.Collect(*)").ToHashSetEx()
-
-from m in Application.Methods.UsingAny(gcCollectMethods)
-select new {
- m,
- gcCollectMethodCalled = m.MethodsCalled.Intersect(gcCollectMethods),
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// It is preferable to avoid calling **GC.Collect()**
-// explicitly in order to avoid some performance pitfall.
-//
-// More in information on this here:
-// http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
-//
-// This rule matches application methods that call an
-// overload of the method *GC.Collect()*.
-//
-
-//
-// Remove matched calls to *GC.Collect()*.
-//]]>
- Don't call GC.Collect() without calling GC.WaitForPendingFinalizers()
-// ND2205:DontCallGCCollectWithoutCallingGCWaitForPendingFinalizers
-
-warnif count > 0
-
-let gcCollectMethods = ThirdParty.Methods.WithFullNameWildcardMatch(
- "System.GC.Collect(*)").ToHashSetEx()
-
-from m in Application.Methods.UsingAny(gcCollectMethods) where
- !m.IsUsing ("System.GC.WaitForPendingFinalizers()".AllowNoMatch())
-select new {
- m,
- gcCollectMethodCalled = m.MethodsCalled.Intersect(gcCollectMethods),
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// It is preferable to avoid calling **GC.Collect()**
-// explicitly in order to avoid some performance
-// pitfall. This situation is checked through the
-// default rules: *Remove calls to GC.Collect()*
-//
-// But if you wish to call *GC.Collect()* anyway,
-// you must do it this way:
-//
-// GC.Collect();
-//
-// GC.WaitForPendingFinalizers();
-//
-// GC.Collect();
-//
-// To make sure that finalizer got executed, and
-// object with finalizer got cleaned properly.
-//
-// This rule matches application methods that call an
-// overload of the method *GC.Collect()*, without calling
-// *GC.WaitForPendingFinalizers()*.
-//
-
-//
-// To fix a violation of this rule, if you really
-// need to call *GC.Collect()*, make sure to call
-// *GC.WaitForPendingFinalizers()* properly.
-//]]>
- Enum Storage should be Int32
-// ND2206:EnumStorageShouldBeInt32
-
-warnif count > 0 from f in JustMyCode.Fields where
- f.ParentType.IsEnumeration &&
- f.Name == @"value__" &&
- f.FieldType != null &&
- f.FieldType.FullName != "System.Int32" &&
- !f.IsThirdParty
-select new {
- f,
- f.SizeOfInst,
- f.FieldType,
- Debt = 7.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// An enumeration is a value type that defines a set of related named constants.
-// By default, the **System.Int32** data type is used to store the constant value.
-//
-// Even though you can change this underlying type, it is not necessary or
-// recommended for most scenarios. Note that *no significant performance gain* is
-// achieved by using a data type that is smaller than *Int32*. If you cannot use
-// the default data type, you should use one of the Common Language System
-// (CLS)-compliant integral types, *Byte*, *Int16*, *Int32*, or *Int64* to make
-// sure that all values of the enumeration can be represented in CLS-compliant
-// programming languages.
-//
-// This rule matches enumerations whose underlying type used to store
-// values is not *System.Int32*.
-//
-
-//
-// To fix a violation of this rule, unless size or compatibility issues exist,
-// use *Int32*. For situations where *Int32* is not large enough to hold the values,
-// use *Int64*. If backward compatibility requires a smaller data type, use
-// *Byte* or *Int16*.
-//]]>
- Do not raise too general exception types
-// ND2207:DoNotRaiseTooGeneralExceptionTypes
-
-warnif count > 0
-
-let tooGeneralExceptionTypes = ThirdParty.Types.WithFullNameIn(
- "System.Exception",
- "System.ApplicationException",
- "System.SystemException")
-
-from m in JustMyCode.Methods.ThatCreateAny(tooGeneralExceptionTypes)
-// Make sure we don't match constructor of exception types
-// that actually instantiate System.Exception.
-where !m.IsConstructor || tooGeneralExceptionTypes.All(t => !m.ParentType.DeriveFrom(t))
-let exceptionsCreated = tooGeneralExceptionTypes.Where(t => m.IsUsing(t))
-select new {
- m,
- exceptionsCreated,
- Debt = (15 + 5*exceptionsCreated.Count()).ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// The following exception types are too general
-// to provide sufficient information to the user:
-//
-// • System.Exception
-//
-// • System.ApplicationException
-//
-// • System.SystemException
-//
-// If you throw such a general exception type in a library or framework,
-// it forces consumers to catch all exceptions,
-// including unknown exceptions that they do not know how to handle.
-//
-// This rule matches methods that create an instance of
-// such general exception class.
-//
-
-//
-// To fix a violation of this rule, change the type of the thrown exception
-// to either a more derived type that already exists in the framework,
-// or create your own type that derives from *System.Exception*.
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 15 minutes per method matched, plus 5 minutes per too general
-// exception types instantiated by the method.
-//]]>
- Do not raise reserved exception types
-// ND2208:DoNotRaiseReservedExceptionTypes
-
-warnif count > 0
-
-let reservedExceptions = ThirdParty.Types.WithFullNameIn(
- "System.NullReferenceException",
- "System.ExecutionEngineException",
- "System.IndexOutOfRangeException",
- "System.OutOfMemoryException",
- "System.StackOverflowException",
- "System.InvalidProgramException",
- "System.AccessViolationException",
- "System.CannotUnloadAppDomainException",
- "System.BadImageFormatException",
- "System.DataMisalignedException")
-
-from m in Application.Methods.ThatCreateAny(reservedExceptions)
-let reservedExceptionsCreated = reservedExceptions.Where(t => m.IsUsing(t))
-select new {
- m,
- reservedExceptionsCreated,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// The following exception types are reserved
-// and should be thrown only by the Common Language Runtime:
-//
-// • System.ExecutionEngineException
-//
-// • System.IndexOutOfRangeException
-//
-// • System.NullReferenceException
-//
-// • System.OutOfMemoryException
-//
-// • System.StackOverflowException
-//
-// • System.InvalidProgramException
-//
-// • System.AccessViolationException
-//
-// • System.CannotUnloadAppDomainException
-//
-// • System.BadImageFormatException
-//
-// • System.DataMisalignedException
-//
-// Do not throw an exception of such reserved type.
-//
-// This rule matches methods that create an instance of
-// such reserved exception class.
-//
-
-//
-// To fix a violation of this rule, change the type of the
-// thrown exception to a specific type that is not one of
-// the reserved types.
-//
-// Concerning the particular case of a method throwing
-// *System.NullReferenceException*, often the fix will be either
-// to throw instead *System.ArgumentNullException*, either to
-// use a contract (through MS Code Contracts API or *Debug.Assert()*)
-// to signify that a null reference at that point can only be
-// the consequence of a bug.
-//
-// More generally the idea of using a contract instead of throwing
-// an exception in case of *corrupted state / bug consequence* detected
-// is a powerful idea. It replaces a behavior (throwing exception)
-// with a declarative assertion that basically means: at that point a bug
-// somehow provoqued the detected corrupted state and continuing
-// any processing from now is potentially harmful. The process should be
-// shutdown and the circonstances of the failure should be reported
-// as a bug to the product team.
-//]]>
- Uri fields should be of type System.Uri
-// ND2209:UriFieldsShouldBeOfTypeSystemUri
-
-warnif count > 0 from f in Application.Fields where
- (f.NameLike (@"Uri$") ||
- f.NameLike (@"Url$")) &&
- f.FieldType != null &&
- f.FieldType.FullName != "System.Uri"
-select new {
- f,
- f.FieldType,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// A field with the name ending with *'Uri'* or *'Url'* is deemed
-// to represent a *Uniform Resource Identifier or Locator*.
-// Such field should be of type **System.Uri**.
-//
-// This rule matches fields with the name ending with *'Uri'* or
-// *'Url'* that are not typed with *System.Uri*.
-//
-
-//
-// Rename the field, or change the field type to *System.Uri*.
-//
-// By default issues of this rule have a **Low** severity
-// because they reflect more an advice than a problem.
-//]]>
- Types should not extend System.ApplicationException
-// ND2210:TypesShouldNotExtendSystemApplicationException
-
-warnif count > 0 from t in Application.Types where
- t.DeriveFrom("System.ApplicationException".AllowNoMatch())
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// At .NET Framework version 1 time, it was
-// recommended to derive new exceptions from
-// *ApplicationException*.
-//
-// The recommendation has changed and new
-// exceptions should derive from **System.Exception**
-// or one of its subclasses in the *System* namespace.
-//
-// This rule matches application exception classes
-// that derive from *ApplicationException*.
-//
-
-//
-// Make sure that matched exception types,
-// derive from **System.Exception** or one of its
-// subclasses in the *System* namespace.
-//]]>
- Don't Implement ICloneable
-// ND2211:DontImplementICloneable
-
-warnif count > 0
-from t in Application.Types
-where t.Implement("System.ICloneable".AllowNoMatch())
-
- // Don't warn for classes that derive from a class that implements ICloneable
- && !t.BaseClasses.Any(c => c.Implement("System.ICloneable".AllowNoMatch()))
-
-select new {
- t,
- Debt = 1.ToHours().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// The interface *System.ICloneable* is proposed since the first version of .NET.
-// It is considered as a bad API for several reasons.
-//
-// First, this interface existed even before .NET 2.0 that introduced generics.
-// Hence this interface is not generic and the *Clone()* method returns an *object*
-// reference that needs to be *downcasted* to be useful.
-//
-// Second, this interface doesn't make explicit whether the cloning should be
-// **deep** or **shallow**. The difference between the two behaviors
-// is fundamental (explanation here https://stackoverflow.com/a/184745/27194).
-// Not being able to make the intention explicit leads to confusion.
-//
-// Third, classes that derive from a class that implements *ICloneable*
-// **must** also implement the *Clone()* method, and it is easy to forget
-// this constraint.
-//
-// This rule doesn't warn for classes that derive from a class that
-// implements ICloneable. In this case the issue must be fixed
-// in the base class, or is maybe not fixable if the base class
-// is declared in a third-party assembly.
-//
-
-//
-// Don't implement anymore this interface.
-//
-// You can rename the remaining *Clone()* methods to
-// *DeepClone()* or *ShallowClone()* with a typed result.
-//
-// Or you can propose two custom generic interfaces
-// *IDeepCloneable* with the single method *DeepClone():T*
-// and *IShallowCloneable* with the single method *ShallowClone():T*.
-//
-// Finally you can write custom NDepend rules to make sure
-// that all classes that derive from a class with a virtual
-// clone method, override this method.
-//]]>
-
-
- Collection properties should be read only
-// ND2300:CollectionPropertiesShouldBeReadOnly
-
-warnif count > 0
-
-// First find collectionTypes
-let collectionInterfaces = ThirdParty.Types.WithFullNameIn(
- "System.Collections.ICollection",
- "System.Collections.Generic.ICollection")
-where collectionInterfaces.Count() > 0
-let collectionTypes = Types.ThatImplementAny(collectionInterfaces)
- .Union(collectionInterfaces)
- .ToHashSetEx()
-
-// Then find all property setters that have an associated
-// getter that returns a collection type.
-from propGetter in JustMyCode.Methods.Where(
- m => m.IsPropertyGetter &&
- m.ReturnType != null &&
- collectionTypes.Contains(m.ReturnType))
-
-let propSetter = propGetter.ParentType.Methods.WithSimpleName(
- propGetter.SimpleName.Replace("get_","set_")
- ).FirstOrDefault()
-
-where propSetter != null &&
- !propSetter.IsPrivate && // Ignore private setters since this is private implementation detail
- !propSetter.ParentType.IsPrivate && // Ignore setters of private types
-
- // Ignore properties of serializable types
- !propSetter.ParentType.TypesUsed.Any(t1 => t1.IsAttributeClass && t1.ParentNamespace.Name == "Newtonsoft.Json") &&
- !propSetter.ParentType.HasAttribute("System.Runtime.Serialization.DataContractAttribute".AllowNoMatch()) &&
- !propSetter.ParentType.HasAttribute("System.Xml.Serialization.XmlRootAttribute".AllowNoMatch())
-
-select new {
- propSetter,
- CollectionType = propGetter.ReturnType,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// A writable collection property allows a user to replace the collection with
-// a completely different collection. A read-only property stops the collection
-// from being replaced but still allows the individual members to be set. If
-// replacing the collection is a goal, the preferred *design pattern* is to include
-// a method to remove all the elements from the collection and a method to
-// re-populate the collection. See the *Clear()* and *AddRange()* methods of the
-// *System.Collections.Generic.List* class for an example of this pattern.
-//
-// Both binary and XML serialization support read-only properties that are
-// collections. The *System.Xml.Serialization.XmlSerializer* class has specific
-// requirements for types that implement *ICollection* and *System.Collections.IEnumerable*
-// in order to be serializable.
-//
-// This rule matches property setter methods that assign a collection object.
-//
-
-//
-// To fix a violation of this rule, make the property read-only and, if
-// the design requires it, add methods to clear and re-populate the collection.
-//]]>
- Don't use .NET 1.x HashTable and ArrayList (deprecated)
-// ND2301:DontUseDotNET1HashTableAndArrayList
-
-warnif count > 0
-let forbiddenTypes = ThirdParty.Types.WithFullNameIn(
- "System.Collections.HashTable",
- "System.Collections.ArrayList",
- "System.Collections.Queue",
- "System.Collections.Stack",
- "System.Collections.SortedList")
-where forbiddenTypes.Count() > 0
-from m in Application.Methods.ThatCreateAny(forbiddenTypes)
-let forbiddenTypesUsed = m.MethodsCalled.Where(m1 => m1.IsConstructor && forbiddenTypes.Contains(m1.ParentType)).ParentTypes()
-select new {
- m,
- forbiddenTypesUsed,
- Debt = 15.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule has been deprecated and, as a consequence, it is disabled by default.
-// Feel free to re-enable it if it makes sense in your dev environment.
-//
-// This rule warns about application methods that use a non-generic
-// collection class, including **ArrayList**, **HashTable**, **Queue**,
-// **Stack** or **SortedList**.
-//
-
-//
-// **List** should be preferred over **ArrayList**.
-// It is generic hence you get strongly typed elements.
-// Also, it is faster with *T* as a value types since it avoids boxing.
-//
-// For the same reasons:
-//
-// • **Dictionary** should be prevered over **HashTable**.
-//
-// • **Queue** should be prevered over **Queue**.
-//
-// • **Stack** should be prevered over **Stack**.
-//
-// • **SortedDictionary** or **SortedList** should be prevered over **SortedList**.
-//
-// You can be forced to use *non generic* collections
-// because you are using third party code that requires
-// working with these classes or because you are
-// coding with .NET 1.x, but nowadays this situation should
-// question about using newer updates of .NET.
-// .NET 1.x is an immature platform conpared to newer .NET
-// updates.
-//]]>
- Caution with List.Contains()
-// ND2302:CautionWithListContains
-
-// warnif count > 0 // This query is n ot a rule per default
-
-let containsMethods = ThirdParty.Methods.WithFullNameIn(
- "System.Collections.Generic.List.Contains(T)",
- "System.Collections.Generic.IList.Contains(T)",
- "System.Collections.ArrayList.Contains(Object)")
-
-from m in Application.Methods.UsingAny(containsMethods)
-select new {
- m,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This code query matches calls to *List.Contains()* method.
-//
-// The cost of checking if a list contains an object is proportional
-// to the size of the list. In other words it is a *O(N)* operation.
-// For large lists and/or frequent calls to *Contains()*, prefer using
-// the *System.Collections.Generic.HashSet* class
-// where calls to *Contains()* take a constant
-// time (*O(0)* operation).
-//
-// This code query is not a code rule, because more often than not,
-// calling *O(N) Contains()* is not a mistake. This code query
-// aims at pointing out this potential performance pitfall.
-//]]>
- Prefer return collection abstraction instead of implementation
-// ND2303:PreferReturnCollectionAbstractionInsteadOfImplementation
-
-// warnif count > 0 // This query is n ot a rule per default
-
-let implTypes = ThirdParty.Types.WithFullNameIn(
- "System.Collections.Generic.List",
- "System.Collections.Generic.HashSet",
- "System.Collections.Generic.Dictionary")
-
-from m in Application.Methods.WithReturnTypeIn(implTypes)
-select new {
- m,
- m.ReturnType,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Low
-}
-
-//
-// This code query matches methods that return a
-// collection implementation, such as *List*
-// *HashSet* or *Dictionary*.
-//
-// Most often than not, clients of a method don't
-// need to know the exact implementation of the
-// collection returned. It is preferable to return
-// a collection interface such as *IList*,
-// *ICollection*, *IEnumerable* or
-// *IDictionary*.
-//
-// Using the collection interface instead of the
-// implementation shouldn't applies to all cases,
-// hence this code query is not code rule.
-//]]>
-
-
- P/Invokes should be static and not be publicly visible
-// ND2400:PInvokesShouldBeStaticAndNotBePubliclyVisible
-
-warnif count > 0 from m in Application.Methods where
- !m.IsThirdParty &&
- (m.HasAttribute ("System.Runtime.InteropServices.DllImportAttribute".AllowNoMatch())) &&
- ( m.IsPubliclyVisible ||
- !m.IsStatic)
-select new {
- m,
- m.Visibility,
- m.IsStatic,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// Methods that are marked with the **DllImportAttribute** attribute
-// (or methods that are defined by using the **Declare** keyword in Visual Basic)
-// use **Platform Invocation Services** to access unmanaged code.
-//
-// Such methods should not be exposed. By keeping these methods *private* or *internal*,
-// you make sure that your library cannot be used to breach security by allowing
-// callers access to unmanaged APIs that they could not call otherwise.
-//
-// This rule matches methods tagged with *DllImportAttribute* attribute
-// that are declared as *public* or declared as *non-static*.
-//
-
-//
-// To fix a violation of this rule, change the access level of the method
-// and/or declare it as static.
-//]]>
- Move P/Invokes to NativeMethods class
-// ND2401:MovePInvokesToNativeMethodsClass
-
-warnif count > 0 from m in Application.Methods where
- m.HasAttribute ("System.Runtime.InteropServices.DllImportAttribute".AllowNoMatch()) &&
- m.ParentType.SimpleName != "NativeMethods"
-select new {
- m,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// **Platform Invocation methods**, such as those that are marked by using the
-// **System.Runtime.InteropServices.DllImportAttribute** attribute, or methods
-// that are defined by using the **Declare** keyword in Visual Basic, access
-// unmanaged code. These methods should be in one of the following classes:
-//
-// • **NativeMethods** - This class does not suppress stack walks for unmanaged
-// code permission. (*System.Security.SuppressUnmanagedCodeSecurityAttribute*
-// must not be applied to this class.) This class is for methods that can be
-// used anywhere because a stack walk will be performed.
-//
-// • **SafeNativeMethods** - This class suppresses stack walks for unmanaged
-// code permission. (*System.Security.SuppressUnmanagedCodeSecurityAttribute*
-//is applied to this class.) This class is for methods that are safe for anyone
-// to call. Callers of these methods are not required to perform a full security
-// review to make sure that the usage is secure because the methods are harmless
-// for any caller.
-//
-// • **UnsafeNativeMethods** - This class suppresses stack walks for unmanaged
-// code permission. (*System.Security.SuppressUnmanagedCodeSecurityAttribute*
-// is applied to this class.) This class is for methods that are potentially
-// dangerous. Any caller of these methods must perform a full security review
-// to make sure that the usage is secure because no stack walk will be performed.
-//
-// These classes are declared as *static internal*. The methods in these
-// classes are *static* and *internal*.
-//
-// This rule matches *P/Invoke* methods not declared in such *NativeMethods*
-// class.
-//
-
-//
-// To fix a violation of this rule, move the method to the appropriate
-// **NativeMethods** class. For most applications, moving P/Invokes to a new
-// class that is named **NativeMethods** is enough.
-//]]>
- NativeMethods class should be static and internal
-// ND2402:NativeMethodsClassShouldBeStaticAndInternal
-
-warnif count > 0 from t in Application.Types.WithNameIn(
- @"NativeMethods", "SafeNativeMethods", "UnsafeNativeMethods") where
- t.IsPublic || !t.IsStatic
-select new {
- t,
- t.Visibility,
- t.IsStatic,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// In the description of the default rule *Move P/Invokes to NativeMethods class*
-// it is explained that *NativeMethods* classes that host *P/Invoke* methods,
-// should be declared as *static* and *internal*.
-//
-// This code rule warns about *NativeMethods* classes that are not declared
-// *static* and *internal*.
-//
-
-//
-// Matched *NativeMethods* classes must be declared as *static* and *internal*.
-//]]>
-
-
- Don't create threads explicitly
-// ND2500:DontCreateThreadsExplicitly
-
-warnif count > 0 from m in Application.Methods where
- m.CreateA ("System.Threading.Thread".AllowNoMatch())
-select new {
- m,
- Debt = 60.ToMinutes().ToDebt(),
- Severity = Severity.Critical
-}
-
-//
-// This code rule warns about methods that create *threads* explicitly
-// by creating an instance of the class *System.Threading.Thread*.
-//
-// Prefer using the thread pool instead of creating manually your
-// own threads. Threads are costly objects. They take approximately
-// 200,000 cycles to create and about 100,000 cycles to destroy.
-// By default they reserve 1 Mega Bytes of virtual memory for its
-// stack and use 2,000-8,000 cycles for each context switch.
-//
-// As a consequence, it is preferable to let the thread pool
-// recycle threads.
-//
-
-//
-// Instead of creating explicitly threads, use the **Task Parralel
-// Library** *(TPL)* that relies on the CLR thread pool.
-//
-// Introduction to TPL: https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
-//
-// TPL and the CLR v4 thread pool:
-// http://www.danielmoth.com/Blog/New-And-Improved-CLR-4-Thread-Pool-Engine.aspx
-//
-// By default issues of this rule have a **Critical** severity
-// because creating threads can have severe consequences.
-//]]>
- Don't use dangerous threading methods
-// ND2501:DontUseDangerousThreadingMethods
-
-warnif count > 0
-
-let wrongMethods = ThirdParty.Methods.WithFullNameIn(
-
- "System.Threading.Thread.Abort()",
- "System.Threading.Thread.Abort(Object)",
-
- "System.Threading.Thread.Sleep(Int32)",
-
- "System.Threading.Thread.Suspend()",
- "System.Threading.Thread.Resume()")
-
-from m in Application.Methods.UsingAny(wrongMethods)
-select new {
- m,
- suppressCallsTo = m.MethodsCalled.Intersect(wrongMethods),
- Debt = 40.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns about using the methods
-// *Abort()*, *Sleep()*, *Suspend()* or *Resume()*
-// declared by the *Thread* class.
-//
-// • Usage of *Thread.Abort()* is dangerous.
-// More information on this here:
-// http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
-//
-// • Usage of *Thread.Sleep()* is a sign of
-// flawed design. More information on this here:
-// http://msmvps.com/blogs/peterritchie/archive/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program.aspx
-//
-// • *Suspend()* and *Resume()* are dangerous threading methods, marked as obsolete.
-// More information on workaround here:
-// http://stackoverflow.com/questions/382173/what-are-alternative-ways-to-suspend-and-resume-a-thread
-//
-
-//
-// Suppress calls to *Thread* methods exposed in the
-// *suppressCallsTo* column in the rule result.
-//
-// Use instead facilities offered by the **Task Parralel
-// Library** *(TPL)* :
-// https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
-//]]>
- Monitor TryEnter/Exit must be both called within the same method
-// ND2502:MonitorTryEnterExitMustBeBothCalledWithinTheSameMethod
-
-warnif count > 0
-
-let enterMethods = ThirdParty.Methods.WithFullNameWildcardMatchIn(
- "System.Threading.Monitor.Enter(*",
- "System.Threading.Monitor.TryEnter(*")
-
-from m in Application.Methods.UsingAny(enterMethods)
-where
- !m.IsUsing ("System.Threading.Monitor.Exit(Object)".AllowNoMatch())
-select new {
- m,
- enterMethodsCalled = m.MethodsCalled.Intersect(enterMethods),
- Debt = 20.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns when **System.Threading.Monitor** *Enter()*
-// (or *TryEnter()*) and *Exit() methods are not called within
-// the same method.
-//
-// Doing so makes the code *less readable*, because it gets harder
-// to locate when **critical sections** begin and end.
-//
-// Also, you expose yourself to complex and error-prone scenarios.
-//
-
-//
-// Refactor matched methods to make sure that *Monitor critical
-// sections* begin and end within the same method. Basics scenarios
-// can be handled through the C# **lock** keyword. Using explicitly
-// the class *Monitor* should be left for advanced situations,
-// that require calls to methods like *Wait()* and *Pulse()*.
-//
-// More information on using the *Monitor* class can be found here:
-// http://www.codeproject.com/Articles/13453/Practical-NET-and-C-Chapter
-//]]>
- ReaderWriterLock AcquireLock/ReleaseLock must be both called within the same method
-// ND2503:ReaderWriterLockAcquireLockReleaseLockMustBeBothCalledWithinTheSameMethod
-
-warnif count > 0
-
-let acquireLockMethods = ThirdParty.Methods.WithFullNameWildcardMatch(
- "System.Threading.ReaderWriterLock.Acquire*Lock(*")
-
-let releaseLockMethods = ThirdParty.Methods.WithFullNameWildcardMatch(
- "System.Threading.ReaderWriterLock.Release*Lock(*")
-
-from m in Application.Methods.UsingAny(acquireLockMethods)
- .Except(Application.Methods.UsingAny(releaseLockMethods))
-select new {
- m,
- acquireLockMethods = m.MethodsCalled.Intersect(acquireLockMethods),
- Debt = 20.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns when **System.Threading.ReaderWriterLock**
-// acquire and release, reader or writer locks methods are not called
-// within the same method.
-//
-// Doing so makes the code *less readable*, because it gets harder
-// to locate when **critical sections** begin and end.
-//
-// Also, you expose yourself to complex and error-prone scenarios.
-//
-
-//
-// Refactor matched methods to make sure that *ReaderWriterLock
-// read or write critical sections* begin and end within the
-// same method.
-//]]>
- Don't tag instance fields with ThreadStaticAttribute
-// ND2504:DontTagInstanceFieldsWithThreadStaticAttribute
-
-warnif count > 0
-from f in Application.Fields
-where !f.IsStatic &&
- f.HasAttribute ("System.ThreadStaticAttribute".AllowNoMatch())
-select new {
- f,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule warns when the attribute **System.ThreadStaticAttribute**
-// is tagging *instance* fields. As explained in documentation, this attribute
-// is designed to tag only *static* fields.
-// https://msdn.microsoft.com/en-us/library/system.threadstaticattribute
-//
-
-//
-// Refactor the code to make sure that all fields tagged with
-// *ThreadStaticAttribute* are *static*.
-//]]>
- Method non-synchronized that read mutable states
-// ND2505:MethodNonSynchronizedThatReadMutableStates
-
-from m in Application.Methods where
- (m.ReadsMutableObjectState || m.ReadsMutableTypeState) &&
- !m.IsUsing ("System.Threading.Monitor".AllowNoMatch()) &&
- !m.IsUsing ("System.Threading.ReaderWriterLock".AllowNoMatch())
-select new {
- m,
- mutableFieldsUsed = m.FieldsUsed.Where(f => !f.IsImmutable)
-}
-
-//
-// Mutable object states are instance fields that
-// can be modified through the lifetime of the object.
-//
-// Mutable type states are static fields that can be
-// modified through the lifetime of the program.
-//
-// This query lists methods that read mutable state
-// without synchronizing access. In the case of
-// multi-threaded program, doing so can lead to
-// state corruption.
-//
-// This code query is not a code rule because more often
-// than not, a match of this query is not an issue.
-//]]>
-
-
- Method should not return concrete XmlNode
-// ND2600:MethodShouldNotReturnConcreteXmlNode
-
-warnif count > 0
-
-let concreteXmlTypes = ThirdParty.Types.ThatDeriveFromAny(
- ThirdParty.Types.WithFullName("System.Xml.XmlNode"))
-
-from m in Application.Methods.WithReturnTypeIn(concreteXmlTypes)
-select new {
- m,
- m.ReturnType,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns about method whose return type is
-// **System.Xml.XmlNode** or any type derived from *XmlNode*.
-//
-// *XmlNode* implements the interface **System.Xml.Xpath.IXPathNavigable**.
-// In most situation, returning this interface instead of the concrete
-// type is a better *design* choice that will abstract client code
-// from implementation details.
-//
-
-//
-// To fix a violation of this rule, change the concrete returned type
-// to the suggested interface *IXPathNavigable* and refactor clients
-// code if possible.
-//]]>
- Types should not extend System.Xml.XmlDocument
-// ND2601:TypesShouldNotExtendSystemXmlXmlDocument
-
-warnif count > 0 from t in Application.Types where
- t.DeriveFrom("System.Xml.XmlDocument".AllowNoMatch())
-select new {
- t,
- Debt = 20.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule warns aboud subclasses of **System.Xml.XmlDocument**.
-//
-// Do not create a subclass of *XmlDocument* if you want to
-// create an XML view of an underlying object model or data source.
-//
-
-//
-// Instead of subclassing *XmlDocument*, you can use the interface
-// **System.Xml.XPath.IXPathNavigable** implemented by the class
-// *XmlDocument*.
-//
-// An alternative of using *XmlDocument*, is to use
-// **System.Xml.Linq.XDocument**, aka **LINQ2XML**.
-// More information on this can be found here:
-// http://stackoverflow.com/questions/1542073/xdocument-or-xmldocument
-//]]>
-
-
- Float and Date Parsing must be culture aware
-// ND2700:FloatAndDateParsingMustBeCultureAware
-
-warnif count > 0
-
-let cultureUnawareMethods =
- (from m in ThirdParty.Types.WithFullNameIn(
- "System.DateTime",
- "System.Single",
- "System.Double",
- "System.Decimal").ChildMethods()
- where m.NbParameters > 0 &&
- (m.SimpleName.EqualsAny(
- "Parse", "TryParse", "ToString")) &&
- !m.Name.Contains("IFormatProvider")
- select m).ToHashSetEx()
-
-from m in Application.Methods.UsingAny(cultureUnawareMethods)
-let cultureUnawareMethodsCalled = m.MethodsCalled.Intersect(cultureUnawareMethods)
-select new {
- m,
- shouldntCall = cultureUnawareMethodsCalled,
- Debt = (5 + 3*cultureUnawareMethodsCalled.Count()).ToMinutes().ToDebt(),
- Severity = 5*cultureUnawareMethodsCalled.Count().ToMinutes().ToAnnualInterest()
-}
-
-//
-// Globalization is the design and development of applications that support
-// localized user interfaces and regional data for users in multiple cultures.
-//
-// This rule warns about the usage of *non-globalized overloads* of
-// the methods **Parse()**, **TryParse()** and **ToString()**,
-// of the types **DateTime**, **float**, **double** and **decimal**.
-// This is the symptom that your application is *at least partially*
-// not globalized.
-//
-// *Non-globalized overloads* of these methods are the overloads
-// that don't take a parameter of type **IFormatProvider**.
-//
-
-//
-// Globalize your applicaton and make sure to use the globalized overloads
-// of these methods. In the column **MethodsCallingMe** of this rule result
-// are listed the methods of your application that call the
-// *non-globalized overloads*.
-//
-// More information on **Creating Globally Aware Applications** here:
-// https://msdn.microsoft.com/en-us/library/cc853414(VS.95).aspx
-//
-// The estimated Debt, which means the effort to fix such issue,
-// is equal to 5 minutes per application method calling at least one
-// non-culture aware method called, plus 3 minutes per non-culture aware
-// method called.
-//]]>
-
-
- Mark assemblies with assembly version
-// ND2800:MarkAssembliesWithAssemblyVersion
-
-warnif count > 0 from a in Application.Assemblies where
- !a.HasAttribute ("System.Reflection.AssemblyVersionAttribute".AllowNoMatch())
-select new {
- a,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// The identity of an assembly is composed of the following information:
-//
-// • Assembly name
-//
-// • Version number
-//
-// • Culture
-//
-// • Public key (for strong-named assemblies).
-//
-// The .NET Framework uses the version number to uniquely identify an
-// assembly, and to bind to types in strong-named assemblies. The
-// version number is used together with version and publisher policy.
-// By default, applications run only with the assembly version with
-// which they were built.
-//
-// This rule matches assemblies that are not tagged with
-// **System.Reflection.AssemblyVersionAttribute**.
-//
-
-//
-// To fix a violation of this rule, add a version number to the assembly
-// by using the *System.Reflection.AssemblyVersionAttribute* attribute.
-//]]>
- Assemblies should have the same version
-// ND2801:AssembliesShouldHaveTheSameVersion
-
-warnif count > 0
-let versionsLookup = Application.Assemblies.ToLookup(a => a.Version, a=> a)
-let mostRepresentedVersion = versionsLookup.OrderByDescending(v => v.Count()).First().Key
-from v in versionsLookup
-where v.Key != mostRepresentedVersion
-from a in v.ToArray()
-select new {
- a ,
- version = v.Key,
- mostRepresentedVersion,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule reports application assemblies that have a version different
-// than the version shared by most of application assemblies.
-//
-// Before fixing these issues, double check if there is a valid reason
-// for dealing with more than one assembly version number.
-// Typically this happens when the analyzed code base is made of assemblies
-// that are not *compiled, developed or deployed* together.
-//
-
-//
-// If all assemblies of your application should have the same version number,
-// just use the attribute **System.Reflection.AssemblyVersion** in a source
-// file shared by the assemblies.
-//
-// Typically this source file is generated by a dedicated *MSBuild* task
-// like this one http://www.msbuildextensionpack.com/help/4.0.5.0/html/d6c3b5e8-00d4-c826-1a73-3cfe637f3827.htm.
-//
-// Here you can find interesting assemblies versioning advices.
-// http://stackoverflow.com/a/3905443/27194
-//
-// By default issues of this rule have a severity set to **major** since
-// unproper assemblies versioning can lead to complicated deployment problem.
-//]]>
-
-
- Public methods returning a reference needs a contract to ensure that a non-null reference is returned
-// ND2900:PublicMethodsReturningAReferenceNeedsAContractToEnsureThatANonNullReferenceIsReturned
-
-warnif count > 0
-let ensureMethods = Application.Methods.WithFullName(
- "System.Diagnostics.Contracts.__ContractsRuntime.Ensures(Boolean,String,String)")
-
-from ensureMethod in ensureMethods
-from m in ensureMethod.ParentAssembly.ChildMethods where
- m.IsPubliclyVisible &&
- !m.IsAbstract &&
- m.ReturnType != null &&
- // Identify that the return type is a reference type
- (m.ReturnType.IsClass || m.ReturnType.IsInterface) &&
- !m.IsUsing(ensureMethod) &&
-
- // Don't match method not implemented yet!
- !m.CreateA("System.NotImplementedException".AllowNoMatch())
-
-select new {
- m,
- ReturnTypeReference = m.ReturnType,
- Debt = (5+3*m.MethodsCallingMe.Count()).ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// **Code Contracts** are useful to decrease ambiguity between callers and callees.
-// Not ensuring that a reference returned by a method is *non-null* leaves ambiguity
-// for the caller. This rule matches methods returning an instance of a reference type
-// (class or interface) that doesn't use a **Contract.Ensure()** method.
-//
-// *Contract.Ensure()* is defined in the **Microsoft Code Contracts for .NET**
-// library, and is typically used to write a code contract on returned reference:
-// *Contract.Ensures(Contract.Result() != null, "returned reference is not null");*
-// https://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970
-//
-
-//
-// Use *Microsoft Code Contracts for .NET* on the public surface of your API,
-// to remove most ambiguity presented to your client. Most of such ambiguities
-// are about *null* or *not null* references.
-//
-// Don't use *null* reference if you need to define a method that might not
-// return a result. Use instead the **TryXXX()** pattern exposed for example
-// in the *System.Int32.TryParse()* method.
-//
-// The estimated Debt, which means the effort to fix such issue, is equal
-// to 5 minutes per public application method that might return a null reference
-// plus 3 minutes per method calling such method.
-//]]>
-
-
-
- Discard generated Assemblies from JustMyCode
-// ND3000:DiscardGeneratedAssembliesFromJustMyCode
-
-notmycode
-from a in Application.Assemblies where
-// Assemblies generated for Xsl IL compilation for example are tagged with this attribute
-a.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch())
-select a
-
-//
-// This code query is prefixed with **notmycode**.
-// This means that all application assemblies matched by this
-// code query are removed from the *code base view* **JustMyCode.Assemblies**.
-// It also means that all *namespaces*, *types*, *methods* and
-// *fields* contained in a matched assembly are removed from
-// the code base view *JustMyCode*.
-// The code base view *JustMyCode* is used by most default code queries
-// and rules.
-//
-// So far this query only matches application assemblies tagged
-// with *System.CodeDom.Compiler.GeneratedCodeAttribute*.
-// Make sure to make this query richer to discard your generated
-// assemblies from the NDepend rules results.
-//
-// *notmycode* queries are executed before running others
-// queries and rules. Also modifying a *notmycode* query
-// provokes re-run of queries and rules that rely
-// on the *JustMyCode* code base view.
-//
-// Several *notmycode* queries can be written to match *assemblies*,
-// in which case this results in cumulative effect.
-//
-// Online documentation:
-// https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode
-//]]>
- Discard generated Namespaces from JustMyCode
-// ND3001:DiscardGeneratedNamespacesFromJustMyCode
-
-notmycode
-
-// First gather assemblies written with VB.NET
-let vbnetAssemblies = Application.Assemblies.Where(
- a => a.SourceDecls.Any(decl => decl.SourceFile.FileNameExtension.ToLower() == ".vb"))
-// Then find the My namespace and its child namespaces.
-let vbnetMyNamespaces = vbnetAssemblies.ChildNamespaces().Where(
- n => n.SimpleName == "My" ||
- n.ParentNamespaces.Any(nParent => nParent.SimpleName == "My"))
-
-
-let generatedNamespace = Application.Namespaces.WithFullNameIn(
- // COM/Import mshtml namespace and all its types are not-my-code
- "mshtml",
- // Roslyn can generate types in these namespaces, consider them as not-my-code
- "Microsoft.CodeAnalysis",
- "System.Runtime.CompilerServices"
-
-).Concat(Application.Namespaces.WithSimpleNameIn(
- // Don't match types generated by the Refit infrastructure like the class PreserveAttribute
- "RefitInternalGenerated"))
-
-// Discard types generated in Microsoft.Office.* namespaces.
-// Issues won't be reported on this code. Especially issues related
-// to the rule "Interface name should begin with a 'I'" broken
-// by many interfaces in these namespaces.
-let microsoftOffices = Application.Namespaces.Where(n => n.Name.StartsWith("Microsoft.Office"))
-
-from n in vbnetMyNamespaces.Concat(generatedNamespace).Concat(microsoftOffices)
-select n
-
-//
-// This code query is prefixed with **notmycode**.
-// This means that all application namespaces matched by this
-// code query are removed from the *code base view* **JustMyCode.Namespaces**.
-// It also means that all *types*, *methods* and *fields* contained in a
-// matched namespace are removed from the code base view *JustMyCode*.
-// The code base view *JustMyCode* is used by most default code queries
-// and rules.
-//
-// So far this query matches the **My** namespaces generated
-// by the VB.NET compiler. This query also matches namespaces named
-// **mshtml** or **Microsoft.Office.*** that are generated by tools.
-//
-// *notmycode* queries are executed before running others
-// queries and rules. Also modifying a *notmycode* query
-// provokes re-run of queries and rules that rely
-// on the *JustMyCode* code base view.
-//
-// Several *notmycode* queries can be written to match *namespaces*,
-// in which case this results in cumulative effect.
-//
-// Online documentation:
-// https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode
-//]]>
- Discard generated Types from JustMyCode
-// ND3002:DiscardGeneratedTypesFromJustMyCode
-
-notmycode
-
-// Define some sets to quickly test EntityFramework generated types
-let efContexts = Application.Types.Where(t =>
- t.DeriveFrom("System.Data.Entity.DbContext".AllowNoMatch()) &&
- t.SourceDecls.Count(sd => sd.SourceFile.FileName.ToLower().EndsWithAny(".context.cs", ".context.vb")) == 1).ToHashSetEx()
-let efEntities = Application.Types.UsedByAny(efContexts).ToHashSetEx()
-let efMigrations = Application.Types.Where(t => t.DeriveFrom("System.Data.Entity.Migrations.DbMigration".AllowNoMatch())).ToHashSetEx()
-let efModelSnapshots = Application.Types.Where(t => t.DeriveFrom("Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot".AllowNoMatch())).ToHashSetEx()
-
-from t in Application.Types where
-
- // Don't consider anonymous types as JustMyCode
- // C# and VB.NET anonymous types generated by the compiler satisfies these conditions
- (t.IsGeneratedByCompiler &&
- t.ParentNamespace.Name.Length == 0 &&
- t.SimpleNameLike("AnonymousType")) ||
-
- // Resources, Settings, or typed DataSet generated types for example, are tagged with this attribute
- t.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||
-
- // This attribute identifies a type or member that is not part of the user code for an application.
- t.HasAttribute ("System.Diagnostics.DebuggerNonUserCodeAttribute".AllowNoMatch()) ||
-
- // This attribute identifies a type that is defined with COM, elsewhere, so consider it not-my-code.
- t.HasAttribute ("System.Runtime.InteropServices.GuidAttribute".AllowNoMatch()) ||
-
- // Delegate types are always generated
- t.IsDelegate ||
-
- // Discard ASP.NET page types generated by aspnet_compiler.exe
- // See: https://www.ndepend.com/FAQ.aspx#ASPNET
- t.ParentNamespace.Name.EqualsAny("ASP", "__ASP") ||
-
- // Discard ASP.NET special types
- (t.SimpleName.EqualsAny("Startup","BundleConfig","RouteConfig") &&
- ThirdParty.Assemblies.WithNameWildcardMatchIn("System.Web*", "Microsoft.AspNetCore*").Any()) ||
-
- // Discard DataSet classes and their nested types
- (t.DeriveFrom("System.Data.DataSet".AllowNoMatch()) &&
- t.HasAttribute("System.ComponentModel.DesignerCategoryAttribute".AllowNoMatch())) ||
- (t.IsNested && t.ParentType != null &&
- t.ParentType.DeriveFrom("System.Data.DataSet".AllowNoMatch()) &&
- t.ParentType.HasAttribute("System.ComponentModel.DesignerCategoryAttribute".AllowNoMatch())) ||
-
- // Discard DataSet TableAdapterManager classes their nested types
- (t.SimpleName == "TableAdapterManager" &&
- t.DeriveFrom("System.ComponentModel.Component".AllowNoMatch())) ||
- (t.IsNested && t.ParentType != null &&
- t.ParentType.SimpleName == "TableAdapterManager" &&
- t.ParentType.DeriveFrom("System.ComponentModel.Component".AllowNoMatch())) ||
-
- // Discard Xamarin form generated types that contain the method LoadDataTemplate()
- (t.IsNested &&
- t.SimpleName.StartsWith("") &&
- t.Methods.Count(m => m.SimpleName == "LoadDataTemplate") == 1 &&
- t.ParentAssembly.AssembliesUsed.Count(a => a.Name.StartsWith("Xamarin")) > 0) ||
-
- // Discard Xamarin Resource types
- (t.IsNested &&
- t.ParentType != null &&
- t.ParentType.Name == "Resource" &&
- t.ParentAssembly.AssembliesUsed.Count(a => a.Name.StartsWith("Xamarin")) > 0) ||
-
- // Discard Entity Framework generated DB context types and entities types used by DB context types!
- efContexts.Contains(t) ||
- efEntities.Contains(t) ||
- efMigrations.Contains(t) ||
- efModelSnapshots.Contains(t) ||
-
- // Discard types generated for code contract
- t.FullName.StartsWith("System.Diagnostics.Contracts.__ContractsRuntime") ||
- t.FullName == "System.Diagnostics.Contracts.RuntimeContractsAttribute" ||
-
- // Discard all types declared in a folder path containing the word "generated"
- (t.SourceFileDeclAvailable &&
- t.SourceDecls.All(s => s.SourceFile.FilePath.ParentDirectoryPath.ToString().ToLower().Contains("generated"))) ||
-
- // Types created by the test infrastructure
- t.FullName == "AutoGeneratedProgram" ||
-
- // Discard special types generated by the Roslyn compiler that are typically used by several methods
- // and as a consequence, cannot be merged in application code through the option
- // NDepend Project Properties > Analysis > Merge Code Generated by Compiler into Application Code
- (t.IsGeneratedByCompiler && t.IsNested && t.SimpleName.StartsWith("<>c"))
-
-select t
-
-//
-// This code query is prefixed with **notmycode**.
-// This means that all application types matched by this
-// code query are removed from the *code base view* **JustMyCode.Types**.
-// It also means that all *methods* and *fields* contained in a
-// matched type are removed from the code base view *JustMyCode*.
-// The code base view *JustMyCode* is used by most default code queries
-// and rules.
-//
-// So far this query matches several well-identified generated
-// types, like the ones tagged with *System.CodeDom.Compiler.GeneratedCodeAttribute*.
-// Make sure to make this query richer to discard your generated
-// types from the NDepend rules results.
-//
-// *notmycode* queries are executed before running others
-// queries and rules. Also modifying a *notmycode* query
-// provokes re-run of queries and rules that rely
-// on the *JustMyCode* code base view.
-//
-// Several *notmycode* queries can be written to match *types*,
-// in which case this results in cumulative effect.
-//
-// Online documentation:
-// https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode
-//]]>
- Discard generated and designer Methods from JustMyCode
-// ND3003:DiscardGeneratedAndDesignerMethodsFromJustMyCode
-
-notmycode
-
-//
-// First define source files paths to discard
-//
-from a in Application.Assemblies
-where a.SourceFileDeclAvailable
-let asmSourceFilesPaths = a.SourceDecls.Select(s => s.SourceFile.FilePath)
-
-let sourceFilesPathsToDiscard = (
- from filePath in asmSourceFilesPaths
- let filePathLower= filePath.ToString().ToLower()
- where
- filePathLower.EndsWithAny(
- ".g.cs", // Popular pattern to name generated files.
- ".g.vb",
- ".generated.cs",
- ".generated.vb") ||
- filePathLower.EndsWithAny(
- ".xaml", // notmycode WPF xaml code
- ".designer.cs", // notmycode C# Windows Forms designer code
- ".designer.vb") // notmycode VB.NET Windows Forms designer code
- ||
- // notmycode methods in source files in a directory containing generated
- filePathLower.Contains("generated")
- select filePath
-).ToHashSetEx()
-
-//
-// Second: discard methods in sourceFilesPathsToDiscard
-//
-from m in a.ChildMethods
-where (m.SourceFileDeclAvailable &&
- sourceFilesPathsToDiscard.Contains(m.SourceDecls.First().SourceFile.FilePath)) ||
- // Generated methods might be tagged with this attribute
- m.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||
-
- // This attributes identifies a type or member that is not part of the user code for an application.
- m.HasAttribute ("System.Diagnostics.DebuggerNonUserCodeAttribute".AllowNoMatch()) ||
-
- // Event adder/remover methods generated by the compiler.
- ((m.IsEventAdder || m.IsEventRemover) && !m.SourceFileDeclAvailable) ||
-
- // Default/implicit constructor generated by the compiler on class and structures that don't have constructor
- (m.IsConstructor &&
- m.NbParameters == 0 &&
- (m.IsPublic || (m.IsProtected && m.ParentType.IsAbstract)) &&
- !m.SourceFileDeclAvailable)
-
-select new { m, m.NbLinesOfCode }
-
-//
-// This code query is prefixed with **notmycode**.
-// This means that all application methods matched by this
-// code query are removed from the *code base view* **JustMyCode.Methods**.
-// The code base view *JustMyCode* is used by most default code queries
-// and rules.
-//
-// So far this query matches several well-identified generated
-// methods, like the ones tagged with *System.CodeDom.Compiler.GeneratedCodeAttribute*,
-// or the ones declared in a source file suffixed with *.designer.cs*.
-// Make sure to make this query richer to discard your generated
-// methods from the NDepend rules results.
-//
-// *notmycode* queries are executed before running others
-// queries and rules. Also modifying a *notmycode* query
-// provokes re-run of queries and rules that rely
-// on the *JustMyCode* code base view.
-//
-// Several *notmycode* queries can be written to match *methods*,
-// in which case this results in cumulative effect.
-//
-// Online documentation:
-// https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode
-//]]>
- Discard generated Fields from JustMyCode
-// ND3004:DiscardGeneratedFieldsFromJustMyCode
-
-notmycode
-
-// Define WindowsForm fields defined as fields assigned by the InitializeComponent() WindowsForm methods.
-let winFormInitializeComponentsMethods =
- Application.Methods.WithName("InitializeComponent()")
- .Where(m => m.ParentType.BaseClass != null && m.ParentType.BaseClass.ParentNamespace.Name == "System.Windows.Forms")
-let winFormFields = winFormInitializeComponentsMethods.SelectMany(m => m.FieldsAssigned).ToHashSetEx()
-
-from f in Application.Fields where
-
- // Discard WindowsForm fields
- winFormFields.Contains(f) ||
-
- // Eliminate "components" generated in Windows Form Control context
- (f.Name == "components" && f.ParentType.DeriveFrom("System.Windows.Forms.Control".AllowNoMatch())) ||
-
- // Eliminate tagHelper generated fields
- f.Name == "_tagHelperStringValueBuffer" ||
-
- // Eliminate XAML generated fields
- // IComponentConnector is XAML specific and is automatically implemented for every Window, Page and UserControl.
- f.ParentType.Implement( "System.Windows.Markup.IComponentConnector".AllowNoMatch()) || // WPF IComponentConnector
- f.ParentType.Implement("Windows.UI.Xaml.Markup.IComponentConnector".AllowNoMatch()) || // UWP IComponentConnector
-
- f.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||
-
- // Property backing fields generated by the compiler
- (f.IsGeneratedByCompiler && !f.IsEventDelegateObject) ||
-
- // Match fields generated by the ASP.NET infrastructure
- // in System.Web.UI classes like Page, Control, MasterPage...
- (f.FieldType != null &&
- f.ParentType.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWith("System.Web.UI")) &&
- (f.FieldType.ParentNamespace.Name.StartsWith("System.Web.UI") ||
- f.FieldType.BaseClasses.Any(bc => bc.ParentNamespace.Name.StartsWith("System.Web.UI"))
- )) ||
-
- // Match fields named 'mappingSource' for DataContext classes
- (f.Name == "mappingSource" && f.ParentType.DeriveFrom("System.Data.Linq.DataContext".AllowNoMatch()))
-
-select f
-
-//
-// This code query is prefixed with **notmycode**.
-// This means that all application fields matched by this
-// code query are removed from the *code base view* **JustMyCode.Fields**.
-// The code base view *JustMyCode* is used by most default code queries
-// and rules.
-//
-// This query matches application fields tagged
-// with *System.CodeDom.Compiler.GeneratedCodeAttribute*, and
-// *Windows Form*, *WPF* and *UWP* fields generated by the designer.
-// Make sure to make this query richer to discard your generated
-// fields from the NDepend rules results.
-//
-// *notmycode* queries are executed before running others
-// queries and rules. Also modifying a *notmycode* query
-// provokes re-run of queries and rules that rely
-// on the *JustMyCode* code base view.
-//
-// Several *notmycode* queries can be written to match *fields*,
-// in which case this results in cumulative effect.
-//
-// Online documentation:
-// https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode
-//]]>
- JustMyCode code elements
-from elem in JustMyCode.CodeElements
-select new {
- elem,
- loc = elem.IsCodeContainer ? elem.AsCodeContainer.NbLinesOfCode : null
-}
-
-//
-// This code query enumerates all
-// *assemblies*, *namespaces*, *types*, *methods* and *fields*
-// in your application, that are considered as being your code.
-//
-// This means concretely that the *ICodeBaseView* **JustMyCode**
-// only shows these code elements. This code base view is used by
-// many default code rule to avoid being warned on code elements
-// that you don't consider as your code - typically the code
-// elements generated by a tool.
-//
-// These code elements are the ones that are not matched
-// by any quere prefixed with **notmycode**.
-//]]>
- NotMyCode code elements
-from elem in Application.CodeElements.Where(element => !JustMyCode.Contains(element))
-select new {
- elem,
- loc = elem.IsCodeContainer ? elem.AsCodeContainer.NbLinesOfCode : null
-}
-
-//
-// This code query enumerates all
-// *assemblies*, *namespaces*, *types*, *methods* and *fields*
-// in your application, that are considered as not being your code.
-//
-// This means concretely that the *ICodeBaseView* **JustMyCode**
-// hide these code elements. This code base view is used by
-// many default code rules to avoid being warned on code elements
-// that you don't consider as your code - typically the code
-// elements generated by a tool.
-//
-// These code elements are the ones matched by queries prefixed with
-// **notmycode**.
-//]]>
-
-
-
-
-from issue in Issues
-where issue.WasAdded()
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }]]>
-
-from issue in Issues
-where issue.WasFixed()
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }]]>
-
-from issue in Issues
-where !issue.WasAdded() &&
- (issue.DebtDiff() > Debt.Zero || issue.AnnualInterestDiff() > AnnualInterest.Zero)
-select new {
- issue,
- issue.Debt, debtDiff = issue.DebtDiff(),
- issue.AnnualInterest, annualInterestDiff = issue.AnnualInterestDiff(),
- issue.Severity
-}
-
-//
-// An issue is considered worsened if its *debt* increased since the baseline.
-//
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-//
-]]>
-
-from issue in Issues
-where issue.Severity == Severity.Blocker
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// An issue with the severity **Blocker** cannot move to production, it must be fixed.
-//
-// The severity of an issue is inferred from the issue *annual interest*
-// and thresholds defined in the NDepend Project Properties > Issue and Debt.
-//]]>
-
-from issue in Issues
-where issue.Severity == Severity.Critical
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// An issue with a severity level **Critical** shouldn't move to production.
-// It still can for business imperative needs purposes, but at worth it must be fixed during the next iterations.
-//
-// The severity of an issue is inferred from the issue *annual interest*
-// and thresholds defined in the NDepend Project Properties > Issue and Debt.
-//]]>
-
-from issue in Issues
-where issue.Severity == Severity.High
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// An issue with a severity level **High** should be fixed quickly, but can wait until the next scheduled interval.
-//
-// The severity of an issue is inferred from the issue *annual interest*
-// and thresholds defined in the NDepend Project Properties > issue and Debt.
-//]]>
-
-from issue in Issues
-where issue.Severity == Severity.Medium
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// An issue with a severity level **Medium** is a warning that if not fixed, won't have a significant impact on development.
-//
-// The severity of an issue is inferred from the issue *annual interest*
-// and thresholds defined in the NDepend Project Properties > issue and Debt.
-//]]>
-
-from issue in Issues
-where issue.Severity == Severity.Low
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// The severity level **Low** is used by issues that have a zero, or close to zero,
-// value for **Annual Interest**.
-//
-// Issues with a **Low** or **Medium** severity level represents small improvements,
-// ways to make the code looks more elegant.
-//
-// The **Broken Window Theory** https://en.wikipedia.org/wiki/Broken_windows_theory states that:
-//
-// *"Consider a building with a few broken windows.
-// If the windows are not repaired, the tendency is for vandals to break a few more windows.
-// Eventually, they may even break into the building, and if it's unoccupied, perhaps become
-// squatters or light fires inside."*
-//
-
-// Issues with a *Low* or *Medium* severity level represents the *broken windows* of a code base.
-// If they are not fixed, the tendency is for developers to not care for living
-// in an elegant code, which will result in extra-maintenance-cost in the long term.
-//
-// The severity of an issue is inferred from the issue *annual interest*
-// and thresholds defined in the NDepend Project Properties > issue and Debt.
-//]]>
-
-from issue in Issues
-where issue.Severity.EqualsAny(Severity.Blocker, Severity.Critical, Severity.High)
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// The number of issues with a severity Blocker, Critical or High.
-//
-// An issue with the severity **Blocker** cannot move to production, it must be fixed.
-//
-// An issue with a severity level **Critical** shouldn't move to production.
-// It still can for business imperative needs purposes, but at worth it must be fixed during the next iterations.
-//
-// An issue with a severity level **High** should be fixed quickly, but can wait until the next scheduled interval.
-//]]>
-
-from issue in Issues
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// The number of issues no matter the issue severity.
-//]]>
-
-from issue in context.IssuesSet.AllSuppressedIssues
-select new { issue, issue.Debt, issue.AnnualInterest, issue.Severity }
-
-//
-// The number of issues suppressed with the usage of SuppressMessage.
-// See the suppressed issues documentation here:
-// https://www.ndepend.com/docs/suppress-issues
-//]]>
-
-
-
-from rule in Rules
-select new {
- rule,
- issues = rule.Issues(),
- debt = rule.Debt(),
- annualInterest = rule.AnnualInterest(),
- maxSeverity = rule.IsViolated() && rule.Issues().Any() ?
- (Severity?)rule.Issues().Max(i => i.Severity) : null
-}
-
-//
-// This trend metric counts the number of active rules.
-// This count includes violated and not violated rules.
-// This count includes critical and non critical rules.
-//
-// When no baseline is available, rules that rely on diff are not counted.
-// If you observe that this count slightly decreases with no apparent reason,
-// the reason is certainly that rules that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-from rule in Rules
-where rule.IsViolated()
-select new {
- rule,
- issues = rule.Issues(),
- debt = rule.Debt(),
- annualInterest = rule.AnnualInterest(),
- maxSeverity = rule.IsViolated() && rule.Issues().Any() ?
- (Severity?)rule.Issues().Max(i => i.Severity) : null
-}
-
-//
-// This trend metric counts the number of active rules that are violated.
-// This count includes critical and non critical rules.
-//
-// When no baseline is available, rules that rely on diff are not counted.
-// If you observe that this count slightly decreases with no apparent reason,
-// the reason is certainly that rules that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-from rule in Rules
-where rule.IsViolated() && rule.IsCritical
-select new {
- rule,
- issues = rule.Issues(),
- debt = rule.Debt(),
- annualInterest = rule.AnnualInterest(),
- maxSeverity = rule.IsViolated() && rule.Issues().Any() ?
- (Severity?)rule.Issues().Max(i => i.Severity) : null
-}
-
-//
-// This trend metric counts the number of critical active rules that are violated.
-//
-// The concept of critical rule is useful to pinpoint certain rules that should not be violated.
-//
-// When no baseline is available, rules that rely on diff are not counted.
-// If you observe that this count slightly decreases with no apparent reason,
-// the reason is certainly that rules that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-
-
-from qualityGate in QualityGates
-select new {
- qualityGate ,
- qualityGate.ValueString,
- qualityGate.Status,
-}
-
-//
-// This trend metric counts the number of active quality gates,
-// no matter the gate status (Pass, Warn, Fail).
-//
-// When no baseline is available, quality gates that rely on diff are not counted.
-// If you observe that this count slightly decreases with no apparent reason,
-// the reason is certainly that quality gates that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-from qualityGate in QualityGates
-where qualityGate.Warn
-select new {
- qualityGate ,
- qualityGate.ValueString,
-}
-
-//
-// This trend metric counts the number of active quality gates that warns.
-//
-// When no baseline is available, quality gates that rely on diff are not counted.
-// If you observe that this count slightly decreases with no apparent reason,
-// the reason is certainly that quality gates that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-from qualityGate in QualityGates
-where qualityGate.Fail
-select new {
- qualityGate ,
- qualityGate.ValueString,
-}
-
-//
-// This trend metric counts the number of active quality gates that fails.
-//
-// When no baseline is available, quality gates that rely on diff are not counted.
-// If you observe that this count slightly decreases with no apparent reason,
-// the reason is certainly that quality gates that rely on diff are not counted
-// because the baseline is not defined.
-//]]>
-
-
-
-let timeToDev = codeBase.EffortToDevelop()
-let debt = Issues.Sum(i => i.Debt)
-select 100d * debt.ToManDay() / timeToDev.ToManDay()
-
-//
-// This Trend Metric name is suffixed with (Metric)
-// to avoid query name collision with the Quality Gate with same name.
-//
-// Infer a percentage from:
-//
-// • the estimated total time to develop the code base
-//
-// • and the the estimated total time to fix all issues (the Debt).
-//
-// Estimated total time to develop the code base is inferred from
-// # lines of code of the code base and from the
-// *Estimated number of man-day to develop 1000 logicial lines of code*
-// setting found in NDepend Project Properties > Issue and Debt.
-//
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-// ]]>
-
-Issues.Sum(i => i.Debt).ToManDay()
-
-//
-// This Trend Metric name is suffixed with (Metric)
-// to avoid query name collision with the Quality Gate with same name.
-//
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-//]]>
-
-let debt = Issues.Sum(i => i.Debt)
-let debtInBaseline = IssuesInBaseline.Sum(i => i.Debt)
-select (debt - debtInBaseline).ToManDay()
-
-//
-// This Trend Metric name is suffixed with (Metric)
-// to avoid query name collision with the Quality Gate with same name.
-//
-// Debt added (or fixed if negative) since baseline.
-//
-// Debt documentation: https://www.ndepend.com/docs/technical-debt#Debt
-//]]>
-
-Issues.Sum(i => i.AnnualInterest).ToManDay()
-
-//
-// This Trend Metric name is suffixed with (Metric)
-// to avoid query name collision with the Quality Gate with same name.
-//
-// Annual Interest documentation: https://www.ndepend.com/docs/technical-debt#AnnualInterest
-//]]>
-
-let ai = Issues.Sum(i => i.AnnualInterest)
-let aiInBaseline = IssuesInBaseline.Sum(i => i.AnnualInterest)
-select (ai - aiInBaseline).ToManDay()
-
-//
-// This Trend Metric name is suffixed with (Metric)
-// to avoid query name collision with the Quality Gate with same name.
-//
-// Annual Interest added (or fixed if negative) since baseline.
-//
-// Annual Interest documentation: https://www.ndepend.com/docs/technical-debt#AnnualInterest
-//]]>
-
-(Issues.Sum(i =>i.Debt).BreakingPoint(Issues.Sum(i =>i.AnnualInterest))).TotalYears()
-
-//
-// The **breaking point** of a set of issues is the **debt** divided by the **annual interest**.
-//
-// The *debt* is the estimated cost-to-fix the issues.
-//
-// The *annual interest* is the estimated cost-to-**not**-fix the issues, per year.
-//
-// Hence the *breaking point* is the point in time from now, when not fixing the issues cost as much as fixing the issue.
-//
-// Breaking Point documentation: https://www.ndepend.com/docs/technical-debt#BreakingPoint
-// ]]>
-
-let issues = Issues.Where(i => i.Severity.EqualsAny(Severity.Blocker, Severity.Critical, Severity.High))
-select (issues.Sum(i =>i.Debt).BreakingPoint(issues.Sum(i =>i.AnnualInterest))).TotalYears()
-
-//
-// The **breaking point** of a set of issues is the **debt** divided by the **annual interest**.
-//
-// The *debt* is the estimated cost-to-fix the issues.
-//
-// The *annual interest* is the estimated cost-to-**not**-fix the issues, per year.
-//
-// Hence the *breaking point* is the point in time from now, when not fixing the issues cost as much as fixing the issue.
-//
-// Breaking Point documentation: https://www.ndepend.com/docs/technical-debt#BreakingPoint
-// ]]>
-
-
-
-codeBase.NbLinesOfCode]]>
-
-JustMyCode.Methods.Sum(m => m.NbLinesOfCode)
-
-// JustMyCode is defined by code queries prefixed with 'notmycode'
-// in the group 'Defining JustMyCode'.
-]]>
-
-Application.Methods.Except(JustMyCode.Methods).Sum(m => m.NbLinesOfCode)
-
-// JustMyCode is defined by code queries prefixed with 'notmycode'
-// in the group 'Defining JustMyCode'.
-]]>
-
-from a in Application.Assemblies
-let nbLocAdded = !a.IsPresentInBothBuilds()
- ? a.NbLinesOfCode
- : (a.NbLinesOfCode != null && a.OlderVersion().NbLinesOfCode != null)
- ? a.NbLinesOfCode - (int)a.OlderVersion().NbLinesOfCode
- : 0
-select (double?)nbLocAdded
-
-
-// A value is computed by this Trend Metric query
-// only if a Baseline for Comparison is provided.
-// See Project Properties > Analysis > Baseline for Comparison
-]]>
-
-Application.Assemblies.SelectMany(
- a => a.SourceDecls.Select(sd => sd.SourceFile.FilePathString.ToLower()))
-.Distinct()
-.Count()
-
-//
-// This trend metric counts the number of source files.
-//
-// If a value 0 is obtained, it means that at analysis time,
-// assemblies PDB files were not available.
-// https://www.ndepend.com/docs/ndepend-analysis-inputs-explanation
-//
-// So far source files cannot be matched by a code query.
-// However editing the query "Application Types" and then
-// *Group by source file declarations* will list source files
-// with types source declarations.
-//]]>
-
-codeBase.NbILInstructions
-]]>
-
-Application.Methods.Except(JustMyCode.Methods).Sum(m => m.NbILInstructions)
-
-// JustMyCode is defined by code queries prefixed with 'notmycode'
-// in the group 'Defining JustMyCode'.
-]]>
-
-codeBase.NbLinesOfComment
-
-//
-// This trend metric returns the number of lines of comment
-// counted in application source files.
-//
-// So far commenting information is only extracted from C# source code
-// and VB.NET support is planned.
-//]]>
-
-codeBase.PercentageComment
-
-//
-// This trend metric returns the percentage of comment
-// compared to the number of **logical**lines of code.
-//
-// So far commenting information is only extracted from C# source code
-// and VB.NET support is planned.
-//]]>
-
-from a in Application.Assemblies
-select new {
- a,
- Debt = a.AllDebt(),
- Issues = a.AllIssues(),
- a.NbLinesOfCode
-}
-
-//
-// This trend metric query counts all application assemblies.
-// For each assembly it shows the estimated **all** technical-debt and **all** issues.
-// **All** means debt and issues of the assembly and of its child namespaces, types and members.
-//]]>
-
-from n in Application.Namespaces
-select new {
- n,
- Debt = n.AllDebt(),
- Issues = n.AllIssues(),
- n.NbLinesOfCode
-}
-
-//
-// This trend metric query counts all application namespaces.
-// For each namespace it shows the estimated **all** technical-debt and **all** issues.
-// **All** means debt and issues of the namespace and of its child types and members.
-//]]>
-
-from t in Application.Types.Where(t => !t.IsGeneratedByCompiler)
-select new {
- t,
- Debt = t.AllDebt(),
- Issues = t.AllIssues(),
- t.NbLinesOfCode
-}
-
-//
-// This trend metric query counts all application types non-generated by compiler.
-// For each type it shows the estimated **all** technical-debt and **all** issues.
-// **All** means debt and issues of the type and of its child members.
-//]]>
-
-Application.Types.Where(t => t.IsPubliclyVisible && !t.IsGeneratedByCompiler)]]>
-
-Application.Types.Where(t => t.IsClass && !t.IsGeneratedByCompiler)]]>
-
-Application.Types.Where(t => t.IsClass && t.IsAbstract && !t.IsGeneratedByCompiler)]]>
-
-Application.Types.Where(t => t.IsInterface)]]>
-
-Application.Types.Where(t => t.IsStructure && !t.IsGeneratedByCompiler)]]>
-
-from m in Application.Methods.Where(m => !m.IsGeneratedByCompiler)
-select new {
- m,
- Debt = m.Debt(),
- Issues = m.Issues(),
- m.NbLinesOfCode
-}
-
-//
-// This trend metric query counts all application methods non-generated by compiler.
-// For each method it shows the estimated technical-debt and the issues.
-//]]>
-
-Application.Methods.Where(m => m.IsAbstract)]]>
-
-Application.Methods.Where(m => !m.IsAbstract && !m.IsGeneratedByCompiler)]]>
-
-from f in Application.Fields.Where(f =>
- !f.IsEnumValue &&
- !f.ParentType.IsEnumeration &&
- !f.IsGeneratedByCompiler &&
- !f.IsLiteral)
-select new {
- f,
- Debt = f.AllDebt(),
- Issues = f.AllIssues()
-}
-
-//
-// This trend metric query counts all application fields non-generated by compiler
-// that are not enumeration values nor constant values.
-// For each field it shows the estimated technical-debt and the issues.
-//]]>
-
-
-
-JustMyCode.Methods
- .Max(m => m.NbLinesOfCode)
-
-// Here is the code query to get the (JustMyCode) method with largest # Lines of Code
-// JustMyCode.Methods.OrderByDescending(m => m.NbLinesOfCode).Take(1).Select(m => new {m, m.NbLinesOfCode})]]>
-
-Application.Methods.Where(m => m.NbLinesOfCode > 0)
- .Average(m => m.NbLinesOfCode)]]>
-
-Application.Methods.Where(m => m.NbLinesOfCode >= 3)
- .Average(m => m.NbLinesOfCode)]]>
-
-JustMyCode.Types
- .Max(t => t.NbLinesOfCode)
-
-// Here is the code query to get the (JustMyCode) type with largest # Lines of Code
-// JustMyCode.Types.OrderByDescending(t => t.NbLinesOfCode).Take(1).Select(t => new {t, t.NbLinesOfCode})]]>
-
-Application.Types.Where(t => t.NbLinesOfCode > 0)
- .Average(t => t.NbLinesOfCode)]]>
-
-Application.Methods
- .Max(m => m.CyclomaticComplexity)
-
-// Here is the code query to get the most complex method, according to Cyclomatic Complexity
-// Application.Methods.OrderByDescending(m => m.CyclomaticComplexity).Take(1).Select(m => new {m, m.CyclomaticComplexity})]]>
-
-Application.Methods.Where(m => m.NbLinesOfCode> 0)
- .Average(m => m.CyclomaticComplexity)]]>
-
-Application.Methods
- .Max(m => m.ILCyclomaticComplexity)
-
-// Here is the code query to get the most complex method, according to Cyclomatic Complexity computed from IL code.
-// Application.Methods.OrderByDescending(m => m.ILCyclomaticComplexity).Take(1).Select(m => new {m, m.CyclomaticComplexity})]]>
-
-Application.Methods.Where(m => m.NbILInstructions> 0)
- .Average(m => m.ILCyclomaticComplexity)]]>
-
-Application.Methods
- .Max(m => m.ILNestingDepth)
-
-// Here is the code query to get the method with higher ILNestingDepth.
-// Application.Methods.OrderByDescending(m => m.ILNestingDepth).Take(1).Select(m => new {m, m.ILNestingDepth})]]>
-
-Application.Methods.Where(m => m.NbILInstructions> 0)
- .Average(m => m.ILNestingDepth)]]>
-
-Application.Types
- .Max(t => t.NbMethods)
-
-// Here is the code query to get the (JustMyCode) type with largest # of Methods
-// JustMyCode.Types.OrderByDescending(t => t.NbMethods).Take(1).Select(t => new {t, t.Methods})]]>
-
-Application.Types.Average(t => t.NbMethods)]]>
-
-Application.Types.Where(t => t.IsInterface)
- .Max(t => t.NbMethods)
-
-// Here is the code query to get the (JustMyCode) type with largest # of Methods
-// JustMyCode.Types.OrderByDescending(t => t.NbMethods).Take(1).Select(t => new {t, t.Methods})]]>
-
-JustMyCode.Types.Where(t => t.IsInterface)
- .Average(t => t.NbMethods)]]>
-
-
-
-codeBase.PercentageCoverage]]>
-
-codeBase.NbLinesOfCodeCovered]]>
-
-codeBase.NbLinesOfCodeNotCovered]]>
-
-Application.Methods.Where(m => m.ExcludedFromCoverageStatistics).Sum(m => m.NbLinesOfCode).ToNullableDouble()
-
-//
-// **Lines of Code Uncoverable** are lines of code in methods tagged with an *Uncoverable attribute*
-// or methods in types or assemblies tagged with an *Uncoverable attribute*.
-//
-// These methods can be listed with the code query:
-// *from m in Application.Methods where m.ExcludedFromCoverageStatistics select new { m, m.NbLinesOfCode }*
-//
-// Typically the attribute *System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute*
-// is used as the *Uncoverable attribute*.
-//
-// An additional custom *Uncoverable attribute* can be defined in the:
-// NDepend Project Properties > Analysis > Code Coverage > Un-Coverable attributes.
-//
-// If coverage is imported from VS coverage technologies those attributes are
-// also considered as *Uncoverable attribute*:
-// *System.Diagnostics.DebuggerNonUserCodeAttribute*
-// *System.Diagnostics.DebuggerHiddenAttribute*.
-//
-// If coverage data imported at analysis time is not *in-sync* with the analyzed code base,
-// this code query will also list methods not defined in the coverage data imported.
-//]]>
-
-Application.Types.Where(t => t.PercentageCoverage == 100)
- .Sum(t => t.NbLinesOfCodeCovered)
-
-//
-// A line of code covered by tests is *even more valuable* if it is in a type 100% covered by test.
-//
-// Covering 90% of a class is not enough.
-//
-// • It means that this 10% uncovered code is hard-to-test,
-//
-// • which means that this code is not well-designed,
-//
-// • which means that it is error-prone.
-//
-// Better test error-prone code, isn't it?
-//]]>
-
-Application.Methods.Where(m => m.PercentageCoverage == 100)
- .Sum(m => m.NbLinesOfCodeCovered)
-
-//
-// The same remark than in the Trend Metric **# Lines of Code in Types 100% Covered**
-// applies for method 100% covered.
-//
-// A line of code covered by tests is *even more valuable* if it is in a method 100% covered by test.
-//]]>
-
-
-(from m in JustMyCode.Methods
-
-// Don't match too short methods
-where m.NbLinesOfCode > 10
-
-let CC = m.CyclomaticComplexity
-let uncov = (100 - m.PercentageCoverage) / 100f
-let CRAP = (CC * CC * uncov * uncov * uncov) + CC
-where CRAP != null && CRAP > 30 select CRAP)
-.Max(CRAP => CRAP)
-
-//
-// **Change Risk Analyzer and Predictor** (i.e. CRAP) is a code metric
-// that helps in pinpointing overly complex and untested code.
-// Is has been first defined here:
-// http://www.artima.com/weblogs/viewpost.jsp?thread=215899
-//
-// The Formula is: **CRAP(m) = CC(m)^2 * (1 – cov(m)/100)^3 + CC(m)**
-//
-// • where *CC(m)* is the *cyclomatic complexity* of the method *m*
-//
-// • and *cov(m)* is the *percentage coverage* by tests of the method *m*
-//
-// Matched methods cumulates two highly *error prone* code smells:
-//
-// • A complex method, difficult to develop and maintain.
-//
-// • Non 100% covered code, difficult to refactor without any regression bug.
-//
-// The higher the CRAP score, the more painful to maintain and error prone is the method.
-//
-// An arbitrary threshold of 30 is fixed for this code rule as suggested by inventors.
-//
-// Notice that no amount of testing will keep methods with a Cyclomatic Complexity
-// higher than 30, out of CRAP territory.
-//
-// Notice that CRAP score is not computed for too short methods
-// with less than 10 lines of code.
-//
-// To list methods with higher C.R.A.P scores, please refer to the default rule:
-// *Test and Code Coverage* > *C.R.A.P method code metric*
-//]]>
-
-
-(from m in JustMyCode.Methods
-
-// Don't match too short methods
-where m.NbLinesOfCode > 10
-
-let CC = m.CyclomaticComplexity
-let uncov = (100 - m.PercentageCoverage) / 100f
-let CRAP = (CC * CC * uncov * uncov * uncov) + CC
-where CRAP != null && CRAP > 30 select CRAP)
-.Average(CRAP => CRAP)
-
-//
-// **Change Risk Analyzer and Predictor** (i.e. CRAP) is a code metric
-// that helps in pinpointing overly complex and untested code.
-// Is has been first defined here:
-// http://www.artima.com/weblogs/viewpost.jsp?thread=215899
-//
-// The Formula is: **CRAP(m) = CC(m)^2 * (1 – cov(m)/100)^3 + CC(m)**
-//
-// • where *CC(m)* is the *cyclomatic complexity* of the method *m*
-//
-// • and *cov(m)* is the *percentage coverage* by tests of the method *m*
-//
-// Matched methods cumulates two highly *error prone* code smells:
-//
-// • A complex method, difficult to develop and maintain.
-//
-// • Non 100% covered code, difficult to refactor without any regression bug.
-//
-// The higher the CRAP score, the more painful to maintain and error prone is the method.
-//
-// An arbitrary threshold of 30 is fixed for this code rule as suggested by inventors.
-//
-// Notice that no amount of testing will keep methods with a Cyclomatic Complexity
-// higher than 30, out of CRAP territory.
-//
-// Notice that CRAP score is not computed for too short methods
-// with less than 10 lines of code.
-//
-// To list methods with higher C.R.A.P scores, please refer to the default rule:
-// *Test and Code Coverage* > *C.R.A.P method code metric*
-//]]>
-
-
-
-from a in ThirdParty.Assemblies
-select new { a, a.AssembliesUsingMe }]]>
-
-from n in ThirdParty.Namespaces
-select new { n, n.NamespacesUsingMe }]]>
-
-from t in ThirdParty.Types
-select new { t, t.TypesUsingMe }]]>
-
-from m in ThirdParty.Methods
-select new { m, m.MethodsCallingMe }]]>
-
-from f in ThirdParty.Fields
-where !f.ParentType.IsEnumeration
-select new { f, f.MethodsUsingMe }]]>
-
-from elem in ThirdParty.CodeElements
-where !(elem.IsField && elem.AsField.ParentType.IsEnumeration)
-let users = elem.IsMethod ? elem.AsMethod.MethodsCallingMe.Cast() :
- elem.IsField ? elem.AsField.MethodsUsingMe.Cast() :
- elem.IsType ? elem.AsType.TypesUsingMe.Cast() :
- elem.IsNamespace ? elem.AsNamespace.NamespacesUsingMe.Cast() :
- elem.AsAssembly.AssembliesUsingMe.Cast()
-select new { elem, users }
-]]>
-
-
-
- New assemblies
-from a in Application.Assemblies where a.WasAdded()
-select new { a, a.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *assemblies* that have been added since the *baseline*.
-//]]>
- Assemblies removed
-from a in codeBase.OlderVersion().Application.Assemblies where a.WasRemoved()
-select new { a, a.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *assemblies* that have been removed since the *baseline*.
-//]]>
- Assemblies where code was changed
-from a in Application.Assemblies where a.CodeWasChanged()
-select new {
- a,
- a.NbLinesOfCode,
- oldNbLinesOfCode = a.OlderVersion().NbLinesOfCode.GetValueOrDefault() ,
- delta = (int) a.NbLinesOfCode.GetValueOrDefault() - a.OlderVersion().NbLinesOfCode.GetValueOrDefault()
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *assemblies* in which, code has been changed since the *baseline*.
-//]]>
- New namespaces
-from n in Application.Namespaces where
- !n.ParentAssembly.WasAdded() &&
- n.WasAdded()
-select new { n, n.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *namespaces* that have been added since the *baseline*.
-//]]>
- Namespaces removed
-from n in codeBase.OlderVersion().Application.Namespaces where
- !n.ParentAssembly.WasRemoved() &&
- n.WasRemoved()
-select new { n, n.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *namespaces* that have been removed since the *baseline*.
-//]]>
- Namespaces where code was changed
-from n in Application.Namespaces where n.CodeWasChanged()
-select new {
- n,
- n.NbLinesOfCode,
- oldNbLinesOfCode = n.OlderVersion().NbLinesOfCode.GetValueOrDefault() ,
- delta = (int) n.NbLinesOfCode.GetValueOrDefault() - n.OlderVersion().NbLinesOfCode.GetValueOrDefault()
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *namespaces* in which, code has been changed since the *baseline*.
-//]]>
- New types
-from t in Application.Types where
- !t.ParentNamespace.WasAdded() &&
- t.WasAdded() &&
- !t.IsGeneratedByCompiler
-select new { t, t.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *types* that have been added since the *baseline*.
-//]]>
- Types removed
-from t in codeBase.OlderVersion().Application.Types where
- !t.ParentNamespace.WasRemoved() &&
- t.WasRemoved() &&
- !t.IsGeneratedByCompiler
-select new { t, t.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *types* that have been removed since the *baseline*.
-//]]>
- Types where code was changed
-
-from t in Application.Types where t.CodeWasChanged()
-//select new { t, t.NbLinesOfCode }
-select new {
- t,
- t.NbLinesOfCode,
- oldNbLinesOfCode = t.OlderVersion().NbLinesOfCode ,
- delta = (int?) t.NbLinesOfCode - t.OlderVersion().NbLinesOfCode
-}
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *types* in which, code has been changed since the *baseline*.
-//
-// To visualize changes in code, right-click a matched type and select:
-//
-// • Compare older and newer versions of source file
-//
-// • Compare older and newer versions disassembled with Reflector
-//]]>
- Heuristic to find types moved from one namespace or assembly to another
-let typesRemoved = codeBase.OlderVersion().Types.Where(t => t.WasRemoved())
-let typesAdded = Types.Where(t => t.WasAdded())
-
-from tMoved in typesAdded.Join(
- typesRemoved,
- t => t.Name,
- t => t.Name,
- (tNewer, tOlder) => new { tNewer,
- OlderParentNamespace = tOlder.ParentNamespace,
- OlderParentAssembly = tOlder.ParentAssembly } )
-select tMoved
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *types* moved from one namespace or assembly to another.
-// The heuristic implemented consists in making a **join LINQ query** on
-// type name (without namespace prefix), applied to the two sets of types *added*
-// and types *removed*.
-//]]>
- Types directly using one or several types changed
-let typesChanged = Application.Types.Where(t => t.CodeWasChanged()).ToHashSetEx()
-
-from t in JustMyCode.Types.UsingAny(typesChanged) where
- !t.CodeWasChanged() &&
- !t.WasAdded()
-let typesChangedUsed = t.TypesUsed.Intersect(typesChanged)
-select new { t, typesChangedUsed }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists types *unchanged* since the *baseline*
-// but that use directly some *types* where code has been changed
-// since the *baseline*.
-//
-// For such matched type, the code hasen't been changed, but still the overall
-// behavior might have been changed.
-//
-// The query result includes types changed directly used,
-//]]>
- Types indirectly using one or several types changed
-let typesChanged = Application.Types.Where(t => t.CodeWasChanged()).ToHashSetEx()
-
-// 'depth' represents a code metric defined on types using
-// directly or indirectly any type where code was changed.
-let depth = JustMyCode.Types.DepthOfIsUsingAny(typesChanged)
-
-from t in depth.DefinitionDomain where
- !t.CodeWasChanged() &&
- !t.WasAdded()
-
-let typesChangedDirectlyUsed = t.TypesUsed.Intersect(typesChanged)
-let depthOfUsingTypesChanged = depth[t]
-orderby depthOfUsingTypesChanged
-
-select new {
- t,
- depthOfUsingTypesChanged,
- typesChangedDirectlyUsed
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists types *unchanged* since the *baseline*
-// but that **use directly or indirectly** some *types* where
-// code has been changed since the *baseline*.
-//
-// For such matched type, the code hasen't been changed, but still the overall
-// behavior might have been changed.
-//
-// The query result includes types changed directly used, and the **depth of usage**
-// of types indirectly used, *depth of usage* as defined in the documentation of
-// *DepthOfIsUsingAny()* NDepend API method:
-// https://www.ndepend.com/api/webframe.html?NDepend.API~NDepend.CodeModel.ExtensionMethodsSequenceUsage~DepthOfIsUsingAny.html
-//]]>
- New methods
-from m in Application.Methods where
- !m.ParentType.WasAdded() &&
- m.WasAdded() &&
- !m.IsGeneratedByCompiler
-select new { m, m.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *methods* that have been added since the *baseline*.
-//]]>
- Methods removed
-from m in codeBase.OlderVersion().Application.Methods where
- !m.ParentType.WasRemoved() &&
- m.WasRemoved() &&
- !m.IsGeneratedByCompiler
-select new { m, m.NbLinesOfCode }
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *methods* that have been removed since the *baseline*.
-//]]>
- Methods where code was changed
-from m in Application.Methods where m.CodeWasChanged()
-select new {
- m,
- m.NbLinesOfCode,
- oldNbLinesOfCode = m.OlderVersion().NbLinesOfCode ,
- delta = (int?) m.NbLinesOfCode - m.OlderVersion().NbLinesOfCode
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *methods* in which, code has been changed since the *baseline*.
-//
-// To visualize changes in code, right-click a matched method and select:
-//
-// • Compare older and newer versions of source file
-//
-// • Compare older and newer versions disassembled with Reflector
-//]]>
- Methods directly calling one or several methods changed
-let methodsChanged = Application.Methods.Where(m => m.CodeWasChanged()).ToHashSetEx()
-
-from m in JustMyCode.Methods.UsingAny(methodsChanged ) where
- !m.CodeWasChanged() &&
- !m.WasAdded()
-let methodsChangedCalled = m.MethodsCalled.Intersect(methodsChanged)
-select new {
- m,
- methodsChangedCalled
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists methods *unchanged* since the *baseline*
-// but that call directly some *methods* where code has been changed
-// since the *baseline*.
-//
-// For such matched method, the code hasen't been changed, but still the overall
-// behavior might have been changed.
-//
-// The query result includes methods changed directly used,
-//]]>
- Methods indirectly calling one or several methods changed
-let methodsChanged = Application.Methods.Where(m => m.CodeWasChanged()).ToHashSetEx()
-
-// 'depth' represents a code metric defined on methods using
-// directly or indirectly any method where code was changed.
-let depth = JustMyCode.Methods.DepthOfIsUsingAny(methodsChanged)
-
-from m in depth.DefinitionDomain where
- !m.CodeWasChanged() &&
- !m.WasAdded()
-
-let methodsChangedDirectlyUsed = m.MethodsCalled.Intersect(methodsChanged)
-let depthOfUsingMethodsChanged = depth[m]
-orderby depthOfUsingMethodsChanged
-
-select new {
- m,
- depthOfUsingMethodsChanged,
- methodsChangedDirectlyUsed
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists methods *unchanged* since the *baseline*
-// but that **use directly or indirectly** some *methods* where
-// code has been changed since the *baseline*.
-//
-// For such matched method, the code hasen't been changed, but still the overall
-// behavior might have been changed.
-//
-// The query result includes methods changed directly used, and the **depth of usage**
-// of methods indirectly used, *depth of usage* as defined in the documentation of
-// *DepthOfIsUsingAny()* NDepend API method:
-// https://www.ndepend.com/api/webframe.html?NDepend.API~NDepend.CodeModel.ExtensionMethodsSequenceUsage~DepthOfIsUsingAny.html
-//]]>
- New fields
-from f in Application.Fields where
- !f.ParentType.WasAdded() &&
- f.WasAdded() &&
- !f.IsGeneratedByCompiler
-select f
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *fields* that have been added since the *baseline*.
-//]]>
- Fields removed
-from f in codeBase.OlderVersion().Application.Fields where
- !f.ParentType.WasRemoved() &&
- f.WasRemoved() &&
- !f.IsGeneratedByCompiler
-select f
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *fields* that have been removed since the *baseline*.
-//]]>
- Third party types that were not used and that are now used
-from t in ThirdParty.Types where t.IsUsedRecently()
-select new {
- t,
- t.Methods,
- t.Fields,
- t.TypesUsingMe
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *types* defined in **third-party assemblies**, that were not
-// used at *baseline* time, and that are now used.
-//]]>
- Third party types that were used and that are not used anymore
-from t in codeBase.OlderVersion().Types where t.IsNotUsedAnymore()
-select new {
- t,
- t.Methods,
- t.Fields,
- TypesThatUsedMe = t.TypesUsingMe
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *types* defined in **third-party assemblies**, that were
-// used at *baseline* time, and that are not used anymore.
-//]]>
- Third party methods that were not used and that are now used
-from m in ThirdParty.Methods where
- m.IsUsedRecently() &&
- !m.ParentType.IsUsedRecently()
-select new {
- m,
- m.MethodsCallingMe
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *methods* defined in **third-party assemblies**, that were not
-// used at *baseline* time, and that are now used.
-//]]>
- Third party methods that were used and that are not used anymore
-from m in codeBase.OlderVersion().Methods where
- m.IsNotUsedAnymore() &&
- !m.ParentType.IsNotUsedAnymore()
-select new {
- m,
- MethodsThatCalledMe = m.MethodsCallingMe
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *methods* defined in **third-party assemblies**, that were
-// used at *baseline* time, and that are not used anymore.
-//]]>
- Third party fields that were not used and that are now used
-from f in ThirdParty.Fields where
- f.IsUsedRecently() &&
- !f.ParentType.IsUsedRecently()
-select new {
- f,
- f.MethodsUsingMe
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *fields* defined in **third-party assemblies**, that were not
-// used at *baseline* time, and that are now used.
-//]]>
- Third party fields that were used and that are not used anymore
-from f in codeBase.OlderVersion().Fields where
- f.IsNotUsedAnymore() &&
- !f.ParentType.IsNotUsedAnymore()
-select new {
- f,
- MethodsThatUsedMe = f.MethodsUsingMe
-}
-
-//
-// This query is executed only if a *baseline for comparison* is defined (*diff mode*).
-//
-// This code query lists *fields* defined in **third-party assemblies**, that were
-// used at *baseline* time, and that are not used anymore.
-//]]>
-
-
- Most used types (Rank)
-(from t in Application.Types
- where !t.IsGeneratedByCompiler
- orderby t.Rank descending
- select new { t, t.Rank, t.TypesUsingMe }).Take(100)
-
-//
-// **TypeRank** values are computed by applying
-// the **Google PageRank** algorithm on the
-// graph of types' dependencies. Types with
-// high *Rank* are the most used ones. Not necessarily
-// the ones with the most users types, but the ones
-// used by many types, themselves having a lot of
-// types users.
-//
-// See the definition of the TypeRank metric here:
-// https://www.ndepend.com/docs/code-metrics#TypeRank
-//
-// This code query lists the 100 application types
-// with the higher rank.
-//
-// The main consequence of being used a lot for a
-// type is that each change (both *syntax change*
-// and *behavior change*) will result in potentially
-// a lot of **pain** since most types clients will be
-// **impacted**.
-//
-// Hence it is preferable that types with higher
-// *TypeRank*, are **interfaces**, that are typically
-// less subject changes.
-//
-// Also interfaces avoid clients relying on
-// implementations details. Hence, when the behavior of
-// classes implementing an interface changes, this
-// shouldn't impact clients of the interface.
-// This is *in essence* the
-// **Liskov Substitution Principle**.
-// http://en.wikipedia.org/wiki/Liskov_substitution_principle
-//]]>
- Most used methods (Rank)
-(from m in Application.Methods
- where !m.IsGeneratedByCompiler
- orderby m.Rank descending
- select new { m, m.Rank, m.MethodsCallingMe }).Take(100)
-
-//
-// **MethodRank** values are computed by applying
-// the **Google PageRank** algorithm on the
-// graph of methods' dependencies. Methods with
-// high *Rank* are the most used ones. Not necessarily
-// the ones with the most callers methods, but the ones
-// called by many methods, themselves having a lot
-// of callers.
-//
-// See the definition of the MethodRank metric here:
-// https://www.ndepend.com/docs/code-metrics#MethodRank
-//
-// This code query lists the 100 application methods
-// with the higher rank.
-//
-// The main consequence of being used a lot for a
-// method is that each change (both *signature change*
-// and *behavior change*) will result in potentially
-// a lot of **pain** since most methods callers will be
-// **impacted**.
-//
-// Hence it is preferable that methods with highest
-// *MethodRank*, are **abstract methods**, that are
-// typically less subject to signature changes.
-//
-// Also abstract methods avoid callers relying on
-// implementations details. Hence, when the code
-// of a method implementing an abstract method changes,
-// this shouldn't impact callers of the abstract method.
-// This is *in essence* the
-// **Liskov Substitution Principle**.
-// http://en.wikipedia.org/wiki/Liskov_substitution_principle
-//]]>
- Most used assemblies (#AssembliesUsingMe)
-(from a in Assemblies orderby a.AssembliesUsingMe.Count() descending
- select new { a, a.AssembliesUsingMe }).Take(100)
-
-//
-// This code query lists the 100 *application* and *third-party*
-// assemblies, with the higher number of assemblies users.
-//]]>
- Most used namespaces (#NamespacesUsingMe )
-(from n in Namespaces orderby n.NbNamespacesUsingMe descending
- select new { n, n.NamespacesUsingMe }).Take(100)
-
-//
-// This code query lists the 100 *application* and *third-party*
-// namespaces, with the higher number of namespaces users.
-//]]>
- Most used types (#TypesUsingMe )
-(from t in Types orderby t.NbTypesUsingMe descending
- where !t.IsGeneratedByCompiler
- select new { t, t.TypesUsingMe }).Take(100)
-
-//
-// This code query lists the 100 *application* and *third-party*
-// types, with the higher number of types users.
-//]]>
- Most used methods (#MethodsCallingMe )
-(from m in Methods orderby m.NbMethodsCallingMe
- where !m.IsGeneratedByCompiler
- select new { m, m.MethodsCallingMe }).Take(100)
-
-//
-// This code query lists the 100 *application* and *third-party*
-// methods, with the higher number of methods callers.
-//]]>
- Namespaces that use many other namespaces (#NamespacesUsed )
-(from n in Application.Namespaces orderby n.NbNamespacesUsed descending
- select new { n, n.NamespacesUsed }).Take(100)
-
-//
-// This code query lists the 100 *application* namespaces
-// with the higher number of namespaces used.
-//]]>
- Types that use many other types (#TypesUsed )
-(from t in Application.Types orderby t.NbTypesUsed descending
- select new { t, t.TypesUsed, isMyCode = JustMyCode.Contains(t) }).Take(100)
-
-//
-// This code query lists the 100 *application* types
-// with the higher number of types used.
-//]]>
- Methods that use many other methods (#MethodsCalled )
-(from m in Application.Methods orderby m.NbMethodsCalled descending
- select new { m, m.MethodsCalled, isMyCode = JustMyCode.Contains(m) }).Take(100)
-
-//
-// This code query lists the 100 *application* methods
-// with the higher number of methods called.
-//]]>
- High-level to low-level assemblies (Level)
-from a in Application.Assemblies orderby a.Level descending
-select new { a, a.Level }
-
-//
-// This code query lists assemblies ordered by **Level** values.
-// See the definition of the *AssemblyLevel* metric here:
-// https://www.ndepend.com/docs/code-metrics#Level
-//]]>
- High-level to low-level namespaces (Level)
-from n in Application.Namespaces orderby n.Level descending
-select new { n, n.Level }
-
-//
-// This code query lists namespaces ordered by **Level** values.
-// See the definition of the *NamespaceLevel* metric here:
-// https://www.ndepend.com/docs/code-metrics#Level
-//]]>
- High-level to low-level types (Level)
-from t in Application.Types orderby t.Level descending
-select new { t, t.Level }
-
-//
-// This code query lists types ordered by **Level** values.
-// See the definition of the *TypeLevel* metric here:
-// https://www.ndepend.com/docs/code-metrics#Level
-//]]>
- High-level to low-level methods (Level)
-from m in Application.Methods orderby m.Level descending
-select new { m, m.Level }
-
-//
-// This code query lists methods ordered by **Level** values.
-// See the definition of the *MethodLevel* metric here:
-// https://www.ndepend.com/docs/code-metrics#Level
-//]]>
-
-
-
- Check that the assembly Asm1 is not using the assembly Asm2
-// ND9901:ExplicitId9901
-warnif count > 0 from a in Application.Assemblies where
- a.IsUsing ("Asm2".AllowNoMatch().MatchAssembly()) &&
- (a.Name == @"Asm1")
-select new {
- a,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to be warned if a particular assembly is using
-// another particular assembly.
-//
-// Such rule can be generated for assemblies **A** and **B**:
-//
-// • by right clicking the cell in the *Dependency Matrix*
-// with **B** in row and **A** in column,
-//
-// • or by right-clicking the concerned arrow in the *Dependency
-// Graph* from **A** to **B**,
-//
-// and in both cases, click the menu
-// **Generate a code rule that warns if this dependency exists**
-//
-// The generated rule will look like this one.
-// It is now up to you to adapt this rule to check exactly
-// your needs.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that the namespace N1.N2 is not using the namespace N3.N4.N5
-// ND9902:ExplicitId9902
-
-warnif count > 0 from n in Application.Namespaces where
- n.IsUsing ("N3.N4.N5".AllowNoMatch().MatchNamespace()) &&
- (n.Name == @"N1.N2")
-select new {
- n,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to be warned if a particular namespace is using
-// another particular namespace.
-//
-// Such rule can be generated for namespaces **A** and **B**:
-//
-// • by right clicking the cell in the *Dependency Matrix*
-// with **B** in row and **A** in column,
-//
-// • or by right-clicking the concerned arrow in the *Dependency
-// Graph* from **A** to **B**,
-//
-// and in both cases, click the menu
-// **Generate a code rule that warns if this dependency exists**
-//
-// The generated rule will look like this one.
-// It is now up to you to adapt this rule to check exactly
-// your needs.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that the assembly Asm1 is only using the assemblies Asm2, Asm3 or mscorlib
-// ND9903:ExplicitId9903
-
-warnif count > 0 from a in Application.Assemblies where
- ( !a.IsUsing ("Asm2".AllowNoMatch().MatchAssembly()) ||
- !a.IsUsing ("Asm3".AllowNoMatch().MatchAssembly()) ||
- !a.IsUsing ("mscorlib".MatchAssembly()) ||
- a.AssembliesUsed.Count() != 3) // Must not be used more than 3 assemblies
-&&
- (a.Name == @"Asm1")
-select new {
- a,
- a.AssembliesUsed,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that a particular assembly
-// is only using a particular set of assemblies.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that the namespace N1.N2 is only using the namespaces N3.N4, N5 or System
-// ND9904:ExplicitId9904
-
-warnif count > 0 from n in Application.Namespaces where
- ( !n.IsUsing("N3.N4".AllowNoMatch().MatchNamespace()) ||
- !n.IsUsing("N5".AllowNoMatch().MatchNamespace()) ||
- !n.IsUsing("System".MatchNamespace()) ||
- n.NamespacesUsed.Count() != 3) // Must not be used more than 3 assemblies
- // AsmCe = Efferent Coupling for assembly
-&&
- (n.Name == @"N1.N2")
-select new {
- n,
- n.NamespacesUsed,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that a particular namespace
-// **is only using** a particular set of namespaces.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that AsmDrawing is the only assembly that is using System.Drawing
-// ND9905:ExplicitId9905
-
-warnif count> 0 from a in Application.Assemblies where
- a.IsUsing ("System.Drawing".AllowNoMatch().MatchAssembly()) &&
- !(a.Name == @"AsmDrawing")
-select new {
- a,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that a particular assembly
-// is **only used by** another particular assembly.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that only 3 assemblies are using System.Drawing
-// ND9906:ExplicitId9906
-
-warnif count != 3 from a in Application.Assemblies where
- a.IsUsing ("System.Drawing".AllowNoMatch().MatchAssembly())
-select new {
- a,
- Debt = 30.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that a particular assembly
-// is **only used by** 3 any others assemblies.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that all methods that call Foo.Fct1() also call Foo.Fct2(Int32)
-// ND9907:ExplicitId9907
-
-warnif count > 0 from m in Application.Methods where
- m.IsUsing ("Foo.Fct1()".AllowNoMatch()) &&
- !m.IsUsing ("Foo.Fct2(Int32)".AllowNoMatch())
-select new {
- m,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that if a method calls a particular method,
-// it must call another particular method.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that all types that derive from Foo, also implement IFoo
-// ND9908:ExplicitId9908
-
-warnif count > 0 from t in Application.Types where
- t.DeriveFrom ("Foo".AllowNoMatch().MatchType()) &&
- !t.Implement ("IFoo".AllowNoMatch().MatchType())
-select new {
- t,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that all classes that derive from a particular base class,
-// also implement a particular interface.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that all types that has the attribute FooAttribute are declared in the namespace N1.N2*
-// ND9909:ExplicitId9909
-
-warnif count > 0 from t in
- Application.Namespaces.WithNameWildcardMatchNotIn("N1.N2*").ChildTypes()
- where
- t.HasAttribute ("FooAttribute".AllowNoMatch())
-select new {
- t,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that all types that are tagged
-// with a particular attribute, are declared in a
-// particular namespace.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that all synchronization objects are only used from the namespaces under MyNamespace.Sync
-// ND9910:ExplicitId9910
-
-warnif count > 0 from n in Application.Namespaces
- where
- (n.IsUsing ("System.Threading.Monitor".AllowNoMatch()) ||
- n.IsUsing ("System.Threading.ReaderWriterLock".AllowNoMatch()) ||
- n.IsUsing ("System.Threading.Mutex".AllowNoMatch()) ||
- n.IsUsing ("System.Threading.EventWaitHandle".AllowNoMatch()) ||
- n.IsUsing ("System.Threading.Semaphore".AllowNoMatch()) ||
- n.IsUsing ("System.Threading.Interlocked".AllowNoMatch()))
- && !n.NameLike (@"^MyNamespace.Sync")
-select new {
- n,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that all synchronization objects
-// are used from a particular namespace.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
-
-
- Check that the namespace N1.N2 is 100% covered by tests
-// ND9911:ExplicitId9911
-
-warnif count > 0 from n in Application.Namespaces where
- (n.Name == @"N1.N2") &&
- n.PercentageCoverage < 100
-select new {
- n,
- n.PercentageCoverage,
- Debt = n.NbLinesOfCodeNotCovered.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This is a sample rule that shows how to check
-// if a particular namespace is 100% covered by tests.
-// Both the string **@"N1.N2"** and the threshold **100** can be adapted to your own needs.
-//
-// To execute this sample rule, coverage data must be imported.
-// More info here: https://www.ndepend.com/docs/code-coverage
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that the assembly Asm is 100% covered by tests
-// ND9912:ExplicitId9912
-
-warnif count > 0 from a in Application.Assemblies where
- (a.Name == @"Asm") &&
- a.PercentageCoverage < 100
-select new {
- a,
- a.PercentageCoverage,
- Debt = a.NbLinesOfCodeNotCovered.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This is a sample rule that shows how to check
-// if a particular assembly is 100% covered by tests.
-// Both the string **@"Asm"** and the threshold **100** can be adapted to your own needs.
-//
-// To execute this sample rule, coverage data must be imported.
-// More info here: https://www.ndepend.com/docs/code-coverage
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that the class Namespace.Foo is 100% covered by tests
-// ND9913:ExplicitId9913
-
-warnif count > 0 from t in Application.Types where
- (t.FullName == @"Namespace.Foo") &&
- t.PercentageCoverage < 100
-select new {
- t,
- t.PercentageCoverage,
- Debt = t.NbLinesOfCodeNotCovered.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// This is a sample rule that shows how to check
-// if a particular class is 100% covered by tests.
-// Both the string **@"Namespace.Foo"** and the threshold **100**
-// can be adapted to your own needs.
-//
-// To execute this sample rule, coverage data must be imported.
-// More info here: https://www.ndepend.com/docs/code-coverage
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that the class Namespace.Foo.Method(Int32) is 100% covered by tests
-// ND9914:ExplicitId9914
-
-warnif count > 0 from t in Application.Types where
- (t.FullName == @"Namespace.Foo.Method(Int32)") &&
- t.PercentageCoverage < 100
-select new {
- t,
- t.PercentageCoverage,
- Debt = t.NbLinesOfCodeNotCovered.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-
-//
-// This is a sample rule that shows how to check
-// if a particular method is 100% covered by tests.
-// Both the string **@"Namespace.Foo.Method(Int32)"** and the threshold **100**
-// can be adapted to your own needs.
-//
-// To execute this sample rule, coverage data must be imported.
-// More info here: https://www.ndepend.com/docs/code-coverage
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
-
-
- Check that all types that derive from Foo, has a name that ends up with Foo
-// ND9915:ExplicitId9915
-
-warnif count > 0 from t in Application.Types where
- t.DeriveFrom ("Foo".AllowNoMatch().MatchType()) &&
- !t.NameLike (@"Foo$")
-select new {
- t,
- t.NbLinesOfCode,
- Debt = 5.ToMinutes().ToDebt(),
- Severity = Severity.Medium
-}
-
-//
-// This rule is a *sample rule that can be adapted to your need*.
-//
-// It shows how to enforce that all classes that derive from
-// a particular class, are named with a particular suffix.
-//
-
-//
-// This is a *sample rule* there is nothing to fix *as is*.
-//]]>
- Check that all namespaces begins with CompanyName.ProductName
-// ND9916:ExplicitId9916
-
-warnif count > 0 from n in Application.Namespaces where
- !n.NameLike (@"^CompanyName.ProductName")
-select new {
- n,
- n.NbLinesOfCode,
- Debt = 10.ToMinutes().ToDebt(),
- Severity = Severity.High
-}
-
-//
-// A practice widely adopted is that, in a product source code,
-// all namespaces start with "CompanyName.ProductName".
-//
-// This rule must be adapted with your own **"CompanyName.ProductName"**.
-//
-
-//
-// Update all namespaces definitions in source code to satisfy this rule.
-//]]>
-
-
-
-
-
\ No newline at end of file
diff --git a/FlightSystem2.sln b/FlightSystem2.sln
deleted file mode 100644
index 3178281..0000000
--- a/FlightSystem2.sln
+++ /dev/null
@@ -1,28 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29509.3
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlightSystem.Api", "FlightSystem2\FlightSystem.Api.csproj", "{AA40BB18-8E8F-487E-A92C-E889C3FE76E4}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {72AC3982-563B-4F89-8859-9A2ABD654EA9}
- EndGlobalSection
- GlobalSection(NDepend) = preSolution
- Project = ".\FlightSystem2.ndproj"
- EndGlobalSection
-EndGlobal
diff --git a/FlightSystem2/.vscode/launch.json b/FlightSystem2/.vscode/launch.json
new file mode 100644
index 0000000..49e5438
--- /dev/null
+++ b/FlightSystem2/.vscode/launch.json
@@ -0,0 +1,36 @@
+{
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/bin/Debug/netcoreapp3.0/FlightSystem.Api.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/FlightSystem2/.vscode/tasks.json b/FlightSystem2/.vscode/tasks.json
new file mode 100644
index 0000000..511202c
--- /dev/null
+++ b/FlightSystem2/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/FlightSystem.Api.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/FlightSystem.Api.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/FlightSystem.Api.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/FlightSystem2/Dockerfile b/FlightSystem2/Dockerfile
deleted file mode 100644
index bcf3934..0000000
--- a/FlightSystem2/Dockerfile
+++ /dev/null
@@ -1,19 +0,0 @@
-FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
-WORKDIR /app
-EXPOSE 343
-
-FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
-WORKDIR /src
-COPY ["FlightSystem2/FlightSystem.Api.csproj", "FlightSystem2/"]
-RUN dotnet restore "FlightSystem2/FlightSystem.Api.csproj"
-COPY . .
-WORKDIR "/src/FlightSystem2"
-RUN dotnet build "FlightSystem.Api.csproj" -c Release -o /app/build
-
-FROM build AS publish
-RUN dotnet publish "FlightSystem.Api.csproj" -c Release -o /app/publish
-
-FROM base AS final
-WORKDIR /app
-COPY --from=publish /app/publish .
-ENTRYPOINT ["dotnet", "FlightSystem.Api.dll"]
\ No newline at end of file
diff --git a/FlightSystem2/Dockerfile.json b/FlightSystem2/Dockerfile.json
deleted file mode 100644
index a827866..0000000
--- a/FlightSystem2/Dockerfile.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "compilerOptions": {
- "noImplicitAny": false,
- "noEmitOnError": true,
- "removeComments": false,
- "sourceMap": true,
- "target": "es5"
- },
- "exclude": [
- "node_modules",
- "wwwroot"
- ]
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/AManagers/ARouteManager.cs b/FlightSystem2/Src/Application/Interfaces/AManagers/ARouteManager.cs
deleted file mode 100644
index 13adaeb..0000000
--- a/FlightSystem2/Src/Application/Interfaces/AManagers/ARouteManager.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using System.Collections.Generic;
-
-namespace FlightSystem.Api.Src.Application.Interfaces.AManagers
-{
- public abstract class ARouteManager : AManager
- {
-
- public abstract List ManageRoutes(ITripParams tripPar);
-
- }
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/IResponseBody.cs b/FlightSystem2/Src/Application/Interfaces/AServices/IResponseBody.cs
deleted file mode 100644
index fa55db2..0000000
--- a/FlightSystem2/Src/Application/Interfaces/AServices/IResponseBody.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using System.Collections.Generic;
-
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
-{
- public interface IResponseBody
- {
- IEnumerable Entities { get; }
- }
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/IAirportData.cs b/FlightSystem2/Src/Application/Interfaces/Data/IAirportData.cs
deleted file mode 100644
index b002c4f..0000000
--- a/FlightSystem2/Src/Application/Interfaces/Data/IAirportData.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using System.Collections.Generic;
-
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
-{
- public interface IAirportData
- {
- public List GetAll();
- }
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/IBackupData.cs b/FlightSystem2/Src/Application/Interfaces/Data/IBackupData.cs
deleted file mode 100644
index a2429f9..0000000
--- a/FlightSystem2/Src/Application/Interfaces/Data/IBackupData.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
-{
- public interface IBackupData
- {
- void SetBackup(IEntity entity);
- }
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/ICountryData.cs b/FlightSystem2/Src/Application/Interfaces/Data/ICountryData.cs
deleted file mode 100644
index b2b6bd0..0000000
--- a/FlightSystem2/Src/Application/Interfaces/Data/ICountryData.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using System.Collections.Generic;
-
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
-{
- public interface ICountryData
- {
- public List GetAll();
- }
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/IFlagImageData.cs b/FlightSystem2/Src/Application/Interfaces/Data/IFlagImageData.cs
deleted file mode 100644
index 7125df5..0000000
--- a/FlightSystem2/Src/Application/Interfaces/Data/IFlagImageData.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using System.Collections.Generic;
-
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
-{
- public interface IFlagImageData
- {
- public void AddFlagsToCountries(IEnumerable countries);
- }
-}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/ILocationsData.cs b/FlightSystem2/Src/Application/Interfaces/Data/ILocationsData.cs
deleted file mode 100644
index 656d3b2..0000000
--- a/FlightSystem2/Src/Application/Interfaces/Data/ILocationsData.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
-{
- public interface ILocationsData
- {
- ILocations GetLocationsAll();
- }
-}
diff --git a/FlightSystem2/Src/Domain/Interfaces/IAirport.cs b/FlightSystem2/Src/Domain/Interfaces/IAirport.cs
deleted file mode 100644
index 0c0fa73..0000000
--- a/FlightSystem2/Src/Domain/Interfaces/IAirport.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace FlightSystem.Api.Src.Domain.Interfaces
-{
- public interface IAirport : IEntity
- {
- public string fullName { get; set; }
-
- public string type { get; }
-
- public string code { get; set; }
-
- public string cityName { get; set; }
-
- public string countryName { get; set; }
- }
-}
diff --git a/FlightSystem2/Src/Domain/Interfaces/IEntity.cs b/FlightSystem2/Src/Domain/Interfaces/IEntity.cs
deleted file mode 100644
index f80ed28..0000000
--- a/FlightSystem2/Src/Domain/Interfaces/IEntity.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace FlightSystem.Api.Src.Domain.Interfaces
-{
- public interface IEntity
- {
- }
-}
diff --git a/FlightSystem2/Src/Integration/Config/IntegrationConfig.cs b/FlightSystem2/Src/Integration/Config/IntegrationConfig.cs
deleted file mode 100644
index 3b4162c..0000000
--- a/FlightSystem2/Src/Integration/Config/IntegrationConfig.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace FlightSystem.Api.Src.Integration.Config
-{
- public static class IntegrationConfig
- {
-
- public static string GetDataBaseUri() { return "bolt://localhost:7687"; }
-
- public static string GetDataBaseUsername() { return "neo4j"; }
- public static string GetDataBasePassword() { return "labas"; }
-
- public static string GetBackupFilePath() { return @"C:\Users\Paulius\Desktop\Flags\Dummies\"; }
-
- public static string GetBackupFileType() { return ".json"; }
-
- public static string GetFlagsFilePath() { return @"C:\Users\Paulius\Desktop\Flags\Flags\"; }
-
- public static string GetFlagsFileType() { return ".png"; }
-
-
- }
-}
diff --git a/Neo4J/Dockerfile b/Neo4J/Dockerfile
new file mode 100644
index 0000000..e75a613
--- /dev/null
+++ b/Neo4J/Dockerfile
@@ -0,0 +1,3 @@
+#Neo4j with some plugins.
+FROM neo4j:3.5.12
+CMD [ "neo4j" ]
\ No newline at end of file
diff --git a/Rebus.sln b/Rebus.sln
new file mode 100644
index 0000000..f0b748c
--- /dev/null
+++ b/Rebus.sln
@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29509.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RebusCore", "RebusCore\RebusCore.csproj", "{AA40BB18-8E8F-487E-A92C-E889C3FE76E4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RebusNeo", "RebusNeo\RebusNeo.csproj", "{346EEC11-1E4E-47D8-9FFE-0080CAE18ACE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {AA40BB18-8E8F-487E-A92C-E889C3FE76E4} = {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RebusAdmin", "RebusAdmin\RebusAdmin.csproj", "{3B6D1248-3FFF-463F-9D28-912269199158}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA40BB18-8E8F-487E-A92C-E889C3FE76E4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {346EEC11-1E4E-47D8-9FFE-0080CAE18ACE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {346EEC11-1E4E-47D8-9FFE-0080CAE18ACE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {346EEC11-1E4E-47D8-9FFE-0080CAE18ACE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {346EEC11-1E4E-47D8-9FFE-0080CAE18ACE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B6D1248-3FFF-463F-9D28-912269199158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B6D1248-3FFF-463F-9D28-912269199158}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B6D1248-3FFF-463F-9D28-912269199158}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B6D1248-3FFF-463F-9D28-912269199158}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {72AC3982-563B-4F89-8859-9A2ABD654EA9}
+ EndGlobalSection
+EndGlobal
diff --git a/RebusAdmin/AsyncHelper.cs b/RebusAdmin/AsyncHelper.cs
new file mode 100644
index 0000000..b2093db
--- /dev/null
+++ b/RebusAdmin/AsyncHelper.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Threading;
+
+namespace RebusAdmin
+{
+ public static class AsyncHelper
+ {
+ private static readonly TaskFactory _taskFactory = new
+ TaskFactory(CancellationToken.None,
+ TaskCreationOptions.None,
+ TaskContinuationOptions.None,
+ TaskScheduler.Default);
+
+ public static TResult RunSync(Func> func)
+ => _taskFactory
+ .StartNew(func)
+ .Unwrap()
+ .GetAwaiter()
+ .GetResult();
+
+ public static void RunSync(Func func)
+ => _taskFactory
+ .StartNew(func)
+ .Unwrap()
+ .GetAwaiter()
+ .GetResult();
+ }
+}
\ No newline at end of file
diff --git a/RebusAdmin/Controllers/BalanceController.cs b/RebusAdmin/Controllers/BalanceController.cs
new file mode 100644
index 0000000..4d5fc73
--- /dev/null
+++ b/RebusAdmin/Controllers/BalanceController.cs
@@ -0,0 +1,27 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using RebusAdmin.Logic;
+using System.Net.Http;
+using System.Net.Http.Headers;
+
+namespace RebusAdmin.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class BalanceController : ControllerBase
+ {
+ private readonly ILogger _logger;
+
+ public BalanceController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ [HttpGet]
+ public string GetAdmin(int userid, string amount)
+ {
+ return AsyncHelper.RunSync(() => WebApiClient.Call(IntegrationConfig.GetRebusNeoUri() + "balanceadmin?userid=" + userid + "&amount=" + amount));
+ }
+ }
+}
diff --git a/RebusAdmin/Controllers/BanUserController.cs b/RebusAdmin/Controllers/BanUserController.cs
new file mode 100644
index 0000000..1dae432
--- /dev/null
+++ b/RebusAdmin/Controllers/BanUserController.cs
@@ -0,0 +1,25 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using RebusAdmin.Logic;
+
+namespace RebusAdmin.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class BanUserController : ControllerBase
+ {
+ private readonly ILogger _logger;
+
+ public BanUserController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ [HttpGet]
+ public string Get(string userName, string action)
+ {
+ return AsyncHelper.RunSync(() => WebApiClient.Call(IntegrationConfig.GetRebusNeoUri() + "banuser?username=" + userName + "&action=" + action));
+ }
+ }
+}
diff --git a/RebusAdmin/Controllers/DataUpdateController.cs b/RebusAdmin/Controllers/DataUpdateController.cs
new file mode 100644
index 0000000..b08a466
--- /dev/null
+++ b/RebusAdmin/Controllers/DataUpdateController.cs
@@ -0,0 +1,26 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using RebusAdmin.Logic;
+
+namespace RebusAdmin.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class DataUpdate : ControllerBase
+ {
+ private readonly ILogger _logger;
+ private DataUpdateManager _dataUpdateManager = new DataUpdateManager();
+
+ public DataUpdate(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ [HttpGet]
+ public string Get(int days)
+ {
+ _dataUpdateManager.updateAllDataFromFiles(days);
+ return _dataUpdateManager.GetResult(days);
+ }
+ }
+}
diff --git a/RebusAdmin/Controllers/ReportController.cs b/RebusAdmin/Controllers/ReportController.cs
new file mode 100644
index 0000000..9a1ea4a
--- /dev/null
+++ b/RebusAdmin/Controllers/ReportController.cs
@@ -0,0 +1,27 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using RebusAdmin.Logic;
+using System.Net.Http;
+using System.Net.Http.Headers;
+
+namespace RebusAdmin.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class ReportController : ControllerBase
+ {
+ private readonly ILogger _logger;
+
+ public ReportController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ [HttpGet]
+ public string Get()
+ {
+ return AsyncHelper.RunSync(() => WebApiClient.Call(IntegrationConfig.GetRebusNeoUri() + "report"));
+ }
+ }
+}
diff --git a/RebusAdmin/Controllers/StatusCheckController.cs b/RebusAdmin/Controllers/StatusCheckController.cs
new file mode 100644
index 0000000..ac754d2
--- /dev/null
+++ b/RebusAdmin/Controllers/StatusCheckController.cs
@@ -0,0 +1,25 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using RebusAdmin.Logic;
+
+namespace RebusAdmin.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class StatusCheckController : ControllerBase
+ {
+ private readonly ILogger _logger;
+ private StatusManager _statusManager = new StatusManager();
+
+ public StatusCheckController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ [HttpGet]
+ public string Get()
+ {
+ return _statusManager.checkStatus().ToString();
+ }
+ }
+}
diff --git a/RebusAdmin/Dockerfile b/RebusAdmin/Dockerfile
new file mode 100644
index 0000000..ae0ac41
--- /dev/null
+++ b/RebusAdmin/Dockerfile
@@ -0,0 +1,24 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
+WORKDIR /app
+ENV ASPNETCORE_URLS=http://+:5003
+EXPOSE 5003
+
+FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
+WORKDIR /src
+COPY ["RebusAdmin/RebusAdmin.csproj", "RebusAdmin/"]
+RUN dotnet restore "RebusAdmin/RebusAdmin.csproj"
+COPY . .
+WORKDIR "/src/RebusAdmin"
+RUN dotnet build "RebusAdmin.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "RebusAdmin.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "RebusAdmin.dll"]
+
+COPY RebusAdmin/Files /app/files
\ No newline at end of file
diff --git a/RebusAdmin/Files/Airports.csv b/RebusAdmin/Files/Airports.csv
new file mode 100644
index 0000000..62d1ddd
--- /dev/null
+++ b/RebusAdmin/Files/Airports.csv
@@ -0,0 +1,29 @@
+Code;Airport;City;Country Code
+LHR;Heathrow Airport;London;GB
+CDG;Charles de Gaulle Airport;Paris;FR
+AMS;Amsterdam Airport Schiphol;Amsterdam;NL
+FRA;Frankfurt Airport;Frankfurt;DE
+ISL;Istanbul Ataturk Airport;Istanbul;TR
+MAD;Adolfo Suarez Madrid-Barajas Airport;Madrid;ES
+BCN;Barcelona El Prat Airport;Barcelona;ES
+LGW;London-Gatwick Airport;London;GB
+MUC;Munich Airport;Munich;DE
+FCO;Leonardo da Vinci-Fiumicino Airport;Rome;IT
+SVO;Sheremetyevo International Airport;Moscow;RU
+ORY;Paris-Orly Airport;Paris;FR
+CPH;Copenhagen Airport;Copenhagen;DK
+BRU;Brussels Airport;Brussels;BE
+HEL;Helsinki Airport;Helsinki;FI
+LTN;Luton Airport;London;GB
+ATL;Hartsfield-Jackson Atlanta International Airport;Atlanta;US
+ORD;Chicago OHare International Airport;Chicago;US
+LAX;Los Angeles International Airport;Los Angeles;US
+JFK;John F. Kennedy International Airport;New York City;US
+DEN;Denver International Airport;Denver;US
+IAD;Washington Dulles International Airport;Washington;US
+LGA;LaGuardia Airport;New York City;US
+YYZ;Toronto Pearson International Airport;Toronto;CA
+PEK;Beijing Capital International Airport;Beijing;CN
+SYD;Sydney Airport;Sydney;AU
+AKL;Auckland Airport;Auckland;NZ
+VNO;Vilnius Airport;Vilnius;LT
diff --git a/RebusAdmin/Files/Cities.csv b/RebusAdmin/Files/Cities.csv
new file mode 100644
index 0000000..5d46f5a
--- /dev/null
+++ b/RebusAdmin/Files/Cities.csv
@@ -0,0 +1,25 @@
+City;Country Code
+London;GB
+Paris;FR
+Amsterdam;NL
+Frankfurt;DE
+Istanbul;TR
+Madrid;ES
+Barcelona;ES
+Munich;DE
+Rome;IT
+Moscow;RU
+Copenhagen;DK
+Brussels;BE
+Helsinki;FI
+Atlanta;US
+Chicago;US
+Los Angeles;US
+New York City;US
+Denver;US
+Washington;US
+Toronto;CA
+Beijing;CN
+Sydney;AU
+Auckland;NZ
+Vilnius;LT
diff --git a/RebusAdmin/Files/Countries.csv b/RebusAdmin/Files/Countries.csv
new file mode 100644
index 0000000..f83e538
--- /dev/null
+++ b/RebusAdmin/Files/Countries.csv
@@ -0,0 +1,18 @@
+Country;Code
+United Kingdom;GB
+France;FR
+Netherlands;NL
+Germany;DE
+Turkey;TR
+Spain;ES
+Italy;IT
+Russia;RU
+Denmark;DK
+Belgium;BE
+Finland;FI
+USA;US
+Canada;CA
+China;CN
+Australia;AU
+New Zeland;NZ
+Lithuania;LT
\ No newline at end of file
diff --git a/RebusAdmin/Files/Flights.csv b/RebusAdmin/Files/Flights.csv
new file mode 100644
index 0000000..62c3739
--- /dev/null
+++ b/RebusAdmin/Files/Flights.csv
@@ -0,0 +1,164 @@
+Code;Fom;To;Departs;Arrives;Price;Arrives on next day
+BA-100;LHR;CDG;05:30;06:20;40;FALSE
+BA-102;LHR;CDG;07:30;08:20;70;FALSE
+BA-104;LHR;CDG;08:10;09:00;50;FALSE
+BA-106;LHR;CDG;12:30;13:20;50;FALSE
+BA-108;LHR;CDG;17:30;18:20;50;FALSE
+BA-110;LHR;CDG;20:30;21:20;40;FALSE
+BA-112;LHR;CDG;22:30;23:20;40;FALSE
+BA-114;LHR;CDG;23:30;00:20;40;TRUE
+BA-200;LHR;FRA;06:00;07:30;60;FALSE
+BA-210;LHR;FRA;08:00;09:30;40;FALSE
+BA-220;LHR;FRA;11:00;12:30;50;FALSE
+BA-230;LHR;FRA;16:00;17:30;40;FALSE
+BA-240;LHR;FRA;19:00;20:30;40;FALSE
+BA-250;LHR;FRA;20:30;22:00;80;FALSE
+BA-300;LHR;BCN;08:00;10:30;60;FALSE
+BA-310;LHR;BCN;11:00;13:30;70;FALSE
+BA-320;LHR;BCN;20:30;23:00;120;FALSE
+BA-400;LHR;MUC;05:30;07:30;70;FALSE
+BA-410;LHR;MUC;11:00;13:00;50;FALSE
+BA-420;LHR;MUC;17:00;19:00;40;FALSE
+BA-430;LHR;MUC;22:00;23:55;40;TRUE
+BA-500;LHR;ISL;08:30;12:30;110;FALSE
+BA-510;LHR;ISL;19:30;23:30;90;FALSE
+BA-600;LHR;ORY;07:30;08:30;30;FALSE
+BA-610;LHR;ORY;12:30;13:30;30;FALSE
+BA-10001;LHR;JFK;06:30;15:20;420;FALSE
+BA-10002;LHR;YYZ;07:30;16:20;480;FALSE
+BA-700;LGW;HEL;07:30;10:00;70;FALSE
+BA-710;LGW;HEL;10:30;13:00;50;FALSE
+BA-720;LGW;HEL;17:30;20:00;70;FALSE
+BA-730;LGW;HEL;21:30;23:55;100;TRUE
+BA-800;LGW;CDG;07:00;08:00;40;FALSE
+BA-810;LGW;CDG;09:00;10:00;40;FALSE
+BA-820;LGW;CDG;15:00;16:00;50;FALSE
+BA-830;LGW;CDG;21:00;22:00;40;FALSE
+BA-900;LGW;FRA;23:00;23:55;25;TRUE
+BA-1000;LTN;MAD;06:00;08:00;60;FALSE
+BA-1010;LTN;MAD;10:00;12:00;70;FALSE
+BA-1020;LTN;MAD;15:00;17:00;70;FALSE
+BA-1030;LTN;MAD;19:00;21:00;80;FALSE
+BA-1040;LTN;MAD;23:00;01:00;50;TRUE
+AY-100;HEL;LHR;06:00;08:30;170;FALSE
+AY-110;HEL;LHR;09:00;11:30;70;FALSE
+AY-120;HEL;LHR;17:00;19:30;80;FALSE
+AY-130;HEL;LHR;19:00;21:30;70;FALSE
+AY-140;HEL;LHR;21:00;23:30;60;FALSE
+AY-200;HEL;CDG;08:00;10:30;80;FALSE
+AY-210;HEL;CDG;17:00;19:30;80;FALSE
+AY-220;HEL;CDG;20:00;22:30;90;FALSE
+AY-300;HEL;AMS;07:00;09:30;80;FALSE
+AY-310;HEL;AMS;11:00;13:30;70;FALSE
+AY-320;HEL;AMS;18:00;20:30;50;FALSE
+AY-400;HEL;SVO;08:00;10:00;100;FALSE
+AY-410;HEL;SVO;13:00;15:00;80;FALSE
+AY-420;HEL;SVO;21:00;23:00;80;FALSE
+AY-500;HEL;BRU;12:00;14:20;60;FALSE
+AY-510;HEL;BRU;22:00;00:20;50;TRUE
+IB-100;MAD;CDG;07:00;09:00;30;FALSE
+IB-110;MAD;CDG;11:00;13:00;70;FALSE
+IB-120;MAD;CDG;13:30;15:30;70;FALSE
+IB-130;MAD;CDG;16:30;18:30;50;FALSE
+IB-140;MAD;CDG;19:30;21:30;100;FALSE
+IB-200;MAD;BCN;05:30;06:30;30;FALSE
+IB-210;MAD;BCN;07:30;08:30;50;FALSE
+IB-220;MAD;BCN;11:30;12:30;40;FALSE
+IB-230;MAD;BCN;14:30;15:30;40;FALSE
+IB-240;MAD;BCN;17:30;18:30;20;FALSE
+IB-250;MAD;BCN;19:30;20:30;40;FALSE
+IB-260;MAD;BCN;20:30;21:30;50;FALSE
+IB-270;MAD;BCN;21:30;22:30;25;FALSE
+IB-280;MAD;BCN;22:30;23:30;45;FALSE
+IB-300;MAD;LHR;05:45;08:00;70;FALSE
+IB-310;MAD;LHR;08:45;11:00;60;FALSE
+IB-320;MAD;LHR;12:45;15:00;50;FALSE
+IB-330;MAD;LHR;18:45;21:00;90;FALSE
+IB-340;MAD;LHR;20:45;23:00;70;FALSE
+IB-350;MAD;LHR;22:45;01:00;60;TRUE
+IB-400;MAD;LGW;09:00;11:15;90;FALSE
+IB-410;MAD;LGW;15:00;17:15;70;FALSE
+IB-420;MAD;LGW;22:00;00:15;60;TRUE
+IB-500;MAD;CPH;07:00;09:30;80;FALSE
+IB-510;MAD;CPH;11:00;13:30;80;FALSE
+IB-520;MAD;CPH;18:00;20:30;60;FALSE
+IB-530;MAD;CPH;22:00;00:30;80;TRUE
+IB-610;MAD;FRA;07:30;10:00;70;FALSE
+IB-620;MAD;FRA;09:30;12:00;80;FALSE
+IB-630;MAD;FRA;15:30;18:00;60;FALSE
+IB-640;MAD;FRA;20:30;23:00;50;FALSE
+IB-70000;MAD;IAD;21:30;06:20;500;TRUE
+IB-800;BCN;CDG;06:00;08:00;50;FALSE
+IB-810;BCN;CDG;11:00;13:00;70;FALSE
+IB-820;BCN;CDG;17:00;19:00;50;FALSE
+IB-830;BCN;CDG;20:00;22:00;40;FALSE
+AF-100;CDG;LHR;06:00;06:50;50;FALSE
+AF-110;CDG;LHR;08:00;08:50;30;FALSE
+AF-120;CDG;LHR;12:00;12:50;30;FALSE
+AF-130;CDG;LHR;15:00;15:50;50;FALSE
+AF-140;CDG;LHR;18:00;18:50;30;FALSE
+AF-150;CDG;LHR;22:00;22:50;50;FALSE
+AF-200;CDG;AMS;06:30;07:30;50;FALSE
+AF-210;CDG;AMS;09:30;10:30;50;FALSE
+AF-220;CDG;AMS;11:30;13:30;40;FALSE
+AF-230;CDG;AMS;19:30;20:30;40;FALSE
+AF-240;CDG;AMS;22:30;23:30;30;FALSE
+AF-30000;CDG;ISL;04:30;13:20;160;FALSE
+AF-40000;CDG;FCO;05:30;14:20;120;FALSE
+AF-50000;CDG;CPH;06:30;15:20;120;FALSE
+AF-600;CDG;BRU;07:30;08:10;30;FALSE
+AF-610;CDG;BRU;10:30;11:10;30;FALSE
+AF-620;CDG;BRU;18:30;19:10;20;FALSE
+AF-700;ORY;LTN;08:30;09:20;30;FALSE
+AF-710;ORY;LTN;14:30;15:20;30;FALSE
+AF-720;ORY;LTN;21:30;22:20;30;FALSE
+AF-800;ORY;BRU;09:30;18:20;40;FALSE
+LH-100;FRA;MUC;06:00;06:40;30;FALSE
+LH-110;FRA;MUC;08:00;08:40;30;FALSE
+LH-120;FRA;MUC;11:00;11:40;40;FALSE
+LH-130;FRA;MUC;15:00;15:40;20;FALSE
+LH-140;FRA;MUC;19:00;19:40;20;FALSE
+LH-150;FRA;MUC;23:00;23:40;30;FALSE
+LH-200;FRA;LHR;07:00;08:30;50;FALSE
+LH-210;FRA;LHR;13:00;14:30;40;FALSE
+LH-220;FRA;LHR;15:00;16:30;40;FALSE
+LH-230;FRA;LHR;19:00;20:30;50;FALSE
+LH-300;FRA;CDG;06:30;07:50;40;FALSE
+LH-310;FRA;CDG;09:30;10:50;50;FALSE
+LH-320;FRA;CDG;15:30;16:50;40;FALSE
+LH-330;FRA;CDG;19:30;20:50;30;FALSE
+LH-340;FRA;CDG;23:30;00:50;40;TRUE
+LH-400;FRA;MAD;06:30;08:30;70;FALSE
+LH-410;FRA;MAD;08:30;10:30;60;FALSE
+LH-420;FRA;MAD;14:30;16:30;60;FALSE
+LH-430;FRA;MAD;19:30;21:30;60;FALSE
+LH-510;FRA;VNO;08:30;10:30;60;FALSE
+LH-520;FRA;VNO;18:30;20:30;60;FALSE
+SN-100;BRU;LHR;06:00;07:00;30;FALSE
+SN-110;BRU;LHR;09:00;10:00;20;FALSE
+SN-120;BRU;LHR;15:00;16:00;30;FALSE
+SN-130;BRU;LHR;23:00;23:55;20;FALSE
+SN-200;BRU;CDG;09:00;09:40;25;FALSE
+SN-210;BRU;CDG;15:00;15:40;30;FALSE
+SN-220;BRU;CDG;19:00;19:40;20;FALSE
+SN-230;BRU;CDG;23:00;23:40;20;FALSE
+SN-300;BRU;ORY;06:30;07:10;30;FALSE
+SN-310;BRU;ORY;13:30;14:10;20;FALSE
+SN-400;BRU;AMS;06:00;06:30;25;FALSE
+SN-410;BRU;AMS;08:00;08:30;30;FALSE
+SN-420;BRU;AMS;14:00;14:30;20;FALSE
+SN-440;BRU;AMS;17:00;17:30;35;FALSE
+SN-450;BRU;AMS;19:00;19:30;20;FALSE
+SN-460;BRU;AMS;23:00;23:30;25;FALSE
+SN-500;BRU;MAD;16:00;18:30;60;FALSE
+SN-510;BRU;MAD;22:00;00:30;70;TRUE
+SN-600;BRU;BCN;07:00;09:10;70;FALSE
+SN-610;BRU;BCN;16:00;18:10;50;FALSE
+SN-700;BRU;FRA;07:00;07:50;20;FALSE
+SN-710;BRU;FRA;12:00;12:50;40;FALSE
+SN-720;BRU;FRA;20:00;20:50;35;FALSE
+SN-800;BRU;MUC;17:00;18:10;40;FALSE
+SN-900;BRU;CPH;11:00;12:20;40;FALSE
+SN-1000;BRU;HEL;06:00;08:20;40;FALSE
+SN-1010;BRU;HEL;18:00;20:20;70;FALSE
+SN-1100;BRU;LGW;23:00;23:50;20;FALSE
diff --git a/RebusAdmin/Logic/DataUpdateManager.cs b/RebusAdmin/Logic/DataUpdateManager.cs
new file mode 100644
index 0000000..0dc72c6
--- /dev/null
+++ b/RebusAdmin/Logic/DataUpdateManager.cs
@@ -0,0 +1,308 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace RebusAdmin.Logic
+{
+ public class Airports
+ {
+ public string Code { get; set; }
+ public string Name { get; set; }
+ public string City { get; set; }
+ public string Country { get; set; }
+ }
+
+ public class Flights
+ {
+ public string Company { get; set; }
+ public int FlightNum { get; set; }
+ public string From { get; set; }
+ public string To { get; set; }
+ public string Departs { get; set; }
+ public string Arrives { get; set; }
+ public bool ArrOnNextDay { get; set; }
+ public int Price { get; set; }
+ }
+
+ public class Countries
+ {
+ public string Name { get; set; }
+
+ public string Code { get; set; }
+ }
+
+ public class Cities
+ {
+ public string Name { get; set; }
+ public string Country { get; set; }
+ }
+
+ public class DataUpdateManager
+ {
+ private int _nodes = 0;
+ private int _relations = 0;
+
+ private readonly DateTime _start = new DateTime(2020, 01, 01);
+ private DateTime _end = new DateTime(2019, 12, 31);
+
+ public string GetResult(int days) { return "Database deleted and created! Nodes:" + _nodes.ToString() + ", Relations:" + (_relations + 2 * days).ToString(); }
+
+ public void updateAllDataFromFiles(int days)
+ {
+ _end = _end.AddDays(days);
+
+ DeleteAll();
+ CreateCountries();
+ CreateCities();
+ CreateAirports();
+ CreateAirportDays();
+ CreateFlights();
+
+ Console.WriteLine(GetResult(days));
+ }
+
+ public void DeleteAll()
+ {
+ Neo4JContext.RunQuery("MATCH (n) DETACH DELETE n");
+ }
+
+ public void CreateCountries()
+ {
+ List countries = ReadCountries();
+ foreach (var i in countries)
+ {
+ Neo4JContext.RunQuery("create (:country{name:'" + i.Name + "', code:'" + i.Code + "'})");
+ _nodes++;
+ }
+ }
+
+ public void CreateCities()
+ {
+ List cities = ReadCities();
+ foreach (var i in cities)
+ {
+ Neo4JContext.RunQuery("create (:city{name:'" + i.Name + "', country:'" + i.Country + "'})");
+ _nodes++;
+ Neo4JContext.RunQuery("match (a:city{name:'" + i.Name + "'}), (b:country{code:'" + i.Country + "'}) merge (a)-[:inCountry]->(b)");
+ _relations++;
+ }
+ }
+
+ public void CreateAirports()
+ {
+ List airports = ReadAirports();
+ foreach (var i in airports)
+ {
+ Neo4JContext.RunQuery("create (:airport{name:'" + i.Code + "', fullName:'" + i.Name + "', city:'" + i.City + "', country:'" + i.Country + "'})");
+ _nodes++;
+ Neo4JContext.RunQuery("match (a:airport{name:'" + i.Code + "'}), (b:city{name:'" + i.City + "'}) merge (a)-[:inCity]->(b)");
+ _relations++;
+ }
+ }
+
+ private void CreateAirportDays()
+ {
+ List airports = ReadAirports();
+ foreach (var i in airports)
+ {
+ DateTime begin = _start;
+ DateTime end = _end;
+
+ for (DateTime date = begin; date <= end; date = date.AddDays(1))
+ {
+ string dateStr = date.ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+
+ Neo4JContext.RunQuery("create (:airportDay{name:'" + i.Code + ":" + dateStr + "'})");
+ _nodes++;
+ Neo4JContext.RunQuery("match (a:airportDay{name:'" + i.Code + ":" + dateStr + "'}), (b:airport{name:'" + i.Code + "'}) merge (a)<-[:hasDay]-(b)");
+ _relations++;
+ }
+ }
+ System.Console.WriteLine("Main setup finished. New Nodes:" + _nodes.ToString() + ", Relations:" + (_relations).ToString());
+ }
+
+ public void CreateFlights()
+ {
+ List flights = ReadFlights();
+
+ string dateStr, dateNextStr;
+
+ DateTime begin = _start;
+ DateTime end = _end;
+
+ int num = 1;
+ for (DateTime date = begin; date <= end; date = date.AddDays(1))
+ {
+
+ int nodes = 0;
+ int relations = 0;
+
+ foreach (var i in flights)
+ {
+
+ if (i.ArrOnNextDay == false)
+ {
+ dateStr = date.ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+ dateNextStr = date.AddDays(1).ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+
+ Neo4JContext.RunQuery("create (:flight{name:'" + i.Company + "-" + num + i.FlightNum + "', departs: time('" + i.Departs + "'), arrives: time('" + i.Arrives + "'), price: " + i.Price + "})");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + i.FlightNum + "'}), (b:airportDay{name:'" + i.From + ":" + dateStr + "'}) merge (b)-[:" + i.To + "flight]->(a)");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + i.FlightNum + "'}), (b:airportDay{name:'" + i.To + ":" + dateStr + "'}) merge (a)-[:" + i.To + "flight]->(b)");
+
+ Neo4JContext.RunQuery("create (:flight{name:'" + i.Company + "-" + num + (i.FlightNum + 1) + "', departs: time('" + i.Departs + "'), arrives: time('" + i.Arrives + "'), price: " + i.Price + "})");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + (i.FlightNum + 1) + "'}), (b:airportDay{name:'" + i.From + ":" + dateStr + "'}) merge (b)<-[:" + i.To + "flight]-(a)");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + (i.FlightNum + 1) + "'}), (b:airportDay{name:'" + i.To + ":" + dateStr + "'}) merge (a)<-[:" + i.To + "flight]-(b)");
+
+ nodes += 2;
+ relations += 4;
+ }
+ else if (date != end)
+ {
+ dateStr = date.ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+ dateNextStr = date.AddDays(1).ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+
+ Neo4JContext.RunQuery("create (:flight{name:'" + i.Company + "-" + num + i.FlightNum + "', departs: time('" + i.Departs + "'), arrives: time('" + i.Arrives + "'), price: " + i.Price + "})");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + i.FlightNum + "'}), (b:airportDay{name:'" + i.From + ":" + dateStr + "'}) merge (b)-[:" + i.To + "flight]->(a)");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + i.FlightNum + "'}), (b:airportDay{name:'" + i.To + ":" + dateNextStr + "'}) merge (a)-[:" + i.To + "flight]->(b)");
+
+ dateNextStr = date.ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+ dateStr = date.AddDays(1).ToString("yyyy-M-d", System.Globalization.CultureInfo.InvariantCulture);
+
+ Neo4JContext.RunQuery("create (:flight{name:'" + i.Company + "-" + num + (i.FlightNum + 1) + "', departs: time('" + i.Departs + "'), arrives: time('" + i.Arrives + "'), price: " + i.Price + "})");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + (i.FlightNum + 1) + "'}), (b:airportDay{name:'" + i.From + ":" + dateStr + "'}) merge (b)<-[:" + i.To + "flight]-(a)");
+ Neo4JContext.RunQuery("match (a:flight{name:'" + i.Company + "-" + num + (i.FlightNum + 1) + "'}), (b:airportDay{name:'" + i.To + ":" + dateNextStr + "'}) merge (a)<-[:" + i.To + "flight]-(b)");
+
+ nodes += 2;
+ _relations += 4;
+ }
+ }
+ _nodes += nodes;
+ _relations += relations;
+ System.Console.WriteLine("Loading days. Day " + num + ". New Nodes:" + _nodes.ToString() + ", Relations:" + (_relations).ToString());
+
+ num++;
+ }
+ }
+
+
+ public List ReadCountries()
+ {
+ List retList = new List();
+
+ using (var reader = new StreamReader(IntegrationConfig.GetDataLocation() + "Countries.csv"))
+ {
+ int i = 0;
+ while (!reader.EndOfStream)
+ {
+ var line = reader.ReadLine();
+ var values = line.Split(';');
+
+ if (i != 0)
+ {
+ Countries country = new Countries()
+ {
+ Name = values[0],
+ Code = values[1]
+ };
+ retList.Add(country);
+ }
+ i++;
+ }
+ }
+ return retList;
+ }
+
+ public List ReadCities()
+ {
+ List retList = new List();
+
+ using (var reader = new StreamReader(IntegrationConfig.GetDataLocation() + "Cities.csv"))
+ {
+ int i = 0;
+ while (!reader.EndOfStream)
+ {
+ var line = reader.ReadLine();
+ var values = line.Split(';');
+
+ if (i != 0)
+ {
+ Cities city = new Cities()
+ {
+ Name = values[0],
+ Country = values[1]
+ };
+ retList.Add(city);
+ }
+ i++;
+ }
+ }
+
+ return retList;
+ }
+
+ public List ReadAirports()
+ {
+ List retList = new List();
+
+ using (var reader = new StreamReader(IntegrationConfig.GetDataLocation() + "Airports.csv"))
+ {
+ int i = 0;
+ while (!reader.EndOfStream)
+ {
+ var line = reader.ReadLine();
+ var values = line.Split(';');
+
+ if (i != 0)
+ {
+ Airports airport = new Airports()
+ {
+ Code = values[0],
+ Name = values[1],
+ City = values[2],
+ Country = values[3]
+ };
+ retList.Add(airport);
+ }
+ i++;
+ }
+ }
+
+ return retList;
+ }
+
+ public List ReadFlights()
+ {
+ List retList = new List();
+
+ using (var reader = new StreamReader(IntegrationConfig.GetDataLocation() + "Flights.csv"))
+ {
+ var i = 0;
+ while (!reader.EndOfStream)
+ {
+ var line = reader.ReadLine();
+ var values = line.Split(';');
+
+ if (i != 0)
+ {
+ var flight = new Flights()
+ {
+ Company = values[0].Substring(0, 2),
+ FlightNum = int.Parse(values[0].Substring(3)),
+ From = values[1],
+ To = values[2],
+ Departs = values[3],
+ Arrives = values[4],
+ Price = int.Parse(values[5]),
+ ArrOnNextDay = bool.Parse(values[6])
+ };
+ retList.Add(flight);
+ }
+ i++;
+ }
+ }
+
+ return retList;
+ }
+
+ }
+}
diff --git a/RebusAdmin/Logic/IntegrationConfig.cs b/RebusAdmin/Logic/IntegrationConfig.cs
new file mode 100644
index 0000000..625dcdb
--- /dev/null
+++ b/RebusAdmin/Logic/IntegrationConfig.cs
@@ -0,0 +1,15 @@
+namespace RebusAdmin.Logic
+{
+ public static class IntegrationConfig
+ {
+
+ public static string GetDataBaseUri() { return OperatingSys.IsLinux() ? "bolt://neo4j:7687" : "bolt://localhost:7687"; }
+
+ public static string GetRebusNeoUri() { return "http://rebusneo:5002/"; }
+
+ public static string GetDataBaseUsername() { return "neo4j"; }
+ public static string GetDataBasePassword() { return "123"; }
+
+ public static string GetDataLocation() { return OperatingSys.IsLinux() ? "/app/files/" : @"C:\Users\pkuprevicius\Documents\dotnet\FlightSystem2\RebusAdmin\Files\"; }
+ }
+}
diff --git a/RebusAdmin/Logic/Neo4JContext.cs b/RebusAdmin/Logic/Neo4JContext.cs
new file mode 100644
index 0000000..304a79d
--- /dev/null
+++ b/RebusAdmin/Logic/Neo4JContext.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Threading.Tasks;
+using Neo4j.Driver.V1;
+
+namespace RebusAdmin.Logic
+{
+ public static class Neo4JContext
+ {
+ public static readonly ISession session = GraphDatabase.Driver(IntegrationConfig.GetDataBaseUri(), AuthTokens.Basic(IntegrationConfig.GetDataBaseUsername(), IntegrationConfig.GetDataBasePassword())).Session();
+
+ public static IStatementResult RunQuery(string query)
+ {
+ try
+ {
+ return session.Run(query);
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ finally
+ {
+ }
+ }
+
+ public static bool RunTestQuery()
+ {
+ try
+ {
+ var rez = session.Run("");
+ }
+ catch (ServiceUnavailableException)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/RebusAdmin/Logic/OperatingSys.cs b/RebusAdmin/Logic/OperatingSys.cs
new file mode 100644
index 0000000..7c1d1ab
--- /dev/null
+++ b/RebusAdmin/Logic/OperatingSys.cs
@@ -0,0 +1,10 @@
+using System.Runtime.InteropServices;
+
+public static class OperatingSys
+{
+ public static bool IsWindows() =>
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+
+ public static bool IsLinux() =>
+ RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+}
\ No newline at end of file
diff --git a/RebusAdmin/Logic/StatusManager.cs b/RebusAdmin/Logic/StatusManager.cs
new file mode 100644
index 0000000..1d080ba
--- /dev/null
+++ b/RebusAdmin/Logic/StatusManager.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace RebusAdmin.Logic
+{
+ public class StatusManager
+ {
+ public bool checkStatus()
+ {
+ return false;
+ }
+
+ }
+}
diff --git a/RebusAdmin/Program.cs b/RebusAdmin/Program.cs
new file mode 100644
index 0000000..b4666bc
--- /dev/null
+++ b/RebusAdmin/Program.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace RebusAdmin
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/RebusAdmin/Properties/launchSettings.json b/RebusAdmin/Properties/launchSettings.json
new file mode 100644
index 0000000..be2030b
--- /dev/null
+++ b/RebusAdmin/Properties/launchSettings.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:48195",
+ "sslPort": 44333
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "statuscheck",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "RebusAdmin": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "statuscheck",
+ "applicationUrl": "https://localhost:6004;http://localhost:6003",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/RebusAdmin/RebusAdmin.csproj b/RebusAdmin/RebusAdmin.csproj
new file mode 100644
index 0000000..9cc9513
--- /dev/null
+++ b/RebusAdmin/RebusAdmin.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
diff --git a/RebusAdmin/Startup.cs b/RebusAdmin/Startup.cs
new file mode 100644
index 0000000..2aa7627
--- /dev/null
+++ b/RebusAdmin/Startup.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.HttpsPolicy;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace RebusAdmin
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddControllers();
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseHttpsRedirection();
+
+ app.UseRouting();
+
+ app.UseAuthorization();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+ }
+}
diff --git a/RebusAdmin/WebApiClient.cs b/RebusAdmin/WebApiClient.cs
new file mode 100644
index 0000000..548bc8c
--- /dev/null
+++ b/RebusAdmin/WebApiClient.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace RebusAdmin
+{
+ class WebApiClient
+ {
+ private static readonly HttpClient client = new HttpClient();
+ private static string response = "httpError";
+
+ public static async Task Call(string uri)
+ {
+ // Call asynchronous network methods in a try/catch block to handle exceptions.
+ try
+ {
+ response = await client.GetStringAsync(uri);
+ }
+ catch (HttpRequestException)
+ {
+ //FIXME
+ return response;
+ }
+ System.Console.WriteLine(response);
+ return response;
+ }
+ }
+}
\ No newline at end of file
diff --git a/RebusAdmin/appsettings.Development.json b/RebusAdmin/appsettings.Development.json
new file mode 100644
index 0000000..8983e0f
--- /dev/null
+++ b/RebusAdmin/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/FlightSystem2/appsettings.json b/RebusAdmin/appsettings.json
similarity index 100%
rename from FlightSystem2/appsettings.json
rename to RebusAdmin/appsettings.json
diff --git a/RebusCore/Dockerfile b/RebusCore/Dockerfile
new file mode 100644
index 0000000..033bd71
--- /dev/null
+++ b/RebusCore/Dockerfile
@@ -0,0 +1,24 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
+WORKDIR /app
+ENV ASPNETCORE_URLS=http://+:5001
+EXPOSE 5001
+
+FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
+WORKDIR /src
+COPY ["RebusCore/RebusCore.csproj", "RebusCore/"]
+RUN dotnet restore "RebusCore/RebusCore.csproj"
+COPY . .
+WORKDIR "/src/RebusCore"
+RUN dotnet build "RebusCore.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "RebusCore.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "RebusCore.dll"]
+
+COPY RebusCore/Files /app/files
\ No newline at end of file
diff --git a/RebusCore/Files/flags/ad.png b/RebusCore/Files/flags/ad.png
new file mode 100644
index 0000000..c58bc93
Binary files /dev/null and b/RebusCore/Files/flags/ad.png differ
diff --git a/RebusCore/Files/flags/ae.png b/RebusCore/Files/flags/ae.png
new file mode 100644
index 0000000..088ef8e
Binary files /dev/null and b/RebusCore/Files/flags/ae.png differ
diff --git a/RebusCore/Files/flags/af.png b/RebusCore/Files/flags/af.png
new file mode 100644
index 0000000..995b351
Binary files /dev/null and b/RebusCore/Files/flags/af.png differ
diff --git a/RebusCore/Files/flags/ag.png b/RebusCore/Files/flags/ag.png
new file mode 100644
index 0000000..5f8b4f6
Binary files /dev/null and b/RebusCore/Files/flags/ag.png differ
diff --git a/RebusCore/Files/flags/al.png b/RebusCore/Files/flags/al.png
new file mode 100644
index 0000000..2e516ec
Binary files /dev/null and b/RebusCore/Files/flags/al.png differ
diff --git a/RebusCore/Files/flags/am.png b/RebusCore/Files/flags/am.png
new file mode 100644
index 0000000..d529a99
Binary files /dev/null and b/RebusCore/Files/flags/am.png differ
diff --git a/RebusCore/Files/flags/ao.png b/RebusCore/Files/flags/ao.png
new file mode 100644
index 0000000..4cdfb0e
Binary files /dev/null and b/RebusCore/Files/flags/ao.png differ
diff --git a/RebusCore/Files/flags/ar.png b/RebusCore/Files/flags/ar.png
new file mode 100644
index 0000000..b31ec92
Binary files /dev/null and b/RebusCore/Files/flags/ar.png differ
diff --git a/RebusCore/Files/flags/at.png b/RebusCore/Files/flags/at.png
new file mode 100644
index 0000000..993b903
Binary files /dev/null and b/RebusCore/Files/flags/at.png differ
diff --git a/RebusCore/Files/flags/au.png b/RebusCore/Files/flags/au.png
new file mode 100644
index 0000000..ef20b66
Binary files /dev/null and b/RebusCore/Files/flags/au.png differ
diff --git a/RebusCore/Files/flags/az.png b/RebusCore/Files/flags/az.png
new file mode 100644
index 0000000..3fb7ccb
Binary files /dev/null and b/RebusCore/Files/flags/az.png differ
diff --git a/RebusCore/Files/flags/ba.png b/RebusCore/Files/flags/ba.png
new file mode 100644
index 0000000..fa4d609
Binary files /dev/null and b/RebusCore/Files/flags/ba.png differ
diff --git a/RebusCore/Files/flags/bb.png b/RebusCore/Files/flags/bb.png
new file mode 100644
index 0000000..5e87a9e
Binary files /dev/null and b/RebusCore/Files/flags/bb.png differ
diff --git a/RebusCore/Files/flags/bd.png b/RebusCore/Files/flags/bd.png
new file mode 100644
index 0000000..c55d3d7
Binary files /dev/null and b/RebusCore/Files/flags/bd.png differ
diff --git a/RebusCore/Files/flags/be.png b/RebusCore/Files/flags/be.png
new file mode 100644
index 0000000..449446a
Binary files /dev/null and b/RebusCore/Files/flags/be.png differ
diff --git a/RebusCore/Files/flags/bf.png b/RebusCore/Files/flags/bf.png
new file mode 100644
index 0000000..f3a7288
Binary files /dev/null and b/RebusCore/Files/flags/bf.png differ
diff --git a/RebusCore/Files/flags/bg.png b/RebusCore/Files/flags/bg.png
new file mode 100644
index 0000000..ec03d4f
Binary files /dev/null and b/RebusCore/Files/flags/bg.png differ
diff --git a/RebusCore/Files/flags/bh.png b/RebusCore/Files/flags/bh.png
new file mode 100644
index 0000000..61bad9b
Binary files /dev/null and b/RebusCore/Files/flags/bh.png differ
diff --git a/RebusCore/Files/flags/bi.png b/RebusCore/Files/flags/bi.png
new file mode 100644
index 0000000..d82b894
Binary files /dev/null and b/RebusCore/Files/flags/bi.png differ
diff --git a/RebusCore/Files/flags/bj.png b/RebusCore/Files/flags/bj.png
new file mode 100644
index 0000000..220c8e7
Binary files /dev/null and b/RebusCore/Files/flags/bj.png differ
diff --git a/RebusCore/Files/flags/bn.png b/RebusCore/Files/flags/bn.png
new file mode 100644
index 0000000..944a7be
Binary files /dev/null and b/RebusCore/Files/flags/bn.png differ
diff --git a/RebusCore/Files/flags/bo.png b/RebusCore/Files/flags/bo.png
new file mode 100644
index 0000000..aec2cc6
Binary files /dev/null and b/RebusCore/Files/flags/bo.png differ
diff --git a/RebusCore/Files/flags/br.png b/RebusCore/Files/flags/br.png
new file mode 100644
index 0000000..b54f27d
Binary files /dev/null and b/RebusCore/Files/flags/br.png differ
diff --git a/RebusCore/Files/flags/bs.png b/RebusCore/Files/flags/bs.png
new file mode 100644
index 0000000..43db8c1
Binary files /dev/null and b/RebusCore/Files/flags/bs.png differ
diff --git a/RebusCore/Files/flags/bt.png b/RebusCore/Files/flags/bt.png
new file mode 100644
index 0000000..dfd0d6a
Binary files /dev/null and b/RebusCore/Files/flags/bt.png differ
diff --git a/RebusCore/Files/flags/bw.png b/RebusCore/Files/flags/bw.png
new file mode 100644
index 0000000..0a74b72
Binary files /dev/null and b/RebusCore/Files/flags/bw.png differ
diff --git a/RebusCore/Files/flags/by.png b/RebusCore/Files/flags/by.png
new file mode 100644
index 0000000..1c9f546
Binary files /dev/null and b/RebusCore/Files/flags/by.png differ
diff --git a/RebusCore/Files/flags/bz.png b/RebusCore/Files/flags/bz.png
new file mode 100644
index 0000000..ef37f6d
Binary files /dev/null and b/RebusCore/Files/flags/bz.png differ
diff --git a/RebusCore/Files/flags/ca.png b/RebusCore/Files/flags/ca.png
new file mode 100644
index 0000000..524f815
Binary files /dev/null and b/RebusCore/Files/flags/ca.png differ
diff --git a/RebusCore/Files/flags/cd.png b/RebusCore/Files/flags/cd.png
new file mode 100644
index 0000000..a96eccf
Binary files /dev/null and b/RebusCore/Files/flags/cd.png differ
diff --git a/RebusCore/Files/flags/cf.png b/RebusCore/Files/flags/cf.png
new file mode 100644
index 0000000..e203020
Binary files /dev/null and b/RebusCore/Files/flags/cf.png differ
diff --git a/RebusCore/Files/flags/cg.png b/RebusCore/Files/flags/cg.png
new file mode 100644
index 0000000..7afcfe0
Binary files /dev/null and b/RebusCore/Files/flags/cg.png differ
diff --git a/RebusCore/Files/flags/ch.png b/RebusCore/Files/flags/ch.png
new file mode 100644
index 0000000..bd447d2
Binary files /dev/null and b/RebusCore/Files/flags/ch.png differ
diff --git a/RebusCore/Files/flags/ci.png b/RebusCore/Files/flags/ci.png
new file mode 100644
index 0000000..14fceff
Binary files /dev/null and b/RebusCore/Files/flags/ci.png differ
diff --git a/RebusCore/Files/flags/ck.png b/RebusCore/Files/flags/ck.png
new file mode 100644
index 0000000..d74b82d
Binary files /dev/null and b/RebusCore/Files/flags/ck.png differ
diff --git a/RebusCore/Files/flags/cl.png b/RebusCore/Files/flags/cl.png
new file mode 100644
index 0000000..741c34b
Binary files /dev/null and b/RebusCore/Files/flags/cl.png differ
diff --git a/RebusCore/Files/flags/cm.png b/RebusCore/Files/flags/cm.png
new file mode 100644
index 0000000..e2a308b
Binary files /dev/null and b/RebusCore/Files/flags/cm.png differ
diff --git a/RebusCore/Files/flags/cn.png b/RebusCore/Files/flags/cn.png
new file mode 100644
index 0000000..7474dde
Binary files /dev/null and b/RebusCore/Files/flags/cn.png differ
diff --git a/RebusCore/Files/flags/co.png b/RebusCore/Files/flags/co.png
new file mode 100644
index 0000000..477177b
Binary files /dev/null and b/RebusCore/Files/flags/co.png differ
diff --git a/RebusCore/Files/flags/cr.png b/RebusCore/Files/flags/cr.png
new file mode 100644
index 0000000..62cc81a
Binary files /dev/null and b/RebusCore/Files/flags/cr.png differ
diff --git a/RebusCore/Files/flags/cu.png b/RebusCore/Files/flags/cu.png
new file mode 100644
index 0000000..4ada582
Binary files /dev/null and b/RebusCore/Files/flags/cu.png differ
diff --git a/RebusCore/Files/flags/cv.png b/RebusCore/Files/flags/cv.png
new file mode 100644
index 0000000..e45bfdb
Binary files /dev/null and b/RebusCore/Files/flags/cv.png differ
diff --git a/RebusCore/Files/flags/cy.png b/RebusCore/Files/flags/cy.png
new file mode 100644
index 0000000..e909ebc
Binary files /dev/null and b/RebusCore/Files/flags/cy.png differ
diff --git a/RebusCore/Files/flags/cz.png b/RebusCore/Files/flags/cz.png
new file mode 100644
index 0000000..acfac56
Binary files /dev/null and b/RebusCore/Files/flags/cz.png differ
diff --git a/RebusCore/Files/flags/de.png b/RebusCore/Files/flags/de.png
new file mode 100644
index 0000000..2dbd9b0
Binary files /dev/null and b/RebusCore/Files/flags/de.png differ
diff --git a/RebusCore/Files/flags/dj.png b/RebusCore/Files/flags/dj.png
new file mode 100644
index 0000000..147636a
Binary files /dev/null and b/RebusCore/Files/flags/dj.png differ
diff --git a/RebusCore/Files/flags/dk.png b/RebusCore/Files/flags/dk.png
new file mode 100644
index 0000000..65d6b35
Binary files /dev/null and b/RebusCore/Files/flags/dk.png differ
diff --git a/RebusCore/Files/flags/dm.png b/RebusCore/Files/flags/dm.png
new file mode 100644
index 0000000..04a92e1
Binary files /dev/null and b/RebusCore/Files/flags/dm.png differ
diff --git a/RebusCore/Files/flags/do.png b/RebusCore/Files/flags/do.png
new file mode 100644
index 0000000..12e017e
Binary files /dev/null and b/RebusCore/Files/flags/do.png differ
diff --git a/RebusCore/Files/flags/dz.png b/RebusCore/Files/flags/dz.png
new file mode 100644
index 0000000..4670a0e
Binary files /dev/null and b/RebusCore/Files/flags/dz.png differ
diff --git a/RebusCore/Files/flags/ec.png b/RebusCore/Files/flags/ec.png
new file mode 100644
index 0000000..9289152
Binary files /dev/null and b/RebusCore/Files/flags/ec.png differ
diff --git a/RebusCore/Files/flags/ee.png b/RebusCore/Files/flags/ee.png
new file mode 100644
index 0000000..1067640
Binary files /dev/null and b/RebusCore/Files/flags/ee.png differ
diff --git a/RebusCore/Files/flags/eg.png b/RebusCore/Files/flags/eg.png
new file mode 100644
index 0000000..238d535
Binary files /dev/null and b/RebusCore/Files/flags/eg.png differ
diff --git a/RebusCore/Files/flags/eh.png b/RebusCore/Files/flags/eh.png
new file mode 100644
index 0000000..b8cf7ef
Binary files /dev/null and b/RebusCore/Files/flags/eh.png differ
diff --git a/RebusCore/Files/flags/er.png b/RebusCore/Files/flags/er.png
new file mode 100644
index 0000000..546b1b9
Binary files /dev/null and b/RebusCore/Files/flags/er.png differ
diff --git a/RebusCore/Files/flags/es.png b/RebusCore/Files/flags/es.png
new file mode 100644
index 0000000..a8ad334
Binary files /dev/null and b/RebusCore/Files/flags/es.png differ
diff --git a/RebusCore/Files/flags/et.png b/RebusCore/Files/flags/et.png
new file mode 100644
index 0000000..e807c21
Binary files /dev/null and b/RebusCore/Files/flags/et.png differ
diff --git a/RebusCore/Files/flags/fi.png b/RebusCore/Files/flags/fi.png
new file mode 100644
index 0000000..1ad1797
Binary files /dev/null and b/RebusCore/Files/flags/fi.png differ
diff --git a/RebusCore/Files/flags/fj.png b/RebusCore/Files/flags/fj.png
new file mode 100644
index 0000000..6bf7371
Binary files /dev/null and b/RebusCore/Files/flags/fj.png differ
diff --git a/RebusCore/Files/flags/fm.png b/RebusCore/Files/flags/fm.png
new file mode 100644
index 0000000..32d5b83
Binary files /dev/null and b/RebusCore/Files/flags/fm.png differ
diff --git a/RebusCore/Files/flags/fr.png b/RebusCore/Files/flags/fr.png
new file mode 100644
index 0000000..a768476
Binary files /dev/null and b/RebusCore/Files/flags/fr.png differ
diff --git a/RebusCore/Files/flags/ga.png b/RebusCore/Files/flags/ga.png
new file mode 100644
index 0000000..32c68bf
Binary files /dev/null and b/RebusCore/Files/flags/ga.png differ
diff --git a/RebusCore/Files/flags/gb.png b/RebusCore/Files/flags/gb.png
new file mode 100644
index 0000000..3b6668e
Binary files /dev/null and b/RebusCore/Files/flags/gb.png differ
diff --git a/RebusCore/Files/flags/gd.png b/RebusCore/Files/flags/gd.png
new file mode 100644
index 0000000..9a68c48
Binary files /dev/null and b/RebusCore/Files/flags/gd.png differ
diff --git a/RebusCore/Files/flags/ge.png b/RebusCore/Files/flags/ge.png
new file mode 100644
index 0000000..108e367
Binary files /dev/null and b/RebusCore/Files/flags/ge.png differ
diff --git a/RebusCore/Files/flags/gh.png b/RebusCore/Files/flags/gh.png
new file mode 100644
index 0000000..c2bf9d0
Binary files /dev/null and b/RebusCore/Files/flags/gh.png differ
diff --git a/RebusCore/Files/flags/gm.png b/RebusCore/Files/flags/gm.png
new file mode 100644
index 0000000..b929a80
Binary files /dev/null and b/RebusCore/Files/flags/gm.png differ
diff --git a/RebusCore/Files/flags/gn.png b/RebusCore/Files/flags/gn.png
new file mode 100644
index 0000000..be43ceb
Binary files /dev/null and b/RebusCore/Files/flags/gn.png differ
diff --git a/RebusCore/Files/flags/gq.png b/RebusCore/Files/flags/gq.png
new file mode 100644
index 0000000..db9415a
Binary files /dev/null and b/RebusCore/Files/flags/gq.png differ
diff --git a/RebusCore/Files/flags/gr.png b/RebusCore/Files/flags/gr.png
new file mode 100644
index 0000000..0944411
Binary files /dev/null and b/RebusCore/Files/flags/gr.png differ
diff --git a/RebusCore/Files/flags/gt.png b/RebusCore/Files/flags/gt.png
new file mode 100644
index 0000000..76c5db7
Binary files /dev/null and b/RebusCore/Files/flags/gt.png differ
diff --git a/RebusCore/Files/flags/gw.png b/RebusCore/Files/flags/gw.png
new file mode 100644
index 0000000..06dc510
Binary files /dev/null and b/RebusCore/Files/flags/gw.png differ
diff --git a/RebusCore/Files/flags/gy.png b/RebusCore/Files/flags/gy.png
new file mode 100644
index 0000000..4f9b232
Binary files /dev/null and b/RebusCore/Files/flags/gy.png differ
diff --git a/RebusCore/Files/flags/hn.png b/RebusCore/Files/flags/hn.png
new file mode 100644
index 0000000..b1a9f5f
Binary files /dev/null and b/RebusCore/Files/flags/hn.png differ
diff --git a/RebusCore/Files/flags/hr.png b/RebusCore/Files/flags/hr.png
new file mode 100644
index 0000000..6820513
Binary files /dev/null and b/RebusCore/Files/flags/hr.png differ
diff --git a/RebusCore/Files/flags/ht.png b/RebusCore/Files/flags/ht.png
new file mode 100644
index 0000000..ba76abd
Binary files /dev/null and b/RebusCore/Files/flags/ht.png differ
diff --git a/RebusCore/Files/flags/hu.png b/RebusCore/Files/flags/hu.png
new file mode 100644
index 0000000..eeee4ca
Binary files /dev/null and b/RebusCore/Files/flags/hu.png differ
diff --git a/RebusCore/Files/flags/id.png b/RebusCore/Files/flags/id.png
new file mode 100644
index 0000000..e96bc74
Binary files /dev/null and b/RebusCore/Files/flags/id.png differ
diff --git a/RebusCore/Files/flags/ie.png b/RebusCore/Files/flags/ie.png
new file mode 100644
index 0000000..52e2ad4
Binary files /dev/null and b/RebusCore/Files/flags/ie.png differ
diff --git a/RebusCore/Files/flags/il.png b/RebusCore/Files/flags/il.png
new file mode 100644
index 0000000..c85c9d3
Binary files /dev/null and b/RebusCore/Files/flags/il.png differ
diff --git a/RebusCore/Files/flags/in.png b/RebusCore/Files/flags/in.png
new file mode 100644
index 0000000..be5acd3
Binary files /dev/null and b/RebusCore/Files/flags/in.png differ
diff --git a/RebusCore/Files/flags/iq.png b/RebusCore/Files/flags/iq.png
new file mode 100644
index 0000000..f370c9a
Binary files /dev/null and b/RebusCore/Files/flags/iq.png differ
diff --git a/RebusCore/Files/flags/ir.png b/RebusCore/Files/flags/ir.png
new file mode 100644
index 0000000..7f647fa
Binary files /dev/null and b/RebusCore/Files/flags/ir.png differ
diff --git a/RebusCore/Files/flags/is.png b/RebusCore/Files/flags/is.png
new file mode 100644
index 0000000..74c9e03
Binary files /dev/null and b/RebusCore/Files/flags/is.png differ
diff --git a/RebusCore/Files/flags/it.png b/RebusCore/Files/flags/it.png
new file mode 100644
index 0000000..d62e50b
Binary files /dev/null and b/RebusCore/Files/flags/it.png differ
diff --git a/RebusCore/Files/flags/jm.png b/RebusCore/Files/flags/jm.png
new file mode 100644
index 0000000..a960d3d
Binary files /dev/null and b/RebusCore/Files/flags/jm.png differ
diff --git a/RebusCore/Files/flags/jo.png b/RebusCore/Files/flags/jo.png
new file mode 100644
index 0000000..e8b743a
Binary files /dev/null and b/RebusCore/Files/flags/jo.png differ
diff --git a/RebusCore/Files/flags/jp.png b/RebusCore/Files/flags/jp.png
new file mode 100644
index 0000000..fd1ce05
Binary files /dev/null and b/RebusCore/Files/flags/jp.png differ
diff --git a/RebusCore/Files/flags/ke.png b/RebusCore/Files/flags/ke.png
new file mode 100644
index 0000000..dbf559f
Binary files /dev/null and b/RebusCore/Files/flags/ke.png differ
diff --git a/RebusCore/Files/flags/kg.png b/RebusCore/Files/flags/kg.png
new file mode 100644
index 0000000..c0fe3e5
Binary files /dev/null and b/RebusCore/Files/flags/kg.png differ
diff --git a/RebusCore/Files/flags/kh.png b/RebusCore/Files/flags/kh.png
new file mode 100644
index 0000000..b9340f7
Binary files /dev/null and b/RebusCore/Files/flags/kh.png differ
diff --git a/RebusCore/Files/flags/ki.png b/RebusCore/Files/flags/ki.png
new file mode 100644
index 0000000..6b718d1
Binary files /dev/null and b/RebusCore/Files/flags/ki.png differ
diff --git a/RebusCore/Files/flags/km.png b/RebusCore/Files/flags/km.png
new file mode 100644
index 0000000..dbbd8f4
Binary files /dev/null and b/RebusCore/Files/flags/km.png differ
diff --git a/RebusCore/Files/flags/kn.png b/RebusCore/Files/flags/kn.png
new file mode 100644
index 0000000..028bef5
Binary files /dev/null and b/RebusCore/Files/flags/kn.png differ
diff --git a/RebusCore/Files/flags/kp.png b/RebusCore/Files/flags/kp.png
new file mode 100644
index 0000000..3fee379
Binary files /dev/null and b/RebusCore/Files/flags/kp.png differ
diff --git a/RebusCore/Files/flags/kr.png b/RebusCore/Files/flags/kr.png
new file mode 100644
index 0000000..d0022a2
Binary files /dev/null and b/RebusCore/Files/flags/kr.png differ
diff --git a/RebusCore/Files/flags/kw.png b/RebusCore/Files/flags/kw.png
new file mode 100644
index 0000000..7f701d5
Binary files /dev/null and b/RebusCore/Files/flags/kw.png differ
diff --git a/RebusCore/Files/flags/kz.png b/RebusCore/Files/flags/kz.png
new file mode 100644
index 0000000..1c23ee1
Binary files /dev/null and b/RebusCore/Files/flags/kz.png differ
diff --git a/RebusCore/Files/flags/la.png b/RebusCore/Files/flags/la.png
new file mode 100644
index 0000000..9758884
Binary files /dev/null and b/RebusCore/Files/flags/la.png differ
diff --git a/RebusCore/Files/flags/lb.png b/RebusCore/Files/flags/lb.png
new file mode 100644
index 0000000..80b3256
Binary files /dev/null and b/RebusCore/Files/flags/lb.png differ
diff --git a/RebusCore/Files/flags/lc.png b/RebusCore/Files/flags/lc.png
new file mode 100644
index 0000000..dc2de27
Binary files /dev/null and b/RebusCore/Files/flags/lc.png differ
diff --git a/RebusCore/Files/flags/li.png b/RebusCore/Files/flags/li.png
new file mode 100644
index 0000000..c635a63
Binary files /dev/null and b/RebusCore/Files/flags/li.png differ
diff --git a/RebusCore/Files/flags/lk.png b/RebusCore/Files/flags/lk.png
new file mode 100644
index 0000000..12e6a00
Binary files /dev/null and b/RebusCore/Files/flags/lk.png differ
diff --git a/RebusCore/Files/flags/lr.png b/RebusCore/Files/flags/lr.png
new file mode 100644
index 0000000..0b998ab
Binary files /dev/null and b/RebusCore/Files/flags/lr.png differ
diff --git a/RebusCore/Files/flags/ls.png b/RebusCore/Files/flags/ls.png
new file mode 100644
index 0000000..ba9ed2d
Binary files /dev/null and b/RebusCore/Files/flags/ls.png differ
diff --git a/RebusCore/Files/flags/lt.png b/RebusCore/Files/flags/lt.png
new file mode 100644
index 0000000..257930e
Binary files /dev/null and b/RebusCore/Files/flags/lt.png differ
diff --git a/RebusCore/Files/flags/lu.png b/RebusCore/Files/flags/lu.png
new file mode 100644
index 0000000..64b5dd6
Binary files /dev/null and b/RebusCore/Files/flags/lu.png differ
diff --git a/RebusCore/Files/flags/lv.png b/RebusCore/Files/flags/lv.png
new file mode 100644
index 0000000..fb8345e
Binary files /dev/null and b/RebusCore/Files/flags/lv.png differ
diff --git a/RebusCore/Files/flags/ly.png b/RebusCore/Files/flags/ly.png
new file mode 100644
index 0000000..b90fc93
Binary files /dev/null and b/RebusCore/Files/flags/ly.png differ
diff --git a/RebusCore/Files/flags/ma.png b/RebusCore/Files/flags/ma.png
new file mode 100644
index 0000000..8e62535
Binary files /dev/null and b/RebusCore/Files/flags/ma.png differ
diff --git a/RebusCore/Files/flags/mc.png b/RebusCore/Files/flags/mc.png
new file mode 100644
index 0000000..194a09e
Binary files /dev/null and b/RebusCore/Files/flags/mc.png differ
diff --git a/RebusCore/Files/flags/md.png b/RebusCore/Files/flags/md.png
new file mode 100644
index 0000000..0071401
Binary files /dev/null and b/RebusCore/Files/flags/md.png differ
diff --git a/RebusCore/Files/flags/me.png b/RebusCore/Files/flags/me.png
new file mode 100644
index 0000000..0952236
Binary files /dev/null and b/RebusCore/Files/flags/me.png differ
diff --git a/RebusCore/Files/flags/mg.png b/RebusCore/Files/flags/mg.png
new file mode 100644
index 0000000..4b4b065
Binary files /dev/null and b/RebusCore/Files/flags/mg.png differ
diff --git a/RebusCore/Files/flags/mh.png b/RebusCore/Files/flags/mh.png
new file mode 100644
index 0000000..3e7a4b5
Binary files /dev/null and b/RebusCore/Files/flags/mh.png differ
diff --git a/RebusCore/Files/flags/mk.png b/RebusCore/Files/flags/mk.png
new file mode 100644
index 0000000..4cb42a7
Binary files /dev/null and b/RebusCore/Files/flags/mk.png differ
diff --git a/RebusCore/Files/flags/ml.png b/RebusCore/Files/flags/ml.png
new file mode 100644
index 0000000..182848a
Binary files /dev/null and b/RebusCore/Files/flags/ml.png differ
diff --git a/RebusCore/Files/flags/mm.png b/RebusCore/Files/flags/mm.png
new file mode 100644
index 0000000..f486f85
Binary files /dev/null and b/RebusCore/Files/flags/mm.png differ
diff --git a/RebusCore/Files/flags/mn.png b/RebusCore/Files/flags/mn.png
new file mode 100644
index 0000000..dd0bb39
Binary files /dev/null and b/RebusCore/Files/flags/mn.png differ
diff --git a/RebusCore/Files/flags/mr.png b/RebusCore/Files/flags/mr.png
new file mode 100644
index 0000000..caf0365
Binary files /dev/null and b/RebusCore/Files/flags/mr.png differ
diff --git a/RebusCore/Files/flags/mt.png b/RebusCore/Files/flags/mt.png
new file mode 100644
index 0000000..b4d686e
Binary files /dev/null and b/RebusCore/Files/flags/mt.png differ
diff --git a/RebusCore/Files/flags/mu.png b/RebusCore/Files/flags/mu.png
new file mode 100644
index 0000000..03f524f
Binary files /dev/null and b/RebusCore/Files/flags/mu.png differ
diff --git a/RebusCore/Files/flags/mv.png b/RebusCore/Files/flags/mv.png
new file mode 100644
index 0000000..ab4aae4
Binary files /dev/null and b/RebusCore/Files/flags/mv.png differ
diff --git a/RebusCore/Files/flags/mw.png b/RebusCore/Files/flags/mw.png
new file mode 100644
index 0000000..bf38ff9
Binary files /dev/null and b/RebusCore/Files/flags/mw.png differ
diff --git a/RebusCore/Files/flags/mx.png b/RebusCore/Files/flags/mx.png
new file mode 100644
index 0000000..783148b
Binary files /dev/null and b/RebusCore/Files/flags/mx.png differ
diff --git a/RebusCore/Files/flags/my.png b/RebusCore/Files/flags/my.png
new file mode 100644
index 0000000..5a9ae41
Binary files /dev/null and b/RebusCore/Files/flags/my.png differ
diff --git a/RebusCore/Files/flags/mz.png b/RebusCore/Files/flags/mz.png
new file mode 100644
index 0000000..0e4c983
Binary files /dev/null and b/RebusCore/Files/flags/mz.png differ
diff --git a/RebusCore/Files/flags/na.png b/RebusCore/Files/flags/na.png
new file mode 100644
index 0000000..620937b
Binary files /dev/null and b/RebusCore/Files/flags/na.png differ
diff --git a/RebusCore/Files/flags/ne.png b/RebusCore/Files/flags/ne.png
new file mode 100644
index 0000000..0762231
Binary files /dev/null and b/RebusCore/Files/flags/ne.png differ
diff --git a/RebusCore/Files/flags/ng.png b/RebusCore/Files/flags/ng.png
new file mode 100644
index 0000000..ba56e9e
Binary files /dev/null and b/RebusCore/Files/flags/ng.png differ
diff --git a/RebusCore/Files/flags/ni.png b/RebusCore/Files/flags/ni.png
new file mode 100644
index 0000000..9b6dbf5
Binary files /dev/null and b/RebusCore/Files/flags/ni.png differ
diff --git a/RebusCore/Files/flags/nl.png b/RebusCore/Files/flags/nl.png
new file mode 100644
index 0000000..aeb72b6
Binary files /dev/null and b/RebusCore/Files/flags/nl.png differ
diff --git a/RebusCore/Files/flags/no.png b/RebusCore/Files/flags/no.png
new file mode 100644
index 0000000..e14f90f
Binary files /dev/null and b/RebusCore/Files/flags/no.png differ
diff --git a/RebusCore/Files/flags/np.png b/RebusCore/Files/flags/np.png
new file mode 100644
index 0000000..fd0cd6e
Binary files /dev/null and b/RebusCore/Files/flags/np.png differ
diff --git a/RebusCore/Files/flags/nr.png b/RebusCore/Files/flags/nr.png
new file mode 100644
index 0000000..7214086
Binary files /dev/null and b/RebusCore/Files/flags/nr.png differ
diff --git a/RebusCore/Files/flags/nu.png b/RebusCore/Files/flags/nu.png
new file mode 100644
index 0000000..c7d8797
Binary files /dev/null and b/RebusCore/Files/flags/nu.png differ
diff --git a/RebusCore/Files/flags/nz.png b/RebusCore/Files/flags/nz.png
new file mode 100644
index 0000000..1f25035
Binary files /dev/null and b/RebusCore/Files/flags/nz.png differ
diff --git a/RebusCore/Files/flags/om.png b/RebusCore/Files/flags/om.png
new file mode 100644
index 0000000..05c99d9
Binary files /dev/null and b/RebusCore/Files/flags/om.png differ
diff --git a/RebusCore/Files/flags/pa.png b/RebusCore/Files/flags/pa.png
new file mode 100644
index 0000000..96d4c8e
Binary files /dev/null and b/RebusCore/Files/flags/pa.png differ
diff --git a/RebusCore/Files/flags/pe.png b/RebusCore/Files/flags/pe.png
new file mode 100644
index 0000000..e4d623e
Binary files /dev/null and b/RebusCore/Files/flags/pe.png differ
diff --git a/RebusCore/Files/flags/pg.png b/RebusCore/Files/flags/pg.png
new file mode 100644
index 0000000..5011a16
Binary files /dev/null and b/RebusCore/Files/flags/pg.png differ
diff --git a/RebusCore/Files/flags/ph.png b/RebusCore/Files/flags/ph.png
new file mode 100644
index 0000000..41ddff2
Binary files /dev/null and b/RebusCore/Files/flags/ph.png differ
diff --git a/RebusCore/Files/flags/pk.png b/RebusCore/Files/flags/pk.png
new file mode 100644
index 0000000..76020fe
Binary files /dev/null and b/RebusCore/Files/flags/pk.png differ
diff --git a/RebusCore/Files/flags/pl.png b/RebusCore/Files/flags/pl.png
new file mode 100644
index 0000000..d4db002
Binary files /dev/null and b/RebusCore/Files/flags/pl.png differ
diff --git a/RebusCore/Files/flags/ps.png b/RebusCore/Files/flags/ps.png
new file mode 100644
index 0000000..540f058
Binary files /dev/null and b/RebusCore/Files/flags/ps.png differ
diff --git a/RebusCore/Files/flags/pt.png b/RebusCore/Files/flags/pt.png
new file mode 100644
index 0000000..e0619bc
Binary files /dev/null and b/RebusCore/Files/flags/pt.png differ
diff --git a/RebusCore/Files/flags/pw.png b/RebusCore/Files/flags/pw.png
new file mode 100644
index 0000000..be101ba
Binary files /dev/null and b/RebusCore/Files/flags/pw.png differ
diff --git a/RebusCore/Files/flags/py.png b/RebusCore/Files/flags/py.png
new file mode 100644
index 0000000..b2e2d5c
Binary files /dev/null and b/RebusCore/Files/flags/py.png differ
diff --git a/RebusCore/Files/flags/qa.png b/RebusCore/Files/flags/qa.png
new file mode 100644
index 0000000..0e615fe
Binary files /dev/null and b/RebusCore/Files/flags/qa.png differ
diff --git a/RebusCore/Files/flags/ro.png b/RebusCore/Files/flags/ro.png
new file mode 100644
index 0000000..57f34f3
Binary files /dev/null and b/RebusCore/Files/flags/ro.png differ
diff --git a/RebusCore/Files/flags/rs.png b/RebusCore/Files/flags/rs.png
new file mode 100644
index 0000000..7273ea7
Binary files /dev/null and b/RebusCore/Files/flags/rs.png differ
diff --git a/RebusCore/Files/flags/ru.png b/RebusCore/Files/flags/ru.png
new file mode 100644
index 0000000..79d2101
Binary files /dev/null and b/RebusCore/Files/flags/ru.png differ
diff --git a/RebusCore/Files/flags/rw.png b/RebusCore/Files/flags/rw.png
new file mode 100644
index 0000000..5b859ea
Binary files /dev/null and b/RebusCore/Files/flags/rw.png differ
diff --git a/RebusCore/Files/flags/sa.png b/RebusCore/Files/flags/sa.png
new file mode 100644
index 0000000..0df5b92
Binary files /dev/null and b/RebusCore/Files/flags/sa.png differ
diff --git a/RebusCore/Files/flags/sb.png b/RebusCore/Files/flags/sb.png
new file mode 100644
index 0000000..832f7ce
Binary files /dev/null and b/RebusCore/Files/flags/sb.png differ
diff --git a/RebusCore/Files/flags/sc.png b/RebusCore/Files/flags/sc.png
new file mode 100644
index 0000000..a497589
Binary files /dev/null and b/RebusCore/Files/flags/sc.png differ
diff --git a/RebusCore/Files/flags/sd.png b/RebusCore/Files/flags/sd.png
new file mode 100644
index 0000000..386f3e8
Binary files /dev/null and b/RebusCore/Files/flags/sd.png differ
diff --git a/RebusCore/Files/flags/se.png b/RebusCore/Files/flags/se.png
new file mode 100644
index 0000000..9e12578
Binary files /dev/null and b/RebusCore/Files/flags/se.png differ
diff --git a/RebusCore/Files/flags/sg.png b/RebusCore/Files/flags/sg.png
new file mode 100644
index 0000000..7e89814
Binary files /dev/null and b/RebusCore/Files/flags/sg.png differ
diff --git a/RebusCore/Files/flags/si.png b/RebusCore/Files/flags/si.png
new file mode 100644
index 0000000..3692b66
Binary files /dev/null and b/RebusCore/Files/flags/si.png differ
diff --git a/RebusCore/Files/flags/sk.png b/RebusCore/Files/flags/sk.png
new file mode 100644
index 0000000..8a73d64
Binary files /dev/null and b/RebusCore/Files/flags/sk.png differ
diff --git a/RebusCore/Files/flags/sl.png b/RebusCore/Files/flags/sl.png
new file mode 100644
index 0000000..b68450d
Binary files /dev/null and b/RebusCore/Files/flags/sl.png differ
diff --git a/RebusCore/Files/flags/sm.png b/RebusCore/Files/flags/sm.png
new file mode 100644
index 0000000..43f1965
Binary files /dev/null and b/RebusCore/Files/flags/sm.png differ
diff --git a/RebusCore/Files/flags/sn.png b/RebusCore/Files/flags/sn.png
new file mode 100644
index 0000000..fcd0244
Binary files /dev/null and b/RebusCore/Files/flags/sn.png differ
diff --git a/RebusCore/Files/flags/so.png b/RebusCore/Files/flags/so.png
new file mode 100644
index 0000000..819490b
Binary files /dev/null and b/RebusCore/Files/flags/so.png differ
diff --git a/RebusCore/Files/flags/sr.png b/RebusCore/Files/flags/sr.png
new file mode 100644
index 0000000..9ac4337
Binary files /dev/null and b/RebusCore/Files/flags/sr.png differ
diff --git a/RebusCore/Files/flags/ss.png b/RebusCore/Files/flags/ss.png
new file mode 100644
index 0000000..dbc04d5
Binary files /dev/null and b/RebusCore/Files/flags/ss.png differ
diff --git a/RebusCore/Files/flags/st.png b/RebusCore/Files/flags/st.png
new file mode 100644
index 0000000..b4edccb
Binary files /dev/null and b/RebusCore/Files/flags/st.png differ
diff --git a/RebusCore/Files/flags/sv.png b/RebusCore/Files/flags/sv.png
new file mode 100644
index 0000000..7fe790c
Binary files /dev/null and b/RebusCore/Files/flags/sv.png differ
diff --git a/RebusCore/Files/flags/sy.png b/RebusCore/Files/flags/sy.png
new file mode 100644
index 0000000..c78f9d5
Binary files /dev/null and b/RebusCore/Files/flags/sy.png differ
diff --git a/RebusCore/Files/flags/sz.png b/RebusCore/Files/flags/sz.png
new file mode 100644
index 0000000..6550515
Binary files /dev/null and b/RebusCore/Files/flags/sz.png differ
diff --git a/RebusCore/Files/flags/td.png b/RebusCore/Files/flags/td.png
new file mode 100644
index 0000000..c0c76da
Binary files /dev/null and b/RebusCore/Files/flags/td.png differ
diff --git a/RebusCore/Files/flags/tg.png b/RebusCore/Files/flags/tg.png
new file mode 100644
index 0000000..31f1a00
Binary files /dev/null and b/RebusCore/Files/flags/tg.png differ
diff --git a/RebusCore/Files/flags/th.png b/RebusCore/Files/flags/th.png
new file mode 100644
index 0000000..5cf74c9
Binary files /dev/null and b/RebusCore/Files/flags/th.png differ
diff --git a/RebusCore/Files/flags/tj.png b/RebusCore/Files/flags/tj.png
new file mode 100644
index 0000000..1d83e4c
Binary files /dev/null and b/RebusCore/Files/flags/tj.png differ
diff --git a/RebusCore/Files/flags/tl.png b/RebusCore/Files/flags/tl.png
new file mode 100644
index 0000000..c646f33
Binary files /dev/null and b/RebusCore/Files/flags/tl.png differ
diff --git a/RebusCore/Files/flags/tm.png b/RebusCore/Files/flags/tm.png
new file mode 100644
index 0000000..5dd8fb9
Binary files /dev/null and b/RebusCore/Files/flags/tm.png differ
diff --git a/RebusCore/Files/flags/tn.png b/RebusCore/Files/flags/tn.png
new file mode 100644
index 0000000..09ce235
Binary files /dev/null and b/RebusCore/Files/flags/tn.png differ
diff --git a/RebusCore/Files/flags/to.png b/RebusCore/Files/flags/to.png
new file mode 100644
index 0000000..34b5aa1
Binary files /dev/null and b/RebusCore/Files/flags/to.png differ
diff --git a/RebusCore/Files/flags/tr.png b/RebusCore/Files/flags/tr.png
new file mode 100644
index 0000000..a67740a
Binary files /dev/null and b/RebusCore/Files/flags/tr.png differ
diff --git a/RebusCore/Files/flags/tt.png b/RebusCore/Files/flags/tt.png
new file mode 100644
index 0000000..61ee0b0
Binary files /dev/null and b/RebusCore/Files/flags/tt.png differ
diff --git a/RebusCore/Files/flags/tv.png b/RebusCore/Files/flags/tv.png
new file mode 100644
index 0000000..16f8616
Binary files /dev/null and b/RebusCore/Files/flags/tv.png differ
diff --git a/RebusCore/Files/flags/tw.png b/RebusCore/Files/flags/tw.png
new file mode 100644
index 0000000..88cc0df
Binary files /dev/null and b/RebusCore/Files/flags/tw.png differ
diff --git a/RebusCore/Files/flags/tz.png b/RebusCore/Files/flags/tz.png
new file mode 100644
index 0000000..94ca541
Binary files /dev/null and b/RebusCore/Files/flags/tz.png differ
diff --git a/RebusCore/Files/flags/ua.png b/RebusCore/Files/flags/ua.png
new file mode 100644
index 0000000..80301f4
Binary files /dev/null and b/RebusCore/Files/flags/ua.png differ
diff --git a/RebusCore/Files/flags/ug.png b/RebusCore/Files/flags/ug.png
new file mode 100644
index 0000000..fec8a45
Binary files /dev/null and b/RebusCore/Files/flags/ug.png differ
diff --git a/RebusCore/Files/flags/us.png b/RebusCore/Files/flags/us.png
new file mode 100644
index 0000000..07ddf4e
Binary files /dev/null and b/RebusCore/Files/flags/us.png differ
diff --git a/RebusCore/Files/flags/uy.png b/RebusCore/Files/flags/uy.png
new file mode 100644
index 0000000..d49a4f1
Binary files /dev/null and b/RebusCore/Files/flags/uy.png differ
diff --git a/RebusCore/Files/flags/uz.png b/RebusCore/Files/flags/uz.png
new file mode 100644
index 0000000..37688d8
Binary files /dev/null and b/RebusCore/Files/flags/uz.png differ
diff --git a/RebusCore/Files/flags/va.png b/RebusCore/Files/flags/va.png
new file mode 100644
index 0000000..9938009
Binary files /dev/null and b/RebusCore/Files/flags/va.png differ
diff --git a/RebusCore/Files/flags/vc.png b/RebusCore/Files/flags/vc.png
new file mode 100644
index 0000000..55018b1
Binary files /dev/null and b/RebusCore/Files/flags/vc.png differ
diff --git a/RebusCore/Files/flags/ve.png b/RebusCore/Files/flags/ve.png
new file mode 100644
index 0000000..4c8b135
Binary files /dev/null and b/RebusCore/Files/flags/ve.png differ
diff --git a/RebusCore/Files/flags/vn.png b/RebusCore/Files/flags/vn.png
new file mode 100644
index 0000000..e9edf37
Binary files /dev/null and b/RebusCore/Files/flags/vn.png differ
diff --git a/RebusCore/Files/flags/vu.png b/RebusCore/Files/flags/vu.png
new file mode 100644
index 0000000..b221447
Binary files /dev/null and b/RebusCore/Files/flags/vu.png differ
diff --git a/RebusCore/Files/flags/ws.png b/RebusCore/Files/flags/ws.png
new file mode 100644
index 0000000..b44c452
Binary files /dev/null and b/RebusCore/Files/flags/ws.png differ
diff --git a/RebusCore/Files/flags/xk.png b/RebusCore/Files/flags/xk.png
new file mode 100644
index 0000000..e1824f1
Binary files /dev/null and b/RebusCore/Files/flags/xk.png differ
diff --git a/RebusCore/Files/flags/ye.png b/RebusCore/Files/flags/ye.png
new file mode 100644
index 0000000..61a0a56
Binary files /dev/null and b/RebusCore/Files/flags/ye.png differ
diff --git a/RebusCore/Files/flags/za.png b/RebusCore/Files/flags/za.png
new file mode 100644
index 0000000..b6ac53e
Binary files /dev/null and b/RebusCore/Files/flags/za.png differ
diff --git a/RebusCore/Files/flags/zm.png b/RebusCore/Files/flags/zm.png
new file mode 100644
index 0000000..a8b5749
Binary files /dev/null and b/RebusCore/Files/flags/zm.png differ
diff --git a/RebusCore/Files/flags/zw.png b/RebusCore/Files/flags/zw.png
new file mode 100644
index 0000000..004cd2a
Binary files /dev/null and b/RebusCore/Files/flags/zw.png differ
diff --git a/FlightSystem2/Properties/launchSettings.json b/RebusCore/Properties/launchSettings.json
similarity index 94%
rename from FlightSystem2/Properties/launchSettings.json
rename to RebusCore/Properties/launchSettings.json
index e2389b2..d2e3098 100644
--- a/FlightSystem2/Properties/launchSettings.json
+++ b/RebusCore/Properties/launchSettings.json
@@ -17,10 +17,10 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
- "FlightSystem2": {
+ "RebusCore": {
"commandName": "Project",
"launchBrowser": true,
- "launchUrl": "weatherforecast",
+ "launchUrl": "allflights",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
diff --git a/FlightSystem2/FlightSystem.Api.csproj b/RebusCore/RebusCore.csproj
similarity index 100%
rename from FlightSystem2/FlightSystem.Api.csproj
rename to RebusCore/RebusCore.csproj
diff --git a/FlightSystem2/Src/Application/Interfaces/AManagers/AFlightManager.cs b/RebusCore/Src/Application/Interfaces/AManagers/AFlightManager.cs
similarity index 57%
rename from FlightSystem2/Src/Application/Interfaces/AManagers/AFlightManager.cs
rename to RebusCore/Src/Application/Interfaces/AManagers/AFlightManager.cs
index c0b72ce..3eadcea 100644
--- a/FlightSystem2/Src/Application/Interfaces/AManagers/AFlightManager.cs
+++ b/RebusCore/Src/Application/Interfaces/AManagers/AFlightManager.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Interfaces.AManagers
+namespace FlightSystem.Api.Application.Interfaces.AManagers
{
public abstract class AFlightManager : AManager
{
@@ -9,5 +9,7 @@ public abstract class AFlightManager : AManager
public abstract IFlight GetFlightById(ulong Id);
public abstract List GetFlightsByTripParams(ITripParams tripParams);
+
+ public abstract string GetStringFlightById(ulong Id);
}
}
diff --git a/FlightSystem2/Src/Application/Interfaces/AManagers/AJourneyManager.cs b/RebusCore/Src/Application/Interfaces/AManagers/AJourneyManager.cs
similarity index 72%
rename from FlightSystem2/Src/Application/Interfaces/AManagers/AJourneyManager.cs
rename to RebusCore/Src/Application/Interfaces/AManagers/AJourneyManager.cs
index 75ad721..d623858 100644
--- a/FlightSystem2/Src/Application/Interfaces/AManagers/AJourneyManager.cs
+++ b/RebusCore/Src/Application/Interfaces/AManagers/AJourneyManager.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Services.Converters;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Integration.Common.Services.Converters;
-namespace FlightSystem.Api.Src.Application.Interfaces.AManagers
+namespace FlightSystem.Api.Application.Interfaces.AManagers
{
public abstract class AJourneyManager : AManager
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AManagers/ALocationManager.cs b/RebusCore/Src/Application/Interfaces/AManagers/ALocationManager.cs
similarity index 64%
rename from FlightSystem2/Src/Application/Interfaces/AManagers/ALocationManager.cs
rename to RebusCore/Src/Application/Interfaces/AManagers/ALocationManager.cs
index c5e81dc..6366c6e 100644
--- a/FlightSystem2/Src/Application/Interfaces/AManagers/ALocationManager.cs
+++ b/RebusCore/Src/Application/Interfaces/AManagers/ALocationManager.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Application.Interfaces.AManagers
+namespace FlightSystem.Api.Application.Interfaces.AManagers
{
public abstract class ALocationManager : AManager
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AManagers/AManager.cs b/RebusCore/Src/Application/Interfaces/AManagers/AManager.cs
similarity index 54%
rename from FlightSystem2/Src/Application/Interfaces/AManagers/AManager.cs
rename to RebusCore/Src/Application/Interfaces/AManagers/AManager.cs
index 7d167a9..799e639 100644
--- a/FlightSystem2/Src/Application/Interfaces/AManagers/AManager.cs
+++ b/RebusCore/Src/Application/Interfaces/AManagers/AManager.cs
@@ -1,14 +1,13 @@
-using FlightSystem.Api.Src.Application.Common.Factories;
-using FlightSystem.Api.Src.Application.Interfaces.Factories;
-using FlightSystem.Api.Src.Domain.Implementations.Factories;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Services.Converters;
-using FlightSystem.Api.Src.Integration.Common.Services.Logger;
-using FlightSystem.Api.Src.Integration.Common.Services.Response;
-using FlightSystem.Api.Src.Repository.Common;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Factories;
+using FlightSystem.Api.Domain.Implementations.Factories;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Integration.Common.Services.Converters;
+using FlightSystem.Api.Integration.Common.Services.Logger;
+using FlightSystem.Api.Integration.Common.Services.Response;
+using FlightSystem.Api.Repository.Common;
-namespace FlightSystem.Api.Src.Application.Interfaces.AManagers
+namespace FlightSystem.Api.Application.Interfaces.AManagers
{
public abstract class AManager
{
diff --git a/RebusCore/Src/Application/Interfaces/AManagers/ARouteManager.cs b/RebusCore/Src/Application/Interfaces/AManagers/ARouteManager.cs
new file mode 100644
index 0000000..a7435fb
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/AManagers/ARouteManager.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
+
+namespace FlightSystem.Api.Application.Interfaces.AManagers
+{
+ public abstract class ARouteManager : AManager
+ {
+
+ public abstract List ManageRoutes(ITripParams tripPar);
+
+ }
+}
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/IDateConverter.cs b/RebusCore/Src/Application/Interfaces/AServices/IDateConverter.cs
similarity index 79%
rename from FlightSystem2/Src/Application/Interfaces/AServices/IDateConverter.cs
rename to RebusCore/Src/Application/Interfaces/AServices/IDateConverter.cs
index 3c4b24d..4c82f80 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/IDateConverter.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/IDateConverter.cs
@@ -1,6 +1,6 @@
using System;
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface IDateConverter
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/IImageConverter.cs b/RebusCore/Src/Application/Interfaces/AServices/IImageConverter.cs
similarity index 75%
rename from FlightSystem2/Src/Application/Interfaces/AServices/IImageConverter.cs
rename to RebusCore/Src/Application/Interfaces/AServices/IImageConverter.cs
index f9846d0..7fd86e3 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/IImageConverter.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/IImageConverter.cs
@@ -1,6 +1,6 @@
using System.Drawing;
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface IImageConverter
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/ILogger.cs b/RebusCore/Src/Application/Interfaces/AServices/ILogger.cs
similarity index 70%
rename from FlightSystem2/Src/Application/Interfaces/AServices/ILogger.cs
rename to RebusCore/Src/Application/Interfaces/AServices/ILogger.cs
index 9b7e3c0..9597ca5 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/ILogger.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/ILogger.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface ILogger
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/IResponse.cs b/RebusCore/Src/Application/Interfaces/AServices/IResponse.cs
similarity index 69%
rename from FlightSystem2/Src/Application/Interfaces/AServices/IResponse.cs
rename to RebusCore/Src/Application/Interfaces/AServices/IResponse.cs
index 63624e2..1a05db7 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/IResponse.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/IResponse.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface IResponse
{
diff --git a/RebusCore/Src/Application/Interfaces/AServices/IResponseBody.cs b/RebusCore/Src/Application/Interfaces/AServices/IResponseBody.cs
new file mode 100644
index 0000000..b7970b2
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/AServices/IResponseBody.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
+
+namespace FlightSystem.Api.Application.Interfaces.AServices
+{
+ public interface IResponseBody
+ {
+ IEnumerable Entities { get; }
+ }
+}
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/IResponseError.cs b/RebusCore/Src/Application/Interfaces/AServices/IResponseError.cs
similarity index 61%
rename from FlightSystem2/Src/Application/Interfaces/AServices/IResponseError.cs
rename to RebusCore/Src/Application/Interfaces/AServices/IResponseError.cs
index 2a6d0d8..edf4892 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/IResponseError.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/IResponseError.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface IResponseError
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/IResponseHeader.cs b/RebusCore/Src/Application/Interfaces/AServices/IResponseHeader.cs
similarity index 62%
rename from FlightSystem2/Src/Application/Interfaces/AServices/IResponseHeader.cs
rename to RebusCore/Src/Application/Interfaces/AServices/IResponseHeader.cs
index f9a627c..3276490 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/IResponseHeader.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/IResponseHeader.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface IResponseHeader
{
diff --git a/FlightSystem2/Src/Application/Interfaces/AServices/ISerializer.cs b/RebusCore/Src/Application/Interfaces/AServices/ISerializer.cs
similarity index 69%
rename from FlightSystem2/Src/Application/Interfaces/AServices/ISerializer.cs
rename to RebusCore/Src/Application/Interfaces/AServices/ISerializer.cs
index adb3fc9..b8b3a33 100644
--- a/FlightSystem2/Src/Application/Interfaces/AServices/ISerializer.cs
+++ b/RebusCore/Src/Application/Interfaces/AServices/ISerializer.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Integration.Common.Interfaces
+namespace FlightSystem.Api.Application.Interfaces.AServices
{
public interface ISerializer
{
diff --git a/RebusCore/Src/Application/Interfaces/Data/IAirportData.cs b/RebusCore/Src/Application/Interfaces/Data/IAirportData.cs
new file mode 100644
index 0000000..8d3fd0a
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/Data/IAirportData.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Implementations.Entities;
+
+namespace FlightSystem.Api.Application.Interfaces.Data
+{
+ public interface IAirportData
+ {
+ public List GetAll();
+ }
+}
diff --git a/RebusCore/Src/Application/Interfaces/Data/IBackupData.cs b/RebusCore/Src/Application/Interfaces/Data/IBackupData.cs
new file mode 100644
index 0000000..5d003f5
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/Data/IBackupData.cs
@@ -0,0 +1,9 @@
+using FlightSystem.Api.Domain.Interfaces;
+
+namespace FlightSystem.Api.Application.Interfaces.Data
+{
+ public interface IBackupData
+ {
+ void SetBackup(IEntity entity);
+ }
+}
diff --git a/RebusCore/Src/Application/Interfaces/Data/ICountryData.cs b/RebusCore/Src/Application/Interfaces/Data/ICountryData.cs
new file mode 100644
index 0000000..48f7f4d
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/Data/ICountryData.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Implementations.Entities;
+
+namespace FlightSystem.Api.Application.Interfaces.Data
+{
+ public interface ICountryData
+ {
+ public List GetAll();
+ }
+}
diff --git a/RebusCore/Src/Application/Interfaces/Data/IFlagImageData.cs b/RebusCore/Src/Application/Interfaces/Data/IFlagImageData.cs
new file mode 100644
index 0000000..1013ac1
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/Data/IFlagImageData.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
+
+namespace FlightSystem.Api.Application.Interfaces.Data
+{
+ public interface IFlagImageData
+ {
+ public void AddFlagsToCountries(IEnumerable countries);
+ }
+}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/IFlightData.cs b/RebusCore/Src/Application/Interfaces/Data/IFlightData.cs
similarity index 69%
rename from FlightSystem2/Src/Application/Interfaces/Data/IFlightData.cs
rename to RebusCore/Src/Application/Interfaces/Data/IFlightData.cs
index bcded74..df58b07 100644
--- a/FlightSystem2/Src/Application/Interfaces/Data/IFlightData.cs
+++ b/RebusCore/Src/Application/Interfaces/Data/IFlightData.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
+namespace FlightSystem.Api.Application.Interfaces.Data
{
public interface IFlightData
{
diff --git a/RebusCore/Src/Application/Interfaces/Data/ILocationsData.cs b/RebusCore/Src/Application/Interfaces/Data/ILocationsData.cs
new file mode 100644
index 0000000..023ad06
--- /dev/null
+++ b/RebusCore/Src/Application/Interfaces/Data/ILocationsData.cs
@@ -0,0 +1,9 @@
+using FlightSystem.Api.Domain.Interfaces;
+
+namespace FlightSystem.Api.Application.Interfaces.Data
+{
+ public interface ILocationsData
+ {
+ ILocations GetLocationsAll();
+ }
+}
diff --git a/FlightSystem2/Src/Application/Interfaces/Data/IRouteData.cs b/RebusCore/Src/Application/Interfaces/Data/IRouteData.cs
similarity index 68%
rename from FlightSystem2/Src/Application/Interfaces/Data/IRouteData.cs
rename to RebusCore/Src/Application/Interfaces/Data/IRouteData.cs
index 92898e4..4677c57 100644
--- a/FlightSystem2/Src/Application/Interfaces/Data/IRouteData.cs
+++ b/RebusCore/Src/Application/Interfaces/Data/IRouteData.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Interfaces.Data
+namespace FlightSystem.Api.Application.Interfaces.Data
{
public interface IRouteData
{
diff --git a/FlightSystem2/Src/Application/Interfaces/Factories/IDataFactory.cs b/RebusCore/Src/Application/Interfaces/Factories/IDataFactory.cs
similarity index 68%
rename from FlightSystem2/Src/Application/Interfaces/Factories/IDataFactory.cs
rename to RebusCore/Src/Application/Interfaces/Factories/IDataFactory.cs
index cf335dd..702a6da 100644
--- a/FlightSystem2/Src/Application/Interfaces/Factories/IDataFactory.cs
+++ b/RebusCore/Src/Application/Interfaces/Factories/IDataFactory.cs
@@ -1,6 +1,6 @@
-using FlightSystem.Api.Src.Application.Interfaces.Data;
+using FlightSystem.Api.Application.Interfaces.Data;
-namespace FlightSystem.Api.Src.Application.Interfaces.Factories
+namespace FlightSystem.Api.Application.Interfaces.Factories
{
public interface IDataFactory
{
diff --git a/FlightSystem2/Src/Application/Interfaces/Factories/IResponseFactory.cs b/RebusCore/Src/Application/Interfaces/Factories/IResponseFactory.cs
similarity index 65%
rename from FlightSystem2/Src/Application/Interfaces/Factories/IResponseFactory.cs
rename to RebusCore/Src/Application/Interfaces/Factories/IResponseFactory.cs
index 8ef6500..2bdcc31 100644
--- a/FlightSystem2/Src/Application/Interfaces/Factories/IResponseFactory.cs
+++ b/RebusCore/Src/Application/Interfaces/Factories/IResponseFactory.cs
@@ -1,8 +1,8 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Common.Factories
+namespace FlightSystem.Api.Application.Interfaces.Factories
{
public interface IResponseFactory
{
diff --git a/FlightSystem2/Src/Application/Managers/FlightManager.cs b/RebusCore/Src/Application/Managers/FlightManager.cs
similarity index 52%
rename from FlightSystem2/Src/Application/Managers/FlightManager.cs
rename to RebusCore/Src/Application/Managers/FlightManager.cs
index 7bd9828..7056bfa 100644
--- a/FlightSystem2/Src/Application/Managers/FlightManager.cs
+++ b/RebusCore/Src/Application/Managers/FlightManager.cs
@@ -1,10 +1,11 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Linq;
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Managers
+namespace FlightSystem.Api.Application.Managers
{
public class FlightManager : AFlightManager
{
@@ -27,6 +28,23 @@ public override IFlight GetFlightById(ulong Id)
return flightData.GetById(Id);
}
+ public override string GetStringFlightById(ulong Id)
+ {
+ try
+ {
+ List entities = entityFactory.CreateEntities();
+ entities.Add(flightData.GetById(Id));
+ return responseFactory.CreateResponse("", entities);
+ }
+ catch (Exception ex)
+ {
+ string message = String.Format("Exception caught: {0}", ex);
+ logger.LogMessage(message);
+ return responseFactory.CreateResponse(message, null);
+ }
+
+ }
+
public override List GetFlightsByTripParams(ITripParams tripParams)
{
List flights = flightData.GetDirectFlightsByTripParams(tripParams);
diff --git a/FlightSystem2/Src/Application/Managers/JourneyManager.cs b/RebusCore/Src/Application/Managers/JourneyManager.cs
similarity index 94%
rename from FlightSystem2/Src/Application/Managers/JourneyManager.cs
rename to RebusCore/Src/Application/Managers/JourneyManager.cs
index f6e95e1..b168eaf 100644
--- a/FlightSystem2/Src/Application/Managers/JourneyManager.cs
+++ b/RebusCore/Src/Application/Managers/JourneyManager.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Managers
+namespace FlightSystem.Api.Application.Managers
{
public class JourneyManager : AJourneyManager
{
diff --git a/FlightSystem2/Src/Application/Managers/LocationManager.cs b/RebusCore/Src/Application/Managers/LocationManager.cs
similarity index 83%
rename from FlightSystem2/Src/Application/Managers/LocationManager.cs
rename to RebusCore/Src/Application/Managers/LocationManager.cs
index 0d43cbe..085b202 100644
--- a/FlightSystem2/Src/Application/Managers/LocationManager.cs
+++ b/RebusCore/Src/Application/Managers/LocationManager.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Managers
+namespace FlightSystem.Api.Application.Managers
{
public class LocationManager : ALocationManager
{
diff --git a/FlightSystem2/Src/Application/Managers/RouteManager.cs b/RebusCore/Src/Application/Managers/RouteManager.cs
similarity index 87%
rename from FlightSystem2/Src/Application/Managers/RouteManager.cs
rename to RebusCore/Src/Application/Managers/RouteManager.cs
index 6b0556a..a70ccb6 100644
--- a/FlightSystem2/Src/Application/Managers/RouteManager.cs
+++ b/RebusCore/Src/Application/Managers/RouteManager.cs
@@ -1,11 +1,11 @@
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Application.Managers
+namespace FlightSystem.Api.Application.Managers
{
public class RouteManager : ARouteManager
{
@@ -37,7 +37,7 @@ public override List ManageRoutes(ITripParams tripPar)
if (numOfRoutes >= maxRoutesFromDb)
return SortAndCutRoutes(routes);
- routes.ToList().AddRange(Get1StopRoutes());
+ routes.AddRange(Get1StopRoutes());
if (numOfRoutes >= maxRoutesFromDb)
return SortAndCutRoutes(routes);
@@ -90,12 +90,13 @@ private void AddRouteInfo(List routes)
route.price += flight.price;
}
route.timeSpan = route.flights[route.flights.Count() - 1].arrives - route.flights[0].departs;
+ route.best = (int)route.timeSpan.TotalMinutes + (int)route.price;
}
}
private List SortAndCutRoutes(List routes)
{
- //routes.Sort(); //update
+ routes = routes.OrderBy(o=>o.best).ToList();
try
{
routes.RemoveRange(maxRoutesReturn, routes.Count() - maxRoutesReturn);
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Airport.cs b/RebusCore/Src/Domain/Implementations/Entities/Airport.cs
similarity index 92%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Airport.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Airport.cs
index 4418f6e..62fb64d 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Airport.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Airport.cs
@@ -1,5 +1,5 @@
+using FlightSystem.Api.Domain.Interfaces;
using Newtonsoft.Json;
-using FlightSystem.Api.Src.Domain.Interfaces;
namespace FlightSystem.Api.Domain.Implementations.Entities
{
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/City.cs b/RebusCore/Src/Domain/Implementations/Entities/City.cs
similarity index 100%
rename from FlightSystem2/Src/Domain/Implementations/Entities/City.cs
rename to RebusCore/Src/Domain/Implementations/Entities/City.cs
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Country.cs b/RebusCore/Src/Domain/Implementations/Entities/Country.cs
similarity index 90%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Country.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Country.cs
index 89b22d0..e354e2d 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Country.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Country.cs
@@ -1,4 +1,4 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Domain.Interfaces;
using Newtonsoft.Json;
namespace FlightSystem.Api.Domain.Implementations.Entities
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Entity.cs b/RebusCore/Src/Domain/Implementations/Entities/Entity.cs
similarity index 70%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Entity.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Entity.cs
index 22550e6..e1087d4 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Entity.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Entity.cs
@@ -1,4 +1,4 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Domain.Interfaces;
namespace FlightSystem.Api.Domain.Implementations.Entities
{
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Flight.cs b/RebusCore/Src/Domain/Implementations/Entities/Flight.cs
similarity index 95%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Flight.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Flight.cs
index e8bf6ec..5c48e09 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Flight.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Flight.cs
@@ -1,5 +1,5 @@
using System;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Domain.Interfaces;
using Newtonsoft.Json;
namespace FlightSystem.Api.Domain.Implementations.Entities
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Journey.cs b/RebusCore/Src/Domain/Implementations/Entities/Journey.cs
similarity index 90%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Journey.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Journey.cs
index 4df5ec7..0e221df 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Journey.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Journey.cs
@@ -1,6 +1,6 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
namespace FlightSystem.Api.Domain.Implementations.Entities
{
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Locations.cs b/RebusCore/Src/Domain/Implementations/Entities/Locations.cs
similarity index 89%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Locations.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Locations.cs
index d4c5559..71e3dd6 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Locations.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Locations.cs
@@ -1,6 +1,6 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
namespace FlightSystem.Api.Domain.Implementations.Entities
{
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Route.cs b/RebusCore/Src/Domain/Implementations/Entities/Route.cs
similarity index 85%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Route.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Route.cs
index 8c2e2dc..bb051f9 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Route.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Route.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
namespace FlightSystem.Api.Domain.Implementations.Entities
{
@@ -15,6 +15,9 @@ public class Route : Entity, IRoute
[JsonProperty]
public TimeSpan timeSpan { get; set; }
+ [JsonProperty]
+ public int best { get; set; }
+
[JsonProperty]
public List flights {
get { return _flights; }
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/Trip.cs b/RebusCore/Src/Domain/Implementations/Entities/Trip.cs
similarity index 91%
rename from FlightSystem2/Src/Domain/Implementations/Entities/Trip.cs
rename to RebusCore/Src/Domain/Implementations/Entities/Trip.cs
index 2c82aa2..ce97e0d 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/Trip.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/Trip.cs
@@ -1,6 +1,6 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using System.Collections.Generic;
+using FlightSystem.Api.Domain.Interfaces;
namespace FlightSystem.Api.Domain.Implementations.Entities
{
diff --git a/FlightSystem2/Src/Domain/Implementations/Entities/TripParams.cs b/RebusCore/Src/Domain/Implementations/Entities/TripParams.cs
similarity index 93%
rename from FlightSystem2/Src/Domain/Implementations/Entities/TripParams.cs
rename to RebusCore/Src/Domain/Implementations/Entities/TripParams.cs
index e5d5cd2..ab5c717 100644
--- a/FlightSystem2/Src/Domain/Implementations/Entities/TripParams.cs
+++ b/RebusCore/Src/Domain/Implementations/Entities/TripParams.cs
@@ -1,4 +1,4 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Domain.Interfaces;
using Newtonsoft.Json;
namespace FlightSystem.Api.Domain.Implementations.Entities
diff --git a/FlightSystem2/Src/Domain/Implementations/Factories/EntityFactory.cs b/RebusCore/Src/Domain/Implementations/Factories/EntityFactory.cs
similarity index 80%
rename from FlightSystem2/Src/Domain/Implementations/Factories/EntityFactory.cs
rename to RebusCore/Src/Domain/Implementations/Factories/EntityFactory.cs
index 41be7c4..690ac91 100644
--- a/FlightSystem2/Src/Domain/Implementations/Factories/EntityFactory.cs
+++ b/RebusCore/Src/Domain/Implementations/Factories/EntityFactory.cs
@@ -1,8 +1,8 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Domain.Implementations.Factories
+namespace FlightSystem.Api.Domain.Implementations.Factories
{
public class EntityFactory : IEntityFactory
{
diff --git a/RebusCore/Src/Domain/Interfaces/IAirport.cs b/RebusCore/Src/Domain/Interfaces/IAirport.cs
new file mode 100644
index 0000000..42ad406
--- /dev/null
+++ b/RebusCore/Src/Domain/Interfaces/IAirport.cs
@@ -0,0 +1,15 @@
+namespace FlightSystem.Api.Domain.Interfaces
+{
+ public interface IAirport : IEntity
+ {
+ string fullName { get; set; }
+
+ string type { get; }
+
+ string code { get; set; }
+
+ string cityName { get; set; }
+
+ string countryName { get; set; }
+ }
+}
diff --git a/FlightSystem2/Src/Domain/Interfaces/ICountry.cs b/RebusCore/Src/Domain/Interfaces/ICountry.cs
similarity index 81%
rename from FlightSystem2/Src/Domain/Interfaces/ICountry.cs
rename to RebusCore/Src/Domain/Interfaces/ICountry.cs
index b9b3e82..3d542d2 100644
--- a/FlightSystem2/Src/Domain/Interfaces/ICountry.cs
+++ b/RebusCore/Src/Domain/Interfaces/ICountry.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface ICountry : IEntity
{
diff --git a/RebusCore/Src/Domain/Interfaces/IEntity.cs b/RebusCore/Src/Domain/Interfaces/IEntity.cs
new file mode 100644
index 0000000..3fdc7a3
--- /dev/null
+++ b/RebusCore/Src/Domain/Interfaces/IEntity.cs
@@ -0,0 +1,6 @@
+namespace FlightSystem.Api.Domain.Interfaces
+{
+ public interface IEntity
+ {
+ }
+}
diff --git a/FlightSystem2/Src/Domain/Interfaces/IEntityFactory.cs b/RebusCore/Src/Domain/Interfaces/IEntityFactory.cs
similarity index 90%
rename from FlightSystem2/Src/Domain/Interfaces/IEntityFactory.cs
rename to RebusCore/Src/Domain/Interfaces/IEntityFactory.cs
index f46d13c..41d795a 100644
--- a/FlightSystem2/Src/Domain/Interfaces/IEntityFactory.cs
+++ b/RebusCore/Src/Domain/Interfaces/IEntityFactory.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface IEntityFactory
{
diff --git a/FlightSystem2/Src/Domain/Interfaces/IFlight.cs b/RebusCore/Src/Domain/Interfaces/IFlight.cs
similarity index 89%
rename from FlightSystem2/Src/Domain/Interfaces/IFlight.cs
rename to RebusCore/Src/Domain/Interfaces/IFlight.cs
index 740de6d..e3875bd 100644
--- a/FlightSystem2/Src/Domain/Interfaces/IFlight.cs
+++ b/RebusCore/Src/Domain/Interfaces/IFlight.cs
@@ -1,6 +1,6 @@
using System;
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface IFlight : IEntity
{
diff --git a/FlightSystem2/Src/Domain/Interfaces/IJourney.cs b/RebusCore/Src/Domain/Interfaces/IJourney.cs
similarity index 81%
rename from FlightSystem2/Src/Domain/Interfaces/IJourney.cs
rename to RebusCore/Src/Domain/Interfaces/IJourney.cs
index e75b9f1..09b603d 100644
--- a/FlightSystem2/Src/Domain/Interfaces/IJourney.cs
+++ b/RebusCore/Src/Domain/Interfaces/IJourney.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface IJourney : IEntity
{
diff --git a/FlightSystem2/Src/Domain/Interfaces/ILocations.cs b/RebusCore/Src/Domain/Interfaces/ILocations.cs
similarity index 81%
rename from FlightSystem2/Src/Domain/Interfaces/ILocations.cs
rename to RebusCore/Src/Domain/Interfaces/ILocations.cs
index 5106913..c65054d 100644
--- a/FlightSystem2/Src/Domain/Interfaces/ILocations.cs
+++ b/RebusCore/Src/Domain/Interfaces/ILocations.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface ILocations : IEntity
{
diff --git a/FlightSystem2/Src/Domain/Interfaces/IRoute.cs b/RebusCore/Src/Domain/Interfaces/IRoute.cs
similarity index 74%
rename from FlightSystem2/Src/Domain/Interfaces/IRoute.cs
rename to RebusCore/Src/Domain/Interfaces/IRoute.cs
index 6bea776..5e9c33a 100644
--- a/FlightSystem2/Src/Domain/Interfaces/IRoute.cs
+++ b/RebusCore/Src/Domain/Interfaces/IRoute.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface IRoute : IEntity
{
@@ -9,6 +9,8 @@ public interface IRoute : IEntity
public TimeSpan timeSpan { get; set; }
+ public int best { get; set; }
+
public List flights { get; set; }
}
}
diff --git a/FlightSystem2/Src/Domain/Interfaces/ITrip.cs b/RebusCore/Src/Domain/Interfaces/ITrip.cs
similarity index 82%
rename from FlightSystem2/Src/Domain/Interfaces/ITrip.cs
rename to RebusCore/Src/Domain/Interfaces/ITrip.cs
index 5960a5d..5d175a1 100644
--- a/FlightSystem2/Src/Domain/Interfaces/ITrip.cs
+++ b/RebusCore/Src/Domain/Interfaces/ITrip.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface ITrip : IEntity
{
diff --git a/FlightSystem2/Src/Domain/Interfaces/ITripParams.cs b/RebusCore/Src/Domain/Interfaces/ITripParams.cs
similarity index 81%
rename from FlightSystem2/Src/Domain/Interfaces/ITripParams.cs
rename to RebusCore/Src/Domain/Interfaces/ITripParams.cs
index 0f00c9a..4120178 100644
--- a/FlightSystem2/Src/Domain/Interfaces/ITripParams.cs
+++ b/RebusCore/Src/Domain/Interfaces/ITripParams.cs
@@ -1,4 +1,4 @@
-namespace FlightSystem.Api.Src.Domain.Interfaces
+namespace FlightSystem.Api.Domain.Interfaces
{
public interface ITripParams : IEntity
{
diff --git a/FlightSystem2/Src/Integration/Common/Services/Converters/DatesConverter.cs b/RebusCore/Src/Integration/Common/Services/Converters/DatesConverter.cs
similarity index 83%
rename from FlightSystem2/Src/Integration/Common/Services/Converters/DatesConverter.cs
rename to RebusCore/Src/Integration/Common/Services/Converters/DatesConverter.cs
index b90ea91..5f7feca 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Converters/DatesConverter.cs
+++ b/RebusCore/Src/Integration/Common/Services/Converters/DatesConverter.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using System;
+using System;
+using FlightSystem.Api.Application.Interfaces.AServices;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Converters
+namespace FlightSystem.Api.Integration.Common.Services.Converters
{
public class DatesConverter : IDateConverter
{
diff --git a/FlightSystem2/Src/Integration/Common/Services/Converters/JSONSerializer.cs b/RebusCore/Src/Integration/Common/Services/Converters/JSONSerializer.cs
similarity index 83%
rename from FlightSystem2/Src/Integration/Common/Services/Converters/JSONSerializer.cs
rename to RebusCore/Src/Integration/Common/Services/Converters/JSONSerializer.cs
index c425ca9..3b89b03 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Converters/JSONSerializer.cs
+++ b/RebusCore/Src/Integration/Common/Services/Converters/JSONSerializer.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AServices;
using Newtonsoft.Json;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Converters
+namespace FlightSystem.Api.Integration.Common.Services.Converters
{
public class JSONSerializer : ISerializer
{
diff --git a/FlightSystem2/Src/Integration/Common/Services/Converters/MyImageConverter.cs b/RebusCore/Src/Integration/Common/Services/Converters/MyImageConverter.cs
similarity index 85%
rename from FlightSystem2/Src/Integration/Common/Services/Converters/MyImageConverter.cs
rename to RebusCore/Src/Integration/Common/Services/Converters/MyImageConverter.cs
index 1471fff..4221a01 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Converters/MyImageConverter.cs
+++ b/RebusCore/Src/Integration/Common/Services/Converters/MyImageConverter.cs
@@ -1,9 +1,9 @@
using System;
using System.Drawing;
using System.IO;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AServices;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Converters
+namespace FlightSystem.Api.Integration.Common.Services.Converters
{
public class MyImageConverter : IImageConverter
{
diff --git a/FlightSystem2/Src/Integration/Common/Services/Logger/ConsoleLogger.cs b/RebusCore/Src/Integration/Common/Services/Logger/ConsoleLogger.cs
similarity index 67%
rename from FlightSystem2/Src/Integration/Common/Services/Logger/ConsoleLogger.cs
rename to RebusCore/Src/Integration/Common/Services/Logger/ConsoleLogger.cs
index 85b2044..3106228 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Logger/ConsoleLogger.cs
+++ b/RebusCore/Src/Integration/Common/Services/Logger/ConsoleLogger.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using System;
+using System;
+using FlightSystem.Api.Application.Interfaces.AServices;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Logger
+namespace FlightSystem.Api.Integration.Common.Services.Logger
{
public class ConsoleLogger : ILogger
{
diff --git a/FlightSystem2/Src/Integration/Common/Services/Response/JSONResponseFactory.cs b/RebusCore/Src/Integration/Common/Services/Response/JSONResponseFactory.cs
similarity index 80%
rename from FlightSystem2/Src/Integration/Common/Services/Response/JSONResponseFactory.cs
rename to RebusCore/Src/Integration/Common/Services/Response/JSONResponseFactory.cs
index 3402d72..1589028 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Response/JSONResponseFactory.cs
+++ b/RebusCore/Src/Integration/Common/Services/Response/JSONResponseFactory.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Common.Factories;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Factories;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Response
+namespace FlightSystem.Api.Integration.Common.Services.Response
{
public class JSONResponseFactory : IResponseFactory
{
diff --git a/FlightSystem2/Src/Integration/Common/Services/Response/Response.cs b/RebusCore/Src/Integration/Common/Services/Response/Response.cs
similarity index 79%
rename from FlightSystem2/Src/Integration/Common/Services/Response/Response.cs
rename to RebusCore/Src/Integration/Common/Services/Response/Response.cs
index 7637f4f..497f2db 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Response/Response.cs
+++ b/RebusCore/Src/Integration/Common/Services/Response/Response.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AServices;
using Newtonsoft.Json;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Response
+namespace FlightSystem.Api.Integration.Common.Services.Response
{
[JsonObject(MemberSerialization.OptIn)]
public class Response : IResponse
diff --git a/FlightSystem2/Src/Integration/Common/Services/Response/ResponseBody.cs b/RebusCore/Src/Integration/Common/Services/Response/ResponseBody.cs
similarity index 64%
rename from FlightSystem2/Src/Integration/Common/Services/Response/ResponseBody.cs
rename to RebusCore/Src/Integration/Common/Services/Response/ResponseBody.cs
index bbbfefa..b2e6896 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Response/ResponseBody.cs
+++ b/RebusCore/Src/Integration/Common/Services/Response/ResponseBody.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
+using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Domain.Interfaces;
using Newtonsoft.Json;
-using System.Collections.Generic;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Response
+namespace FlightSystem.Api.Integration.Common.Services.Response
{
[JsonObject(MemberSerialization.OptIn)]
public class ResponseBody : IResponseBody
diff --git a/FlightSystem2/Src/Integration/Common/Services/Response/ResponseError.cs b/RebusCore/Src/Integration/Common/Services/Response/ResponseError.cs
similarity index 75%
rename from FlightSystem2/Src/Integration/Common/Services/Response/ResponseError.cs
rename to RebusCore/Src/Integration/Common/Services/Response/ResponseError.cs
index c344818..3b8b7f2 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Response/ResponseError.cs
+++ b/RebusCore/Src/Integration/Common/Services/Response/ResponseError.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AServices;
using Newtonsoft.Json;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Response
+namespace FlightSystem.Api.Integration.Common.Services.Response
{
[JsonObject(MemberSerialization.OptIn)]
public class ResponseError : IResponseError
diff --git a/FlightSystem2/Src/Integration/Common/Services/Response/ResponseHeader.cs b/RebusCore/Src/Integration/Common/Services/Response/ResponseHeader.cs
similarity index 75%
rename from FlightSystem2/Src/Integration/Common/Services/Response/ResponseHeader.cs
rename to RebusCore/Src/Integration/Common/Services/Response/ResponseHeader.cs
index 00729b0..ecabd3a 100644
--- a/FlightSystem2/Src/Integration/Common/Services/Response/ResponseHeader.cs
+++ b/RebusCore/Src/Integration/Common/Services/Response/ResponseHeader.cs
@@ -1,7 +1,7 @@
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
+using FlightSystem.Api.Application.Interfaces.AServices;
using Newtonsoft.Json;
-namespace FlightSystem.Api.Src.Integration.Common.Services.Response
+namespace FlightSystem.Api.Integration.Common.Services.Response
{
[JsonObject(MemberSerialization.OptIn)]
public class ResponseHeader : IResponseHeader
diff --git a/RebusCore/Src/Integration/Config/IntegrationConfig.cs b/RebusCore/Src/Integration/Config/IntegrationConfig.cs
new file mode 100644
index 0000000..83853b1
--- /dev/null
+++ b/RebusCore/Src/Integration/Config/IntegrationConfig.cs
@@ -0,0 +1,21 @@
+namespace FlightSystem.Api.Integration.Config
+{
+ public static class IntegrationConfig
+ {
+
+ public static string GetDataBaseUri() { return "bolt://neo4j:7687"; }
+
+ public static string GetDataBaseUsername() { return "neo4j"; }
+ public static string GetDataBasePassword() { return "123"; }
+
+ public static string GetBackupFilePath() { return @"C:\Users\Paulius\Desktop\Dummies\"; }
+
+ public static string GetBackupFileType() { return ".json"; }
+
+ public static string GetFlagsFilePath() { return "/app/files/flags/"; }
+
+ public static string GetFlagsFileType() { return ".png"; }
+
+
+ }
+}
diff --git a/FlightSystem2/Src/Integration/Config/Program.cs b/RebusCore/Src/Integration/Config/Program.cs
similarity index 90%
rename from FlightSystem2/Src/Integration/Config/Program.cs
rename to RebusCore/Src/Integration/Config/Program.cs
index 8225554..fa1273f 100644
--- a/FlightSystem2/Src/Integration/Config/Program.cs
+++ b/RebusCore/Src/Integration/Config/Program.cs
@@ -1,10 +1,10 @@
using System;
-using FlightSystem.Api.Src.Repository.Neo4J.Common;
+using FlightSystem.Api.Repository.Neo4J.Common;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace FlightSystem
+namespace FlightSystem.Api.Integration.Config
{
public class Program
{
diff --git a/FlightSystem2/Src/Integration/Config/Startup.cs b/RebusCore/Src/Integration/Config/Startup.cs
similarity index 96%
rename from FlightSystem2/Src/Integration/Config/Startup.cs
rename to RebusCore/Src/Integration/Config/Startup.cs
index db37755..ed967df 100644
--- a/FlightSystem2/Src/Integration/Config/Startup.cs
+++ b/RebusCore/Src/Integration/Config/Startup.cs
@@ -4,7 +4,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace FlightSystem
+namespace FlightSystem.Api.Integration.Config
{
public class Startup
{
diff --git a/FlightSystem2/Src/Integration/Controllers/AllFlightsController.cs b/RebusCore/Src/Integration/Controllers/AllFlightsController.cs
similarity index 77%
rename from FlightSystem2/Src/Integration/Controllers/AllFlightsController.cs
rename to RebusCore/Src/Integration/Controllers/AllFlightsController.cs
index 14c85b3..8196d2c 100644
--- a/FlightSystem2/Src/Integration/Controllers/AllFlightsController.cs
+++ b/RebusCore/Src/Integration/Controllers/AllFlightsController.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Managers;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Managers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
-namespace FlightSystem.Api.Src.Integration.Controllers
+namespace RebusCore.Src.Integration.Controllers
{
[ApiController]
[Route("[controller]")]
diff --git a/FlightSystem2/Src/Integration/Controllers/AllLocationsController.cs b/RebusCore/Src/Integration/Controllers/AllLocationsController.cs
similarity index 78%
rename from FlightSystem2/Src/Integration/Controllers/AllLocationsController.cs
rename to RebusCore/Src/Integration/Controllers/AllLocationsController.cs
index 0afbfbd..a7cf6ca 100644
--- a/FlightSystem2/Src/Integration/Controllers/AllLocationsController.cs
+++ b/RebusCore/Src/Integration/Controllers/AllLocationsController.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Managers;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Managers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
-namespace FlightSystem.Api.Src.Integration.Controllers
+namespace RebusCore.Src.Integration.Controllers
{
[ApiController]
[Route("[controller]")]
diff --git a/FlightSystem2/Src/Integration/Controllers/FlightController.cs b/RebusCore/Src/Integration/Controllers/FlightController.cs
similarity index 68%
rename from FlightSystem2/Src/Integration/Controllers/FlightController.cs
rename to RebusCore/Src/Integration/Controllers/FlightController.cs
index b22d778..c5fba43 100644
--- a/FlightSystem2/Src/Integration/Controllers/FlightController.cs
+++ b/RebusCore/Src/Integration/Controllers/FlightController.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Managers;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Managers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
-namespace FlightSystem.Api.Src.Integration.Controllers
+namespace RebusCore.Src.Integration.Controllers
{
[ApiController]
[Route("[controller]")]
@@ -21,7 +21,7 @@ public FlightController(ILogger logger)
[HttpGet]
public string Get(ulong flightId)
{
- return _flightManager.GetFlightById(flightId).ToString();
+ return _flightManager.GetStringFlightById(flightId);
}
}
}
\ No newline at end of file
diff --git a/FlightSystem2/Src/Integration/Controllers/JourneyController.cs b/RebusCore/Src/Integration/Controllers/JourneyController.cs
similarity index 85%
rename from FlightSystem2/Src/Integration/Controllers/JourneyController.cs
rename to RebusCore/Src/Integration/Controllers/JourneyController.cs
index e93b8b8..24a2eca 100644
--- a/FlightSystem2/Src/Integration/Controllers/JourneyController.cs
+++ b/RebusCore/Src/Integration/Controllers/JourneyController.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Interfaces.AManagers;
-using FlightSystem.Api.Src.Application.Managers;
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Managers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
-namespace FlightSystem.Api.Src.Integration.Controllers
+namespace RebusCore.Src.Integration.Controllers
{
[ApiController]
[Route("[controller]")]
diff --git a/RebusCore/Src/Integration/Controllers/TestConnController.cs b/RebusCore/Src/Integration/Controllers/TestConnController.cs
new file mode 100644
index 0000000..5519d69
--- /dev/null
+++ b/RebusCore/Src/Integration/Controllers/TestConnController.cs
@@ -0,0 +1,32 @@
+using FlightSystem.Api.Application.Interfaces.AManagers;
+using FlightSystem.Api.Application.Managers;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using FlightSystem.Api.Repository.Neo4J.Common;
+
+namespace RebusCore.Src.Integration.Controllers
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class TestConnController : ControllerBase
+ {
+ private AFlightManager _flightManager = new FlightManager();
+
+ private readonly ILogger _logger;
+
+ public TestConnController(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ /* FIXME remove dirrect realations. Maybe use application logic instead */
+ [HttpGet]
+ public string Get()
+ {
+ if (Neo4JContext.RunQuery("MATCH (a { name: 'TEST' }) RETURN a").ToString() == "Neo4j.Driver.Internal.Result.StatementResult"){
+ return "TEST_OK";
+ }
+ return "TEST_ERR";
+ }
+ }
+}
diff --git a/FlightSystem2/Src/Repository/Common/DataFactoryDelegation.cs b/RebusCore/Src/Repository/Common/DataFactoryDelegation.cs
similarity index 80%
rename from FlightSystem2/Src/Repository/Common/DataFactoryDelegation.cs
rename to RebusCore/Src/Repository/Common/DataFactoryDelegation.cs
index b1703f0..f47dc40 100644
--- a/FlightSystem2/Src/Repository/Common/DataFactoryDelegation.cs
+++ b/RebusCore/Src/Repository/Common/DataFactoryDelegation.cs
@@ -1,10 +1,10 @@
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Application.Interfaces.Factories;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Repository.FileSystem.Common;
-using FlightSystem.Api.Src.Repository.Neo4J.Common;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Application.Interfaces.Factories;
+using FlightSystem.Api.Repository.FileSystem.Common;
+using FlightSystem.Api.Repository.Neo4J.Common;
-namespace FlightSystem.Api.Src.Repository.Common
+namespace FlightSystem.Api.Repository.Common
{
public class DataFactoryDelegation : IDataFactory
{
diff --git a/FlightSystem2/Src/Repository/Common/Neo4JDataFactory.cs b/RebusCore/Src/Repository/Common/Neo4JDataFactory.cs
similarity index 78%
rename from FlightSystem2/Src/Repository/Common/Neo4JDataFactory.cs
rename to RebusCore/Src/Repository/Common/Neo4JDataFactory.cs
index 6838e8f..943e5de 100644
--- a/FlightSystem2/Src/Repository/Common/Neo4JDataFactory.cs
+++ b/RebusCore/Src/Repository/Common/Neo4JDataFactory.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Application.Interfaces.Factories;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Repository.FileSystem.Data;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Application.Interfaces.Factories;
+using FlightSystem.Api.Repository.FileSystem.Data;
-namespace FlightSystem.Api.Src.Repository.Common
+namespace FlightSystem.Api.Repository.Common
{
public class Neo4JDataFactory : IDataFactory
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Common/FileSystemDataFactory.cs b/RebusCore/Src/Repository/FileSystem/Common/FileSystemDataFactory.cs
similarity index 78%
rename from FlightSystem2/Src/Repository/FileSystem/Common/FileSystemDataFactory.cs
rename to RebusCore/Src/Repository/FileSystem/Common/FileSystemDataFactory.cs
index a749deb..e8f8d43 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Common/FileSystemDataFactory.cs
+++ b/RebusCore/Src/Repository/FileSystem/Common/FileSystemDataFactory.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Application.Interfaces.Factories;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Repository.FileSystem.Data;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Application.Interfaces.Factories;
+using FlightSystem.Api.Repository.FileSystem.Data;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Common
+namespace FlightSystem.Api.Repository.FileSystem.Common
{
public class FileSystemDataFactory : IDataFactory
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/AirportData.cs b/RebusCore/Src/Repository/FileSystem/Data/AirportData.cs
similarity index 51%
rename from FlightSystem2/Src/Repository/FileSystem/Data/AirportData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/AirportData.cs
index e903df4..2daea78 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/AirportData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/AirportData.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using System;
+using System;
using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class AirportData : IAirportData
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/BackupData.cs b/RebusCore/Src/Repository/FileSystem/Data/BackupData.cs
similarity index 67%
rename from FlightSystem2/Src/Repository/FileSystem/Data/BackupData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/BackupData.cs
index ef2316c..8ee1bf7 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/BackupData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/BackupData.cs
@@ -1,11 +1,11 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Integration.Config;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Integration.Config;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class BackupData : IBackupData
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/CountryData.cs b/RebusCore/Src/Repository/FileSystem/Data/CountryData.cs
similarity index 51%
rename from FlightSystem2/Src/Repository/FileSystem/Data/CountryData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/CountryData.cs
index 31d7619..efbaf66 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/CountryData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/CountryData.cs
@@ -1,9 +1,9 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using System;
+using System;
using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class CountryData : ICountryData
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/FlagImageData.cs b/RebusCore/Src/Repository/FileSystem/Data/FlagImageData.cs
similarity index 68%
rename from FlightSystem2/Src/Repository/FileSystem/Data/FlagImageData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/FlagImageData.cs
index 103125a..86471fa 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/FlagImageData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/FlagImageData.cs
@@ -1,11 +1,12 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Drawing;
-using FlightSystem.Api.Src.Integration.Config;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Integration.Config;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class FlagImageData : IFlagImageData
{
@@ -32,12 +33,13 @@ private string GetFlagImageString(string countryCode)
try
{
- image = Image.FromFile(IntegrationConfig.GetFlagsFilePath() + countryCode + IntegrationConfig.GetFlagsFileType());
+ image = Image.FromFile(IntegrationConfig.GetFlagsFilePath() + countryCode.ToLower() + IntegrationConfig.GetFlagsFileType());
}
- catch (System.IO.IOException e)
+ catch (Exception e)
{
_logger.LogObject("Exception caught: {0}", e);
+ return "";
}
return _imageConverter.ImageToString(image);
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/FlightData.cs b/RebusCore/Src/Repository/FileSystem/Data/FlightData.cs
similarity index 71%
rename from FlightSystem2/Src/Repository/FileSystem/Data/FlightData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/FlightData.cs
index e410157..dd1d7e3 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/FlightData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/FlightData.cs
@@ -1,12 +1,12 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Integration.Config;
-using System;
+using System;
using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Integration.Config;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class FlightData : IFlightData
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/LocationsData.cs b/RebusCore/Src/Repository/FileSystem/Data/LocationsData.cs
similarity index 63%
rename from FlightSystem2/Src/Repository/FileSystem/Data/LocationsData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/LocationsData.cs
index 650e17e..baf7009 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/LocationsData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/LocationsData.cs
@@ -1,10 +1,10 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Integration.Config;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Integration.Config;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class LocationsData : ILocationsData
{
diff --git a/FlightSystem2/Src/Repository/FileSystem/Data/RouteData.cs b/RebusCore/Src/Repository/FileSystem/Data/RouteData.cs
similarity index 66%
rename from FlightSystem2/Src/Repository/FileSystem/Data/RouteData.cs
rename to RebusCore/Src/Repository/FileSystem/Data/RouteData.cs
index a7bc160..93b7bd2 100644
--- a/FlightSystem2/Src/Repository/FileSystem/Data/RouteData.cs
+++ b/RebusCore/Src/Repository/FileSystem/Data/RouteData.cs
@@ -1,11 +1,11 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Integration.Common.Interfaces;
-using FlightSystem.Api.Src.Integration.Config;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.AServices;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Integration.Config;
-namespace FlightSystem.Api.Src.Repository.FileSystem.Data
+namespace FlightSystem.Api.Repository.FileSystem.Data
{
public class RouteData : IRouteData
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Common/FlightParser.cs b/RebusCore/Src/Repository/Neo4J/Common/FlightParser.cs
similarity index 96%
rename from FlightSystem2/Src/Repository/Neo4J/Common/FlightParser.cs
rename to RebusCore/Src/Repository/Neo4J/Common/FlightParser.cs
index 10d2cd9..67db7bf 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Common/FlightParser.cs
+++ b/RebusCore/Src/Repository/Neo4J/Common/FlightParser.cs
@@ -1,8 +1,8 @@
using System;
-using Neo4j.Driver.V1;
using FlightSystem.Api.Domain.Implementations.Entities;
+using Neo4j.Driver.V1;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Common
+namespace FlightSystem.Api.Repository.Neo4J.Common
{
public class FlightParser
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Common/Neo4JContext.cs b/RebusCore/Src/Repository/Neo4J/Common/Neo4JContext.cs
similarity index 86%
rename from FlightSystem2/Src/Repository/Neo4J/Common/Neo4JContext.cs
rename to RebusCore/Src/Repository/Neo4J/Common/Neo4JContext.cs
index bd79732..b98555d 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Common/Neo4JContext.cs
+++ b/RebusCore/Src/Repository/Neo4J/Common/Neo4JContext.cs
@@ -1,10 +1,8 @@
using System;
-using System.Collections.Generic;
+using FlightSystem.Api.Integration.Config;
using Neo4j.Driver.V1;
-using System.Threading.Tasks;
-using FlightSystem.Api.Src.Integration.Config;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Common
+namespace FlightSystem.Api.Repository.Neo4J.Common
{
public static class Neo4JContext
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Data/AirportData.cs b/RebusCore/Src/Repository/Neo4J/Data/AirportData.cs
similarity index 85%
rename from FlightSystem2/Src/Repository/Neo4J/Data/AirportData.cs
rename to RebusCore/Src/Repository/Neo4J/Data/AirportData.cs
index b067e1d..4b0a5fd 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Data/AirportData.cs
+++ b/RebusCore/Src/Repository/Neo4J/Data/AirportData.cs
@@ -1,10 +1,10 @@
using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.Data;
using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Repository.Neo4J.Common;
+using FlightSystem.Api.Repository.Neo4J.Common;
using Neo4j.Driver.V1;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Data
+namespace FlightSystem.Api.Repository.Neo4J.Data
{
public class AirportData : IAirportData
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Data/CountryData.cs b/RebusCore/Src/Repository/Neo4J/Data/CountryData.cs
similarity index 84%
rename from FlightSystem2/Src/Repository/Neo4J/Data/CountryData.cs
rename to RebusCore/Src/Repository/Neo4J/Data/CountryData.cs
index 87fa564..6bf1312 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Data/CountryData.cs
+++ b/RebusCore/Src/Repository/Neo4J/Data/CountryData.cs
@@ -1,10 +1,10 @@
using System.Collections.Generic;
+using FlightSystem.Api.Application.Interfaces.Data;
using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Repository.Neo4J.Common;
+using FlightSystem.Api.Repository.Neo4J.Common;
using Neo4j.Driver.V1;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Data
+namespace FlightSystem.Api.Repository.Neo4J.Data
{
public class CountryData : ICountryData
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Data/FlightData.cs b/RebusCore/Src/Repository/Neo4J/Data/FlightData.cs
similarity index 93%
rename from FlightSystem2/Src/Repository/Neo4J/Data/FlightData.cs
rename to RebusCore/Src/Repository/Neo4J/Data/FlightData.cs
index a043968..a00032d 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Data/FlightData.cs
+++ b/RebusCore/Src/Repository/Neo4J/Data/FlightData.cs
@@ -1,11 +1,11 @@
using System.Collections.Generic;
-using Neo4j.Driver.V1;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Repository.Neo4J.Common;
+using FlightSystem.Api.Application.Interfaces.Data;
using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Repository.Neo4J.Common;
+using Neo4j.Driver.V1;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Data
+namespace FlightSystem.Api.Repository.Neo4J.Data
{
public class FlightData : IFlightData
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Data/LocationsData.cs b/RebusCore/Src/Repository/Neo4J/Data/LocationsData.cs
similarity index 61%
rename from FlightSystem2/Src/Repository/Neo4J/Data/LocationsData.cs
rename to RebusCore/Src/Repository/Neo4J/Data/LocationsData.cs
index 0167677..adb31bf 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Data/LocationsData.cs
+++ b/RebusCore/Src/Repository/Neo4J/Data/LocationsData.cs
@@ -1,8 +1,8 @@
-using FlightSystem.Api.Domain.Implementations.Entities;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Domain.Interfaces;
+using FlightSystem.Api.Application.Interfaces.Data;
+using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Data
+namespace FlightSystem.Api.Repository.Neo4J.Data
{
public class LocationsData : ILocationsData
{
diff --git a/FlightSystem2/Src/Repository/Neo4J/Data/RouteData.cs b/RebusCore/Src/Repository/Neo4J/Data/RouteData.cs
similarity index 97%
rename from FlightSystem2/Src/Repository/Neo4J/Data/RouteData.cs
rename to RebusCore/Src/Repository/Neo4J/Data/RouteData.cs
index e8bb12f..5cef488 100644
--- a/FlightSystem2/Src/Repository/Neo4J/Data/RouteData.cs
+++ b/RebusCore/Src/Repository/Neo4J/Data/RouteData.cs
@@ -1,11 +1,11 @@
using System.Collections.Generic;
-using Neo4j.Driver.V1;
-using FlightSystem.Api.Src.Domain.Interfaces;
-using FlightSystem.Api.Src.Application.Interfaces.Data;
-using FlightSystem.Api.Src.Repository.Neo4J.Common;
+using FlightSystem.Api.Application.Interfaces.Data;
using FlightSystem.Api.Domain.Implementations.Entities;
+using FlightSystem.Api.Domain.Interfaces;
+using FlightSystem.Api.Repository.Neo4J.Common;
+using Neo4j.Driver.V1;
-namespace FlightSystem.Api.Src.Repository.Neo4J.Data
+namespace FlightSystem.Api.Repository.Neo4J.Data
{
public class RouteData : IRouteData
{
diff --git a/FlightSystem2/appsettings.Development.json b/RebusCore/appsettings.Development.json
similarity index 100%
rename from FlightSystem2/appsettings.Development.json
rename to RebusCore/appsettings.Development.json
diff --git a/RebusNeo/Dockerfile b/RebusNeo/Dockerfile
new file mode 100644
index 0000000..586d386
--- /dev/null
+++ b/RebusNeo/Dockerfile
@@ -0,0 +1,24 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
+WORKDIR /app
+ENV ASPNETCORE_URLS=http://+:5002
+EXPOSE 5002
+
+FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
+WORKDIR /src
+COPY ["RebusNeo/RebusNeo.csproj", "RebusNeo/"]
+RUN dotnet restore "RebusNeo/RebusNeo.csproj"
+COPY . .
+WORKDIR "/src/RebusNeo"
+RUN dotnet build "RebusNeo.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "RebusNeo.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "RebusNeo.dll"]
+
+COPY RebusNeo/Files /app/files
\ No newline at end of file
diff --git a/RebusNeo/Files/test.txt b/RebusNeo/Files/test.txt
new file mode 100644
index 0000000..a0aba93
--- /dev/null
+++ b/RebusNeo/Files/test.txt
@@ -0,0 +1 @@
+OK
\ No newline at end of file
diff --git a/RebusNeo/Files/test_flight.json b/RebusNeo/Files/test_flight.json
new file mode 100644
index 0000000..8114af8
--- /dev/null
+++ b/RebusNeo/Files/test_flight.json
@@ -0,0 +1,2296 @@
+{
+ "Header": {
+ "ResponseError": {
+ "ErrorCode": 0,
+ "ErrorMessage": ""
+ }
+ },
+ "ResponseBody": {
+ "Entities": [
+ {
+ "trips": [
+ {
+ "tripParams": {
+ "origin": "AMS",
+ "destination": "BRU",
+ "depDate": "2019-10-1",
+ "onlyDirect": false
+ },
+ "numOfRoutes": 20,
+ "routes": [
+ {
+ "price": 25.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123495",
+ "flightCode": "SN-1461",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 25.0
+ }
+ ]
+ },
+ {
+ "price": 20.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123435",
+ "flightCode": "SN-1451",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T19:00:00",
+ "arrives": "2019-10-01T19:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 35.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123375",
+ "flightCode": "SN-1441",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T17:00:00",
+ "arrives": "2019-10-01T17:30:00",
+ "price": 35.0
+ }
+ ]
+ },
+ {
+ "price": 20.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123315",
+ "flightCode": "SN-1421",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T14:00:00",
+ "arrives": "2019-10-01T14:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 30.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123255",
+ "flightCode": "SN-1411",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T08:00:00",
+ "arrives": "2019-10-01T08:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 25.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123195",
+ "flightCode": "SN-1401",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-01T06:30:00",
+ "price": 25.0
+ }
+ ]
+ },
+ {
+ "price": 90.0,
+ "timeSpan": "-11:30:00",
+ "flights": [
+ {
+ "flightId": "120665",
+ "flightCode": "AF-1221",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T11:30:00",
+ "arrives": "2019-10-01T13:30:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "120424",
+ "flightCode": "AF-1140",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T18:00:00",
+ "arrives": "2019-10-01T18:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 100.0,
+ "timeSpan": "-11:30:00",
+ "flights": [
+ {
+ "flightId": "120665",
+ "flightCode": "AF-1221",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T11:30:00",
+ "arrives": "2019-10-01T13:30:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "83447",
+ "flightCode": "BA-1111",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T20:30:00",
+ "arrives": "2019-10-01T21:20:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 100.0,
+ "timeSpan": "12:20:00",
+ "flights": [
+ {
+ "flightId": "120665",
+ "flightCode": "AF-1221",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T11:30:00",
+ "arrives": "2019-10-01T13:30:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "116638",
+ "flightCode": "BA-1831",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "London-Gatwick Airport",
+ "type": "Airport",
+ "code": "LGW",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T21:00:00",
+ "arrives": "2019-10-01T22:00:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "124213",
+ "flightCode": "SN-11101",
+ "fromAirport": {
+ "fullName": "London-Gatwick Airport",
+ "type": "Airport",
+ "code": "LGW",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T23:50:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 100.0,
+ "timeSpan": "-09:30:00",
+ "flights": [
+ {
+ "flightId": "120605",
+ "flightCode": "AF-1211",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T09:30:00",
+ "arrives": "2019-10-01T10:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "120424",
+ "flightCode": "AF-1140",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T18:00:00",
+ "arrives": "2019-10-01T18:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 100.0,
+ "timeSpan": "-09:30:00",
+ "flights": [
+ {
+ "flightId": "120605",
+ "flightCode": "AF-1211",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T09:30:00",
+ "arrives": "2019-10-01T10:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "120304",
+ "flightCode": "AF-1120",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 100.0,
+ "timeSpan": "-06:30:00",
+ "flights": [
+ {
+ "flightId": "120545",
+ "flightCode": "AF-1201",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T06:30:00",
+ "arrives": "2019-10-01T07:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "120424",
+ "flightCode": "AF-1140",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T18:00:00",
+ "arrives": "2019-10-01T18:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 100.0,
+ "timeSpan": "-06:30:00",
+ "flights": [
+ {
+ "flightId": "120545",
+ "flightCode": "AF-1201",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T06:30:00",
+ "arrives": "2019-10-01T07:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "120304",
+ "flightCode": "AF-1120",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "-11:30:00",
+ "flights": [
+ {
+ "flightId": "120665",
+ "flightCode": "AF-1221",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T11:30:00",
+ "arrives": "2019-10-01T13:30:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "83387",
+ "flightCode": "BA-1109",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T17:30:00",
+ "arrives": "2019-10-01T18:20:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "12:20:00",
+ "flights": [
+ {
+ "flightId": "120665",
+ "flightCode": "AF-1221",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T11:30:00",
+ "arrives": "2019-10-01T13:30:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "116578",
+ "flightCode": "BA-1821",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "London-Gatwick Airport",
+ "type": "Airport",
+ "code": "LGW",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T15:00:00",
+ "arrives": "2019-10-01T16:00:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "124213",
+ "flightCode": "SN-11101",
+ "fromAirport": {
+ "fullName": "London-Gatwick Airport",
+ "type": "Airport",
+ "code": "LGW",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T23:50:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "-11:30:00",
+ "flights": [
+ {
+ "flightId": "120665",
+ "flightCode": "AF-1221",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T11:30:00",
+ "arrives": "2019-10-01T13:30:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "120364",
+ "flightCode": "AF-1130",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T15:00:00",
+ "arrives": "2019-10-01T15:50:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "-09:30:00",
+ "flights": [
+ {
+ "flightId": "120605",
+ "flightCode": "AF-1211",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T09:30:00",
+ "arrives": "2019-10-01T10:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "83447",
+ "flightCode": "BA-1111",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T20:30:00",
+ "arrives": "2019-10-01T21:20:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "122765",
+ "flightCode": "SN-1131",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "14:20:00",
+ "flights": [
+ {
+ "flightId": "120605",
+ "flightCode": "AF-1211",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T09:30:00",
+ "arrives": "2019-10-01T10:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "116638",
+ "flightCode": "BA-1831",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "London-Gatwick Airport",
+ "type": "Airport",
+ "code": "LGW",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T21:00:00",
+ "arrives": "2019-10-01T22:00:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "124213",
+ "flightCode": "SN-11101",
+ "fromAirport": {
+ "fullName": "London-Gatwick Airport",
+ "type": "Airport",
+ "code": "LGW",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T23:50:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "06:30:00",
+ "flights": [
+ {
+ "flightId": "120605",
+ "flightCode": "AF-1211",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T09:30:00",
+ "arrives": "2019-10-01T10:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "120304",
+ "flightCode": "AF-1120",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122705",
+ "flightCode": "SN-1121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T15:00:00",
+ "arrives": "2019-10-01T16:00:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 110.0,
+ "timeSpan": "09:30:00",
+ "flights": [
+ {
+ "flightId": "120545",
+ "flightCode": "AF-1201",
+ "fromAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T06:30:00",
+ "arrives": "2019-10-01T07:30:00",
+ "price": 50.0
+ },
+ {
+ "flightId": "120304",
+ "flightCode": "AF-1120",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122705",
+ "flightCode": "SN-1121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-01T15:00:00",
+ "arrives": "2019-10-01T16:00:00",
+ "price": 30.0
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "tripParams": {
+ "origin": "BRU",
+ "destination": "AMS",
+ "depDate": "2019-10-1",
+ "onlyDirect": false
+ },
+ "numOfRoutes": 20,
+ "routes": [
+ {
+ "price": 25.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123194",
+ "flightCode": "SN-1400",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-01T06:30:00",
+ "price": 25.0
+ }
+ ]
+ },
+ {
+ "price": 30.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123254",
+ "flightCode": "SN-1410",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T08:00:00",
+ "arrives": "2019-10-01T08:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 20.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123314",
+ "flightCode": "SN-1420",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T14:00:00",
+ "arrives": "2019-10-01T14:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 35.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123374",
+ "flightCode": "SN-1440",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T17:00:00",
+ "arrives": "2019-10-01T17:30:00",
+ "price": 35.0
+ }
+ ]
+ },
+ {
+ "price": 20.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123434",
+ "flightCode": "SN-1450",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T19:00:00",
+ "arrives": "2019-10-01T19:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 25.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "123494",
+ "flightCode": "SN-1460",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 25.0
+ }
+ ]
+ },
+ {
+ "price": 70.0,
+ "timeSpan": "10.13:30:00",
+ "flights": [
+ {
+ "flightId": "122604",
+ "flightCode": "SN-11100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-11T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122665",
+ "flightCode": "SN-11111",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-11T09:00:00",
+ "arrives": "2019-10-11T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "123454",
+ "flightCode": "SN-11450",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-11T19:00:00",
+ "arrives": "2019-10-11T19:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 70.0,
+ "timeSpan": "10.08:30:00",
+ "flights": [
+ {
+ "flightId": "122604",
+ "flightCode": "SN-11100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-11T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122665",
+ "flightCode": "SN-11111",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-11T09:00:00",
+ "arrives": "2019-10-11T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "123334",
+ "flightCode": "SN-11420",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-11T14:00:00",
+ "arrives": "2019-10-11T14:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 80.0,
+ "timeSpan": "16:30:00",
+ "flights": [
+ {
+ "flightId": "123775",
+ "flightCode": "SN-1700",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Frankfurt Airport",
+ "type": "Airport",
+ "code": "FRA",
+ "cityName": "Frankfurt",
+ "countryName": "DE"
+ },
+ "departs": "2019-10-01T07:00:00",
+ "arrives": "2019-10-01T07:50:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "122224",
+ "flightCode": "LH-1330",
+ "fromAirport": {
+ "fullName": "Frankfurt Airport",
+ "type": "Airport",
+ "code": "FRA",
+ "cityName": "Frankfurt",
+ "countryName": "DE"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T19:30:00",
+ "arrives": "2019-10-01T20:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 80.0,
+ "timeSpan": "14:30:00",
+ "flights": [
+ {
+ "flightId": "122644",
+ "flightCode": "SN-1110",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T09:00:00",
+ "arrives": "2019-10-01T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "120425",
+ "flightCode": "AF-1141",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T18:00:00",
+ "arrives": "2019-10-01T18:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 80.0,
+ "timeSpan": "14:30:00",
+ "flights": [
+ {
+ "flightId": "122644",
+ "flightCode": "SN-1110",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T09:00:00",
+ "arrives": "2019-10-01T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "120305",
+ "flightCode": "AF-1121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 80.0,
+ "timeSpan": "00:30:00",
+ "flights": [
+ {
+ "flightId": "122764",
+ "flightCode": "SN-1130",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T23:00:00",
+ "arrives": "2019-10-01T00:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "120305",
+ "flightCode": "AF-1121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 80.0,
+ "timeSpan": "10.13:30:00",
+ "flights": [
+ {
+ "flightId": "122604",
+ "flightCode": "SN-11100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-11T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122725",
+ "flightCode": "SN-11121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-11T15:00:00",
+ "arrives": "2019-10-11T16:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "123454",
+ "flightCode": "SN-11450",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-11T19:00:00",
+ "arrives": "2019-10-11T19:30:00",
+ "price": 20.0
+ }
+ ]
+ },
+ {
+ "price": 85.0,
+ "timeSpan": "10.17:30:00",
+ "flights": [
+ {
+ "flightId": "122604",
+ "flightCode": "SN-11100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-11T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122725",
+ "flightCode": "SN-11121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-11T15:00:00",
+ "arrives": "2019-10-11T16:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "123514",
+ "flightCode": "SN-11460",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-11T23:00:00",
+ "arrives": "2019-10-11T23:30:00",
+ "price": 25.0
+ }
+ ]
+ },
+ {
+ "price": 85.0,
+ "timeSpan": "10.11:30:00",
+ "flights": [
+ {
+ "flightId": "122604",
+ "flightCode": "SN-11100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-11T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "122665",
+ "flightCode": "SN-11111",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "departs": "2019-10-11T09:00:00",
+ "arrives": "2019-10-11T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "123394",
+ "flightCode": "SN-11440",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-11T17:00:00",
+ "arrives": "2019-10-11T17:30:00",
+ "price": 35.0
+ }
+ ]
+ },
+ {
+ "price": 90.0,
+ "timeSpan": "16:30:00",
+ "flights": [
+ {
+ "flightId": "123775",
+ "flightCode": "SN-1700",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Frankfurt Airport",
+ "type": "Airport",
+ "code": "FRA",
+ "cityName": "Frankfurt",
+ "countryName": "DE"
+ },
+ "departs": "2019-10-01T07:00:00",
+ "arrives": "2019-10-01T07:50:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "122164",
+ "flightCode": "LH-1320",
+ "fromAirport": {
+ "fullName": "Frankfurt Airport",
+ "type": "Airport",
+ "code": "FRA",
+ "cityName": "Frankfurt",
+ "countryName": "DE"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T15:30:00",
+ "arrives": "2019-10-01T16:50:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 90.0,
+ "timeSpan": "17:30:00",
+ "flights": [
+ {
+ "flightId": "122584",
+ "flightCode": "SN-1100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-01T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120425",
+ "flightCode": "AF-1141",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T18:00:00",
+ "arrives": "2019-10-01T18:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 90.0,
+ "timeSpan": "17:30:00",
+ "flights": [
+ {
+ "flightId": "122584",
+ "flightCode": "SN-1100",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T06:00:00",
+ "arrives": "2019-10-01T07:00:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120305",
+ "flightCode": "AF-1121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 90.0,
+ "timeSpan": "14:30:00",
+ "flights": [
+ {
+ "flightId": "122644",
+ "flightCode": "SN-1110",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T09:00:00",
+ "arrives": "2019-10-01T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "83446",
+ "flightCode": "BA-1110",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T20:30:00",
+ "arrives": "2019-10-01T21:20:00",
+ "price": 40.0
+ },
+ {
+ "flightId": "120784",
+ "flightCode": "AF-1240",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T22:30:00",
+ "arrives": "2019-10-01T23:30:00",
+ "price": 30.0
+ }
+ ]
+ },
+ {
+ "price": 90.0,
+ "timeSpan": "11:30:00",
+ "flights": [
+ {
+ "flightId": "122644",
+ "flightCode": "SN-1110",
+ "fromAirport": {
+ "fullName": "Brussels Airport",
+ "type": "Airport",
+ "code": "BRU",
+ "cityName": "Brussels",
+ "countryName": "BE"
+ },
+ "toAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "departs": "2019-10-01T09:00:00",
+ "arrives": "2019-10-01T10:00:00",
+ "price": 20.0
+ },
+ {
+ "flightId": "120305",
+ "flightCode": "AF-1121",
+ "fromAirport": {
+ "fullName": "Heathrow Airport",
+ "type": "Airport",
+ "code": "LHR",
+ "cityName": "London",
+ "countryName": "GB"
+ },
+ "toAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "departs": "2019-10-01T12:00:00",
+ "arrives": "2019-10-01T12:50:00",
+ "price": 30.0
+ },
+ {
+ "flightId": "120724",
+ "flightCode": "AF-1230",
+ "fromAirport": {
+ "fullName": "Charles de Gaulle Airport",
+ "type": "Airport",
+ "code": "CDG",
+ "cityName": "Paris",
+ "countryName": "FR"
+ },
+ "toAirport": {
+ "fullName": "Amsterdam Airport Schiphol",
+ "type": "Airport",
+ "code": "AMS",
+ "cityName": "Amsterdam",
+ "countryName": "NL"
+ },
+ "departs": "2019-10-01T19:30:00",
+ "arrives": "2019-10-01T20:30:00",
+ "price": 40.0
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "numOfPass": 1,
+ "passClass": "economy"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/RebusNeo/Migrations/20200429062057_UserTest.Designer.cs b/RebusNeo/Migrations/20200429062057_UserTest.Designer.cs
new file mode 100644
index 0000000..4a7d0cf
--- /dev/null
+++ b/RebusNeo/Migrations/20200429062057_UserTest.Designer.cs
@@ -0,0 +1,43 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200429062057_UserTest")]
+ partial class UserTest
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("userEmail")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userLoginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("UserInfoItems");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429062057_UserTest.cs b/RebusNeo/Migrations/20200429062057_UserTest.cs
new file mode 100644
index 0000000..d50ac3c
--- /dev/null
+++ b/RebusNeo/Migrations/20200429062057_UserTest.cs
@@ -0,0 +1,30 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "UserInfoItems",
+ columns: table => new
+ {
+ id = table.Column(nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ userLoginName = table.Column(nullable: true),
+ userEmail = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_UserInfoItems", x => x.id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "UserInfoItems");
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429071302_UserTest1.Designer.cs b/RebusNeo/Migrations/20200429071302_UserTest1.Designer.cs
new file mode 100644
index 0000000..68bc462
--- /dev/null
+++ b/RebusNeo/Migrations/20200429071302_UserTest1.Designer.cs
@@ -0,0 +1,43 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200429071302_UserTest1")]
+ partial class UserTest1
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("userEmail")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userLoginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429071302_UserTest1.cs b/RebusNeo/Migrations/20200429071302_UserTest1.cs
new file mode 100644
index 0000000..1ef1131
--- /dev/null
+++ b/RebusNeo/Migrations/20200429071302_UserTest1.cs
@@ -0,0 +1,39 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest1 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropPrimaryKey(
+ name: "PK_UserInfoItems",
+ table: "UserInfoItems");
+
+ migrationBuilder.RenameTable(
+ name: "UserInfoItems",
+ newName: "userInfo");
+
+ migrationBuilder.AddPrimaryKey(
+ name: "PK_userInfo",
+ table: "userInfo",
+ column: "id");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropPrimaryKey(
+ name: "PK_userInfo",
+ table: "userInfo");
+
+ migrationBuilder.RenameTable(
+ name: "userInfo",
+ newName: "UserInfoItems");
+
+ migrationBuilder.AddPrimaryKey(
+ name: "PK_UserInfoItems",
+ table: "UserInfoItems",
+ column: "id");
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429072852_UserTest2.Designer.cs b/RebusNeo/Migrations/20200429072852_UserTest2.Designer.cs
new file mode 100644
index 0000000..ddc0e47
--- /dev/null
+++ b/RebusNeo/Migrations/20200429072852_UserTest2.Designer.cs
@@ -0,0 +1,49 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200429072852_UserTest2")]
+ partial class UserTest2
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429072852_UserTest2.cs b/RebusNeo/Migrations/20200429072852_UserTest2.cs
new file mode 100644
index 0000000..3fe1948
--- /dev/null
+++ b/RebusNeo/Migrations/20200429072852_UserTest2.cs
@@ -0,0 +1,69 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest2 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "userEmail",
+ table: "userInfo");
+
+ migrationBuilder.DropColumn(
+ name: "userLoginName",
+ table: "userInfo");
+
+ migrationBuilder.AddColumn(
+ name: "email",
+ table: "userInfo",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "loginName",
+ table: "userInfo",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "password",
+ table: "userInfo",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "salt",
+ table: "userInfo",
+ nullable: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "email",
+ table: "userInfo");
+
+ migrationBuilder.DropColumn(
+ name: "loginName",
+ table: "userInfo");
+
+ migrationBuilder.DropColumn(
+ name: "password",
+ table: "userInfo");
+
+ migrationBuilder.DropColumn(
+ name: "salt",
+ table: "userInfo");
+
+ migrationBuilder.AddColumn(
+ name: "userEmail",
+ table: "userInfo",
+ type: "nvarchar(max)",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "userLoginName",
+ table: "userInfo",
+ type: "nvarchar(max)",
+ nullable: true);
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429081544_UserTest3.Designer.cs b/RebusNeo/Migrations/20200429081544_UserTest3.Designer.cs
new file mode 100644
index 0000000..7d75632
--- /dev/null
+++ b/RebusNeo/Migrations/20200429081544_UserTest3.Designer.cs
@@ -0,0 +1,49 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200429081544_UserTest3")]
+ partial class UserTest3
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429081544_UserTest3.cs b/RebusNeo/Migrations/20200429081544_UserTest3.cs
new file mode 100644
index 0000000..529aea7
--- /dev/null
+++ b/RebusNeo/Migrations/20200429081544_UserTest3.cs
@@ -0,0 +1,17 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest3 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429085133_UserTest4.Designer.cs b/RebusNeo/Migrations/20200429085133_UserTest4.Designer.cs
new file mode 100644
index 0000000..13cf5c2
--- /dev/null
+++ b/RebusNeo/Migrations/20200429085133_UserTest4.Designer.cs
@@ -0,0 +1,49 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200429085133_UserTest4")]
+ partial class UserTest4
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200429085133_UserTest4.cs b/RebusNeo/Migrations/20200429085133_UserTest4.cs
new file mode 100644
index 0000000..0c513bf
--- /dev/null
+++ b/RebusNeo/Migrations/20200429085133_UserTest4.cs
@@ -0,0 +1,17 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest4 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200512193156_UserTest5.Designer.cs b/RebusNeo/Migrations/20200512193156_UserTest5.Designer.cs
new file mode 100644
index 0000000..b71aa6e
--- /dev/null
+++ b/RebusNeo/Migrations/20200512193156_UserTest5.Designer.cs
@@ -0,0 +1,71 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200512193156_UserTest5")]
+ partial class UserTest5
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200512193156_UserTest5.cs b/RebusNeo/Migrations/20200512193156_UserTest5.cs
new file mode 100644
index 0000000..40612a3
--- /dev/null
+++ b/RebusNeo/Migrations/20200512193156_UserTest5.cs
@@ -0,0 +1,32 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest5 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "token",
+ columns: table => new
+ {
+ id = table.Column(nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ token = table.Column(nullable: true),
+ userid = table.Column(nullable: false),
+ expireDate = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_token", x => x.id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "token");
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200512193428_UserTest6.Designer.cs b/RebusNeo/Migrations/20200512193428_UserTest6.Designer.cs
new file mode 100644
index 0000000..c08149d
--- /dev/null
+++ b/RebusNeo/Migrations/20200512193428_UserTest6.Designer.cs
@@ -0,0 +1,71 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200512193428_UserTest6")]
+ partial class UserTest6
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200512193428_UserTest6.cs b/RebusNeo/Migrations/20200512193428_UserTest6.cs
new file mode 100644
index 0000000..51e0418
--- /dev/null
+++ b/RebusNeo/Migrations/20200512193428_UserTest6.cs
@@ -0,0 +1,17 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest6 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200512211018_UserTest7.Designer.cs b/RebusNeo/Migrations/20200512211018_UserTest7.Designer.cs
new file mode 100644
index 0000000..7ac9015
--- /dev/null
+++ b/RebusNeo/Migrations/20200512211018_UserTest7.Designer.cs
@@ -0,0 +1,107 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200512211018_UserTest7")]
+ partial class UserTest7
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.PersonalInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("city")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("country")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("firstname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("house")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("lastname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("phonenumber")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("street")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("personalInfo");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200512211018_UserTest7.cs b/RebusNeo/Migrations/20200512211018_UserTest7.cs
new file mode 100644
index 0000000..6dca83d
--- /dev/null
+++ b/RebusNeo/Migrations/20200512211018_UserTest7.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest7 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "personalInfo",
+ columns: table => new
+ {
+ id = table.Column(nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ userid = table.Column(nullable: false),
+ firstname = table.Column(nullable: true),
+ lastname = table.Column(nullable: true),
+ phonenumber = table.Column(nullable: true),
+ country = table.Column(nullable: true),
+ city = table.Column(nullable: true),
+ street = table.Column(nullable: true),
+ house = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_personalInfo", x => x.id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "personalInfo");
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200513094703_UserTesta.Designer.cs b/RebusNeo/Migrations/20200513094703_UserTesta.Designer.cs
new file mode 100644
index 0000000..dcd9f44
--- /dev/null
+++ b/RebusNeo/Migrations/20200513094703_UserTesta.Designer.cs
@@ -0,0 +1,125 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200513094703_UserTesta")]
+ partial class UserTesta
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Balance", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("balance")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("balance");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.PersonalInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("city")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("country")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("firstname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("house")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("lastname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("phonenumber")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("street")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("personalInfo");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200513094703_UserTesta.cs b/RebusNeo/Migrations/20200513094703_UserTesta.cs
new file mode 100644
index 0000000..61e95ab
--- /dev/null
+++ b/RebusNeo/Migrations/20200513094703_UserTesta.cs
@@ -0,0 +1,30 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTesta : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "balance",
+ columns: table => new
+ {
+ id = table.Column(nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ userid = table.Column(nullable: false),
+ balance = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_balance", x => x.id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "balance");
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200513114101_UserTest10.Designer.cs b/RebusNeo/Migrations/20200513114101_UserTest10.Designer.cs
new file mode 100644
index 0000000..1e9d265
--- /dev/null
+++ b/RebusNeo/Migrations/20200513114101_UserTest10.Designer.cs
@@ -0,0 +1,167 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200513114101_UserTest10")]
+ partial class UserTest10
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Balance", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("balance")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("balance");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Flight", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("cost")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("flightId")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("flight");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Order", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("cost")
+ .HasColumnType("int");
+
+ b.Property("datetime")
+ .HasColumnType("datetime2");
+
+ b.Property("details")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("order");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.PersonalInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("city")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("country")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("firstname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("house")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("lastname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("phonenumber")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("street")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("personalInfo");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200513114101_UserTest10.cs b/RebusNeo/Migrations/20200513114101_UserTest10.cs
new file mode 100644
index 0000000..9c35f10
--- /dev/null
+++ b/RebusNeo/Migrations/20200513114101_UserTest10.cs
@@ -0,0 +1,50 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest10 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "flight",
+ columns: table => new
+ {
+ id = table.Column(nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ flightId = table.Column(nullable: false),
+ cost = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_flight", x => x.id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "order",
+ columns: table => new
+ {
+ id = table.Column(nullable: false)
+ .Annotation("SqlServer:Identity", "1, 1"),
+ userid = table.Column(nullable: false),
+ cost = table.Column(nullable: false),
+ details = table.Column(nullable: true),
+ datetime = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_order", x => x.id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "flight");
+
+ migrationBuilder.DropTable(
+ name: "order");
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200520081836_UserTest11.Designer.cs b/RebusNeo/Migrations/20200520081836_UserTest11.Designer.cs
new file mode 100644
index 0000000..57fe526
--- /dev/null
+++ b/RebusNeo/Migrations/20200520081836_UserTest11.Designer.cs
@@ -0,0 +1,170 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ [Migration("20200520081836_UserTest11")]
+ partial class UserTest11
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Balance", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("balance")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("balance");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Flight", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("cost")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("flightId")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("flight");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Order", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("cost")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("datetime")
+ .HasColumnType("datetime2");
+
+ b.Property("details")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("order");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.PersonalInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("city")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("country")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("firstname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("house")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("lastname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("phonenumber")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("street")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("personalInfo");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("loginName")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("password")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("salt")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("status")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("id");
+
+ b.ToTable("userInfo");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/20200520081836_UserTest11.cs b/RebusNeo/Migrations/20200520081836_UserTest11.cs
new file mode 100644
index 0000000..ba57dfd
--- /dev/null
+++ b/RebusNeo/Migrations/20200520081836_UserTest11.cs
@@ -0,0 +1,36 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace RebusNeo.Migrations
+{
+ public partial class UserTest11 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "status",
+ table: "userInfo",
+ nullable: true);
+
+ migrationBuilder.AlterColumn(
+ name: "cost",
+ table: "order",
+ nullable: false,
+ oldClrType: typeof(int),
+ oldType: "int");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "status",
+ table: "userInfo");
+
+ migrationBuilder.AlterColumn(
+ name: "cost",
+ table: "order",
+ type: "int",
+ nullable: false,
+ oldClrType: typeof(decimal));
+ }
+ }
+}
diff --git a/RebusNeo/Migrations/MSSQLContextModelSnapshot.cs b/RebusNeo/Migrations/MSSQLContextModelSnapshot.cs
new file mode 100644
index 0000000..87fa6b4
--- /dev/null
+++ b/RebusNeo/Migrations/MSSQLContextModelSnapshot.cs
@@ -0,0 +1,168 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using RebusNeo.Src.Repository.MSSQL.Common;
+
+namespace RebusNeo.Migrations
+{
+ [DbContext(typeof(MSSQLContext))]
+ partial class MSSQLContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Balance", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("balance")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("balance");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Flight", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("cost")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("flightId")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("flight");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Order", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("cost")
+ .HasColumnType("decimal(18,2)");
+
+ b.Property("datetime")
+ .HasColumnType("datetime2");
+
+ b.Property("details")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("order");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.PersonalInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("city")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("country")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("firstname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("house")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("lastname")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("phonenumber")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("street")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("personalInfo");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.Token", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("expireDate")
+ .HasColumnType("datetime2");
+
+ b.Property("token")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("userid")
+ .HasColumnType("int");
+
+ b.HasKey("id");
+
+ b.ToTable("token");
+ });
+
+ modelBuilder.Entity("RebusNeo.Src.Domain.Implementations.UserInfo", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int")
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ b.Property("email")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property