Introducing gRPC HTTP API

gRPC is a modern way to communicate between apps. gRPC uses HTTP/2, streaming, Protobuf and message contracts to create high-performance, realtime services. Support for gRPC on ASP.NET Core was added in .NET Core 3.0.

The catch with gRPC is not every platform can use it. Browsers don't fully support HTTP/2, making REST and JSON still the primary way to get data into your browser apps. Even with the benefits that gRPC brings, REST and JSON still have an important place in modern apps. Building gRPC and REST services adds unwanted overhead to app development.

Wouldn't it be great if we could build services once in ASP.NET Core and get gRPC and REST? Now you can! Introducing gRPC HTTP API for ASP.NET Core.

gRPC or REST? Why not both

gRPC HTTP API is an experimental extension for ASP.NET Core that creates RESTful HTTP APIs for gRPC services. Once configured, gRPC HTTP API allows you to call gRPC methods with familiar HTTP concepts:

  • HTTP verbs
  • URL parameter binding
  • JSON requests/responses

RESTful APIs for your gRPC services. No duplication!

I choo-choo-choose you?

Demo

Visit https://grpchttpapi.azurewebsites.net/ to see gRPC HTTP API in action.

Source code of the demo is available here.

Getting started

  1. The first step is to create a gRPC service (if you don't already have one). Create a gRPC client and service is a great tutorial for getting started with gRPC on .NET Core.
  2. Next, add a package reference to Microsoft.AspNetCore.Grpc.HttpApi to the server. Register it in Startup.cs with services.AddGrpcHttpApi().
  3. The last step is annotating your gRPC .proto file with HTTP bindings and routes. The annotations define how gRPC services map to the JSON request and response. You will need to add import "google/api/annotations.proto"; to the gRPC proto file and have a copy of annotations.proto and http.proto in your project.
syntax = "proto3";

import "google/api/annotations.proto";

package greet;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/greeter/{name}"
    };
  }
  rpc SayHelloFrom (HelloRequestFrom) returns (HelloReply) {
    option (google.api.http) = {
      post: "/v1/greeter"
      body: "*"
    };
  }
}

message HelloRequest {
  string name = 1;
}

message HelloRequestFrom {
  string name = 1;
  string from = 2;
}

message HelloReply {
  string message = 1;
}

In the sample above, the SayHello gRPC method can now be invoked as gRPC and as a RESTful API:

  • Request: HTTP/1.1 GET /v1/greeter/world
  • Response: { "message": "Hello world" }

And browser apps call it like any other RESTful API:

fetch('https://localhost:5001/v1/greeter/world')
    .then((response) => response.json())
    .then((result) => {
        console.log(result.message);
        // Hello world
    });

This is a simple example. See HttpRule for more customization options.

FAQ

Q: Are RESTful APIs for gRPC a brand new concept?

A: No. grpc-gateway provides RESTful JSON services for gRPC using the same .proto annotations. grpc-gateway is in heavy use today. For example, GCP uses it to offer gRPC and REST endpoints for GCP services. A key difference between the two technologies is grpc-gateway requires a reverse proxy, while gRPC HTTP API is hosted directly by ASP.NET alongside the gRPC service.

Q: Does this replace ASP.NET Core MVC?

A: No. gRPC HTTP API only supports JSON, and it is very opinionated. Only customization options offered by `HttpRule` are supported. A good scenario to use gRPC HTTP API is building new services using gRPC and JSON.

Q: How is this different than gRPC-Web?

A: gRPC-Web lets you call gRPC services from the browser with the gRPC-Web client and Protobuf. gRPC HTTP API allows you to call your services as if they were RESTful APIs with JSON. It doesn't replace gRPC-Web.

Q: When will this be released?

A: A pre-release package is on NuGet right now! gRPC HTTP API is an experiment and the decision to invest more time on it depends on user feedback.

Try it today!

gRPC HTTP API is a framework idea that I have been playing around with. It is very experimental, but I think it has the opportunity for .NET developers to offer gRPC and REST services much faster than they can today.

