Skip to main content

C#

This article shows you how to analyze your applications written in C# using preZero. It assumes that you have already set up and authenticated with Qwiet.

Requirements

See Prerequisites for more information.

Preparing your application for analysis

Before analyzing your code with preZero, we recommend either:

  • Restoring the dependencies of your application;
  • Building your application (since this will implicitly restore your application's dependencies and produce additional artifacts that may be useful for analysis).

.NET application

You can restore and build a .NET application as follows:

  1. Launch a command prompt

  2. Navigate to your project location

  3. Restore NuGet packages by running

    dotnet restore <MySolution.sln>
  4. Start the build by running

    dotnet build --no-restore <MySolution.sln>

.NET Framework application

You can restore and build a .NET Framework application with the following:

  1. Launch the Developer Command Prompt for Visual Studio

  2. Navigate to your project location

  3. Restore NuGet packages by running

    nuget.exe restore <MySolution.sln>
  4. Start the build by running

    msbuild <MySolution.sln>

Analyzing your C# application

note

Qwiet offers a sample application that you can use to run and test preZero. It also includes a functioning configuration file to demonstrate how you can leverage Azure Pipelines or GitHub Actions to automate code analysis whenever you open a new Pull Request (PR).

To analyze your C# application, run:

# Ensure your application dependencies are restored
sl.exe analyze --app <name> --csharp [<path>]

Non-Windows users should invoke the Qwiet CLI using sl instead of sl.exe.

ParameterDescription
--app <name>The name of the application to be analyzed (maximum length: 100 characters)
--csharpThe flag identifying the application's language
<path>The location of the application's .csproj or .sln file to be analyzed

See the CLI reference for additional sl.exe analyze options.

SCA

To identify open-source vulnerabilities, Qwiet preZero automatically searches for build manifests in the project path you provided when running sl.exe analyze. However, depending on how your project repo is structured, you may need to provide --oss-project-dir <project-path> so that Qwiet preZero can identify your dependencies.

tip

Ensure that the application was built to include all used dependencies.

Tagging results with your branch name

To include the branch name in your preZero results, allowing you to distinguish one set of results from another, add the following to your invocation of Qwiet:

sl.exe analyze --tag branch=`git symbolic-ref --short HEAD`

If you're working in a GitHub environment (e.g., GitHub Actions), you can also use --tag branch=${{ github.head_ref }} to populate your branch name.

If you don't provide a branch name, but Qwiet detects one available in your environment, it will use that name.

Enabling log information

By default, we print logs at the Information level. If you would like more detailed information, pass in the --verbose flag:

sl.exe analyze --csharp --verbose --app Xyz app.csproj

You can find the logs generated by Qwiet in the Windows temp directory.

Troubleshooting

If you have any issues scanning your project, please see our general troubleshooting page, as well as our C#-specific suggestions that follow.

Artifact and dll not found errors

If you see the errors that look like this:

fail: Buildalyzer.Logging.EventProcessor[0]
System.IO.FileNotFoundException: Could not find file '/Users/prabhu/Downloads/EU-OutageStatusQuery/AzureFunctions/OutageStatusFunctions/OmsData.Peco/bin/Debug/netcoreapp3.1/bin/OmsData.Peco.dll'.
File name: '/Users/prabhu/Downloads/EU-OutageStatusQuery/AzureFunctions/OutageStatusFunctions/OmsData.Peco/bin/Debug/netcoreapp3.1/bin/OmsData.Peco.dll'
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)

Or this:

