Astro


I’ve updated this blog to use Astro, a Node.js-based static site generator. Hosting has also changed to GitHub Pages.

Benefits

  • The blog no longer runs on an ancient version of Orchard that I’m afraid to touch.
  • Free and reliable hosting for a static site on GitHub Pages.
  • Secured with HTTPS. Browsers will flag non-HTTPS sites as insecure.
  • General cleanup of content. Decades of different authoring tools (remember Windows Live Writer?), blog engines, domains, and hosts left a trail of broken images and badly formatted HTML. I vibe-coded a migration tool to convert HTML to Markdown and do its best to fix broken images and links.
  • Gain experience with Astro. We (Aspire team) are using it to build aspire.dev.
  • If I ever blog again, I can do it from the comfort of Markdown files in a Git repository.

Wait a minute... statue of liberty... that was our planet. You maniacs, you blew it up. Damn you! Damn you all to hell!

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.

.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.

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

Json.NET GitHub Project

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

.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

Json.NET GitHub Project

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