You can use the pre-release package on NuGet now. Whether more time is invested in making it a supported product depends on user feedback. Give feedback on GitHub or contact me @JamesNK on Twitter. I'm looking forward to seeing how this framework is used.

Json.NET 12.0 Release 1 - .NET Foundation, NuGet and Authenticode signing, SourceLink and more

.NET Foundation

Json.NET has joined the .NET Foundation! The .NET Foundation is an independent organization dedicated to fostering the .NET open source community. The .NET Foundation provides technical and legal guidance .NET open source projects. Joining the .NET Foundation ensures that Json.NET stays open and supported into the future.

Read more on the .NET Foundation blog.

NuGet package and Authenticode signing

Json.NET 12 is the first release to sign the *.nupkg using NuGet package signing and sign the assembly files using Authenticode. Although it isn't a common request, some users of Json.NET have asked for signed binaries because of company policy. This feature is made possible by the .NET Foundation, who offer code signing certificates and a signing service to member projects.

Better debugging with SourceLink

SourceLink is an neat technology that links a library to its source code. Originally created in the community by @ctaggart, SourceLink has been adopted by Microsoft and is supported in Visual Studio. This release adds SourceLink support to Json.NET, making it possible to step into the Json.NET source code as you debug your application.

And lots more

JSON Path supports JavaScript's strict equality operators (=== & !==), StringEnumConverter can use a NamingStrategy and is faster, JavaScriptDateTimeConverter supports JavaScript date constructors with multiple arguments, there is a new option on JsonMergeSettings for case insensitive merging of property names, serializing Span<T> properties no longer errors, and dozens of other new features and bug fixes.

Changes

Here is a complete list of what has changed since Json.NET 11.0 Release 2.

  • New feature - Added NuGet package signing
  • New feature - Added Authenticode assembly signing
  • New feature - Added SourceLink support
  • New feature - Added constructors to StringEnumConverter for setting AllowIntegerValue
  • New feature - Added JsonNameTable and JsonTextReader.PropertyNameTable
  • New feature - Added line information to JsonSerializationException
  • New feature - Added JObject.Property overload with a StringComparison
  • New feature - Added JsonMergeSettings.PropertyNameComparison
  • New feature - Added support for multiple Date constructors with JavaScriptDateTimeConverter
  • New feature - Added support for strict equals and strict not equals in JSON Path queries
  • New feature - Added EncodeSpecialCharacters setting to XmlNodeConverter
  • New feature - Added trace message for serializing to non-writable properties
  • New feature - Added support for NamingStrategy to StringEnumConverter
  • New feature - Added JsonLoadSettings.DuplicatePropertyNameHandling setting
  • Change - JTokenReader now uses JsonReader.DateTimeZoneHandling setting for date values
  • Change - Excluded TargetSite when serializing Exceptions without SerializableAttribute
  • Change - Changed StringEnumConverter.ctor(bool camelCaseText) to obsolete
  • Change - Changed StringEnumConverter.CamelCaseText to obsolete
  • Fix - Fixed incorrect overflow when reading decimal values from JSON
  • Fix - Fixed error message when trying to deserialize an abstract serializable type
  • Fix - Fixed parsing decimals from a string with an exponent
  • Fix - Fixed losing DateTime.Kind when deserializing ISO date strings
  • Fix - Fixed calling constructors with ref and in parameters
  • Fix - Fixed rare race condition in name table when serializing
  • Fix - Fixed unhelpful exception message when unable to convert JSON value to DateTime
  • Fix - Fixed error when deserializing empty array in DataTable
  • Fix - Fixed deserializing empty string to empty byte array
  • Fix - Fixed blank extension data values with required properties and deserializing with constructor
  • Fix - Fixed ignored values being set in extension data when deserializing
  • Fix - Fixed comparing equal integer and floating point values in JSON Path
  • Fix - Fixed BsonReader when reading multiple content
  • Fix - Fixed setting extension data with existing key
  • Fix - Fixed including array attribute in XML with namespaces when converting JSON to XML
  • Fix - Fixed error when serializing ref struct properties by excluding them from serialization

Links

Json.NET GitHub Project

Json.NET 12.0 Release 1 Download - Json.NET source code and assemblies

Json.NET 11.0 Release 1 - .NET Standard 2.0, JsonConverters, JSON Path and more

.NET Standard 2.0

The big new feature in Json.NET 11 Release 1 is targeted support for .NET Standard 2.0.

There are two main benefits of a library like Json.NET targeting .NET Standard 2.0. The first is more APIs: Json.NET with .NET Standard 2.0 almost matches Json.NET on the traditional Windows .NET Framework in features.

For example, fans of serializing DataSets to and from JSON rejoice, .NET Core now supports your pro-DataSet lifestyle:

DataTable dt = new DataTable();
dt.Columns.Add("PackageId", typeof(string));
dt.Columns.Add("Version", typeof(string));
dt.Columns.Add("ReleaseDate", typeof(DateTime));

dt.Rows.Add("Newtonsoft.Json", "11.0.1", new DateTime(2018, 2, 17));
dt.Rows.Add("NUnit", "3.9.0", new DateTime(2017, 11, 10));

string json = JsonConvert.SerializeObject(dt, Formatting.Indented);

Console.WriteLine(json);
// [
//   {
//     "PackageId": "Newtonsoft.Json",
//     "Version": "11.0.1",
//     "ReleaseDate": "2018-02-17T00:00:00"
//   },
//   {
//     "PackageId": "Newtonsoft.Json",
//     "Version": "10.0.3",
//     "ReleaseDate": "2017-06-18T00:00:00"
//   }
// ]

The other benefit of .NET Standard 2.0 is developers are no longer spammed with NuGet dependencies. UWP app authors for example saw NuGet pull in over 100 packages when referencing Json.NET. UWP supporting .NET Standard 2.0 and consuming a netstandard2.0 package eliminates that problem.

JsonConverter Stuff

Json.NET 11 adds a generic JsonConverter<T>. If you only care about serializing one specific type then JsonConverter<T> eliminates boiler plate code from your converter and keeps everything strongly typed.

Also new is a UnixDateTimeConverter. There is no standard for serializing dates in JSON and so UnixDateTimeConverter is a useful converter for anyone who want to store time as an integer Unix epoch in their JSON.

JSON Path Stuff

Json.NET 11 adds support for the regular expression operator in JSON Path queries. JSON Path has no formal specification (other than a blog post) but one common addition to it is support for querying with regular expressions.

JArray packages = JArray.Parse(@"[
  {
    ""PackageId"": ""Newtonsoft.Json"",
    ""Version"": ""11.0.1"",
    ""ReleaseDate"": ""2018-02-17T00:00:00""
  },
  {
    ""PackageId"": ""NUnit"",
    ""Version"": ""3.9.0"",
    ""ReleaseDate"": ""2017-11-10T00:00:00""
  }
]");

List<JToken> newtonsoftPackages = packages.SelectTokens(@"$.[?(@.PackageId =~ /^Newtonsoft\.(.*)$/)]").ToList();

Console.WriteLine(newtonsoftPackages.Count);
// 1

JSON Path has also seen many smaller bug fixes this release to improve its performance and support of escaped characters.

And lots more

Serializing and deserializing enumerations by name is faster and more accurate, JsonReader.SupportMultipleContent supports reading multiple comma delimited fragments of JSON together, JObject exposes ContainsKey, error messages have improved in many exceptional situations, and dozens of other new features and bug fixes.

Changes

Here is a complete list of what has changed since Json.NET 10.0 Release 3.

  • New feature - Added netstandard2.0 build
  • New feature - Added generic JsonConverter<T>
  • New feature - Added UnixDateConverter for converting Unix timestaps
  • New feature - Added support for regex operator in JSON Paths
  • New feature - Added JsonObjectAttribute.ItemNullValueHandling
  • New feature - Added JsonObjectContract.ItemNullValueHandling
  • New feature - Improved performance when resolving serialization contracts by using ConcurrentDictionary
  • New feature - Improved performance of JToken.Path with a faster reverse
  • New feature - Improved performance of parsing Int32 JSON integer values
  • New feature - Improved performance of parsing and writing enum names
  • New feature - Added IgnoreIsSpecifiedMembers to DefaultContractResolver
  • New feature - Added IgnoreShouldSerializeMembers to DefaultContractResolver
  • New feature - Added support for reading multiple comma delimited values with JsonReader.SupportMultipleContent
  • New feature - Improved error message when an object is reused with PreserveReferencesHandling
  • New feature - Added IConvertible support to netstandard1.3
  • New feature - Added INotifyPropertyChanging support to netstandard1.3
  • New feature - Optimized internal buffering when writing very large strings
  • New feature - JObject.ContainsKey is now public
  • New feature - Improved the error message when serialized ByRef properties
  • New feature - Improved the error message when serializing FileInfo/DictionaryInfo without ISerializable
  • New feature - Improved the error message when failing conversion in JsonReader.ReadAsInt32 and JsonReader.ReadAsDecimal
  • New feature - Improved the error message when deserializing badly formatted regex strings
  • Change - Types that implement ISerializable but don't have [SerializableAttribute] are not serialized using ISerializable
  • Change - Changed JsonProperty.MemberConverter to obsolete
  • Change - Changed camel casing logic for all caps words to not leave last character capitalized
  • Change - Changed enum serialization in dictionary keys to use EnumMemberAttribute
  • Fix - Fixed converting default datetime in JSON to XML on netstandard1.3
  • Fix - Fixed deserializing ObservableCollection in .NET Core 2.0
  • Fix - Fixed incorrectly allowing static IsSpecified properties
  • Fix - Fixed not preserving trailing zeros when deserializing decimals
  • Fix - Fixed JValue.CompareTo with number and string values
  • Fix - Fixed not erroring when reading undefined for nullable long
  • Fix - Fixed serializing immutable collections when .NET 4.0 or previous Newtonsoft.Json assembly is GACed
  • Fix - Fixed writing null values by XmlNodeConverter and RegexConverter
  • Fix - Fixed deserializing with a TraceWriter when the reader is not at the start
  • Fix - Fixed TraceJsonWriter.WriteValue(object) writing value twice
  • Fix - Fixed deserializing with constructor and readonly collection property
  • Fix - Fixed error when writing unknown null value as JSON
  • Fix - Fixed merging null string values
  • Fix - Fixed missing CancellationToken usages in JsonTextWriter.WriteAsync
  • Fix - Fixed error with JsonSerializer.Populate and comments in JSON array
  • Fix - Fixed error handling when deserializing certain dictionary and lists
  • Fix - Fixed serializing collection that is nullable
  • Fix - Fixed JsonTextReader sync read in async method
  • Fix - Fixed JsonConverter not called when target type is list and token is a string
  • Fix - Fixed serializing a property that is defined in multiple interfaces
  • Fix - Fixed error when deserializing null value into ConcurrentDictionary
  • Fix - Fixed escaping special characters in generated JSON Paths
  • Fix - Fixed reading escaped special characters in JSON Paths
  • Fix - Fixed using extension data with dictionary that explicitly implements Add method
  • Fix - Fixed parsing enum name to exact casing value before falling back to case-insensitive value
  • Fix - Fixed DataContractAttribute not forcing object serialization of classes
  • Fix - Fixed bug when deserializing into existing non-IList collection
  • Fix - Fixed bug when deserializing into existing non-IDictionary collection
  • Fix - Fixed JsonReader.ReadAsInt32 with BigInteger values

Links

Json.NET GitHub Project

Json.NET 11.0 Release 1 Download - Json.NET source code and assemblies

Json.NET 10.0 Release 1 - Async, performance, documentation and more

Async support

