diff --git a/src/Protocol/Models/FileEvent.cs b/src/Protocol/Models/FileEvent.cs
index 8cc2f5b34..4fd0cc3d7 100644
--- a/src/Protocol/Models/FileEvent.cs
+++ b/src/Protocol/Models/FileEvent.cs
@@ -1,6 +1,7 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
+using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
@@ -12,7 +13,9 @@ public class FileEvent
///
/// The file's URI.
///
+ [JsonConverter(typeof(AbsoluteUriConverter))]
public Uri Uri { get; set; }
+
///
/// The change type.
///
diff --git a/src/Protocol/Models/Location.cs b/src/Protocol/Models/Location.cs
index fc864a04f..defc56498 100644
--- a/src/Protocol/Models/Location.cs
+++ b/src/Protocol/Models/Location.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
+using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
@@ -10,6 +11,7 @@ public class Location : IEquatable
///
/// The uri of the document
///
+ [JsonConverter(typeof(AbsoluteUriConverter))]
public Uri Uri { get; set; }
///
diff --git a/src/Protocol/Models/PublishDiagnosticsParams.cs b/src/Protocol/Models/PublishDiagnosticsParams.cs
index 04624f448..b089c7188 100644
--- a/src/Protocol/Models/PublishDiagnosticsParams.cs
+++ b/src/Protocol/Models/PublishDiagnosticsParams.cs
@@ -2,6 +2,7 @@
using OmniSharp.Extensions.Embedded.MediatR;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
+using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
@@ -10,6 +11,7 @@ public class PublishDiagnosticsParams : IRequest
///
/// The URI for which diagnostic information is reported.
///
+ [JsonConverter(typeof(AbsoluteUriConverter))]
public Uri Uri { get; set; }
///
diff --git a/src/Protocol/Models/TextDocumentIdentifier.cs b/src/Protocol/Models/TextDocumentIdentifier.cs
index 702099099..18f99d855 100644
--- a/src/Protocol/Models/TextDocumentIdentifier.cs
+++ b/src/Protocol/Models/TextDocumentIdentifier.cs
@@ -1,6 +1,7 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
+using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
@@ -15,9 +16,11 @@ public TextDocumentIdentifier(Uri uri)
{
Uri = uri;
}
+
///
/// The text document's URI.
///
+ [JsonConverter(typeof(AbsoluteUriConverter))]
public Uri Uri { get; set; }
}
}
diff --git a/src/Protocol/Models/WorkspaceFolder.cs b/src/Protocol/Models/WorkspaceFolder.cs
index 50a6f38fb..b83e7433d 100644
--- a/src/Protocol/Models/WorkspaceFolder.cs
+++ b/src/Protocol/Models/WorkspaceFolder.cs
@@ -1,4 +1,6 @@
using System;
+using Newtonsoft.Json;
+using OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters;
namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
@@ -7,6 +9,7 @@ public class WorkspaceFolder
///
/// The associated URI for this workspace folder.
///
+ [JsonConverter(typeof(AbsoluteUriConverter))]
public Uri Uri { get; set; }
///
diff --git a/src/Protocol/Serialization/Converters/AbsoluteUriConverter.cs b/src/Protocol/Serialization/Converters/AbsoluteUriConverter.cs
new file mode 100644
index 000000000..b9e9abc87
--- /dev/null
+++ b/src/Protocol/Serialization/Converters/AbsoluteUriConverter.cs
@@ -0,0 +1,57 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// #see https://github.com/NuGet/NuGet.Server
+using System;
+using Newtonsoft.Json;
+
+namespace OmniSharp.Extensions.LanguageServer.Protocol.Serialization.Converters
+{
+ ///
+ /// This is necessary because Newtonsoft.Json creates instances with
+ /// which treats UNC paths as relative. NuGet.Core uses
+ /// which treats UNC paths as absolute. For more details, see:
+ /// https://github.com/JamesNK/Newtonsoft.Json/issues/2128
+ ///
+ class AbsoluteUriConverter : JsonConverter
+ {
+ public override Uri ReadJson(JsonReader reader, Type objectType, Uri existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+ else if (reader.TokenType == JsonToken.String)
+ {
+ var uri = new Uri((string)reader.Value, UriKind.RelativeOrAbsolute);
+ if (!uri.IsAbsoluteUri)
+ {
+ throw new JsonSerializationException($"The Uri must be absolute. Given: {reader.Value}");
+ }
+ return uri;
+ }
+
+ throw new JsonSerializationException("The JSON value must be a string.");
+ }
+
+ public override void WriteJson(JsonWriter writer, Uri value, JsonSerializer serializer)
+ {
+ if (value == null)
+ {
+ writer.WriteNull();
+ return;
+ }
+
+ if (!(value is Uri uriValue))
+ {
+ throw new JsonSerializationException("The value must be a URI.");
+ }
+
+ if (!uriValue.IsAbsoluteUri)
+ {
+ throw new JsonSerializationException("The URI value must be an absolute Uri. Relative URI instances are not allowed.");
+ }
+
+ writer.WriteValue(uriValue.ToString());
+ }
+ }
+}
diff --git a/test/Lsp.Tests/Models/TextDocumentIdentifierTests.cs b/test/Lsp.Tests/Models/TextDocumentIdentifierTests.cs
index 8a2fe60bf..074a0d57f 100644
--- a/test/Lsp.Tests/Models/TextDocumentIdentifierTests.cs
+++ b/test/Lsp.Tests/Models/TextDocumentIdentifierTests.cs
@@ -22,5 +22,41 @@ public void SimpleTest(string expected)
var deresult = new Serializer(ClientVersion.Lsp3).DeserializeObject(expected);
deresult.Should().BeEquivalentTo(model);
}
+
+ [Fact]
+ public void Should_Fail_To_Serialize_When_Given_A_Non_Relative_Uri()
+ {
+ var serializer = new Serializer(ClientVersion.Lsp3);
+ var model = new TextDocumentIdentifier()
+ {
+ Uri = new Uri("./abc23.cs", UriKind.Relative),
+ };
+
+ Action a = () => serializer.SerializeObject(model);
+ a.Should().Throw();
+ }
+
+ [Fact]
+ public void Should_Fail_To_Deserialize_When_Given_A_Non_Relative_Uri()
+ {
+ var serializer = new Serializer(ClientVersion.Lsp3);
+ var json = @"{
+ ""uri"":""./0b0jnxg2.kgh.ps1""
+ }";
+
+ Action a = () => serializer.DeserializeObject(json);
+ a.Should().Throw();
+ }
+
+ [Fact]
+ public void Should_Deserialize_For_Example_Value()
+ {
+ var serializer = new Serializer(ClientVersion.Lsp3);
+ var result = serializer.DeserializeObject(@"{
+ ""uri"":""file:///Users/tyler/Code/PowerShell/vscode/PowerShellEditorServices/test/PowerShellEditorServices.Test.E2E/bin/Debug/netcoreapp2.1/0b0jnxg2.kgh.ps1""
+ }");
+
+ result.Uri.Should().Be(new Uri("file:///Users/tyler/Code/PowerShell/vscode/PowerShellEditorServices/test/PowerShellEditorServices.Test.E2E/bin/Debug/netcoreapp2.1/0b0jnxg2.kgh.ps1", UriKind.Absolute));
+ }
}
}
diff --git a/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs b/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs
index 42b617b62..0ca9c66aa 100644
--- a/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs
+++ b/test/Lsp.Tests/Models/VersionedTextDocumentIdentifierTests.cs
@@ -14,7 +14,8 @@ public class VersionedTextDocumentIdentifierTests
[Theory, JsonFixture]
public void SimpleTest(string expected)
{
- var model = new VersionedTextDocumentIdentifier() {
+ var model = new VersionedTextDocumentIdentifier()
+ {
Uri = new Uri("file:///abc/123.cs"),
Version = 12
};