fail[39m[22m[49m: Buildalyzer.Logging.EventProcessor[0]
2021-02-03T18:39:57.5318095Z Metadata file '/src/src/app/Fool.Marthetron.Shared/bin/Release/netstandard2.1/Fool.Marthetron.Shared.dll' could not be found

This means that you must pass additional build parameters to sl.exe analyze to ensure that the dependent projects can be built successfully. Typically, the developer should be able to provide the necessary build parameters, but we've found the following five flags to be helpful:

sl.exe analyze --app app-name /
--verbose /
--csharp /
"sln file name" /
-- /p:BuildProjectReferences="true" /
/p:SkipCompilerExecution="false" /
/p:CopyBuildOutputToOutputDirectory="true" /
/p:CopyOutputSymbolsToOutputDirectory="true" /
/p:SkipCopyBuildProduct="false"

If the project fails to rebuild after three attempts, even with the addition of build flags, please contact Support for further assistance.

Recursively finding and scanning your solution/project files

The following example shows you how to modify the sl.exe analyze invocation to recursively find all .sln files and scan them with Qwiet:

# Recursively find all .sln files and scan them with Qwiet preZero
# Be sure to change the app.group value from "test-appgroup" to your preferred name
Get-ChildItem -Path . -Filter *.sln -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
sl.exe analyze --csharp --oss-project-dir $($_.Directory) --tag app.group=test-appgroup --app $($_.Name -replace '.sln', '') $($_.FullName)
}

Alternatively, you can recursively find and scan all .csproj files if .sln-based scans are taking too long:

# Recursively find all .csproj files and scan them with Qwiet preZero
# Use this when .sln based scans are taking too long
# Be sure to change the app.group value from ß"test-appgroup" to your preferred name
Get-ChildItem -Path . -Filter *.csproj -Recurse -ErrorAction SilentlyContinue -Force | ForEach-Object {
sl.exe analyze --csharp --oss-project-dir $($_.Directory) --tag app.group=test-appgroup --app $($_.Name -replace '.csproj', '') $($_.FullName)
}

Apps utilizing MSBuild project files

If your primary application refers to dependencies (e.g., dll files), Qwiet's default code analysis mode will not look into the dependency files. However, if the csproj files with source code for dependencies are available, you can modify the parameters passed to sl.exe analyze to ensure that Qwiet analyzes all relevant dependencies.

In short, Qwiet can look at dependencies and dependencies of dependencies (which we call a transitive dependency) during the code analysis process.

To scan your primary solution and its dependencies, include the following flag after initial double ellipsis: --msbuild-proj <path-to-proj-file>. Note that a project file ends with the .proj suffix.

For example:

sl.exe analyze --app yourApp --csharp <path-to-sln-or-csproj> -- --msbuild-proj <path-to-proj-file>

However, if your solution refers to dependencies that, in turn, rely on dependencies, you can indicate to Qwiet that you would like such dependencies included in the analysis. Including the flag --msbuild-proj-iter <integer> allows you to provide the integer specifying the levels of transitive dependencies you want to be included in your scan.

For example, let's say that your sl.exe analyze command is as follows:

sl.exe analyze --app yourApp --csharp <path-to-sln-or-csproj> -- --msbuild-proj <path-to-proj-file> --msbuild-proj-iter 2

Qwiet will look at your primary project file, any direct dependencies, and any dependencies of direct dependencies. Qwiet will ignore any further references.

Example usage

Let's say that you have TheApp, which is structured as follows:

├── TheApp
│ └── TheApp.csproj
├── TheLib
| └── TheLib.csproj
├── AnotherLib
│ └── AnotherLib
│ └── AnotherLib
│ └── AnotherLib.csproj
├── CoolClassLib
│ └── CoolClassLib
│ └── CoolClassLib
│ └── CoolClassLib.csproj
├── NotUsedLib
└── NotUsedLib
└── NotUsedLib
└── NotUsedLib.csproj

The app's .sln file only mentions the TheApp.csproj:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.810.8
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheApp", "TheApp\TheApp.csproj", "{E776BD21-3B47-4184-93B7-7DA198474F1E}"
EndProject
...

TheApp.csproj references its dependencies through a <Reference>item, instead of a <ProjectReference> item (that is, it references .dll files). Its direct dependencies are TheLib and AnotherLib:

<Project Sdk="Microsoft.NET.Sdk.Web">

<ItemGroup>
<Reference Include="TheLib">
<HintPath>..\TheLib.dll</HintPath>
</Reference>
<Reference Include="AnotherLib">
<HintPath>..\AnotherLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

However, AnotherLib references CoolClassLib, making CoolClassLib a transitive dependency of TheApp:

<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<None Remove="CoolClassLib" />
</ItemGroup>
<ItemGroup>
<Reference Include="CoolClassLib">
<HintPath>..\..\..\CoolClassLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

To ensure that Qwiet looks into all of TheApp's dependencies, you must have an MSBuild project file (this is a build specification for all such dependencies). The following is a sample project file called TheAppFullBuild.proj:

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">

<Target Name="Assemblies">
<MSBuild Properties="… Projects="
<path-to>/TheApp/TheLib/TheLib.csproj;
<path-to>/TheApp/AnotherLib/AnotherLib/AnotherLib/AnotherLib.csproj;
<path-to>/TheApp/CoolClassLib/CoolClassLib/CoolClassLib/CoolClassLib.csproj;
<path-to>/TheApp/NotUsedLib/NotUsedLib/NotUsedLib/NotUsedLib.csproj;
"/>
</Target>
</Project>

Therefore, the sl.exe analyze command to scan TheApp is:

sl.exe analyze --app TheApp --csharp TheApp.sln -- --msbuild-proj TheAppFullBuild.proj --msbuild-proj-iter 2

Improving performance by omitting Razor files from the scan

By default, preZero looks for and scans Razor files included in your project. If you would like to disable this functionality to improve performance, you can pass in --disable-razor after a double hyphen:

sl.exe analyze --app yourApp --csharp <path-to-sln-or-csproj> -- --disable-razor

Excluding projects from the scan

preZero allows you to exclude one or more projects from your scan. This is helpful if:

  • You'd like to avoid scanning test projects;
  • You'd like to exclude a project to improve performance;
  • A project within your application is causing your scan to fail.

To exclude projects, pass in --ignore-project after a double hyphen:

sl analyze ... -- --ignore-project /tmp/app/libA.csproj /tmp/app/libB.csproj ...

You can pass in either full or relative file paths, and you can use wildcards when passing in either path type:

# ignore .csproj files in any sub-directory of tests
sl analyze ... -- --ignore-project tests/**/*.csproj

To ensure that preZero recognized the file path provided as part of --ignore-project, look for the following log message:

found via --ignore-project: <your/file/path>

Deprecated flags

The --dotnet, --dotnet-core, and --dotnet-framework flags have been deprecated, since Qwiet AI will automatically select the best option for the application. However, Qwiet AI is backward compatible, so including one of these flags will present no problem. Additionally, if you observe any issues, you may specify the flag that best fits the needs of your application to see if that improves your results.