The headline feature in Json.NET 10 is enabling asyncronously reading and writing JSON with JsonReader and JsonWriter, and asyncronously loading JObject, JArray and friends.

Async support means that reading or writing JSON to the file system or network will never block while waiting on IO. Client applications will be more responsive and web applications more scalable.

JArray largeJson;

// read asynchronously from a file
using (FileStream asyncFileStream = new FileStream(@"large.json", FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
{
    largeJson = await JArray.LoadAsync(new JsonTextReader(new StreamReader(asyncFileStream)));
}

JToken user = largeJson.SelectToken("$[?(@.name == 'Woodard Caldwell')]");
user["isActive"] = false;

// write asynchronously to a file
using (FileStream asyncFileStream = new FileStream(@"large.json", FileMode.Open, FileAccess.Write, FileShare.Write, 4096, true))
{
    await largeJson.WriteToAsync(new JsonTextWriter(new StreamWriter(asyncFileStream)));
}

Although it looks simple on the surface, adding async support to Json.NET was a huge task. Special thanks to Jon Hanna for contributing most of this work.

Performance

Json.NET now supports reading double and decimal values without internally converting the value to a string first. In addition to a small performance boost when deserializing double and decimal values, not creating a string for each double and decimal means less garbage for the garbage collector to clean up.

Obsoleting and removing

In an effort to slim down Json.NET the BSON functionality has been marked as obsolete. A Newtonsoft.Json.Bson package is on NuGet and contains a copy of BsonReader and BsonWriter. Obsolete classes in Newtonsoft.Json will eventually be removed after a few major versions.

Some previously obsoleted types and methods have been removed in Json.NET 10. These APIs aren't commonly used by end users, and all have been obsolete for multiple major versions. Check the detailed release notes below for more information.

Finally the Portable Class Library assembly that targets .NET 4 has been removed from the NuGet package.

And lots more

TypeConverters, BigInteger, ISerializable and XmlDocument are now supported in .NET Core applications, there have been multiple improvements to JSONPath querying of JObject/JArray, dozens of typos have been fixed in Json.NET's documentation, and many, many bugs have been reported and fixed across every part of Json.NET.

Changes

Here is a complete list of what has changed since Json.NET 9.0 Release 1.

  • New feature - Added async read support to JsonReader
  • New feature - Added async write support to JsonWriter
  • New feature - Added async support for loading JObject and JArray
  • New feature - Added non-allocating parsing of double and decimal values
  • New feature - Added support for TypeConverters to netstandard1.0+
  • New feature - Added support for BigInteger to netstandard1.3+
  • New feature - Added support for ISerializable to netstandard1.3+
  • New feature - Added support for XmlDocument to netstandard1.3+
  • New feature - Added support for SerializableAttribute and NonSerializedAttribute to netstandard1.3+
  • New feature - Added ISerializationBinder
  • New feature - Added SerializationBinder properties to JsonSerializer and JsonSerializerSettings
  • New feature - Added TypeNameAssemblyFormatHandling
  • New feature - Added TypeNameAssemblyFormatHandling properties to JsonSerializer and JsonSerializerSettings
  • New feature - Added support for root object selector in JSONPath filters
  • New feature - Added support for multiple names in JSONPath scan filter
  • New feature - Added support for any combination of paths and values in JSONPath filter expressions
  • New feature - Added support for extension data names to NamingStrategy
  • New feature - Added ProcessExtensionDataNames flag to NamingStrategy
  • New feature - Added JsonWriter.AutoCompleteOnClose to control whether JSON is auto-completed on JsonWriter.Close
  • New feature - Added JsonReaderException constructor with path, line number, line position
  • New feature - Added JsonWriterException constructor with path
  • New feature - Added JsonReader.SetToken method overload with option not to update position array index
  • New feature - Added support for automatically calling single constructor on immutable structs
  • Change - Removed .NET 4 portable class library target from NuGet package
  • Change - Removed obsolete JsonConverter.GetSchema method
  • Change - Removed obsolete constructor from DefaultContractResolver
  • Change - Removed obsolete async methods from JsonConvert
  • Change - Removed obsolete OnDeserialized, OnDeserializing, OnSerialized, OnSerializing, OnError from JsonContract
  • Change - Removed obsolete JsonDictionaryContract.PropertyNameResolver
  • Change - Removed obsolete ConstructorParameters, OverrideConstructor, ParametrizedConstructor from JsonObjectContract
  • Change - Obsoleted TypeNameAssemblyFormat properties on JsonSerializer and JsonSerializerSettings
  • Change - Obsoleted SerializationBinder
  • Change - Obsoleted Binder properties on JsonSerializer and JsonSerializerSettings
  • Change - Obsoleted FormatterAssemblyStyle in non-full .NET targets
  • Change - Obsoleted Newtonsoft.Json.Bson (moved to new NuGet package)
  • Change - Improved constructor parameter binding on .NET Core and portable builds
  • Change - Improved error when attempting to convert root JSON object property to an XML attribute
  • Change - Changed exception thrown when parsing invalid Unicode escape sequence to JsonReaderException
  • Change - Changed StringEnumConverter.AllowIntegerValues to also reject reading integer strings
  • Change - Changed StringEnumConverter.AllowIntegerValues to also reject writing enum values with no name
  • Fix - Fixed JsonTextReader.ReadAsXXX methods not erroring on missing commas between values
  • Fix - Fixed error when serializing F# lists with F# 4.1+
  • Fix - Fixed StringEnumConverter reading specified enum names that contain a comma
  • Fix - Fixed using a TraceWriter with nullable bytes
  • Fix - Fixed deserializing null Regex values
  • Fix - Fixed deserializing DataTable with error handling
  • Fix - Fixed DynamicReflectionDelegateFactory creating typed value type constructors
  • Fix - Fixed deserializing with type naming and complex nested generic types
  • Fix - Fixed error when converting certain JSON to XML on .NET Core
  • Fix - Fixed error handling skipping reading the next object value
  • Fix - Fixed date XML precision when converting certain JSON to XML on portable builds
  • Fix - Fixed not serializing readonly properties as references if they have corresponding creator parameters
  • Fix - Fixed type name being written with nullable structs and TypeNameHandling.Auto
  • Fix - Fixed deserializing a duplicate dictionary key from a parameterized constructor
  • Fix - Fixed not erroring when deserializing incomplete JSON with a parameterized constructor
  • Fix - Fixed incorrectly parsing scan filter when name is quoted
  • Fix - Fixed return type for SByte and SByteNullable in JToken.ToObject
  • Fix - Fixed deserializing generic only IList types with a constructor override
  • Fix - Fixed null reference error with ReadAsBytes and an empty JSON object
  • Fix - Fixed StringEnumConverter when EnumMember defines members that differ only by case
  • Fix - Fixed serializing protected override properties
  • Fix - Fixed merging null with complex type and MergeNullValueHandling.Ignore
  • Fix - Fixed roundtripping double.MaxValue and float.MaxValue as dictionary keys
  • Fix - Fixed JsonValidatingReader not closing underlying reader
  • Fix - Fixed writing duplicate nulls to trace with TraceJsonWriter.WriteValue for object, Uri, byte[]
  • Fix - Fixed BsonWriter.WriteValue erroring for null Uri or byte[]
  • Fix - Fixed not calling nullable WriteValue overloads in TraceJsonWriter
  • Fix - Fixed serializer not throwing an error when there is a comment followed by additional content with CheckAdditionalContent
  • Fix - Fixed JObject/JArray Parse not throwing an error when there is a comment followed by additional content
  • Fix - Fixed deserializing non-string values in some XML nodes
  • Fix - Fixed converting XML to JSON when json:Array and xmlns:json attributes are used directly on the array's element
  • Fix - Fixed error when attempting to populate values into read-only collection after creating object from non-default constructor

Links

Json.NET GitHub Project

Json.NET 10.0 Release 1 Download - Json.NET source code and assemblies