提交 3883e580 编写于 作者: H Heejae Chang

move StreamJsonRpc to latest version

latest version of JsonRpc supports custom JsonConverter which I added for these 4 types. Checksum, SolutionId, ProjectId, DocumentId

we can add more to AggregateJsonConverter for common roslyn types.

unit test added
上级 a54f9dbc
......@@ -48,6 +48,7 @@ public static async Task<RemoteHostClient> CreateAsync(Workspace workspace, bool
_inprocServices = inprocServices;
_rpc = JsonRpc.Attach(stream, target: this);
_rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
// handle disconnected situation
_rpc.Disconnected += OnRpcDisconnected;
......
......@@ -84,7 +84,7 @@ internal class VisualStudioDiagnosticAnalyzerExecutor : ICodeAnalysisDiagnosticA
var argument = new DiagnosticArguments(
analyzerDriver.AnalysisOptions.ReportSuppressedDiagnostics,
analyzerDriver.AnalysisOptions.LogAnalyzerExecutionTime,
project.Id, optionAsset.Checksum.ToArray(), hostChecksums, analyzerMap.Keys.ToArray());
project.Id, optionAsset.Checksum, hostChecksums, analyzerMap.Keys.ToArray());
// TODO: send telemetry on session
using (var session = await client.CreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
......@@ -161,11 +161,11 @@ private void ReportAnalyzerExceptions(Project project, ImmutableDictionary<Diagn
}
}
private ImmutableArray<byte[]> GetHostAnalyzerReferences(
private ImmutableArray<Checksum> GetHostAnalyzerReferences(
ISolutionSynchronizationService snapshotService, string language, IEnumerable<AnalyzerReference> references, CancellationToken cancellationToken)
{
// TODO: cache this to somewhere
var builder = ImmutableArray.CreateBuilder<byte[]>();
var builder = ImmutableArray.CreateBuilder<Checksum>();
foreach (var reference in references)
{
var analyzers = reference.GetAnalyzers(language);
......@@ -178,7 +178,7 @@ private void ReportAnalyzerExceptions(Project project, ImmutableDictionary<Diagn
}
var asset = snapshotService.GetGlobalAsset(reference, cancellationToken);
builder.Add(asset.Checksum.ToArray());
builder.Add(asset.Checksum);
}
return builder.ToImmutable();
......
......@@ -124,7 +124,7 @@ private async Task SynchronizePrimaryWorkspaceAsync(CancellationToken cancellati
{
// ask remote host to sync initial asset
var checksum = await solution.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false);
await session.InvokeAsync(WellKnownRemoteHostServices.RemoteHostService_SynchronizePrimaryWorkspaceAsync, new object[] { checksum.ToArray() }).ConfigureAwait(false);
await session.InvokeAsync(WellKnownRemoteHostServices.RemoteHostService_SynchronizePrimaryWorkspaceAsync, checksum).ConfigureAwait(false);
}
}
}
......
......@@ -26,6 +26,8 @@ internal class JsonRpcClient : IDisposable
_cancellationToken = cancellationToken;
_rpc = JsonRpc.Attach(stream, target);
_rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
_rpc.Disconnected += OnDisconnected;
}
......
......@@ -66,8 +66,8 @@ internal class JsonRpcSession : RemoteHostClient.Session
private async Task InitializeAsync()
{
// all roslyn remote service must based on ServiceHubServiceBase which implements Initialize method
await _snapshotClient.InvokeAsync(WellKnownServiceHubServices.ServiceHubServiceBase_Initialize, _currentSessionId, PinnedScope.SolutionChecksum.ToArray()).ConfigureAwait(false);
await _serviceClient.InvokeAsync(WellKnownServiceHubServices.ServiceHubServiceBase_Initialize, _currentSessionId, PinnedScope.SolutionChecksum.ToArray()).ConfigureAwait(false);
await _snapshotClient.InvokeAsync(WellKnownServiceHubServices.ServiceHubServiceBase_Initialize, _currentSessionId, PinnedScope.SolutionChecksum).ConfigureAwait(false);
await _serviceClient.InvokeAsync(WellKnownServiceHubServices.ServiceHubServiceBase_Initialize, _currentSessionId, PinnedScope.SolutionChecksum).ConfigureAwait(false);
}
public override Task InvokeAsync(string targetName, params object[] arguments)
......@@ -220,7 +220,7 @@ private async Task WriteMultipleAssetsAsync(ObjectWriter writer, byte[][] checks
var checksum = kv.Key;
var remotableData = kv.Value;
writer.WriteValue(checksum.ToArray());
checksum.WriteTo(writer);
writer.WriteString(remotableData.Kind);
await remotableData.WriteObjectToAsync(writer, _source.Token).ConfigureAwait(false);
......
......@@ -73,6 +73,7 @@ private static void RegisterWorkspaceHost(Workspace workspace, RemoteHostClient
_hostGroup = hostGroup;
_rpc = JsonRpc.Attach(stream, target: this);
_rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
// handle disconnected situation
_rpc.Disconnected += OnRpcDisconnected;
......
......@@ -77,6 +77,12 @@
<Compile Include="..\..\..\Workspaces\Remote\ServiceHub\Shared\Extensions.cs">
<Link>Shared\Extensions.cs</Link>
</Compile>
<Compile Include="..\..\..\Workspaces\Remote\ServiceHub\Shared\RoslynJsonConverter.cs">
<Link>Shared\RoslynJsonConverter.cs</Link>
</Compile>
<Compile Include="..\..\..\Workspaces\Remote\ServiceHub\Shared\RoslynJsonConverter.SolutionIdConverters.cs">
<Link>Shared\RoslynJsonConverter.SolutionIdConverters.cs</Link>
</Compile>
<Compile Include="..\..\..\Workspaces\Remote\ServiceHub\Shared\ServerDirectStream.cs">
<Link>Shared\ServerDirectStream.cs</Link>
</Compile>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
extern alias hub;
using System;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Remote;
using Newtonsoft.Json;
using Roslyn.Test.Utilities;
using Xunit;
namespace Roslyn.VisualStudio.Next.UnitTests.Remote
{
public class JsonConverterTests
{
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public void TestChecksum()
{
VerifyJsonSerialization(new Checksum(Guid.NewGuid().ToByteArray()));
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public void TestSolutionId()
{
VerifyJsonSerialization(SolutionId.CreateNewId("solution"));
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public void TestProjectId()
{
VerifyJsonSerialization(ProjectId.CreateNewId("project"));
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public void TestDocumentId()
{
VerifyJsonSerialization(DocumentId.CreateNewId(ProjectId.CreateNewId("project"), "document"));
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public void TestDiagnosticArguments()
{
var arguments = new hub::Microsoft.CodeAnalysis.Remote.Diagnostics.DiagnosticArguments(
reportSuppressedDiagnostics: true,
logAnalyzerExecutionTime: false,
projectId: ProjectId.CreateNewId("project"),
optionSetChecksum: Checksum.Null,
hostAnalyzerChecksums: ImmutableArray.CreateRange(new[] { new Checksum(Guid.NewGuid().ToByteArray()), new Checksum(Guid.NewGuid().ToByteArray()) }),
analyzerIds: new[] { "analyzer1", "analyzer2" });
VerifyJsonSerialization(arguments, (x, y) =>
{
if (x.ReportSuppressedDiagnostics == y.ReportSuppressedDiagnostics &&
x.LogAnalyzerExecutionTime == y.LogAnalyzerExecutionTime &&
x.ProjectId == y.ProjectId &&
x.OptionSetChecksum == y.OptionSetChecksum &&
x.HostAnalyzerChecksums.Length == y.HostAnalyzerChecksums.Length &&
x.HostAnalyzerChecksums.Except(y.HostAnalyzerChecksums).Count() == 0 &&
x.AnalyzerIds.Length == y.AnalyzerIds.Length &&
x.AnalyzerIds.Except(y.AnalyzerIds).Count() == 0)
{
return 0;
}
return 1;
});
}
private static void VerifyJsonSerialization<T>(T value, Comparison<T> equality = null)
{
var serializer = new JsonSerializer();
serializer.Converters.Add(hub::Microsoft.CodeAnalysis.Remote.AggregateJsonConverter.Instance);
using (var writer = new StringWriter())
{
serializer.Serialize(writer, value);
using (var reader = new JsonTextReader(new StringReader(writer.ToString())))
{
var deserialized = serializer.Deserialize<T>(reader);
if (equality != null)
{
Assert.Equal(0, equality(value, deserialized));
return;
}
Assert.Equal(value, deserialized);
}
}
}
}
}
\ No newline at end of file
......@@ -205,7 +205,7 @@ private static async Task UpdatePrimaryWorkspace(InProcRemoteHostClient client,
{
await session.InvokeAsync(
WellKnownRemoteHostServices.RemoteHostService_SynchronizePrimaryWorkspaceAsync,
new object[] { (await solution.State.GetChecksumAsync(CancellationToken.None)).ToArray() });
await solution.State.GetChecksumAsync(CancellationToken.None));
}
}
......
......@@ -86,6 +86,7 @@
<ProjectReference Include="..\..\..\Workspaces\Remote\ServiceHub\ServiceHub.csproj">
<Project>{80fddd00-9393-47f7-8baf-7e87ce011068}</Project>
<Name>ServiceHub</Name>
<Aliases>global,hub</Aliases>
</ProjectReference>
<ProjectReference Include="..\..\..\Workspaces\VisualBasic\Portable\BasicWorkspace.vbproj">
<Project>{57ca988d-f010-4bf2-9a2e-07d6dcd2ff2c}</Project>
......@@ -190,6 +191,7 @@
<Compile Include="Mocks\TestHostServices.cs" />
<Compile Include="Mocks\InProcRemoteHostClientFactory.cs" />
<Compile Include="Mocks\TestOptionSet.cs" />
<Compile Include="Remote\JsonConverterTests.cs" />
<Compile Include="Remote\RemoteHostClientServiceFactoryTests.cs" />
<Compile Include="TestUtils.cs" />
<Compile Include="Services\SolutionServiceTests.cs" />
......
......@@ -71,7 +71,7 @@ public Checksum CreateChecksum(object value, CancellationToken cancellationToken
return Checksum.Create(kind, _hostSerializationService.CreateChecksum((AnalyzerReference)value, cancellationToken));
case WellKnownSynchronizationKinds.SourceText:
return Checksum.Create(kind, new Checksum(((SourceText)value).GetChecksum()));
return Checksum.Create(kind, ((SourceText)value).GetChecksum());
default:
// object that is not part of solution is not supported since we don't know what inputs are required to
......
......@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Roslyn.Utilities;
......@@ -14,30 +13,18 @@ namespace Microsoft.CodeAnalysis
/// </summary>
internal sealed partial class Checksum : IObjectWritable, IEquatable<Checksum>
{
public static readonly Checksum Null = new Checksum(ImmutableArray<byte>.Empty);
public static readonly Checksum Null = new Checksum(Array.Empty<byte>());
private readonly ImmutableArray<byte> _checkSum;
private readonly byte[] _checkSum;
private int _lazyHash;
public Checksum(byte[] checksum) :
this(ImmutableArray.Create(checksum))
{
}
public Checksum(ImmutableArray<byte> checksum)
public Checksum(byte[] checksum)
{
// 0 means it is not initialized
_lazyHash = 0;
_checkSum = checksum;
}
public byte[] ToArray()
{
// TODO: think a way to make this better
return _checkSum.ToArray();
}
public bool Equals(Checksum other)
{
if (other == null)
......@@ -78,7 +65,7 @@ public override int GetHashCode()
public override string ToString()
{
return Convert.ToBase64String(ToArray());
return Convert.ToBase64String(_checkSum);
}
private int CalculateHashCode()
......@@ -107,25 +94,12 @@ private int CalculateHashCode()
public void WriteTo(ObjectWriter writer)
{
writer.WriteInt32(_checkSum.Length);
for (var i = 0; i < _checkSum.Length; i++)
{
writer.WriteByte(_checkSum[i]);
}
writer.WriteValue(_checkSum);
}
public static Checksum ReadFrom(ObjectReader reader)
{
var length = reader.ReadInt32();
var builder = ImmutableArray.CreateBuilder<byte>(length);
for (var i = 0; i < length; i++)
{
builder.Add(reader.ReadByte());
}
return new Checksum(builder.MoveToImmutable());
return new Checksum((byte[])reader.ReadValue());
}
public static string GetChecksumLogInfo(Checksum checksum)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Threading;
using Roslyn.Utilities;
using System.Security.Cryptography;
using System.Threading;
using Microsoft.CodeAnalysis.Serialization;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
......@@ -53,6 +53,22 @@ public static Checksum Create<TChecksums>(string kind, TChecksums checksums)
}
}
public static Checksum Create(string kind, ImmutableArray<byte> bytes)
{
using (var stream = SerializableBytes.CreateWritableStream())
using (var writer = new StreamObjectWriter(stream))
{
writer.WriteString(kind);
for (var i = 0; i < bytes.Length; i++)
{
writer.WriteByte(bytes[i]);
}
return Create(stream);
}
}
public static Checksum Create<T>(T value, string kind, Serializer serializer)
{
using (var stream = SerializableBytes.CreateWritableStream())
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Execution;
namespace Microsoft.CodeAnalysis.Remote.Diagnostics
{
......@@ -15,10 +12,9 @@ internal class DiagnosticArguments
{
public bool ReportSuppressedDiagnostics;
public bool LogAnalyzerExecutionTime;
public Guid ProjectIdGuid;
public string ProjectIdDebugName;
public byte[] OptionSetChecksumBytes;
public byte[][] HostAnalyzerChecksumsByteArray;
public ProjectId ProjectId;
public Checksum OptionSetChecksum;
public Checksum[] HostAnalyzerChecksums;
public string[] AnalyzerIds;
public DiagnosticArguments()
......@@ -29,23 +25,18 @@ public DiagnosticArguments()
bool reportSuppressedDiagnostics,
bool logAnalyzerExecutionTime,
ProjectId projectId,
byte[] optionSetChecksum,
ImmutableArray<byte[]> hostAnalyzerChecksums,
Checksum optionSetChecksum,
ImmutableArray<Checksum> hostAnalyzerChecksums,
string[] analyzerIds)
{
ReportSuppressedDiagnostics = reportSuppressedDiagnostics;
LogAnalyzerExecutionTime = logAnalyzerExecutionTime;
ProjectIdGuid = projectId.Id;
ProjectIdDebugName = projectId.DebugName;
ProjectId = projectId;
OptionSetChecksumBytes = optionSetChecksum;
HostAnalyzerChecksumsByteArray = hostAnalyzerChecksums.ToArray();
OptionSetChecksum = optionSetChecksum;
HostAnalyzerChecksums = hostAnalyzerChecksums.ToArray();
AnalyzerIds = analyzerIds;
}
public ProjectId GetProjectId() => ProjectId.CreateFromSerialized(ProjectIdGuid, ProjectIdDebugName);
public IEnumerable<Checksum> GetHostAnalyzerChecksums() => HostAnalyzerChecksumsByteArray.Select(b => new Checksum(b));
public Checksum GetOptionSetChecksum() => new Checksum(OptionSetChecksumBytes);
}
}
\ No newline at end of file
......@@ -69,6 +69,8 @@
<Compile Include="Services\ServiceHubServiceBase.cs" />
<Compile Include="Services\SnapshotService.cs" />
<Compile Include="Shared\Extensions.cs" />
<Compile Include="Shared\RoslynJsonConverter.cs" />
<Compile Include="Shared\RoslynJsonConverter.SolutionIdConverters.cs" />
<Compile Include="Shared\ServerDirectStream.cs" />
<Compile Include="Shared\ClientDirectStream.cs" />
</ItemGroup>
......
......@@ -26,17 +26,17 @@ internal partial class CodeAnalysisService
/// </summary>
public async Task CalculateDiagnosticsAsync(DiagnosticArguments arguments, string streamName)
{
using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_CalculateDiagnosticsAsync, arguments.ProjectIdDebugName, CancellationToken))
using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_CalculateDiagnosticsAsync, arguments.ProjectId.DebugName, CancellationToken))
{
try
{
var optionSet = await RoslynServices.AssetService.GetAssetAsync<OptionSet>(arguments.GetOptionSetChecksum(), CancellationToken).ConfigureAwait(false);
var optionSet = await RoslynServices.AssetService.GetAssetAsync<OptionSet>(arguments.OptionSetChecksum, CancellationToken).ConfigureAwait(false);
// entry point for diagnostic service
var solution = await GetSolutionWithSpecificOptionsAsync(optionSet).ConfigureAwait(false);
var projectId = arguments.GetProjectId();
var analyzers = await GetHostAnalyzerReferences(arguments.GetHostAnalyzerChecksums()).ConfigureAwait(false);
var projectId = arguments.ProjectId;
var analyzers = await GetHostAnalyzerReferences(arguments.HostAnalyzerChecksums).ConfigureAwait(false);
var result = await (new DiagnosticComputer(solution.GetProject(projectId))).GetDiagnosticsAsync(
analyzers, arguments.AnalyzerIds, arguments.ReportSuppressedDiagnostics, arguments.LogAnalyzerExecutionTime, CancellationToken).ConfigureAwait(false);
......
......@@ -43,6 +43,8 @@ protected ServiceHubServiceBase(Stream stream, IServiceProvider serviceProvider)
CancellationToken = _cancellationTokenSource.Token;
Rpc = JsonRpc.Attach(stream, this);
Rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
Rpc.Disconnected += OnRpcDisconnected;
}
......
......@@ -46,7 +46,7 @@ private class JsonRpcAssetSource : AssetSource
using (RoslynLogger.LogBlock(FunctionId.SnapshotService_RequestAssetAsync, GetRequestLogInfo, sessionId, checksums, mergedCancellationToken.Token))
{
return await _owner.Rpc.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync,
new object[] { sessionId, checksums.Select(c => c.ToArray()).ToArray() },
new object[] { sessionId, checksums.ToArray() },
(s, c) => ReadAssets(s, sessionId, checksums, c), mergedCancellationToken.Token).ConfigureAwait(false);
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Newtonsoft.Json;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Remote
{
internal partial class AggregateJsonConverter : JsonConverter
{
private abstract class WorkspaceIdJsonConverter : JsonConverter
{
protected (Guid, string) ReadFromJsonObject(JsonReader reader)
{
Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject);
var (id, debugName) = ReadIdAndName(reader);
Contract.ThrowIfFalse(reader.Read());
Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject);
return (id, debugName);
}
protected void WriteToJsonObject(JsonWriter writer, Guid id, string debugName)
{
writer.WriteStartObject();
WriteIdAndName(writer, id, debugName);
writer.WriteEndObject();
}
protected (Guid, string) ReadIdAndName(JsonReader reader)
{
var id = new Guid(ReadProperty<string>(reader));
var debugName = ReadProperty<string>(reader);
return (id, debugName);
}
protected static void WriteIdAndName(JsonWriter writer, Guid id, string debugName)
{
writer.WritePropertyName(nameof(id));
writer.WriteValue(id);
writer.WritePropertyName(nameof(debugName));
writer.WriteValue(debugName);
}
protected static T ReadProperty<T>(JsonSerializer serializer, JsonReader reader)
{
// read property
Contract.ThrowIfFalse(reader.Read());
Contract.ThrowIfFalse(reader.TokenType == JsonToken.PropertyName);
Contract.ThrowIfFalse(reader.Read());
return serializer.Deserialize<T>(reader);
}
private static T ReadProperty<T>(JsonReader reader)
{
// read property
Contract.ThrowIfFalse(reader.Read());
Contract.ThrowIfFalse(reader.TokenType == JsonToken.PropertyName);
Contract.ThrowIfFalse(reader.Read());
return (T)reader.Value;
}
}
private class SolutionIdJsonConverter : WorkspaceIdJsonConverter
{
public override bool CanConvert(Type objectType) => typeof(SolutionId) == objectType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var (id, debugName) = ReadFromJsonObject(reader);
return SolutionId.CreateFromSerialized(id, debugName);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var solutionId = (SolutionId)value;
WriteToJsonObject(writer, solutionId.Id, solutionId.DebugName);
}
}
private class ProjectIdJsonConverter : WorkspaceIdJsonConverter
{
public override bool CanConvert(Type objectType) => typeof(ProjectId) == objectType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var (id, debugName) = ReadFromJsonObject(reader);
return ProjectId.CreateFromSerialized(id, debugName);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var projectId = (ProjectId)value;
WriteToJsonObject(writer, projectId.Id, projectId.DebugName);
}
}
private class DocumentIdJsonConverter : WorkspaceIdJsonConverter
{
public override bool CanConvert(Type objectType) => typeof(DocumentId) == objectType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Contract.ThrowIfFalse(reader.TokenType == JsonToken.StartObject);
var projectId = ReadProperty<ProjectId>(serializer, reader);
var (id, debugName) = ReadIdAndName(reader);
Contract.ThrowIfFalse(reader.Read());
Contract.ThrowIfFalse(reader.TokenType == JsonToken.EndObject);
return DocumentId.CreateFromSerialized(projectId, id, debugName);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var documentId = (DocumentId)value;
writer.WriteStartObject();
writer.WritePropertyName("projectId");
serializer.Serialize(writer, documentId.ProjectId);
WriteIdAndName(writer, documentId.Id, documentId.DebugName);
writer.WriteEndObject();
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using Newtonsoft.Json;
namespace Microsoft.CodeAnalysis.Remote
{
internal partial class AggregateJsonConverter : JsonConverter
{
public static readonly AggregateJsonConverter Instance = new AggregateJsonConverter();
private readonly ImmutableDictionary<Type, JsonConverter> _map;
private AggregateJsonConverter()
{
_map = CreateConverterMap();
}
public override bool CanConvert(Type objectType)
{
return _map.ContainsKey(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return _map[objectType].ReadJson(reader, objectType, existingValue, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
_map[value.GetType()].WriteJson(writer, value, serializer);
}
private ImmutableDictionary<Type, JsonConverter> CreateConverterMap()
{
var builder = ImmutableDictionary.CreateBuilder<Type, JsonConverter>();
builder.Add(typeof(Checksum), new ChecksumJsonConverter());
builder.Add(typeof(SolutionId), new SolutionIdJsonConverter());
builder.Add(typeof(ProjectId), new ProjectIdJsonConverter());
builder.Add(typeof(DocumentId), new DocumentIdJsonConverter());
return builder.ToImmutable();
}
private class ChecksumJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => typeof(Checksum) == objectType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
new Checksum(Convert.FromBase64String((string)reader.Value));
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
writer.WriteValue(value.ToString());
}
}
}
{
"dependencies": {
"StreamJsonRpc": "0.12.32-alpha-g90be50f449"
"StreamJsonRpc": "1.0.2-rc"
},
"frameworks": {
"net46": { }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册