diff --git a/csharp/ApiDocs/ApiDocs.csproj b/csharp/ApiDocs/ApiDocs.csproj
index a56e605022..644dff0c7e 100644
--- a/csharp/ApiDocs/ApiDocs.csproj
+++ b/csharp/ApiDocs/ApiDocs.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
enable
diff --git a/csharp/Nuget.CSharp.config b/csharp/NuGet.CSharp.config
similarity index 100%
rename from csharp/Nuget.CSharp.config
rename to csharp/NuGet.CSharp.config
diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj b/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj
index 78083a8cc1..39d90c55b7 100644
--- a/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj
+++ b/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj
@@ -21,7 +21,7 @@
-->
PreNet6
- netstandard1.1;netstandard2.0;net5.0;netcoreapp3.1
+ netstandard1.1;netstandard2.0;netcoreapp3.1;net6.0
An span of integers that represent the size of each dimension of the Tensor to create.
- /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor.
+ ///
+ /// An span of integers that represent the size of each dimension of the Tensor to create.
+ ///
+ /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension
+ /// is most minor (closest together): akin to row-major in a rank-2 tensor.
+ /// True to indicate that the last dimension is most major (farthest apart) and the first dimension is most
+ /// minor (closest together): akin to column-major in a rank-2 tensor.
+ /// If you pass `null` for dimensions it will implicitly convert to an empty ReadOnlySpan, which is
+ /// equivalent to the dimensions for a scalar value.
protected Tensor(ReadOnlySpan dimensions, bool reverseStride) : base(typeof(T))
{
- if (dimensions == null)
- {
- throw new ArgumentNullException(nameof(dimensions));
- }
-
this.dimensions = new int[dimensions.Length];
long size = 1;
for (int i = 0; i < dimensions.Length; i++)
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs
index e662676da9..5ebca9b05b 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs
@@ -108,7 +108,19 @@ namespace Microsoft.ML.OnnxRuntime.Tests
var directml_dll_path = AppDomain.CurrentDomain.BaseDirectory;
SetDllDirectory(directml_dll_path);
- opt.AppendExecutionProvider_DML(0);
+
+ try
+ {
+ opt.AppendExecutionProvider_DML(0);
+ }
+ catch (OnnxRuntimeException ortException)
+ {
+ // if we run on a CI machine with the incorrect hardware we might get an error due to that.
+ // allow that as the call made it through to the DML EP so the C# layer is working correctly.
+ // any other exception type or error message is considered a failure.
+ Assert.Contains("The specified device interface or feature level is not supported on this system.",
+ ortException.Message);
+ }
// Restore the default dll search order
SetDllDirectory(null);
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj
index cc4cc5ea65..79de2b95ca 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj
@@ -1,17 +1,19 @@
- netstandard2.0
+
+ netstandard2.0;net6.0
false
$(ProjectDir)..\..
- AnyCPU;x86
+ AnyCPU
bin\$(Configuration)\
- true
- true
- true
- $(OnnxRuntimeCsharpRoot)\..\cmake\external\onnx;\..\cmake\external\onnx\onnx
+ true
+ true
+ true
+ $(OnnxRuntimeCsharpRoot)\..\cmake\external\onnx
-
+
7.2
True
true
@@ -48,6 +50,7 @@
+
@@ -75,9 +78,9 @@
-
-
-
+
+
+
@@ -92,9 +95,27 @@
TextTemplatingFileGenerator
TensorOperations.cs
-
+
+
+ PreserveNewest
+ false
+
+
+
+ PreserveNewest
+ false
+
+
+
+ PreserveNewest
+ false
+
+
+
+
+
@@ -106,11 +127,11 @@
-
+
-
+
@@ -137,4 +158,4 @@
-
\ No newline at end of file
+
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs
index 63ddf51116..83d32fa54b 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs
@@ -148,7 +148,6 @@ namespace Microsoft.ML.OnnxRuntime.Tests
[Collection("Ort Inference Tests")]
public class OrtEnvWithCustomLogger : CustomLoggingFunctionTestBase
{
-
[Fact(DisplayName = "TesEnvWithCustomLogger")]
public void TesEnvWithCustomLogger()
{
@@ -172,7 +171,8 @@ namespace Microsoft.ML.OnnxRuntime.Tests
// Trigger some logging
// Empty stmt intentional
using (var session = new InferenceSession(model))
- ;
+ { }
+
Assert.True(LoggingInvokes > 0);
}
}
@@ -205,8 +205,9 @@ namespace Microsoft.ML.OnnxRuntime.Tests
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
// Trigger some logging
// Empty stmt intentional
- using (var session = new InferenceSession(model))
- ;
+ using (var session = new InferenceSession(model))
+ { }
+
Assert.True(LoggingInvokes > 0);
}
}
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs
index 019c3d58cd..d014dc0766 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs
@@ -38,10 +38,14 @@ namespace Microsoft.ML.OnnxRuntime.Tensors.Tests
this.length = length;
}
+ // A finalizer to allow debugging in test code is allowable.
+ // https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2015
+#pragma warning disable CA2015
~NativeMemory()
{
Dispose(false);
}
+#pragma warning restore CA2015
public static NativeMemory Allocate(int length)
{
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs
index 7816babf48..4088663ea7 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs
@@ -159,7 +159,12 @@ namespace Microsoft.ML.OnnxRuntime.Tensors.Tests
Assert.Equal(24, tensor.Length);
Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride);
- Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: null));
+ // The null is converted to a 'null' ReadOnlySpan which is a valid instance with length zero.
+ // https://learn.microsoft.com/en-us/dotnet/api/system.readonlyspan-1.-ctor?view=netstandard-2.1#system-readonlyspan-1-ctor(-0())
+ // Such a span is valid as dimensions as it represents a scalar.
+ // If we need to differentiate between the two we'd need to change the Tensor ctor to accept a
+ // nullable span in order to tell the user that's invalid.
+ // Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: null));
Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: new[] { 1, -1 }));
// ensure dimensions are immutable
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs
index 42a780b328..08d3d9d6f2 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs
@@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Net.NetworkInformation;
-using Google.Protobuf;
using Microsoft.ML.OnnxRuntime.Tensors;
-using Xunit;
namespace Microsoft.ML.OnnxRuntime.Tests
{
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj
index 78cfc5ca80..020a4745e2 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj
@@ -173,4 +173,4 @@
-->
-
+
\ No newline at end of file
diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj
index 4f99be4882..38cea3f23a 100644
--- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj
+++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj
@@ -1,7 +1,7 @@
- netcoreapp3.1
+ net6.0
false
$(ProjectDir)..\..
AnyCPU;x86
@@ -53,13 +53,39 @@
-
+
+
-
+
+ PreserveNewest
+ false
+
+
+
+ PreserveNewest
+ false
+
+
+
PreserveNewest
false
diff --git a/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml
index 1ea19e5734..d372699aa5 100644
--- a/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml
+++ b/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml
@@ -78,6 +78,7 @@ stages:
--build_shared_lib \
--parallel \
--build_wheel \
+ --build_csharp \
--enable_onnx_tests \
--enable_transformers_tool_test \
--use_cache \
@@ -86,6 +87,44 @@ stages:
ccache -z"
workingDirectory: $(Build.SourcesDirectory)
+ - task: UseDotNet@2
+ displayName: "Setup dotnet"
+ inputs:
+ version: '6.0.408'
+
+ - task: DotNetCoreCLI@2
+ displayName: "Restore C# packages"
+ inputs:
+ command: 'restore'
+ projects: '$(Build.SourcesDirectory)/csharp/OnnxRuntime.DesktopOnly.CSharp.sln'
+
+ # the props file was generated with docker container paths. convert to the 'real' path by replacing the
+ # the container path of '/build'. The '>' prefix is to match the closing angle bracket of the tag.
+ # e.g. /build/... so we only match the start of a path.
+ # We use powershell so we don't need extra escaping of the '/' chars in the path.
+ - task: CmdLine@2
+ displayName: 'Update props from docker path to local and create models link'
+ inputs:
+ script: |
+ pwsh -Command '(Get-Content $(Build.SourcesDirectory)/csharp/Directory.Build.props) -replace ">/build", ">$(Build.BinariesDirectory)" | Set-Content $(Build.SourcesDirectory)/csharp/Directory.Build.props'
+ cat $(Build.SourcesDirectory)/csharp/Directory.Build.props
+ ln -s /data/models $(Build.BinariesDirectory)/models
+
+ - task: DotNetCoreCLI@2
+ displayName: 'dotnet build C# sln'
+ inputs:
+ command: 'build'
+ projects: '$(Build.SourcesDirectory)/csharp/OnnxRuntime.DesktopOnly.CSharp.sln'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'dotnet test C#'
+ inputs:
+ command: 'test'
+ projects: '$(Build.SourcesDirectory)/csharp/OnnxRuntime.DesktopOnly.CSharp.sln'
+ # extra logging so all tests are listed in output to validate what's actually run
+ arguments: '-f net6.0 --no-build -l "console;verbosity=normal"'
+ workingDirectory: $(Build.SourcesDirectory)/csharp
+
- task: CmdLine@2
displayName: 'Install python deps and run java tests'
inputs: