>> Hello, everyone. My name is James Newton-King. Today I'm excited to talk
to you about gRPC on.Net. The agenda for today's talk, first will give a
quick introduction to gRPC for anyone who is new to it. As part of that, I'll demo testing gRPC app using a testing
tool such as Postman. Then we'll take a look at what's
new on.Net 7 and then we'll include performance improvements and new feature called gRPC
JSON transcoding and gRPC support on Azure and how
it's approved in the past year. What is gRPC? It's a popular open-source remote
procedure called framework. RPC frameworks make it easy for
apps to talk to each other. Now, gRPC is run by the Cloud Native Computing
Foundation the CNCF. What Microsoft and.Net
team has done, is we've written a new implementation
of job essay that uses the latest and greatest features on.Net and we have
contributed to the CNCF. gRPC is cross-platform. It's supported by every
major programming language, be it C++, Java, Go, Node, Ruby, Python, C-Sharp, Rust, you name it, there's an
implementation for it. These are all interoperable
with each other. You could have an Xbox game version
and C++ call a gRPC server, and the Cloud version on.Net. They can happily talk to each other. gRPC is contract first. That means the messages
and methods and services, how to find in a contract
known as a Protofile, and that is then used to
drive code generation using tolling that the
gRPC project provides. gRPC it's not new, it was originally
open-source in 2015. But it's a union of two
modern technologies, HTTP/2 at the protocol and transport layer and then
Protobuf as it serialization technologies for producing very
small fast binary messages and also the contract format. Part of Office is the
language neutral syntax that you will find in protofiles. With that, let's demo build
on our very first gRPC app. What I'm going to do is come to Visual Studio and we'll
add a new project. We'll choose to create a
gRPC app from a template. We include a basic Hello World
gRPC template in the.Net ACK. This will create add
posted in ASP.Net Core with an example so it's setup, ready for us to use. We'll create this, and the first thing I'll do is
I'll just update the LogLevel, so we get a bit more logging
while I'm demoing stuff to you. Let's take a look at what
we can find in solution. We've got this greet.proto file this is the contract I
mentioned to you earlier, this is where messages are
defined, services are defined. You can think of the
contract is an interface, and then there's an implementation
for that interface. The implementation is
found in GreeterService. This will use all the types
defined to make greet.proto. This is where you place
your business logic. This is where you place the logic
to handle an incoming message. You can respond to it,
you can validate it, you can use it to cool
off to a database, set files to disk, and then eventually
return a response. Then finally we've got program.cs, this is a standard startup location
where everything's wide up. Let's start off by taking a look
at our GreeterService file. This is a standard C-Sharp class. We've got to construct a head, we doing a bit of DI
to initiate a logger, and we're not going
to use that today. Then we've got this SayHello method. You can think of a service as a controller and
NBC and then a method, gRPC method was I can action. This particular method takes a
request and returns HelloReply, so on that requests, we have a nine property. We're concatenating that with hello, we sending that back to a message and we're returning
it to the client. It's HelloWorld. We give it a name, it'll say hello to that name. But looking at this
type of this file, we have some types so that never
defined anywhere on our solution. We've got GreeterBase,
HelloReply, HelloRequest. Where are these types coming from? The answer to that
is code generation. If we go into the definition
of this GreeterBase file, we can see we've got
an abstract base class being generated for us. It's got this SayHello method, which is virtual, so
we can override it. Then we've got a whole
bunch of code to wire up route some serialization. It all looks ugly, but the beauty of code generation it's writing this code
so you don't have to. We can confirm that
it's still coming from code generation by
looking at the header. We can save this as auto-generated. It's coming from the
greet.proto file and has been generated by the
Google Protobuf compiler. Where is this being driven from? The answer to that is
this greet.proto file. This is where we're
defining the contract for the APIs that our
apps going to provide. In this case, we're
saying we're going to provide a service called Greeter. On that service we've
got to SayHello method, which takes request
or returns reply. Then we've got our name and message properties and these
are typed to be strings. But how does Visual Studio and the compilation know
to do the code generation? Let's wide up in our csproj file. I've got this Protobuf element
that references greet.proto, and then with specifying, we want server code generation. We want a service
base type that we can then implement and
I create a Service. An alternative value
here could be client. In case you want a strongly typed
client to call the gRPC service. Then we've also got
this package reference. This is bringing in the
gRPC server implementation along with the serialized
and the tooling. If we run the set and
then browse to it, we'll see what happens. Let's just open up our console app. This is standard kestrel login to let everything know it's running, and is launched on this port 7160. If we browse to this, we get this message
saying communication with gRPC endpoints must be made
through a gRPC client. Unlike Rust where you can
just navigate to a URL into a path and some
wrap parameters, maybe some query string values
and get back some JSON. With gRPC, both the
client and server need know about that greet.proto file, because it's contract first and our browser doesn't
know anything about it. Now there are a couple
of ways we could taste our server that
we've just created. We could create a.Net client
using that greet.proto file. But what I'm going to
show you today is using a testing tool called Postman
to invoke our server. Postman is probably or pretty
familiar to a lot of you, as always had great
support for invoking RESTful HTTP APIs and has all
kinds of advanced features. But recently it's added
support for gRPC requests. In Postman we can say
as new gRPC request, we can then specify
a URL that we want. This is what we just entered
up here on our browser. We're using HTTPS,
so click the lock. Then if we chose select method, we don't get the methods you get. We don't have SayHello on this
drop-down and that's because Postman store doesn't know
about that pesky contract file. We need to let it know
about greet.proto. Now we could choose to
import the greet.proto file. But what I'm going to do is
I'm going to set up something called gRPC server reflection. Server reflection is open
API for RESTful APIs. Open API is a JSON file. It's located on your server
and it has definitions about all the services that
your server provides. >> gRPC Server Reflection does
the exact same thing except other gRPC servers providing information about
other gRPC services. We want to set that
up on our server. There is excellent support
for a built-into gRPC in.NET, and I will show it
off to you right now. First thing we're going to do is
we're going to add a new package. This is the
"Server.Reflection" package. Then in our "Program.cs" file, which we haven't looked at yet, we're going to add a service. We're going to register
some services with DI. Just like we're registering gRPC, now we're registering some additional services
with gRPC reflection. Finally, we're going to register a map gRPC service in
our HTTP pipeline. Previously, GreeterService
was registered, so we were able to call
our implementation here. We also want to register
our reflection service. That's what we need to do.
If we now run our app again, and we go back to Postman, we can click "Try Again", and when we click that, Postman client goes off to
the server and downloads the available information
about potential services. We've got one service
here, and then one method. We can now start using those to invoke our gRPC service
from our client. We can verify that by taking
a look at the logs that get written by our Kestrel app. We can say a bunch of HTTP
requests have gone off to this "ServerReflection/Servers"
and it's downloaded Reflection Info, and then Postman has used that information and the client
to make a call available. Postman knows about the messages
that we send and receive, so we can click "Generate
Example Message" and then enter message
we want to send. Lets say,.NET Conf 2022. Although I'm entering Jason here, this is just a visual
representation, and Postman will convert
it to Protobuf when it sends it off to the server. We just click "Invoke", and we can see our
name specified here, went off to the server and
was concatenated with hello, and our server was invoked. Again, we can verify that by
taking a look at our server logs, we can see that our say
hello method was invoked, and it called off to
this "SayHello" server, so we got a result back. The great thing about gRPC
and Server Reflection is, once you have it set up, it's very productive
to work with it. If we want to add a new gRPC method, lets call it gRPC NewMethod.
Click "Save" there. Code generation will
automatically run, so we just need to
override our new method, and we'll just "Copy and Paste"
the previous implementation, and we'll just modify that slightly, "Say hello new method. Cool name" equals this. We "Run" our app. We go back to Postman, and we choose "Refresh". Our new method is
immediately available. We can choose it and
we can invoke it. That's how fast and iterative
and productive gRPC can be by combining features
like contract first, code generation, and tooling
with gRPC Server Reflection. A quick overview of
what we just did. We created a server. We set up server reflection, only took a couple of seconds. Then, we configured our testing
tool to use that reflection. Usually this is just as simple
as entering that address. The endpoint for server
reflection is known, so tooling will just go off
and kick servers available, and if it is, it will just
automatically use it. Now, I demoed using Postman. Now, Postman has a lot of features, some of them are commercial, so keep that in mind
if you want to use it. An alternative free open source tool is something called gRPC Web UI. If you want to use the command line, gRPCurl lets you invoke gRPC services from the command
line and get responses back. Let's talk about what's
new in gRPC for.NET 7. Every year we try to
make gRPC faster, and we've made some great
improvements in.NET 7. Now, gRPC runs on HTTP/2, so high performance and Kestrel's
HTTP/2 stack is critical. A long known issue to
the ASP.NET Core team is a bottleneck when writing a HTTP/2 result or response
on a busy connection. Now the way HTTP/2 works is
there are multiple requests running in parallel simultaneously
on one TCP connection, and this is called multiplexing. However, only one thread can
write to a connection at a time. That means we need to limit
access to one thread, which was previously done
with a simple C# lock. Now, locks are a great choice for thread safety a lot of the time, but in this situation, the lock had a lot of contention, there were dozens of
threads fighting over it, and this was hurting performance. The way I like to imagine it is
perhaps there's a small door, and there are dozens
of people who are trying to get through
it simultaneously, and they're all pushing and
shoving each other out of the way, knocking each other down. That's a very inefficient
and wasteful process. What we did in.NET 7 is we switched
that lock to unset the IQ. Instead of fighting over a lock, threads would now line up
in an orderly fashion, place some work on the queue, potentially go off and do other
work while they're waiting, and then get notified
that the write is complete and they can resume
working with the request. This CPU re-architecture saved CPU cycles from fighting
over that lock and better utilize machine resources. Now in a server streaming benchmark, we saw an 800 percent increase in request per second
and after this change. Now this particular benchmark really stresses that lock is probably
a worst case scenario, but even in more typical
gRPC and HTTP/2 usage, we still notice a nice improvements
after this change in.NET 7. Another improvement is
HTTP/2 upload speeds, they're now much
faster when uploading large messages and there is latency. HTTP/2 back-pressure was limiting upload speeds when there's latency. The reason for that, is the client would send a
burst to database server, the server would
say, hey, slow down, I can only handle so much data. The server will then
process that data and then send a notification to the client
that they can resume sending. Unfortunately because of latency, that means there is a pause
when sending or receiving data. You can imagine your data being sent in bursts and the
start-stop fashion. What we did in.NET 7 is
we increased the buffer sizes to find a bit of balance between memory
usage and throughput. Previously, uploading
100 megabyte file in.NET 6 would take
about 27 seconds. In.NET 7 there is a
six-fold improvement, now it's just a bit
over four seconds. Finally, I'd like to
talk about a.NET gRPC perfomance results benchmark
from a community run benchmark. Thanks to the great
improvements in.NET 7 from low-level API improvements
and the BCL improvements, to JIT improvements, to profile guided optimization, all the way up to major re-architectures
in our HTTP/2 layer,.NET performance now meets and even exceeds really fast
frameworks like Go, C++, and Rust when it
comes to gRPC performance. I think this is the real testament to the performance you can get out of.NET and also the quality
of.NET's gRPC implementation. >> gRPC JSON transcoding is a major new productivity
feature in.NET 7. It's an extension for gRPC that
allows a service to act as both a gRPC API and as a
RESTful API at the same time. JSON transcoding is useful for
anyone who wants to provide both types of APIs to their clients without
having to build them twice. You don't want all that duplication of building things once with REST, once we've gRPC and then having
to maintain them forever, wouldn't it be great
if you could just do it once and it worked for both. That is what gRPC JSON
transcoding allows. Let me demo this amazing feature. We'll take our previous
app and we'll extend it to include gRPC JSON transcoding. Again, we're going to add a new
package to our csproj file. We're going to add the gRPC
JSON transcoding package. Then in our program.cs file we're
going to add a new service. Then we're going to
add a couple of new proto-files to our solution. The reason why I'm adding these
new proto-files and these are located and this are
annotation.proto and http.proto. The reason we're adding
these new profiles, as we want to add some
annotations to say hello method. To specify how it maps
to a RESTful API. Like we need to specify a
route to be able to call this. After including these files, we then want to import one of them. We're going to call import
Google APIs, annotations.proto. Then finally after that, we'll just comment out
the previous method. We're going to add
the annotation to it. The annotation as this particular
bit of code down here, you can think of an
annotation like an attribute, and.NET as met data we're
adding to the call. In this case, the metadata
were adding is we're saying, if you want to invoke
this call with HTTP, this is the route
you use to call it. It is a get route as V1 greeter, then this route perimeter of name. This name route parameter, it maps to the request property. Name down on hello requests. Whatever value we enter here, will get mapped down to here
and it will be used when we invoke gRPC service by REST. Theoretically, if I've done everything just right,
we'll compile our app. That succeeded. Lets
launch it again. We'll come back to our browser. Previously, we got this warning saying we
need to use a gRPC Client. Let's see if we can now use REST. We'll type in V1 greeter
and then.NET conf 2022. Success, we can say
our git request as now returning JSON from our
protobuf gRPC endpoint. We can verify that by
taking a look at the logs. Our requests came in. It was a get request to that
URL we just specified at, got mapped to that gRPC endpoint. Then it returned a response, in this case the response was JSON rather than protobuf.
That's pretty cool. This is just a very simple
example of an annotation. You can also support post, you can support route parameters, you can support binding
query parameters, incoming JSON bodies, all kinds of verbs. Get, PUT, post, delete, you name it, you can do it. Once you have JSON
transcoding setup, it's very easy to add new methods. We can just add greeter new method and we're
already set up and ready to go. REST is great. The thing which takes RESTful APIs to the
next level is open API. What I'm going to show
now is heading open API to our transcoded methods. Again, coming back to Csproj
will add a new NuGet package. This one has gRPC.Swagger. We'll add some new services
to our startup file, our program cs file. We'll add some swagger middleware,
some swashbuckle middleware. This middleware will be familiar
to anyone using swashbuckle. We're going to register
UseSwagger and then UseSwaggerUI. Now if I launch this and come
back to it with the browser, I can now navigate to swagger and
I get the Swagger UI experience. I can see my two
endpoints are showing up. I can come in here and I can invoke it just like
you usually would. Flow.net and click "Execute"
and we get back our message. Also if we take a
look at swagger.JSON. As just standard swagger
except instead of talking to a restful endpoint Russian
with minimal API or MBC, in this case we've got a
RESTful API version with gRPC. That's gRPC dress and transcoding. It's a very cool feature, but also very powerful, simple, easy to use and a great
productivity bone if you want to serve both gRPC and
REST at the same time. Let's do a quick overview
of how it works. Imagine we've got a gRPC client
that's talking protobuf. We use a Google.protobuf, deserialize to our hello request. Then we invoke that
method metronome. We've got a RESTful API. Client that's got a custom route, which has got a route parameter. We bind that hello request, we invoke the same method,
and we're good to go. Even though I just showed
off invoking it with wrist, there's no reason
you can't still keep using protobuf to use
it at the same time. It's not one or the other,
it's both at the same time. All right, finally, I like to
talk about gRPC and Azure. I'm happy to say gRPC is now fully
supported on Azure App Service. This request was ASP.Net because most commented
on and voted on issue. It's great to be able to get
that data market is closed. At the actual work to do this
was a joint project between the Azure Service tame
and adult knit team. What we did together was we replaced one pops of the Azure App
Service infrastructure, this thing called a app
service front-end role. We replaced it with a Yap, which is a proxy
toolkit that runs on top of ASP.NET Core and in
this case we're using Kestrel, it means that we can
fully support gRPC because Kestrel has
great support for HB2. There was an 80 percent
throughput improvement, which is great to potentially, we can decommission the
number of proxies we have create greener data centers by
using less resources and energy. Also, because Kestrel has
great support for HB3, provides a gateway for future features get added
to Azure App Service. That's all I have time to
talk to you about today. There's great
documentation available for gRPC on our Docs website. Everything I've talked about, including testing with gRPC, civil reflection and JSON
transcoding as documented here. There are also many
examples available on the gRPC.net repository, including gRPC reflection
and transcoding. Thank you everyone
for joining us today. I hope you are all excited
about gRPC on.NET, and I can't wait to
see what kind of apps you make. Back to the studio.