This commit is contained in:
Microsoft 2016-06-11 12:01:37 -07:00 коммит произвёл Andrew Arnott
Коммит 79fb704bfd
36 изменённых файлов: 3800 добавлений и 0 удалений

288
src/StreamJsonRpc.Desktop/Resources.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,288 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace StreamJsonRpc {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StreamJsonRpc.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Both readable and writable are null..
/// </summary>
internal static string BothReadableWritableAreNull {
get {
return ResourceManager.GetString("BothReadableWritableAreNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Got a request to execute &apos;{0}&apos; but have no callback object. Dropping the request..
/// </summary>
internal static string DroppingRequestDueToNoTargetObject {
get {
return ResourceManager.GetString("DroppingRequestDueToNoTargetObject", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delimiter is empty string..
/// </summary>
internal static string EmptyDelimiter {
get {
return ResourceManager.GetString("EmptyDelimiter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error writing JSON-RPC Result: {0}: {1}.
/// </summary>
internal static string ErrorWritingJsonRpcResult {
get {
return ResourceManager.GetString("ErrorWritingJsonRpcResult", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failure deserializing incoming JSON-RPC &apos;{0}&apos;: {1}.
/// </summary>
internal static string FailureDeserializingJsonRpc {
get {
return ResourceManager.GetString("FailureDeserializingJsonRpc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to JSON-RPC must not be null..
/// </summary>
internal static string JsonRpcCannotBeNull {
get {
return ResourceManager.GetString("JsonRpcCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} has ref or out parameter(s), which is not supported.
/// </summary>
internal static string MethodHasRefOrOutParameters {
get {
return ResourceManager.GetString("MethodHasRefOrOutParameters", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} is not public.
/// </summary>
internal static string MethodIsNotPublic {
get {
return ResourceManager.GetString("MethodIsNotPublic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; method name has different case from requested &apos;{1}&apos;.
/// </summary>
internal static string MethodNameCaseIsDifferent {
get {
return ResourceManager.GetString("MethodNameCaseIsDifferent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} parameter(s): {1}, but the request supplies {2}.
/// </summary>
internal static string MethodParameterCountDoesNotMatch {
get {
return ResourceManager.GetString("MethodParameterCountDoesNotMatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} parameters are not compatible with the request: {1}.
/// </summary>
internal static string MethodParametersNotCompatible {
get {
return ResourceManager.GetString("MethodParametersNotCompatible", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to More than one target method found: {0}..
/// </summary>
internal static string MoreThanOneMethodFound {
get {
return ResourceManager.GetString("MoreThanOneMethodFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reached end of stream..
/// </summary>
internal static string ReachedEndOfStream {
get {
return ResourceManager.GetString("ReachedEndOfStream", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Readable cannot read..
/// </summary>
internal static string ReadableCannotRead {
get {
return ResourceManager.GetString("ReadableCannotRead", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Readable is not set..
/// </summary>
internal static string ReadableNotSet {
get {
return ResourceManager.GetString("ReadableNotSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reading JSON-RPC from the stream failed with {0}: {1}.
/// </summary>
internal static string ReadingJsonRpcStreamFailed {
get {
return ResourceManager.GetString("ReadingJsonRpcStreamFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Response is not error..
/// </summary>
internal static string ResponseIsNotError {
get {
return ResourceManager.GetString("ResponseIsNotError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stream has been disposed.
/// </summary>
internal static string StreamDisposed {
get {
return ResourceManager.GetString("StreamDisposed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The task is not completed..
/// </summary>
internal static string TaskNotCompleted {
get {
return ResourceManager.GetString("TaskNotCompleted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The task was cancelled..
/// </summary>
internal static string TaskWasCancelled {
get {
return ResourceManager.GetString("TaskWasCancelled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unable to find method &apos;{0}/{1}&apos; on {2} for the following reason: {3}.
/// </summary>
internal static string UnableToFindMethod {
get {
return ResourceManager.GetString("UnableToFindMethod", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unexpected error processing JSON-RPC &apos;{0}&apos;: {1}.
/// </summary>
internal static string UnexpectedErrorProcessingJsonRpc {
get {
return ResourceManager.GetString("UnexpectedErrorProcessingJsonRpc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unrecognized incoming JSON-RPC &apos;{0}&apos;.
/// </summary>
internal static string UnrecognizedIncomingJsonRpc {
get {
return ResourceManager.GetString("UnrecognizedIncomingJsonRpc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Writable cannot write..
/// </summary>
internal static string WritableCannotWrite {
get {
return ResourceManager.GetString("WritableCannotWrite", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Writable is not set..
/// </summary>
internal static string WritableNotSet {
get {
return ResourceManager.GetString("WritableNotSet", resourceCulture);
}
}
}
}

Просмотреть файл

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BothReadableWritableAreNull" xml:space="preserve">
<value>Both readable and writable are null.</value>
<comment>'readable' and 'writable' are parameter names and should not be localized.</comment>
</data>
<data name="DroppingRequestDueToNoTargetObject" xml:space="preserve">
<value>Got a request to execute '{0}' but have no callback object. Dropping the request.</value>
<comment>{0} is the method name to execute.</comment>
</data>
<data name="EmptyDelimiter" xml:space="preserve">
<value>Delimiter is empty string.</value>
</data>
<data name="ErrorWritingJsonRpcResult" xml:space="preserve">
<value>Error writing JSON-RPC Result: {0}: {1}</value>
<comment>{0} is the exception type, {1} is the exception message. "JSON-RPC" is a protocol</comment>
</data>
<data name="FailureDeserializingJsonRpc" xml:space="preserve">
<value>Failure deserializing incoming JSON-RPC '{0}': {1}</value>
<comment>{0} is the JSON that could not be deserialized, {1} is the exception message.</comment>
</data>
<data name="JsonRpcCannotBeNull" xml:space="preserve">
<value>JSON-RPC must not be null.</value>
</data>
<data name="MethodHasRefOrOutParameters" xml:space="preserve">
<value>{0} has ref or out parameter(s), which is not supported</value>
<comment>{0} is the method signature.</comment>
</data>
<data name="MethodIsNotPublic" xml:space="preserve">
<value>{0} is not public</value>
<comment>{0} is the method signature.</comment>
</data>
<data name="MethodNameCaseIsDifferent" xml:space="preserve">
<value>'{0}' method name has different case from requested '{1}'</value>
<comment>{0} is the method signature, {1} is the requested method name.</comment>
</data>
<data name="MethodParameterCountDoesNotMatch" xml:space="preserve">
<value>{0} parameter(s): {1}, but the request supplies {2}</value>
<comment>{0} is the method signature, {1} is the method parameter count, {2} is the request parameter count.</comment>
</data>
<data name="MethodParametersNotCompatible" xml:space="preserve">
<value>{0} parameters are not compatible with the request: {1}</value>
<comment>{0} is the method signature, {1} is the error message.</comment>
</data>
<data name="MoreThanOneMethodFound" xml:space="preserve">
<value>More than one target method found: {0}.</value>
<comment>{0} is the list of method signatures.</comment>
</data>
<data name="ReachedEndOfStream" xml:space="preserve">
<value>Reached end of stream.</value>
</data>
<data name="ReadableCannotRead" xml:space="preserve">
<value>Readable cannot read.</value>
</data>
<data name="ReadableNotSet" xml:space="preserve">
<value>Readable is not set.</value>
</data>
<data name="ReadingJsonRpcStreamFailed" xml:space="preserve">
<value>Reading JSON-RPC from the stream failed with {0}: {1}</value>
<comment>{0} is the exception type, {1} is the exception message.</comment>
</data>
<data name="ResponseIsNotError" xml:space="preserve">
<value>Response is not error.</value>
</data>
<data name="StreamDisposed" xml:space="preserve">
<value>Stream has been disposed</value>
</data>
<data name="TaskNotCompleted" xml:space="preserve">
<value>The task is not completed.</value>
</data>
<data name="TaskWasCancelled" xml:space="preserve">
<value>The task was cancelled.</value>
</data>
<data name="UnableToFindMethod" xml:space="preserve">
<value>Unable to find method '{0}/{1}' on {2} for the following reason: {3}</value>
<comment>{0} is the method name, {1} is arity, {2} is target class full name, {3} is the error list.</comment>
</data>
<data name="UnexpectedErrorProcessingJsonRpc" xml:space="preserve">
<value>Unexpected error processing JSON-RPC '{0}': {1}</value>
<comment>{0} is the json, {1} is the exception message.</comment>
</data>
<data name="UnrecognizedIncomingJsonRpc" xml:space="preserve">
<value>Unrecognized incoming JSON-RPC '{0}'</value>
<comment>{0} is the json.</comment>
</data>
<data name="WritableCannotWrite" xml:space="preserve">
<value>Writable cannot write.</value>
</data>
<data name="WritableNotSet" xml:space="preserve">
<value>Writable is not set.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C8FE34FA-B409-4A57-A16F-4407AF728C65}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StreamJsonRpc</RootNamespace>
<AssemblyName>StreamJsonRpc</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;DESKTOP;NET45</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;DESKTOP;NET45</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="..\StreamJsonRpc.Shared\StreamJsonRpc.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,28 @@
{
"dependencies": {
"MicroBuild.VisualStudio": {
"version": "1.0.117-rc",
"suppressParent": "none"
},
"MicroBuild.Core": {
"version": "0.2.0",
"suppressParent": "none"
},
"Nerdbank.GitVersioning": {
"version": "1.4.19",
"suppressParent": "none"
},
"ReadOnlySourceTree": {
"version": "0.1.36-beta",
"suppressParent": "none"
},
"Newtonsoft.Json": "6.0.6",
"Microsoft.VisualStudio.Threading": "14.1.114"
},
"frameworks": {
"net45": { }
},
"runtimes": {
"win": { }
}
}

Просмотреть файл

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>927450a5-18bf-4378-8421-7a7c6864b6ea</ProjectGuid>
</PropertyGroup>
<PropertyGroup>
<NuSpecTemplate>StreamJsonRpc.nuspec</NuSpecTemplate>
<NuProjPath>$(UserProfile)\.nuget\packages\NuProj\0.10.48-beta-gea4a31bbc5\tools\</NuProjPath>
</PropertyGroup>
<Import Project="$(NuProjPath)\NuProj.props" Condition="Exists('$(NuProjPath)\NuProj.props')" />
<PropertyGroup Label="Configuration">
<Id>StreamJsonRpc</Id>
<Title>StreamJsonRpc</Title>
<Authors>Microsoft</Authors>
<Owners>Microsoft</Owners>
<Summary>StreamJsonRpc.NuGet</Summary>
<Description>StreamJsonRpc.NuGet</Description>
<ReleaseNotes>
</ReleaseNotes>
<ProjectUrl>
</ProjectUrl>
<LicenseUrl>https://go.microsoft.com/fwlink/?LinkID=746386</LicenseUrl>
<Copyright>Copyright © Microsoft</Copyright>
<Tags>ServiceHub</Tags>
</PropertyGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<None Include="StreamJsonRpc.nuspec" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StreamJsonRpc\StreamJsonRpc.csproj" />
<ProjectReference Include="..\StreamJsonRpc.Desktop\StreamJsonRpc.Desktop.csproj" />
</ItemGroup>
<Import Project="$(NuProjPath)\NuProj.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd">
<metadata>
<id>placeholder</id>
<version>$version$</version>
<authors>aarnott</authors>
<owners></owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>to be overwritten by project file</description>
<releaseNotes></releaseNotes>
<copyright></copyright>
<tags></tags>
<dependencies>
<group targetFramework="dotnet">
<dependency id="System.Reflection.TypeExtensions" version="4.0.0" />
<dependency id="Microsoft.CSharp" version="4.0.0" />
<dependency id="Microsoft.VisualStudio.Threading" version="14.1.114" />
<dependency id="Microsoft.VisualStudio.Validation" version="14.1.111" />
<dependency id="Newtonsoft.Json" version="6.0.6" />
<dependency id="System.Collections" version="4.0.0" />
<dependency id="System.Diagnostics.Debug" version="4.0.0" />
<dependency id="System.Diagnostics.Tools" version="4.0.0" />
<dependency id="System.Dynamic.Runtime" version="4.0.0" />
<dependency id="System.Globalization" version="4.0.0" />
<dependency id="System.IO" version="4.0.0" />
<dependency id="System.Linq" version="4.0.0" />
<dependency id="System.Reflection" version="4.0.0" />
<dependency id="System.Resources.ResourceManager" version="4.0.0" />
<dependency id="System.Runtime" version="4.0.0" />
<dependency id="System.Runtime.Extensions" version="4.0.0" />
<dependency id="System.Text.Encoding" version="4.0.0" />
<dependency id="System.Threading" version="4.0.0" />
<dependency id="System.Threading.Tasks" version="4.0.0" />
</group>
<group targetFramework="net45">
<dependency id="Microsoft.VisualStudio.Threading" version="14.1.114" />
<dependency id="Newtonsoft.Json" version="6.0.6" />
</group>
</dependencies>
</metadata>
</package>

Просмотреть файл

@ -0,0 +1,27 @@
{
"frameworks": {
"net451": { }
},
"dependencies": {
"MicroBuild.VisualStudio": {
"version": "1.0.117-rc",
"suppressParent": "none"
},
"MicroBuild.Core": {
"version": "0.2.0",
"suppressParent": "none"
},
"Nerdbank.GitVersioning": {
"version": "1.4.19",
"suppressParent": "none"
},
"NuProj": "0.10.48-beta-gea4a31bbc5",
"ReadOnlySourceTree": {
"version": "0.1.36-beta",
"suppressParent": "none"
}
},
"runtimes": {
"win": { }
}
}

Просмотреть файл

@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("StreamJsonRpc.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]

Просмотреть файл

@ -0,0 +1,33 @@
using Newtonsoft.Json;
namespace StreamJsonRpc
{
[JsonObject(MemberSerialization.OptIn)]
internal sealed class JsonRpcError
{
internal JsonRpcError(int code, string message) : this(code, message, data: null)
{
}
[JsonConstructor]
internal JsonRpcError(int code, string message, dynamic data)
{
this.Code = code;
this.Message = message;
this.Data = data;
}
[JsonProperty("code", Required = Required.Always)]
internal int Code { get; private set; }
[JsonProperty("message", Required = Required.Always)]
internal string Message { get; private set; }
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
internal dynamic Data { get; private set; }
public string ErrorStack => this.Data?.stack;
public string ErrorCode =>this.Data?.code;
}
}

Просмотреть файл

@ -0,0 +1,40 @@
namespace StreamJsonRpc
{
internal enum JsonRpcErrorCode : int
{
/// <summary>
/// Indicates the RPC call was made but the target threw an exception.
/// </summary>
InvocationError = -32000,
/// <summary>
/// No callback object was given to the client but an RPC call was attempted.
/// </summary>
NoCallbackObject = -32001,
/// <summary>
/// Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
/// </summary>
ParseError = -32700,
/// <summary>
/// The JSON sent is not a valid Request object.
/// </summary>
InvalidRequest = -32600,
/// <summary>
/// The method does not exist / is not available.
/// </summary>
MethodNotFound = -32601,
/// <summary>
/// Invalid method parameter(s).
/// </summary>
InvalidParams = -32602,
/// <summary>
/// Internal JSON-RPC error.
/// </summary>
InternalError = -32603
}
}

Просмотреть файл

@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace StreamJsonRpc
{
[JsonObject(MemberSerialization.OptIn)]
internal sealed class JsonRpcMessage
{
private JsonRpcMessage()
{
this.JsonRpcVersion = "2.0";
}
private JsonRpcMessage(string method, object[] parameters, string id = null, string jsonrpc = "2.0")
{
this.Parameters = parameters?.Length == 0 ? null : JToken.FromObject(parameters);
this.Method = method;
this.Id = id;
this.JsonRpcVersion = jsonrpc;
}
[JsonProperty("jsonrpc")]
public string JsonRpcVersion { get; private set; }
[JsonProperty("method")]
public string Method { get; private set; }
[JsonProperty("id")]
public string Id { get; private set; }
[JsonProperty("error")]
public JsonRpcError Error { get; private set; }
[JsonProperty("params")]
private JToken Parameters
{
get;
set;
}
[JsonProperty("result")]
private JToken Result
{
get;
set;
}
public bool IsRequest => !string.IsNullOrEmpty(this.Method);
public bool IsResponse => this.IsError || this.Result != null;
public bool IsError => this.Error != null;
public bool IsNotification => this.Id == null;
public int ParameterCount => this.Parameters != null ? this.Parameters.Children().Count() : 0;
public static JsonRpcMessage CreateRequest(string id, string @method, object[] parameters)
{
return new JsonRpcMessage(method, parameters, id);
}
public static JsonRpcMessage CreateResult(string id, object result)
{
return new JsonRpcMessage()
{
Id = id,
Result = result != null ? JToken.FromObject(result) : JValue.CreateNull(),
};
}
public static JsonRpcMessage CreateError(string id, JsonRpcErrorCode error, string message)
{
return CreateError(id, (int)error, message);
}
public static JsonRpcMessage CreateError(string id, JsonRpcErrorCode error, string message, object data)
{
return CreateError(id, (int)error, message, data);
}
public static JsonRpcMessage CreateError(string id, int error, string message)
{
return CreateError(id, error, message, data: null);
}
public static JsonRpcMessage CreateError(string id, int error, string message, object data)
{
return new JsonRpcMessage()
{
Id = id,
Error = new JsonRpcError(error, message, data),
};
}
public T GetResult<T>()
{
return this.Result == null ? default(T) : this.Result.ToObject<T>();
}
public object[] GetParameters(ParameterInfo[] parameterInfos)
{
if (this.Parameters == null || !this.Parameters.Children().Any())
{
return new object[0];
}
if (parameterInfos == null || parameterInfos.Length == 0)
{
return this.Parameters.ToObject<object[]>();
}
int index = 0;
var result = new List<object>(parameterInfos.Length);
foreach (var parameter in this.Parameters.Children())
{
Type type = typeof(object);
if (index < parameterInfos.Length)
{
type = parameterInfos[index].ParameterType;
index++;
}
object value = parameter.ToObject(type);
result.Add(value);
}
for (;index < parameterInfos.Length; index++)
{
result.Add(parameterInfos[index].HasDefaultValue ? parameterInfos[index].DefaultValue : null);
}
return result.ToArray();
}
public string ToJson()
{
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.SerializeObject(this, settings);
}
public static JsonRpcMessage FromJson(string json)
{
var settings = new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
};
return JsonConvert.DeserializeObject<JsonRpcMessage>(json, settings);
}
public static JsonRpcMessage FromJson(JsonReader reader)
{
var settings = new JsonSerializerSettings
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
};
JsonSerializer serializer = JsonSerializer.Create(settings);
JsonRpcMessage result = serializer.Deserialize<JsonRpcMessage>(reader);
if (result == null)
{
throw new JsonException(Resources.JsonRpcCannotBeNull);
}
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
namespace StreamJsonRpc
{
public enum DisconnectedReason
{
Unknown,
StreamError,
ParseError,
Disposed
}
}

Просмотреть файл

@ -0,0 +1,41 @@
using System;
using Microsoft;
namespace StreamJsonRpc
{
public class JsonRpcDisconnectedEventArgs : EventArgs
{
public JsonRpcDisconnectedEventArgs(string description, DisconnectedReason reason)
: this(description, reason, lastMessage: null, exception: null)
{
}
public JsonRpcDisconnectedEventArgs(string description, DisconnectedReason reason, Exception exception)
: this(description, reason, lastMessage: null, exception: exception)
{
}
public JsonRpcDisconnectedEventArgs(string description, DisconnectedReason reason, string lastMessage)
: this(description, reason, lastMessage: lastMessage, exception: null)
{
}
public JsonRpcDisconnectedEventArgs(string description, DisconnectedReason reason, string lastMessage, Exception exception)
{
Requires.NotNullOrWhiteSpace(description, nameof(description));
this.Description = description;
this.Reason = reason;
this.LastMessage = lastMessage;
this.Exception = exception;
}
public string Description { get; }
public DisconnectedReason Reason { get; }
public string LastMessage { get; }
public Exception Exception { get; }
}
}

Просмотреть файл

@ -0,0 +1,37 @@
using System;
namespace StreamJsonRpc
{
/// <summary>
/// Remote RPC exception that indicates that the server target method threw an exception.
/// </summary>
/// <remarks>
/// The details of the target method exception can be found on <see cref="RemoteStackTrace"/> and <see cref="RemoteErrorCode"/>.
/// </remarks>
#if DESKTOP
[System.Serializable]
#endif
public class RemoteInvocationException : RemoteRpcException
{
internal RemoteInvocationException(string message) : base(message)
{
}
public RemoteInvocationException(string message, string remoteStack, string remoteCode) : this(message)
{
this.RemoteStackTrace = remoteStack;
this.RemoteErrorCode = remoteCode;
}
#if DESKTOP
protected RemoteInvocationException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
#endif
public string RemoteStackTrace { get; }
public string RemoteErrorCode { get; }
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System;
using Microsoft;
namespace StreamJsonRpc
{
/// <summary>
/// Remote RPC exception that indicates that the requested target method was not found on the server.
/// </summary>
/// <remarks>
/// Check the exception message for the reasons why the method was not found. It's possible that
/// there was a method with the matching name, but it was not public, had ref or out params, or
/// its arguments were incompatible with the arguments supplied by the client.
/// </remarks>
#if DESKTOP
[System.Serializable]
#endif
public class RemoteMethodNotFoundException : RemoteRpcException
{
/// <summary>
/// Initializes a new instance of <see cref="RemoteMethodNotFoundException"/> with supplied message and target method.
/// </summary>
/// <param name="message">Exception message describing why the method was not found.</param>
/// <param name="targetMethod">Target method that was not found.</param>
internal RemoteMethodNotFoundException(string message, string targetMethod) : base(message)
{
Requires.NotNullOrEmpty(targetMethod, nameof(targetMethod));
this.TargetMethod = targetMethod;
}
#if DESKTOP
protected RemoteMethodNotFoundException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
#endif
/// <summary>
/// Gets the name of the target method that was not found.
/// </summary>
public string TargetMethod { get; }
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using System;
namespace StreamJsonRpc
{
/// <summary>
/// Base exception class for any exception that happen on the server side of JSON RPC communication.
/// Descendants of this exception may be thrown by JSON RPC client in response to calling a server method.
/// </summary>
#if DESKTOP
[System.Serializable]
#endif
public abstract class RemoteRpcException : Exception
{
protected RemoteRpcException(string message) : base(message)
{
}
protected RemoteRpcException(string message, Exception innerException) : base(message, innerException)
{
}
#if DESKTOP
protected RemoteRpcException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
#endif
}
}

Просмотреть файл

@ -0,0 +1,25 @@
using System;
namespace StreamJsonRpc
{
/// <summary>
/// Remote RPC exception that indicates that the server has no target object.
/// </summary>
#if DESKTOP
[System.Serializable]
#endif
public class RemoteTargetNotSetException : RemoteRpcException
{
internal RemoteTargetNotSetException(string message) : base(message)
{
}
#if DESKTOP
protected RemoteTargetNotSetException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context)
{ }
#endif
}
}

Просмотреть файл

@ -0,0 +1,584 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Microsoft.VisualStudio.Threading;
using Microsoft;
namespace StreamJsonRpc
{
public class JsonRpc : IDisposable
{
private class OutstandingCallData
{
internal object TaskCompletionSource { get; }
internal Action<JsonRpcMessage> CompletionHandler { get; }
internal OutstandingCallData(object taskCompletionSource, Action<JsonRpcMessage> completionHandler)
{
this.TaskCompletionSource = taskCompletionSource;
this.CompletionHandler = completionHandler;
}
}
private const int BufferSize = 1024;
private readonly object callbackTarget;
private readonly Encoding encoding;
private readonly Stream stream;
private readonly object dispatcherMapLock = new object();
private readonly object disconnectedEventLock = new object();
private readonly Dictionary<string, OutstandingCallData> resultDispatcherMap = new Dictionary<string, OutstandingCallData>(StringComparer.Ordinal);
private readonly SplitJoinStream splitJoinStream;
private readonly Task readLinesTask;
private readonly CancellationTokenSource disposeCts = new CancellationTokenSource();
private int nextId = 1;
private bool disposed;
private bool hasDisconnectedEventBeenRaised;
public static JsonRpc Attach(Stream stream, object target = null)
{
return new JsonRpc(stream, target);
}
protected JsonRpc(Stream stream, object target = null)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
this.stream = stream;
this.callbackTarget = target;
this.encoding = Encoding.UTF8;
var options = new SplitJoinStreamOptions
{
Encoding = this.encoding,
LeaveOpen = false,
Readable = this.stream,
Writable = this.stream,
ReadTrailing = true
};
this.splitJoinStream = new SplitJoinStream(options);
this.readLinesTask = Task.Run(this.ReadAndHandleRequests, this.disposeCts.Token);
}
private event EventHandler<JsonRpcDisconnectedEventArgs> onDisconnected;
public event EventHandler<JsonRpcDisconnectedEventArgs> Disconnected
{
add
{
Requires.NotNull(value, nameof(value));
bool handlerAdded = false;
lock (this.disconnectedEventLock)
{
if (!this.hasDisconnectedEventBeenRaised)
{
this.onDisconnected += value;
handlerAdded = true;
}
}
if (!handlerAdded)
{
value(this, new JsonRpcDisconnectedEventArgs(Resources.StreamDisposed, DisconnectedReason.Disposed));
}
}
remove
{
Requires.NotNull(value, nameof(value));
this.onDisconnected -= value;
}
}
/// <summary>
/// Invoke a method on the server.
/// </summary>
/// <param name="targetName">The name of the method to invoke on the server. Must not be null or empty string.</param>
/// <param name="arguments">Method arguments, must be serializable to JSON.</param>
/// <returns>A task that completes when the server method executes.</returns>
/// <exception cref="OperationCanceledException">
/// Result task fails with this exception if the communication channel ends before the server indicates completion of the method.
/// </exception>
/// <exception cref="RemoteInvocationException">
/// Result task fails with this exception if the server method throws an exception.
/// </exception>
/// <exception cref="RemoteMethodNotFoundException">
/// Result task fails with this exception if the <paramref name="targetName"/> method is not found on the target object on the server.
/// </exception>
/// <exception cref="RemoteTargetNotSetException">
/// Result task fails with this exception if the server has no target object.
/// </exception>
/// <exception cref="ArgumentNullException">If <paramref name="targetName"/> is null.</exception>
/// <exception cref="ObjectDisposedException">If this instance of <see cref="JsonRpc"/> has been disposed.</exception>
public Task InvokeAsync(string targetName, params object[] arguments)
{
return this.InvokeAsync<object>(targetName, arguments);
}
/// <summary>
/// Invoke a method on the server and get back the result.
/// </summary>
/// <typeparam name="Result">Type of the method result</typeparam>
/// <param name="targetName">The name of the method to invoke on the server. Must not be null or empty string.</param>
/// <param name="arguments">Method arguments, must be serializable to JSON.</param>
/// <returns>A task that completes when the server method executes and returns the result.</returns>
/// <exception cref="OperationCanceledException">
/// Result task fails with this exception if the communication channel ends before the result gets back from the server.
/// </exception>
/// <exception cref="RemoteInvocationException">
/// Result task fails with this exception if the server method throws an exception.
/// </exception>
/// <exception cref="RemoteMethodNotFoundException">
/// Result task fails with this exception if the <paramref name="targetName"/> method is not found on the target object on the server.
/// </exception>
/// <exception cref="RemoteTargetNotSetException">
/// Result task fails with this exception if the server has no target object.
/// </exception>
/// <exception cref="ArgumentNullException">If <paramref name="targetName"/> is null.</exception>
/// <exception cref="ObjectDisposedException">If this instance of <see cref="JsonRpc"/> has been disposed.</exception>
public Task<Result> InvokeAsync<Result>(string targetName, params object[] arguments)
{
if (targetName == null)
{
throw new ArgumentNullException(nameof(targetName));
}
this.ThrowIfDisposed();
string id = Interlocked.Increment(ref this.nextId).ToString(CultureInfo.InvariantCulture);
return InvokeCoreAsync<Result>(id, targetName, arguments);
}
/// <summary>
/// Invoke a method on the server and don't wait for its completion, fire-and-forget style.
/// </summary>
/// <remarks>
/// Any error that happens on the server side is ignored.
/// </remarks>
/// <param name="targetName">The name of the method to invoke on the server. Must not be null or empty string.</param>
/// <param name="arguments">Method arguments, must be serializable to JSON.</param>
/// <returns>A task that completes when the notify request is sent to the channel to the server.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="targetName"/> is null.</exception>
/// <exception cref="ObjectDisposedException">If this instance of <see cref="JsonRpc"/> has been disposed.</exception>
public async Task NotifyAsync(string targetName, params object[] arguments)
{
if (targetName == null)
{
throw new ArgumentNullException(nameof(targetName));
}
this.ThrowIfDisposed();
await this.InvokeCoreAsync<object>(id: null, targetName: targetName, arguments: arguments);
}
#region IDisposable
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
private void OnJsonRpcDisconnected(JsonRpcDisconnectedEventArgs eventArgs)
{
EventHandler<JsonRpcDisconnectedEventArgs> handlersToInvoke = null;
lock (this.disconnectedEventLock)
{
if (!this.hasDisconnectedEventBeenRaised)
{
this.hasDisconnectedEventBeenRaised = true;
handlersToInvoke = this.onDisconnected;
this.onDisconnected = null;
}
}
try
{
// Fire the event first so that subscribers can interact with a non-disposed stream
handlersToInvoke?.Invoke(this, eventArgs);
}
finally
{
// Dispose the stream and cancel pending requests in the finally block
// So this is executed even if Disconnected event handler throws.
this.disposeCts.Cancel();
this.splitJoinStream.Dispose();
this.CancelPendingRequests();
}
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
this.disposed = true;
if (disposing)
{
var disconnectedEventArgs = new JsonRpcDisconnectedEventArgs(Resources.StreamDisposed, DisconnectedReason.Disposed);
this.OnJsonRpcDisconnected(disconnectedEventArgs);
}
}
}
protected void ThrowIfDisposed()
{
if (this.disposed)
{
throw new ObjectDisposedException(this.GetType().Name);
}
}
/// <summary>
/// Invokes the specified RPC method
/// </summary>
/// <typeparam name="ReturnType">RPC method return type</typeparam>
/// <param name="id">An identifier established by the Client that MUST contain a String, Number, or NULL value if included.
/// If it is not included it is assumed to be a notification.</param>
/// <param name="targetName">RPC method name</param>
/// <param name="arguments">RPC method arguments</param>
/// <returns></returns>
protected virtual async Task<ReturnType> InvokeCoreAsync<ReturnType>(string id, string targetName, params object[] arguments)
{
// If somebody calls InvokeInternal<T>(id, "method", null), the null is not passed as an item in the array.
// Instead, the compiler thinks that the null is the array itself and it'll pass null directly.
// To account for this case, we check for null below.
arguments = arguments ?? new object[] { null };
JsonRpcMessage request = JsonRpcMessage.CreateRequest(id, targetName, arguments);
if (id == null)
{
await this.WriteAsync(request.ToJson());
return default(ReturnType);
}
var tcs = new TaskCompletionSource<ReturnType>();
Action<JsonRpcMessage> dispatcher = (response) =>
{
lock (this.dispatcherMapLock)
{
this.resultDispatcherMap.Remove(id);
}
try
{
if (response == null)
{
tcs.TrySetCanceled();
}
else if (response.IsError)
{
tcs.TrySetException(CreateExceptionFromRpcError(response, targetName));
}
else
{
tcs.TrySetResult(response.GetResult<ReturnType>());
}
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
};
lock (this.dispatcherMapLock)
{
this.resultDispatcherMap.Add(id, new OutstandingCallData(tcs, dispatcher));
}
await this.WriteAsync(request.ToJson()).ConfigureAwait(false);
// This task will be completed when the Response object comes back from the other end of the pipe
await tcs.Task.NoThrowAwaitable();
await Task.Yield(); // ensure we don't inline anything further, including the continuation of our caller.
return await tcs.Task;
}
private static RemoteRpcException CreateExceptionFromRpcError(JsonRpcMessage response, string targetName)
{
Requires.NotNull(response, nameof(response));
Requires.Argument(response.IsError, nameof(response), Resources.ResponseIsNotError);
switch (response.Error.Code)
{
case (int)JsonRpcErrorCode.MethodNotFound:
return new RemoteMethodNotFoundException(response.Error.Message, targetName);
case (int)JsonRpcErrorCode.NoCallbackObject:
return new RemoteTargetNotSetException(response.Error.Message);
default:
return new RemoteInvocationException(response.Error.Message, response.Error.ErrorStack, response.Error.ErrorCode);
}
}
private async Task<JsonRpcMessage> DispatchIncomingRequest(JsonRpcMessage request)
{
if (this.callbackTarget == null)
{
string message = string.Format(CultureInfo.CurrentCulture, Resources.DroppingRequestDueToNoTargetObject, request.Method);
return JsonRpcMessage.CreateError(request.Id, JsonRpcErrorCode.NoCallbackObject, message);
}
try
{
var targetMethod = new TargetMethod(request, this.callbackTarget);
if (!targetMethod.IsFound)
{
return JsonRpcMessage.CreateError(request.Id, JsonRpcErrorCode.MethodNotFound, targetMethod.LookupErrorMessage);
}
object result = targetMethod.Invoke();
if (!(result is Task))
{
return JsonRpcMessage.CreateResult(request.Id, result);
}
return await ((Task)result).ContinueWith((t, id) => HandleInvocationTaskResult((string)id, t), request.Id, TaskScheduler.Default);
}
catch (Exception ex)
{
return CreateError(request.Id, ex);
}
}
private static JsonRpcMessage HandleInvocationTaskResult(string id, Task t)
{
if (t == null)
{
throw new ArgumentNullException(nameof(t));
}
if (!t.IsCompleted)
{
throw new ArgumentException(Resources.TaskNotCompleted, nameof(t));
}
if (t.IsFaulted)
{
return CreateError(id, t.Exception);
}
if (t.IsCanceled)
{
return JsonRpcMessage.CreateError(id, JsonRpcErrorCode.InvocationError, Resources.TaskWasCancelled);
}
object taskResult = null;
Type taskType = t.GetType();
// If t is a Task<SomeType>, it will have Result property.
// If t is just a Task, there is no Result property on it.
if (!taskType.Equals(typeof(Task)))
{
const string ResultPropertyName = nameof(Task<int>.Result);
// We can't really write direct code to deal with Task<T>, since we have no idea of T in this context, so we simply use reflection to
// read the result at runtime.
PropertyInfo resultProperty = taskType.GetTypeInfo().GetDeclaredProperty(ResultPropertyName);
taskResult = resultProperty?.GetValue(t);
}
return JsonRpcMessage.CreateResult(id, taskResult);
}
private static JsonRpcMessage CreateError(string id, Exception exception)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
if (exception is TargetInvocationException || (exception is AggregateException && exception.InnerException != null))
{
// Never let the outer (TargetInvocationException) escape because the inner is the interesting one to the caller, the outer is due to
// the fact we are using reflection.
exception = exception.InnerException;
}
string message = $"{exception.Message}{Environment.NewLine}{exception.StackTrace}";
var data = new { stack = exception.StackTrace, code = exception.HResult.ToString(CultureInfo.InvariantCulture) };
return JsonRpcMessage.CreateError(id, JsonRpcErrorCode.InvocationError, message, data);
}
private async Task ReadAndHandleRequests()
{
JsonRpcDisconnectedEventArgs disconnectedEventArgs = null;
try
{
while (!this.disposed)
{
string json = null;
try
{
json = await this.splitJoinStream.ReadAsync(this.disposeCts.Token);
}
catch (OperationCanceledException)
{
}
catch (ObjectDisposedException)
{
}
catch (Exception exception)
{
var e = new JsonRpcDisconnectedEventArgs(string.Format(CultureInfo.CurrentCulture, Resources.ReadingJsonRpcStreamFailed, exception.GetType().Name, exception.Message),
DisconnectedReason.StreamError,
exception);
// Fatal error. Raise disconnected event.
this.OnJsonRpcDisconnected(e);
break;
}
if (json == null)
{
// End of stream reached
disconnectedEventArgs = new JsonRpcDisconnectedEventArgs(Resources.ReachedEndOfStream, DisconnectedReason.Disposed);
break;
}
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() =>
{
try
{
this.HandleRpc(json);
}
catch (Exception exception)
{
var eventArgs = new JsonRpcDisconnectedEventArgs(
string.Format(CultureInfo.CurrentCulture, Resources.UnexpectedErrorProcessingJsonRpc, json, exception.Message),
DisconnectedReason.ParseError,
json,
exception);
// Fatal error. Raise disconnected event.
this.OnJsonRpcDisconnected(eventArgs);
}
}, this.disposeCts.Token);
#pragma warning restore CS4014
}
}
finally
{
if (disconnectedEventArgs == null)
{
disconnectedEventArgs = new JsonRpcDisconnectedEventArgs(Resources.StreamDisposed, DisconnectedReason.Disposed);
}
this.OnJsonRpcDisconnected(disconnectedEventArgs);
}
}
private async Task HandleRpc(string json)
{
JsonRpcMessage rpc;
try
{
rpc = JsonRpcMessage.FromJson(json);
}
catch (JsonException exception)
{
var e = new JsonRpcDisconnectedEventArgs(string.Format(CultureInfo.CurrentCulture, Resources.FailureDeserializingJsonRpc, json, exception.Message),
DisconnectedReason.ParseError,
json,
exception);
// Fatal error. Raise disconnected event.
this.OnJsonRpcDisconnected(e);
return;
}
if (rpc.IsRequest)
{
JsonRpcMessage result = await this.DispatchIncomingRequest(rpc);
if (!rpc.IsNotification)
{
try
{
await this.WriteAsync(result.ToJson());
}
catch (OperationCanceledException)
{
}
catch (ObjectDisposedException)
{
}
catch (Exception exception)
{
var e = new JsonRpcDisconnectedEventArgs(string.Format(CultureInfo.CurrentCulture, Resources.ErrorWritingJsonRpcResult, exception.GetType().Name, exception.Message),
DisconnectedReason.StreamError,
exception);
// Fatal error. Raise disconnected event.
this.OnJsonRpcDisconnected(e);
}
}
return;
}
if (rpc.IsResponse)
{
OutstandingCallData data = null;
lock (this.dispatcherMapLock)
{
if (this.resultDispatcherMap.TryGetValue(rpc.Id, out data))
{
this.resultDispatcherMap.Remove(rpc.Id);
}
}
if (data != null)
{
data.CompletionHandler(rpc);
}
return;
}
// Not a request or return. Raise disconnected event.
this.OnJsonRpcDisconnected(new JsonRpcDisconnectedEventArgs(
string.Format(CultureInfo.CurrentCulture, Resources.UnrecognizedIncomingJsonRpc, json),
DisconnectedReason.ParseError,
json));
}
private async Task WriteAsync(string data)
{
await this.splitJoinStream.WriteAsync(data, this.disposeCts.Token);
}
private void CancelPendingRequests()
{
OutstandingCallData[] pendingRequests;
lock (this.dispatcherMapLock)
{
pendingRequests = this.resultDispatcherMap.Values.ToArray();
}
foreach (OutstandingCallData pendingRequest in pendingRequests)
{
pendingRequest.CompletionHandler(null);
}
}
}
}

Просмотреть файл

@ -0,0 +1,93 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft;
namespace StreamJsonRpc
{
internal sealed class MethodSignature : IEquatable<MethodSignature>
{
private static readonly StringComparer typeNameComparer = StringComparer.Ordinal;
internal MethodSignature(MethodInfo methodInfo)
{
Requires.NotNull(methodInfo, nameof(methodInfo));
this.MethodInfo = methodInfo;
this.Parameters = methodInfo.GetParameters() ?? new ParameterInfo[0];
}
internal MethodInfo MethodInfo { get; }
internal ParameterInfo[] Parameters { get; }
internal bool IsPublic => this.MethodInfo.IsPublic;
internal string Name => this.MethodInfo.Name;
internal int RequiredParamCount => this.Parameters.Count(pi => !pi.IsOptional);
internal int TotalParamCount => this.Parameters.Length;
internal bool HasOutOrRefParameters => this.Parameters.Any(pi => pi.IsOut || pi.ParameterType.IsByRef);
bool IEquatable<MethodSignature>.Equals(MethodSignature other)
{
if (Object.ReferenceEquals(other, null))
{
return false;
}
if (Object.ReferenceEquals(other, this) || Object.ReferenceEquals(this.Parameters, other.Parameters))
{
return true;
}
if (this.Parameters.Length != other.Parameters.Length)
{
return false;
}
for (int index = 0; index < this.Parameters.Length; index++)
{
if (!MethodSignature.typeNameComparer.Equals(
this.Parameters[index].ParameterType.AssemblyQualifiedName,
other.Parameters[index].ParameterType.AssemblyQualifiedName))
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
return (obj is MethodSignature) && ((IEquatable<MethodSignature>)this).Equals((MethodSignature)obj);
}
public override int GetHashCode()
{
uint result = 0;
int bitCount = sizeof(uint) * 8;
const int shift = 1;
foreach (ParameterInfo parameter in this.MethodInfo.GetParameters())
{
// Shifting result 1 bit per each parameter so that the hash is different for
// methods with the same parameter types at different location, e.g.
// foo(int, string) and foo(string, int)
// This will work fine for up to 32 (64 on x64) parameters,
// which should be more than enough for the most applications.
result = result << shift | result >> (bitCount - shift);
result ^= (uint)MethodSignature.typeNameComparer.GetHashCode(parameter.ParameterType.AssemblyQualifiedName);
}
return (int)result;
}
public override string ToString()
{
return this.MethodInfo.ToString();
}
}
}

Просмотреть файл

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft;
namespace StreamJsonRpc
{
internal sealed class TargetMethod
{
private readonly HashSet<string> errorMessages = new HashSet<string>(StringComparer.Ordinal);
private readonly JsonRpcMessage request;
private readonly object callbackObject;
private readonly MethodInfo method;
private readonly object[] parameters;
internal TargetMethod(JsonRpcMessage request, object callbackObject)
{
Requires.NotNull(request, nameof(request));
Requires.NotNull(callbackObject, nameof(callbackObject));
this.request = request;
this.callbackObject = callbackObject;
var targetMethods = new Dictionary<MethodSignature, object[]>();
for (TypeInfo t = callbackObject.GetType().GetTypeInfo(); t != null; t = t.BaseType?.GetTypeInfo())
{
foreach (MethodSignature method in t.GetDeclaredMethods(request.Method).Select(method => new MethodSignature(method)))
{
if (!targetMethods.ContainsKey(method))
{
object[] parameters = TargetMethod.TryGetParameters(request, method, this.errorMessages);
if (parameters != null)
{
targetMethods.Add(method, parameters);
}
}
}
}
if (targetMethods.Count == 1)
{
KeyValuePair<MethodSignature, object[]> methodWithParameters = targetMethods.First();
this.method = methodWithParameters.Key.MethodInfo;
this.parameters = methodWithParameters.Value;
}
else if (targetMethods.Count > 1)
{
this.method = null;
this.parameters = null;
this.errorMessages.Add(string.Format(CultureInfo.CurrentCulture, Resources.MoreThanOneMethodFound, string.Join("; ", targetMethods.Keys)));
}
}
internal bool IsFound => this.method != null;
internal string LookupErrorMessage
{
get
{
return string.Format(
CultureInfo.CurrentCulture,
Resources.UnableToFindMethod,
this.request.Method,
this.request.ParameterCount,
this.callbackObject.GetType().FullName,
string.Join("; ", this.errorMessages));
}
}
internal object Invoke()
{
if (this.method == null)
{
throw new InvalidOperationException(this.LookupErrorMessage);
}
return this.method.Invoke(!this.method.IsStatic ? this.callbackObject : null, this.parameters);
}
private static object[] TryGetParameters(JsonRpcMessage request, MethodSignature method, HashSet<string> errors)
{
if (!method.IsPublic)
{
errors.Add(string.Format(CultureInfo.CurrentCulture, Resources.MethodIsNotPublic, method));
return null;
}
// The method name and the number of parameters must match
if (!string.Equals(method.Name, request.Method, StringComparison.Ordinal))
{
errors.Add(string.Format(CultureInfo.CurrentCulture, Resources.MethodNameCaseIsDifferent, method, request.Method));
return null;
}
if (method.HasOutOrRefParameters)
{
errors.Add(string.Format(CultureInfo.CurrentCulture, Resources.MethodHasRefOrOutParameters, method));
return null;
}
int paramCount = request.ParameterCount;
if (paramCount < method.RequiredParamCount || paramCount > method.TotalParamCount)
{
string methodParameterCount;
if (method.RequiredParamCount == method.TotalParamCount)
{
methodParameterCount = method.RequiredParamCount.ToString(CultureInfo.CurrentCulture);
}
else
{
methodParameterCount = string.Format(CultureInfo.CurrentCulture, "{0} - {1}", method.RequiredParamCount, method.TotalParamCount);
}
errors.Add(string.Format(CultureInfo.CurrentCulture,
Resources.MethodParameterCountDoesNotMatch,
method,
methodParameterCount,
request.ParameterCount));
return null;
}
// Parameters must be compatible
try
{
return request.GetParameters(method.Parameters);
}
catch (Exception exception)
{
errors.Add(string.Format(CultureInfo.CurrentCulture, Resources.MethodParametersNotCompatible, method, exception.Message));
return null;
}
}
}
}

Просмотреть файл

@ -0,0 +1,153 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft;
namespace StreamJsonRpc
{
internal class SplitJoinStream : IDisposable
{
internal const int BufferSize = 1024;
private readonly Stream readable;
private readonly StringBuilder readBuffer;
private readonly Stream writable;
private readonly string delimiter;
private readonly Encoding encoding;
private readonly Decoder decoder;
private readonly bool leaveOpen;
private readonly bool readTrailing;
public SplitJoinStream(SplitJoinStreamOptions options)
{
Requires.NotNull(options, nameof(options));
Requires.Argument(options.Readable != null || options.Writable != null, nameof(options), Resources.BothReadableWritableAreNull);
Requires.Argument(options.Readable == null || options.Readable.CanRead, nameof(options), Resources.ReadableCannotRead);
Requires.Argument(options.Writable == null || options.Writable.CanWrite, nameof(options), Resources.WritableCannotWrite);
Requires.Argument(options.Delimiter != string.Empty, nameof(options), Resources.EmptyDelimiter);
this.readable = options.Readable;
this.writable = options.Writable;
this.delimiter = options.Delimiter ?? "\0";
this.encoding = options.Encoding ?? Encoding.UTF8;
this.decoder = this.encoding.GetDecoder();
this.leaveOpen = options.LeaveOpen;
this.readTrailing = options.ReadTrailing;
if (this.readable != null)
{
this.readBuffer = new StringBuilder(BufferSize);
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public async Task<string> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
{
Verify.Operation(this.readable != null, Resources.ReadableNotSet);
string result = this.PopStringFromReadBuffer();
if (result != null)
{
return result;
}
var byteBuffer = new byte[BufferSize];
while (string.IsNullOrEmpty(result))
{
// We could have used StreamReader, but it doesn't support cancellation.
// So we have to fall back to using the stream directly and Decoder() for decoding it.
// Decoder takes care if there are un-decoded leftovers from the previous reads.
int byteCount = await this.readable.ReadAsync(byteBuffer, 0, byteBuffer.Length, cancellationToken);
if (byteCount == 0)
{
// End of stream reached
result = this.readTrailing && this.readBuffer.Length > 0 ? this.readBuffer.ToString() : null;
this.readBuffer.Clear();
return result;
}
int count = this.decoder.GetCharCount(byteBuffer, 0, byteCount);
var buffer = new char[count];
count = this.decoder.GetChars(byteBuffer, 0, byteCount, buffer, 0);
this.readBuffer.Append(buffer, 0, count);
int startIndex = Math.Max(0, this.readBuffer.Length - count - this.delimiter.Length + 1);
result = this.PopStringFromReadBuffer(startIndex);
}
return result;
}
public async Task WriteAsync(string message, CancellationToken cancellationToken = default(CancellationToken))
{
Verify.Operation(this.writable != null, Resources.WritableNotSet);
var bytes = this.encoding.GetBytes(message + this.delimiter);
await this.writable.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (!this.leaveOpen)
{
if (this.readable != null)
{
this.readable.Dispose();
}
if (this.writable != null && this.writable != this.readable)
{
this.writable.Dispose();
}
}
}
}
private string PopStringFromReadBuffer(int startIndex = 0)
{
int index = startIndex;
while (index < this.readBuffer.Length - this.delimiter.Length + 1)
{
if (this.readBuffer[index] == this.delimiter[0])
{
bool found = true;
for (int j = 1; j < this.delimiter.Length; j++)
{
if (this.readBuffer[index + j] != this.delimiter[j])
{
found = false;
break;
}
}
if (found)
{
string result = this.readBuffer.ToString(0, index);
this.readBuffer.Remove(0, index + this.delimiter.Length);
if (index > 0)
{
return result;
}
continue;
}
}
index++;
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,44 @@
using System.IO;
using System.Text;
namespace StreamJsonRpc
{
internal class SplitJoinStreamOptions
{
public Stream Readable
{
get;
set;
}
public Stream Writable
{
get;
set;
}
public string Delimiter
{
get;
set;
}
public Encoding Encoding
{
get;
set;
}
public bool LeaveOpen
{
get;
set;
}
public bool ReadTrailing
{
get;
set;
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>df6b6dc7-7c77-42f2-84cb-e520b2771375</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>StreamJsonRpc.Shared</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AssemblyInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataContracts\JsonRpcError.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataContracts\JsonRpcErrorCode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataContracts\JsonRpcMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)EventArgs\DisconnectedReason.cs" />
<Compile Include="$(MSBuildThisFileDirectory)EventArgs\JsonRpcDisconnectedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Exceptions\RemoteInvocationException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Exceptions\RemoteMethodNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Exceptions\RemoteRpcException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Exceptions\RemoteTargetNotSetException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)JsonRpc.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Reflection\MethodSignature.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Reflection\TargetMethod.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SplitJoinStream\SplitJoinStream.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SplitJoinStream\SplitJoinStreamOptions.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>df6b6dc7-7c77-42f2-84cb-e520b2771375</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="StreamJsonRpc.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StreamJsonRpc;
using Xunit;
using Xunit.Abstractions;
using System.Threading;
using System.Diagnostics;
using System.IO;
using Microsoft.VisualStudio.Threading;
public class JsonRpcRawStreamTests
{
private static TimeSpan TestTimeout => Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(5);
private readonly CancellationTokenSource timeoutTokenSource = new CancellationTokenSource(TestTimeout);
private CancellationToken TimeoutToken => this.timeoutTokenSource.Token;
[Fact]
public async Task JsonRpcClosesStreamAfterDisconnectedEvent()
{
var server = new Server();
var streams = Nerdbank.FullDuplexStream.CreateStreams();
var clientStream = streams.Item2;
// Use wrapped stream to see when the stream is closed and disposed.
var serverStream = new WrappedStream(streams.Item1);
// Subscribe to disconnected event on the server stream
var serverStreamDisconnected = new TaskCompletionSource<object>();
serverStream.Disconnected += (sender, args) => serverStreamDisconnected.SetResult(null);
using (JsonRpc serverRpc = JsonRpc.Attach(serverStream, server))
{
// Subscribe to disconnected event on json rpc
var disconnectedEventFired = new TaskCompletionSource<JsonRpcDisconnectedEventArgs>();
object disconnectedEventSender = null;
serverRpc.Disconnected += delegate (object sender, JsonRpcDisconnectedEventArgs e)
{
// The stream must not be disposed when the Disconnected even fires
Assert.True(serverStream.IsConnected);
disconnectedEventSender = sender;
disconnectedEventFired.SetResult(e);
};
// Send a bad json to the server
using (var split = new SplitJoinStream(new SplitJoinStreamOptions { Writable = clientStream, LeaveOpen = true }))
{
await split.WriteAsync("{");
}
// The server must fire disonnected event because bad json must make it disconnect
JsonRpcDisconnectedEventArgs args = await disconnectedEventFired.Task.WithCancellation(this.TimeoutToken);
Assert.Same(serverRpc, disconnectedEventSender);
Assert.NotNull(args);
Assert.NotNull(args.Description);
Assert.Equal(DisconnectedReason.ParseError, args.Reason);
Assert.Equal("{", args.LastMessage);
Assert.NotNull(args.Exception);
// Server must dispose the stream now
await serverStreamDisconnected.Task.WithCancellation(this.TimeoutToken);
Assert.True(serverStream.Disposed);
Assert.False(serverStream.IsEndReached);
}
}
public class Server
{
}
}

Просмотреть файл

@ -0,0 +1,395 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;
using Newtonsoft.Json;
using StreamJsonRpc;
using Xunit;
using Xunit.Abstractions;
public class JsonRpcTests : IDisposable
{
private const int CustomTaskResult = 100;
private const string HubName = "TestHub";
private static TimeSpan TestTimeout => Debugger.IsAttached ? Timeout.InfiniteTimeSpan : TimeSpan.FromSeconds(5);
private readonly CancellationTokenSource timeoutTokenSource;
private readonly ITestOutputHelper logger;
private readonly Server server;
private readonly Stream serverStream;
private readonly JsonRpc serverRpc;
private readonly Stream clientStream;
private readonly JsonRpc clientRpc;
public JsonRpcTests(ITestOutputHelper logger)
{
this.logger = logger;
TaskCompletionSource<JsonRpc> serverRpcTcs = new TaskCompletionSource<JsonRpc>();
this.timeoutTokenSource = new CancellationTokenSource(TestTimeout);
this.server = new Server();
var streams = Nerdbank.FullDuplexStream.CreateStreams();
this.serverStream = streams.Item1;
this.clientStream = streams.Item2;
this.serverRpc = JsonRpc.Attach(this.serverStream, this.server);
this.clientRpc = JsonRpc.Attach(this.clientStream);
}
public void Dispose()
{
this.timeoutTokenSource.Dispose();
this.serverRpc.Dispose();
this.clientRpc.Dispose();
this.serverStream.Dispose();
this.clientStream.Dispose();
}
protected CancellationToken TimeoutToken => this.timeoutTokenSource.Token;
[Fact]
public async Task CanInvokeMethodOnServer()
{
string TestLine = "TestLine1" + new string('a', 1024 * 1024);
string result1 = await this.clientRpc.InvokeAsync<string>(nameof(Server.ServerMethod), TestLine);
Assert.Equal(TestLine + "!", result1);
}
[Fact]
public async Task CanInvokeTaskMethodOnServer()
{
await this.clientRpc.InvokeAsync(nameof(Server.ServerMethodThatReturnsTask));
}
[Fact]
public async Task CanInvokeMethodThatReturnsCustomTask()
{
int result = await this.clientRpc.InvokeAsync<int>(nameof(Server.ServerMethodThatReturnsCustomTask));
Assert.StrictEqual(CustomTaskResult, result);
}
[Fact]
public async Task CanInvokeMethodThatReturnsCancelledTask()
{
RemoteInvocationException exception = await Assert.ThrowsAnyAsync<RemoteInvocationException>(() => this.clientRpc.InvokeAsync(nameof(Server.ServerMethodThatReturnsCancelledTask)));
Assert.Null(exception.RemoteErrorCode);
Assert.Null(exception.RemoteStackTrace);
}
[Fact]
public async Task CanInvokeMethodThatReturnsTaskOfInternalClass()
{
// JSON RPC cannot invoke non-public members. A public member cannot have Task<NonPublicType> result.
// Though it can have result of just Task type, and return a Task<NonPublicType>, and dev hub supports that.
InternalClass result = await this.clientRpc.InvokeAsync<InternalClass>(nameof(Server.MethodThatReturnsTaskOfInternalClass));
Assert.NotNull(result);
}
[Fact]
public async Task CanPassExceptionFromServer()
{
const int COR_E_UNAUTHORIZEDACCESS = unchecked((int)0x80070005);
RemoteInvocationException exception = await Assert.ThrowsAnyAsync<RemoteInvocationException>(() => this.clientRpc.InvokeAsync(nameof(Server.MethodThatThrowsUnauthorizedAccessException)));
Assert.NotNull(exception.RemoteStackTrace);
Assert.StrictEqual(COR_E_UNAUTHORIZEDACCESS.ToString(CultureInfo.InvariantCulture), exception.RemoteErrorCode);
}
[Fact]
public async Task CanPassAndCallPrivateMethodsObjects()
{
var result = await this.clientRpc.InvokeAsync<Foo>(nameof(Server.MethodThatAcceptsFoo), new Foo { Bar = "bar", Bazz = 1000 });
Assert.NotNull(result);
Assert.Equal("bar!", result.Bar);
Assert.Equal(1001, result.Bazz);
result = await this.clientRpc.InvokeAsync<Foo>(nameof(Server.MethodThatAcceptsFoo), new { Bar = "bar", Bazz = 1000 });
Assert.NotNull(result);
Assert.Equal("bar!", result.Bar);
Assert.Equal(1001, result.Bazz);
}
[Fact]
public async Task CanCallMethodWithDefaultParameters()
{
var result = await this.clientRpc.InvokeAsync<int>(nameof(Server.MethodWithDefaultParameter), 10);
Assert.Equal(20, result);
result = await this.clientRpc.InvokeAsync<int>(nameof(Server.MethodWithDefaultParameter), 10, 20);
Assert.Equal(30, result);
}
[Fact]
public async Task CanPassNull()
{
var result = await this.clientRpc.InvokeAsync<object>(nameof(Server.MethodThatAccceptsAndReturnsNull), null);
Assert.Null(result);
Assert.True(this.server.NullPassed);
}
[Fact]
public async Task CanSendNotification()
{
await this.clientRpc.NotifyAsync(nameof(Server.NotificationMethod), "foo");
Assert.Equal("foo", await this.server.NotificationReceived);
}
[Fact]
public async Task CanCallAsyncMethod()
{
string result = await this.clientRpc.InvokeAsync<string>(nameof(Server.AsyncMethod), "test");
Assert.Equal("test!", result);
}
[Fact]
public async Task CanCallAsyncMethodThatThrows()
{
RemoteInvocationException exception = await Assert.ThrowsAnyAsync<RemoteInvocationException>(() => this.clientRpc.InvokeAsync<string>(nameof(Server.AsyncMethodThatThrows)));
Assert.NotNull(exception.RemoteStackTrace);
}
[Fact]
public async Task CanCallOverloadedMethod()
{
int result = await this.clientRpc.InvokeAsync<int>(nameof(Server.OverloadedMethod), new Foo { Bar = "bar-bar", Bazz = -100 });
Assert.Equal(1, result);
result = await this.clientRpc.InvokeAsync<int>(nameof(Server.OverloadedMethod), 40);
Assert.Equal(40, result);
}
[Fact]
public async Task ThrowsIfCannotFindMethod()
{
await Assert.ThrowsAsync(typeof(RemoteMethodNotFoundException), () => this.clientRpc.InvokeAsync("missingMethod", 50));
await Assert.ThrowsAsync(typeof(RemoteMethodNotFoundException), () => this.clientRpc.InvokeAsync(nameof(Server.OverloadedMethod), new { X = 100 }));
}
[Fact]
public async Task ThrowsIfTargetNotSet()
{
await Assert.ThrowsAsync(typeof(RemoteTargetNotSetException), () => this.serverRpc.InvokeAsync(nameof(Server.OverloadedMethod)));
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task DisconnectedEventIsFired(bool disposeRpc)
{
var disconnectedEventFired = new TaskCompletionSource<JsonRpcDisconnectedEventArgs>();
// Subscribe to disconnected event
object disconnectedEventSender = null;
this.serverRpc.Disconnected += delegate (object sender, JsonRpcDisconnectedEventArgs e)
{
disconnectedEventSender = sender;
disconnectedEventFired.SetResult(e);
};
// Close server or client stream.
if (disposeRpc)
{
this.serverRpc.Dispose();
}
else
{
this.serverStream.Dispose();
}
JsonRpcDisconnectedEventArgs args = await disconnectedEventFired.Task.WithCancellation(this.TimeoutToken);
Assert.Same(this.serverRpc, disconnectedEventSender);
Assert.NotNull(args);
Assert.NotNull(args.Description);
// Confirm that an event handler added after disconnection also gets raised.
disconnectedEventFired = new TaskCompletionSource<JsonRpcDisconnectedEventArgs>();
this.serverRpc.Disconnected += delegate (object sender, JsonRpcDisconnectedEventArgs e)
{
disconnectedEventSender = sender;
disconnectedEventFired.SetResult(e);
};
args = await disconnectedEventFired.Task;
Assert.Same(this.serverRpc, disconnectedEventSender);
Assert.NotNull(args);
Assert.NotNull(args.Description);
}
[Fact]
public async Task CanCallMethodOnBaseClass()
{
string result = await this.clientRpc.InvokeAsync<string>(nameof(Server.BaseMethod));
Assert.Equal("base", result);
result = await this.clientRpc.InvokeAsync<string>(nameof(Server.VirtualBaseMethod));
Assert.Equal("child", result);
result = await this.clientRpc.InvokeAsync<string>(nameof(Server.RedeclaredBaseMethod));
Assert.Equal("child", result);
}
[Fact]
public async Task CannotCallPrivateMethod()
{
await Assert.ThrowsAsync<RemoteMethodNotFoundException>(() => this.clientRpc.InvokeAsync(nameof(Server.InternalMethod), 10));
}
[Fact]
public async Task CannotCallMethodWithOutParameter()
{
await Assert.ThrowsAsync<RemoteMethodNotFoundException>(() => this.clientRpc.InvokeAsync(nameof(Server.MethodWithOutParameter), 20));
}
[Fact]
public async Task CannotCallMethodWithRefParameter()
{
await Assert.ThrowsAsync<RemoteMethodNotFoundException>(() => this.clientRpc.InvokeAsync(nameof(Server.MethodWithRefParameter), 20));
}
public class BaseClass
{
public string BaseMethod() => "base";
public virtual string VirtualBaseMethod() => "base";
public string RedeclaredBaseMethod() => "base";
}
public class Server : BaseClass
{
private readonly TaskCompletionSource<string> notificationTcs = new TaskCompletionSource<string>();
public bool NullPassed { get; private set; }
public Task<string> NotificationReceived => this.notificationTcs.Task;
public static string ServerMethod(string argument)
{
return argument + "!";
}
public override string VirtualBaseMethod() => "child";
public new string RedeclaredBaseMethod() => "child";
internal void InternalMethod()
{
}
public Task ServerMethodThatReturnsCustomTask()
{
var result = new CustomTask();
result.Start();
return result;
}
public async Task ServerMethodThatReturnsTask()
{
await Task.Yield();
}
public Task ServerMethodThatReturnsCancelledTask()
{
var tcs = new TaskCompletionSource<object>();
tcs.SetCanceled();
return tcs.Task;
}
public void MethodThatThrowsUnauthorizedAccessException()
{
throw new UnauthorizedAccessException();
}
public Foo MethodThatAcceptsFoo(Foo foo)
{
return new Foo
{
Bar = foo.Bar + "!",
Bazz = foo.Bazz + 1,
};
}
public static int MethodWithDefaultParameter(int x, int y = 10)
{
return x + y;
}
public object MethodThatAccceptsAndReturnsNull(object value)
{
this.NullPassed = value == null;
return null;
}
public void NotificationMethod(string arg)
{
this.notificationTcs.SetResult(arg);
}
public async Task<string> AsyncMethod(string arg)
{
await Task.Yield();
return arg + "!";
}
public async Task AsyncMethodThatThrows()
{
await Task.Yield();
throw new Exception();
}
public Task MethodThatReturnsTaskOfInternalClass()
{
var result = new Task<InternalClass>(() => new InternalClass());
result.Start();
return result;
}
public int OverloadedMethod(Foo foo)
{
Assert.NotNull(foo);
return 1;
}
public int OverloadedMethod(int i)
{
return i;
}
public int MethodWithOutParameter(out int i)
{
i = 1;
return 1;
}
public void MethodWithRefParameter(ref int i)
{
i = i + 1;
}
}
public class Foo
{
[JsonProperty(Required = Required.Always)]
public string Bar { get; set; }
public int Bazz { get; set; }
}
private class CustomTask : Task<int>
{
public CustomTask() : base(() => 0) { }
public new int Result { get { return CustomTaskResult; } }
}
internal class InternalClass
{
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using System.Resources;
using System.Reflection;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("StreamJsonRpc.Tests")]
[assembly: AssemblyProduct("StreamJsonRpc.Tests")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2016")]
[assembly: NeutralResourcesLanguage("en")]

Просмотреть файл

@ -0,0 +1,203 @@
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StreamJsonRpc;
using Xunit;
public class SplitJoinStreamTests
{
private const string DefaultDelimiter = "\0";
[Fact]
public async Task CanReadTrailing()
{
const string delimiter = "\r\n";
await this.RunReadTest(
new SplitJoinStreamOptions { Delimiter = delimiter, ReadTrailing = true },
"foo" + delimiter + "bar" + delimiter + delimiter + delimiter + "bazz",
"foo", "bar", "bazz");
}
[Fact]
public async Task CanReadTrailingWithoutDelimiters()
{
const string delimiter = "|";
await this.RunReadTest(
new SplitJoinStreamOptions { Delimiter = delimiter, ReadTrailing = true },
"foo",
"foo");
}
[Fact]
public async Task CanReadWithLongDelimiters()
{
var delimiter = new string('a', 4200);
await this.RunReadTest(
new SplitJoinStreamOptions { Delimiter = delimiter, ReadTrailing = true },
"foo" + delimiter + "bar" + delimiter + "bazz",
"foo", "bar", "bazz");
}
[Fact]
public async Task CanReadMultibyteCharAcrossBufferBoundary()
{
var str = 'a' + new string('Ж', SplitJoinStream.BufferSize / 2);
Assert.Equal(Encoding.UTF8.GetByteCount(str), SplitJoinStream.BufferSize + 1);
await this.RunReadTest(
new SplitJoinStreamOptions(),
str + DefaultDelimiter + str + DefaultDelimiter,
str, str);
}
[Fact]
public async Task CanReadMultibyteDelimiterAcrossBufferBoundary()
{
const string delimiter = "Ж";
var str = new string(' ', SplitJoinStream.BufferSize - 1);
Assert.Equal(Encoding.UTF8.GetByteCount(delimiter), 2);
Assert.Equal(Encoding.UTF8.GetByteCount(str + delimiter), SplitJoinStream.BufferSize + 1);
await this.RunReadTest(
new SplitJoinStreamOptions { Delimiter = delimiter },
str + delimiter + str + delimiter,
str, str);
}
[Fact]
public async Task CanReadSkippingTrailing()
{
await this.RunReadTest(
new SplitJoinStreamOptions(),
DefaultDelimiter + "foo" + DefaultDelimiter + "bar" + DefaultDelimiter + "bazz",
"foo", "bar");
}
[Fact]
public async Task CanReadSkippingTrailingWithoutDelimiters()
{
await this.RunReadTest(new SplitJoinStreamOptions(), "foo" /* Nothing to read */);
}
[Fact]
public async Task CanReadLongString()
{
var longString = new string('a', 4200);
await this.RunReadTest(
new SplitJoinStreamOptions(),
longString + DefaultDelimiter + longString + DefaultDelimiter + DefaultDelimiter + longString,
longString, longString);
}
[Fact]
public async Task CanReadFromStreamWithOnlyDelimiters()
{
await this.RunReadTest(new SplitJoinStreamOptions(), DefaultDelimiter + DefaultDelimiter + DefaultDelimiter /* Nothing to read */);
}
[Fact]
public async Task CanReadFromEmptyStream()
{
await this.RunReadTest(new SplitJoinStreamOptions {}, "" /* Nothing to read */);
}
[Fact]
public async Task CanReadUTF32()
{
await this.RunReadTest(
new SplitJoinStreamOptions { Encoding = Encoding.UTF32 },
"foo" + DefaultDelimiter + "bar" + DefaultDelimiter + DefaultDelimiter + DefaultDelimiter + "bazz",
"foo", "bar");
}
[Fact]
public async Task CanCancelRead()
{
var cts = new CancellationTokenSource();
cts.Cancel();
using (var split = new SplitJoinStream(new SplitJoinStreamOptions { Readable = new MemoryStream(new byte[] { 32, 46 }) }))
{
await Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await split.ReadAsync(cts.Token));
}
}
[Fact]
public void CanDisposeStreamsByDefault()
{
var options = new SplitJoinStreamOptions
{
Readable = new MemoryStream(new byte[] { 32, 46 }),
Writable = new MemoryStream(new byte[] { 55, 45 }),
// LeaveOpen = false, - this is the default
};
using (var split = new SplitJoinStream(options)) {}
Assert.False(options.Writable.CanWrite);
Assert.False(options.Readable.CanWrite);
}
[Fact]
public void CanLeaveStreamsOpen()
{
var options = new SplitJoinStreamOptions
{
Readable = new MemoryStream(new byte[] { 32, 46 }),
Writable = new MemoryStream(new byte[] { 55, 45 }),
LeaveOpen = true,
};
using (var split = new SplitJoinStream(options)) { }
Assert.True(options.Writable.CanWrite);
Assert.True(options.Readable.CanWrite);
}
[Fact]
public async Task CanWrite()
{
const string StringToWrite = "foo";
using (var writable = new MemoryStream())
{
using (var split = new SplitJoinStream(new SplitJoinStreamOptions { Writable = writable, LeaveOpen = true }))
{
await split.WriteAsync(StringToWrite);
}
writable.Position = 0;
using (var reader = new StreamReader(writable))
{
string actual = reader.ReadToEnd();
Assert.Equal(StringToWrite + DefaultDelimiter, actual);
}
}
}
[Fact]
public async Task CanCancelWrite()
{
var cts = new CancellationTokenSource();
cts.Cancel();
using (var split = new SplitJoinStream(new SplitJoinStreamOptions { Writable = new MemoryStream() }))
{
await Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await split.WriteAsync("foo", cts.Token));
}
}
private async Task RunReadTest(SplitJoinStreamOptions options, string input, params string[] expectedReads)
{
var encoding = options.Encoding ?? Encoding.UTF8;
options.Readable = new MemoryStream(encoding.GetBytes(input));
using (var split = new SplitJoinStream(options))
{
foreach (string expectedRead in expectedReads)
{
string message = await split.ReadAsync();
Assert.Equal(expectedRead, message);
}
string messageAfterStreamEnds = await split.ReadAsync();
Assert.Null(messageAfterStreamEnds);
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8BF355B2-E3B0-4615-BFC1-7563EADC4F8B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>
</RootNamespace>
<AssemblyName>StreamJsonRpc.Tests</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<ProjectReference Include="..\StreamJsonRpc\StreamJsonRpc.csproj">
<Project>{dfbd1bca-eae0-4454-9e97-fa9bd9a0f03a}</Project>
<Name>StreamJsonRpc</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="JsonRpcRawStreamTests.cs" />
<Compile Include="JsonRpcTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SplitJoinStreamTests.cs" />
<Compile Include="WrappedStream.cs" />
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,211 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
internal class WrappedStream : Stream
{
protected readonly Stream stream;
private bool isConnected;
private bool isEndReached;
private bool disposed;
private EventHandler disconnectedListeners;
public WrappedStream(Stream stream)
{
this.stream = stream;
}
public bool Disposed => this.disposed;
public bool IsEndReached => this.isEndReached;
#region overridden Stream members
public override bool CanRead => this.stream.CanRead;
public override bool CanSeek => this.stream.CanSeek;
public override bool CanTimeout => this.stream.CanTimeout;
public override bool CanWrite => this.stream.CanWrite;
public override long Length => this.stream.Length;
public override long Position
{
get
{
return this.stream.Position;
}
set
{
this.stream.Position = value;
}
}
public override int ReadTimeout => stream.ReadTimeout;
public override int WriteTimeout => this.stream.WriteTimeout;
public bool IsConnected
{
get
{
bool result = this.GetConnected();
this.SetConnected(result);
return result;
}
}
protected virtual bool GetConnected()
{
return !this.isEndReached && !this.disposed;
}
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
this.UpdateConnectedState();
return this.stream.CopyToAsync(destination, bufferSize, cancellationToken);
}
public override void Flush()
{
this.UpdateConnectedState();
this.stream.Flush();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
this.UpdateConnectedState();
return this.stream.FlushAsync(cancellationToken);
}
public override int Read(byte[] buffer, int offset, int count)
{
this.UpdateConnectedState();
int result = this.stream.Read(buffer, offset, count);
if (result == 0)
{
this.EndReached();
}
return result;
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
this.UpdateConnectedState();
int result = await this.stream.ReadAsync(buffer, offset, count, cancellationToken);
if (result == 0)
{
this.EndReached();
}
return result;
}
public override int ReadByte()
{
this.UpdateConnectedState();
int result = this.stream.ReadByte();
if (result == -1)
{
this.EndReached();
}
return result;
}
public override long Seek(long offset, SeekOrigin origin)
{
this.UpdateConnectedState();
return this.stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
this.UpdateConnectedState();
this.stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
this.UpdateConnectedState();
this.stream.Write(buffer, offset, count);
}
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
this.UpdateConnectedState();
await this.stream.WriteAsync(buffer, offset, count, cancellationToken);
}
public override void WriteByte(byte value)
{
this.UpdateConnectedState();
this.stream.WriteByte(value);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (!this.disposed)
{
this.disposed = true;
this.stream.Dispose();
this.UpdateConnectedState();
}
}
base.Dispose(disposing);
}
#endregion
public event EventHandler Disconnected
{
add
{
if (value != null)
{
this.disconnectedListeners += value;
this.UpdateConnectedState();
}
}
remove
{
this.disconnectedListeners -= value;
}
}
protected void UpdateConnectedState()
{
this.SetConnected(this.GetConnected());
}
private void EndReached()
{
if (!this.isEndReached)
{
this.isEndReached = true;
this.UpdateConnectedState();
}
}
private void SetConnected(bool value)
{
if (this.isConnected != value)
{
this.isConnected = value;
if (!value)
{
this.disconnectedListeners?.Invoke(this, EventArgs.Empty);
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"dependencies": {
"Nerdbank.FullDuplexStream": "1.0.1",
"xunit": "2.1.0",
"xunit.runner.visualstudio": "2.1.0"
},
"frameworks": {
"net46": { }
},
"runtimes": {
"win": { }
}
}

47
src/StreamJsonRpc.sln Normal file
Просмотреть файл

@ -0,0 +1,47 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25401.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamJsonRpc", "StreamJsonRpc\StreamJsonRpc.csproj", "{DFBD1BCA-EAE0-4454-9E97-FA9BD9A0F03A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamJsonRpc.Tests", "StreamJsonRpc.Tests\StreamJsonRpc.Tests.csproj", "{8BF355B2-E3B0-4615-BFC1-7563EADC4F8B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamJsonRpc.Desktop", "StreamJsonRpc.Desktop\StreamJsonRpc.Desktop.csproj", "{C8FE34FA-B409-4A57-A16F-4407AF728C65}"
EndProject
Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "StreamJsonRpc.NuGet", "StreamJsonRpc.NuGet\StreamJsonRpc.NuGet.nuproj", "{927450A5-18BF-4378-8421-7A7C6864B6EA}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "StreamJsonRpc.Shared", "StreamJsonRpc.Shared\StreamJsonRpc.Shared.shproj", "{DF6B6DC7-7C77-42F2-84CB-E520B2771375}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
StreamJsonRpc.Shared\StreamJsonRpc.Shared.projitems*{c8fe34fa-b409-4a57-a16f-4407af728c65}*SharedItemsImports = 4
StreamJsonRpc.Shared\StreamJsonRpc.Shared.projitems*{df6b6dc7-7c77-42f2-84cb-e520b2771375}*SharedItemsImports = 13
StreamJsonRpc.Shared\StreamJsonRpc.Shared.projitems*{dfbd1bca-eae0-4454-9e97-fa9bd9a0f03a}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DFBD1BCA-EAE0-4454-9E97-FA9BD9A0F03A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DFBD1BCA-EAE0-4454-9E97-FA9BD9A0F03A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFBD1BCA-EAE0-4454-9E97-FA9BD9A0F03A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFBD1BCA-EAE0-4454-9E97-FA9BD9A0F03A}.Release|Any CPU.Build.0 = Release|Any CPU
{8BF355B2-E3B0-4615-BFC1-7563EADC4F8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8BF355B2-E3B0-4615-BFC1-7563EADC4F8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8BF355B2-E3B0-4615-BFC1-7563EADC4F8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8BF355B2-E3B0-4615-BFC1-7563EADC4F8B}.Release|Any CPU.Build.0 = Release|Any CPU
{C8FE34FA-B409-4A57-A16F-4407AF728C65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8FE34FA-B409-4A57-A16F-4407AF728C65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8FE34FA-B409-4A57-A16F-4407AF728C65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8FE34FA-B409-4A57-A16F-4407AF728C65}.Release|Any CPU.Build.0 = Release|Any CPU
{927450A5-18BF-4378-8421-7A7C6864B6EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{927450A5-18BF-4378-8421-7A7C6864B6EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{927450A5-18BF-4378-8421-7A7C6864B6EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{927450A5-18BF-4378-8421-7A7C6864B6EA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

289
src/StreamJsonRpc/Resources.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,289 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace StreamJsonRpc {
using System;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StreamJsonRpc.Resources", typeof(Resources).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Both readable and writable are null..
/// </summary>
internal static string BothReadableWritableAreNull {
get {
return ResourceManager.GetString("BothReadableWritableAreNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Got a request to execute &apos;{0}&apos; but have no callback object. Dropping the request..
/// </summary>
internal static string DroppingRequestDueToNoTargetObject {
get {
return ResourceManager.GetString("DroppingRequestDueToNoTargetObject", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delimiter is empty string..
/// </summary>
internal static string EmptyDelimiter {
get {
return ResourceManager.GetString("EmptyDelimiter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error writing JSON RPC Result: {0}: {1}.
/// </summary>
internal static string ErrorWritingJsonRpcResult {
get {
return ResourceManager.GetString("ErrorWritingJsonRpcResult", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failure deserializing incoming JSON RPC &apos;{0}&apos;: {1}.
/// </summary>
internal static string FailureDeserializingJsonRpc {
get {
return ResourceManager.GetString("FailureDeserializingJsonRpc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to JSON RPC must not be null..
/// </summary>
internal static string JsonRpcCannotBeNull {
get {
return ResourceManager.GetString("JsonRpcCannotBeNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} has ref or out parameter(s), which is not supported.
/// </summary>
internal static string MethodHasRefOrOutParameters {
get {
return ResourceManager.GetString("MethodHasRefOrOutParameters", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} is not public.
/// </summary>
internal static string MethodIsNotPublic {
get {
return ResourceManager.GetString("MethodIsNotPublic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; method name has different case from requested &apos;{1}&apos;.
/// </summary>
internal static string MethodNameCaseIsDifferent {
get {
return ResourceManager.GetString("MethodNameCaseIsDifferent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} parameter(s): {1}, but the request supplies {2}.
/// </summary>
internal static string MethodParameterCountDoesNotMatch {
get {
return ResourceManager.GetString("MethodParameterCountDoesNotMatch", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} parameters are not compatible with the request: {1}.
/// </summary>
internal static string MethodParametersNotCompatible {
get {
return ResourceManager.GetString("MethodParametersNotCompatible", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to More than one target method found: {0}..
/// </summary>
internal static string MoreThanOneMethodFound {
get {
return ResourceManager.GetString("MoreThanOneMethodFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reached end of stream..
/// </summary>
internal static string ReachedEndOfStream {
get {
return ResourceManager.GetString("ReachedEndOfStream", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Readable cannot read..
/// </summary>
internal static string ReadableCannotRead {
get {
return ResourceManager.GetString("ReadableCannotRead", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Readable is not set..
/// </summary>
internal static string ReadableNotSet {
get {
return ResourceManager.GetString("ReadableNotSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reading JSON RPC from the stream failed with {0}: {1}.
/// </summary>
internal static string ReadingJsonRpcStreamFailed {
get {
return ResourceManager.GetString("ReadingJsonRpcStreamFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Response is not error..
/// </summary>
internal static string ResponseIsNotError {
get {
return ResourceManager.GetString("ResponseIsNotError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stream has been disposed.
/// </summary>
internal static string StreamDisposed {
get {
return ResourceManager.GetString("StreamDisposed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The task is not completed..
/// </summary>
internal static string TaskNotCompleted {
get {
return ResourceManager.GetString("TaskNotCompleted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The task was cancelled..
/// </summary>
internal static string TaskWasCancelled {
get {
return ResourceManager.GetString("TaskWasCancelled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unable to find method &apos;{0}/{1}&apos; on {2} for the following reasons: {3}.
/// </summary>
internal static string UnableToFindMethod {
get {
return ResourceManager.GetString("UnableToFindMethod", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unexpected error processing JSON RPC &apos;{0}&apos;: {1}.
/// </summary>
internal static string UnexpectedErrorProcessingJsonRpc {
get {
return ResourceManager.GetString("UnexpectedErrorProcessingJsonRpc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unrecognized incoming JSON RPC &apos;{0}&apos;.
/// </summary>
internal static string UnrecognizedIncomingJsonRpc {
get {
return ResourceManager.GetString("UnrecognizedIncomingJsonRpc", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Writable cannot write..
/// </summary>
internal static string WritableCannotWrite {
get {
return ResourceManager.GetString("WritableCannotWrite", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Writable is not set..
/// </summary>
internal static string WritableNotSet {
get {
return ResourceManager.GetString("WritableNotSet", resourceCulture);
}
}
}
}

Просмотреть файл

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BothReadableWritableAreNull" xml:space="preserve">
<value>Both readable and writable are null.</value>
</data>
<data name="DroppingRequestDueToNoTargetObject" xml:space="preserve">
<value>Got a request to execute '{0}' but have no callback object. Dropping the request.</value>
<comment>{0} is the method name to execute.</comment>
</data>
<data name="EmptyDelimiter" xml:space="preserve">
<value>Delimiter is empty string.</value>
</data>
<data name="ErrorWritingJsonRpcResult" xml:space="preserve">
<value>Error writing JSON RPC Result: {0}: {1}</value>
<comment>{0} is the exception type, {1} is the exception message.</comment>
</data>
<data name="FailureDeserializingJsonRpc" xml:space="preserve">
<value>Failure deserializing incoming JSON RPC '{0}': {1}</value>
<comment>{0} is the JSON RPC, {1} is the exception message.</comment>
</data>
<data name="JsonRpcCannotBeNull" xml:space="preserve">
<value>JSON RPC must not be null.</value>
</data>
<data name="MethodHasRefOrOutParameters" xml:space="preserve">
<value>{0} has ref or out parameter(s), which is not supported</value>
<comment>{0} is the method signature.</comment>
</data>
<data name="MethodIsNotPublic" xml:space="preserve">
<value>{0} is not public</value>
<comment>{0} is the method signature.</comment>
</data>
<data name="MethodNameCaseIsDifferent" xml:space="preserve">
<value>'{0}' method name has different case from requested '{1}'</value>
<comment>{0} is the method signature, {1} is the requested method name.</comment>
</data>
<data name="MethodParameterCountDoesNotMatch" xml:space="preserve">
<value>{0} parameter(s): {1}, but the request supplies {2}</value>
<comment>{0} is the method signature, {1} is the method parameter count, {2} is the request parameter count.</comment>
</data>
<data name="MethodParametersNotCompatible" xml:space="preserve">
<value>{0} parameters are not compatible with the request: {1}</value>
<comment>{0} is the method signature, {1} is the error message.</comment>
</data>
<data name="MoreThanOneMethodFound" xml:space="preserve">
<value>More than one target method found: {0}.</value>
<comment>{0} is the list of method signatures.</comment>
</data>
<data name="ReachedEndOfStream" xml:space="preserve">
<value>Reached end of stream.</value>
</data>
<data name="ReadableCannotRead" xml:space="preserve">
<value>Readable cannot read.</value>
</data>
<data name="ReadableNotSet" xml:space="preserve">
<value>Readable is not set.</value>
</data>
<data name="ReadingJsonRpcStreamFailed" xml:space="preserve">
<value>Reading JSON RPC from the stream failed with {0}: {1}</value>
<comment>{0} is the exception type, {1} is the exception message.</comment>
</data>
<data name="ResponseIsNotError" xml:space="preserve">
<value>Response is not error.</value>
</data>
<data name="StreamDisposed" xml:space="preserve">
<value>Stream has been disposed</value>
</data>
<data name="TaskNotCompleted" xml:space="preserve">
<value>The task is not completed.</value>
</data>
<data name="TaskWasCancelled" xml:space="preserve">
<value>The task was cancelled.</value>
</data>
<data name="UnableToFindMethod" xml:space="preserve">
<value>Unable to find method '{0}/{1}' on {2} for the following reasons: {3}</value>
<comment>{0} is the method name, {1} is arity, {2} is target class full name, {3} is the error list.</comment>
</data>
<data name="UnexpectedErrorProcessingJsonRpc" xml:space="preserve">
<value>Unexpected error processing JSON RPC '{0}': {1}</value>
<comment>{0} is the json, {1} is the exception message.</comment>
</data>
<data name="UnrecognizedIncomingJsonRpc" xml:space="preserve">
<value>Unrecognized incoming JSON RPC '{0}'</value>
<comment>{0} is the json.</comment>
</data>
<data name="WritableCannotWrite" xml:space="preserve">
<value>Writable cannot write.</value>
</data>
<data name="WritableNotSet" xml:space="preserve">
<value>Writable is not set.</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DFBD1BCA-EAE0-4454-9E97-FA9BD9A0F03A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StreamJsonRpc</RootNamespace>
<AssemblyName>StreamJsonRpc</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<None Include="project.json" />
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="..\StreamJsonRpc.Shared\StreamJsonRpc.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,29 @@
{
"dependencies": {
"MicroBuild.VisualStudio": {
"version": "1.0.117-rc",
"suppressParent": "none"
},
"MicroBuild.Core": {
"version": "0.2.0",
"suppressParent": "none"
},
"Nerdbank.GitVersioning": {
"version": "1.4.19",
"suppressParent": "none"
},
"Newtonsoft.Json": "6.0.6",
"NuSpec.ReferenceGenerator": "1.4.2",
"Microsoft.VisualStudio.Threading": "14.1.114",
"ReadOnlySourceTree": {
"version": "0.1.36-beta",
"suppressParent": "none"
}
},
"frameworks": {
".NETPortable,Version=v4.5,Profile=Profile111": { }
},
"runtimes": {
"win": { }
}
}