Project bedrock is about further decoupling the components of Kestrel so that we can use it as the foundation for our non-http networking stack.
We want to build on the primitives, patterns and cross cutting concerns that exist today in ASP.NET Core applications. The goal is to enable higher level frameworks (like SignalR or WCF and even ASP.NET Core itself) to build on top of abstractions that don't tie them to a specific connection implementation (OWIN for Connections). As an example, it allows SignalR to run both on top of TCP or Websockets without having to understand what the underlying transport is. We also want to enable building raw low level protocol servers to handle things like MQTT for IOT scenarios.
There are 3 main actors in this server side programming model:
IFeatureCollection
that implements the underlying connection semantics. In short, transports provide a concrete implementation of the ConnectionContext
that flows through the dispatcher to the application. IConnectionBuilder
for a particular binding relevant to the transport. For example, the http dispatcher will expose the IConnectionBuilder
based on a particular route, while the TCP dispatcher will expose an IConnectionBuilder
based on an ip address and port.At the center of this work is a new set of primitives that represent an underlying connection:
```C#
public abstract class ConnectionContext
{
public abstract string ConnectionId { get; set; }
public abstract IFeatureCollection Features { get; }
public abstract IDuplexPipe Transport { get; set; }
public abstract IDictionary<object, object> Items { get; set; }
}
```C#
public interface IConnectionIdFeature
{
string ConnectionId { get; set; }
}
```C#
public interface IConnectionTransportFeature
{
IDuplexPipe Transport { get; set; }
}
```C#
public interface IConnectionItemsFeature
{
IDictionary<object, object> Items { get; set; }
}
The ConnectionContext
is the "HttpContext" of the connection universe. It's an abstraction that represents a persistent connection of some form. This could
be a TCP connection, a websocket connection or something more hybrid (like a connection implemented over a non duplex protocol like server sent events + http posts). The feature collection
is there for the same reason it's there on the HttpContext
, the server or various pieces of "middleware" can add, augment or remove features
from the connection which can enrich the underlying abstraction. The 2 required features are the IConnectionTransportFeature
and the IConnectionIdFeature
.
Next, we introduce the abstraction for executing a connection.
```C#
public delegate Task ConnectionDelegate(ConnectionContext connection);
The `ConnectionDelegate` represents a function that executes some logic per connection. That `Task` return represents the
connection lifetime. When it completes, the application is finished with the connection and the server is free to close it.
In order to build up a pipeline, we need a builder abstraction and a pipeline. The `IConnectionBuilder` (similar to the `IApplicationBuilder`) represents
a sockets pipeline. The middleware signature is `Func<ConnectionDelegate, ConnectionDelegate>` so callers can decorate the next `ConnectionDelegate`
in the chain similar to http middleware in ASP.NET Core.
```C#
public interface IConnectionBuilder
{
IServiceProvider ApplicationServices { get; }
IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware);
ConnectionDelegate Build();
}
These are the fundamental building blocks for building connection oriented applications. This will live in the Microsoft.AspNetCore.Connections.Abstractions package.
This refactoring will enable a few things:
IConnectionBuilder
instead. This means that things like TLS , windows auth and connection logging can be separate middleware components.Transports are responsible for providing the initial IFeatureCollection
implementation for the connection and providing a stream of bytes to the application.
Today we have 2 transport implementations that reside in Kestrel, a System.Net.Sockets and libuv implementation. We plan to keep these 2 because they both offer different sets of features. Libuv can listen on file handles, named pipes, unix domain sockets, and tcp sockets while System.Net.Sockets just has a tcp socket implementation (and unix domain sockets)
We want to enable people to build websocket based frameworks without dealing with low level details like connection management and buffering. As such, we will provide a web socket transport that exposes these connection primitives. This currently lives in the Microsoft.AspNetCore.Http.Connectons package.
SignalR in the past has provided multiple transport implementations historically for browsers that didn't support websockets. These are not full duplex transports but are implemented as such by round tripping a connection id over http requests. We will also provide implementations transports for long polling and server sent events. These implementations will require a special client library that understands the underlying non-duplex protocol. These currently lives in the Microsoft.AspNetCore.Http.Connectons and Microsoft.AspNetCore.Http.Connectons.Client packages.
QUIC is a quickly emerging standard that is looking to improve perceived performance of connection-oriented web applications that are currently using TCP. When QUIC comes around we'll want to be able to support it with the same abstraction.
ASP.NET Core will serve as the basis for our HTTP dispatcher. There will be a RequestDelegate
implementation that serves as the dispatcher built on top of routing.
```C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using SocketsSample.EndPoints;
using SocketsSample.Hubs;
namespace SocketsSample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddConnections();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseConnections(routes =>
{
// Handle mqtt connections over websockets on the /mqtt path
routes.MapWebSocket("mqtt", connectionBuilder =>
{
connectionBuilder.UseMQTT<MQTTHandler>();
});
// Handle SignalR chat connections on the /chat path (multiple transports)
routes.MapConnections("chat", connectionBuilder =>
{
connectionBuilder.UseSignalR<Chat>();
});
});
}
}
}
### Kestrel
Kestrel was originally built as an http server for ASP.NET Core. Since then it's evolved to into a bunch of separate components but has still been hyper focused on http scenarios. As part of this work, there are further refactorings that will happen and kestrel will serve as the generic sockets server that will support multiple protocols. We want to end up with layers that look something like this:
- **Microsoft.AspNetCore.Server.Kestrel.Core** - Dispatcher implementation
- **Microsoft.AspNetCore.Server.Kestrel.Https** - Deprecate this package in favor of (**Microsoft.AspNetCore.Protocols.Tls**)
- **Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions** - Abstractions for plugging different transports into kestrel
- **Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv** - Libuv transport (tcp, pipes, unix sockets)
- **Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets** - System.Net.Sockets transport
- **Microsoft.AspNetCore.Server.Kestrel** - Meta package for ASP.NET Core to avoid breaking changes
We should introduce the following packages:
- **Microsoft.AspNetCore.Protocols.Http** - Http `ConnectionDelegate` middleware
- **Microsoft.AspNetCore.Protocols.Http2** - Http2 `ConnectionDelegate` middleware (do we merge Http and Http2?)
- **Microsoft.AspNetCore.Protocols.Tls** - TLS `ConnectionDelegate` middleware
Here's what the Kestrel for TCP could look like wired up to the generic host:
```C#
var host = new HostBuilder()
.ConfigureServer(options =>
{
// Listen on (*, 5001), then get access to the ISocketBuilder for this binding
options.Listen(IPAddress.Any, 5001, connectionBuilder =>
{
// This is the SignalR middleware running directly on top of TCP
connectionBuilder.UseHub<Chat>();
});
// Listen on (localhost, 8001), then get access to the ISocketBuilder for this binding
options.Listen("localhost", 8001, connectionBuilder =>
{
// Accept connections from an IOT device using the MQTT protocol
connectionBuilder.UseMQTT<MQTTHandler>();
});
options.Listen("localhost", 5000, connectionBuilder =>
{
// TLS required for this end point (this piece of middleware isn't terminal)
connectionBuilder.UseTls("testCert.pfx", "testPassword");
// ASP.NET Core HTTP running inside of a Connections based server
connectionBuilder.UseHttpServer(async context =>
{
await context.Response.WriteAsync("Hello World");
});
});
})
.Build();
host.Run();
It would be really cool to have something equivalent to Transports on the client side as well, so that you could basically have a more abstract HttpClient with a switchable underlying transport mechanism
@davidfowl what do you think about performance hit after introducing such an abstraction?
@davidfowl Great work! I only have one concern...
Since the abstractions will not be aspnet-only, don't you think instead of using Microsoft.AspNetCore.Sockets.Abstractions
we could use just Microsoft.Sockets.Abstractions
for the core abstractions?
I agree that Kestrel and AspNet abstractions should have the respective names, but I think those abstractions are very... Abstracted and like you mentioned, are there to plug and manage very low level primitives.
Great work! Looking forward for it! :)
Similarly, Microsoft.AspNetCore.Sockets.Tls => Microsoft.Sockets.Tls would make sense, but I want the feature more than a name.
@davidfowl What if we needed to read data from USB or serial ports instead of sockets, would that be a scenario where we would have to create a specific Transport?
@dls314
but I want the feature more than a name.
Me too. But I would like to have the package semantics more _clear_. Better to suggest it now then after the release :)
@shaggygi
What if we needed to read data from USB or serial ports instead of sockets, would that be a scenario where we would have to create a specific Transport?
I guess that is the purpose of the transports.
At least that is what I understood from this part:
Transports provide an implementation of an IFeatureCollection that implements the underlying connection semantics.
Does that mean you could push message transport (msmq, rabbitMq, kafka) further down the stack? I suppose those transports would sit at the same abstraction level as SignalR....
@aL3891
It would be really cool to have something equivalent to Transports on the client side as well, so that you could basically have a more abstract HttpClient with a switchable underlying transport mechanism
I've been thinking about a client story as well that gels with this. SignalR has the beginnings of it, but I left it out of this spec.
@galvesribeiro
Since the abstractions will not be aspnet-only, don't you think instead of using Microsoft.AspNetCore.Sockets.Abstractions we could use just Microsoft.Sockets.Abstractions for the core abstractions?
This is something we've struggled with in the past, but AspNetCore will mean more than just our existing HTTP stack, it's the server stack in general. We won't be putting anything in the root namespace (i.e. Microsoft.Sockets). Naming needs some work though, sockets isn't great.
@shaggygi
@davidfowl聽What if we needed to read data from USB or serial ports instead of sockets, would that be a scenario where we would have to create a specific Transport?
Yes that would be a transport.
@no1melman
Does that mean you could push message transport (msmq, rabbitMq, kafka) further down the stack? I suppose those transports would sit at the same abstraction level as SignalR....
I don't fully understand the question. A transport can be anything but I wouldn't start implementing HTTP over a message bus 馃槃 .
I was just thinking that you could make the message queue as the transport, much like you would with signalR, then you're abstracted away from mechanism.
@davidfowl well, if now AspNetCore will become a reference to all the server technologies in .Net and not just web stack anymore, them I'm all for it! :)
I am thoroughly upset by the complete lack of references to The Flintstones in this issue.
if now AspNetCore will become a reference to all the server technologies in .Net and not just web stack anymore, them I'm all for it! :)
Async Serving Power
@no1melman
I was just thinking that you could make the message queue as the transport, much like you would with signalR, then you're abstracted away from mechanism.
SignalR didn't make a message queue the transport, those were fundamentally different abstractions.
@davidfowl
Naming needs some work though, sockets isn't great.
Microsoft.AspNetCore.Bungholes
I really wouldn't mind a better name, shorter and without confusion to old full framework tech for AspNetCore. Especially if it's going to be the reference name for the server stack in general.
Regarding the name, I agree that, considering how low-level and ubiquitous this API would be, removing "AspNetCore" is a good idea.
I think the most fitting keyword to describe it is "Network".
So, maybe Microsoft.Network?
Or just Microsoft.Net (like System.Net) but it sounds like "Microsoft .NET" :)
Microsoft.Network
Well... its wouldn't be strictly true the Transport abstraction is quite flexible; so you could write a stdin/out or filestream Transport and pipe to the program or read and write http from filestream. Or examples earlier it could be from usb or serial port...
Transport is like a driver
Microsoft.Bedrock? :)
Its a cool name imo
It could also be Microsoft.Transport, also fits pretty well conceptually
Network is also a fairly generic term outside of computer science. One of its definition is: "A group or system of interconnected people or things."
So, when you connect something with something else, you create a network.
It may be nice to identify connections by T instead of string. Perhaps IConnectionIdFeature
My guess is that the ConnectionId is a string to simplify passing it around.
If you make it a T, you will need to provide a Comparer (like you mentioned) but also a Serializer. That's a lot of complexity.
Can you give a compelling scenario where it would be much better to use something else than a string?
It may be nice to identify connections by T instead of string. Perhaps IConnectionIdFeature w/ properly comparable T?
Make sense... Would avoid allocations with unnecessary .ToString()
calls.
Socket
generally has a very focused use; could it be more general like Connection
? (Also matching the ConnectionContext
) of which Socket
can be of of the many Connection types.
e.g.
public delegate Task ConnectionDelegate(ConnectionContext connection);
public interface IConnectionBuilder
{
IServiceProvider ApplicationServices { get; }
IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware);
ConnectionDelegate Build();
}
I like @benaadams Connection suggestion. What about namespace System.IO.Connection?
Can you give a compelling scenario where it would be much better to use something else than a string?
I'm not sure I can. My thought is that the connection id might often be used as a hash key and with some T you could get away without a string.GetHashCode
call.
If not T how about going to int?
I like @benaadams Connection suggestion. What about namespace System.IO.Connection?
Avoid the eponymous namespace's class ambiguity with System.IO.Connections?
Can you give a compelling scenario where it would be much better to use something else than a string?
and
My thought is that the connection id might often be used as a hash key and with some T you could get away without a string.GetHashCode call
If you are going to use a Hash function with this value and you are using your own T
type as the Id, its is your responsibility to override GetHashCode()
like in everywhere else you would and want to avoid collisions. I don't see why we need enforce an string
, int
, or whatever type.
Why don't let the user use whatever type they want?
Also yeah, @benaadams suggestion looks great. By using Socket
the user expect a very specific semantics while Connection
is more abstract and fits better with the context of those abstractions.
Can you give a compelling scenario where it would be much better to use something else than a string?
One could argue that byte[] would be better in some cases like when you're dealing with ip addresses, if not T, maybe that's an option
Another reason why something other than a string would be nice is if you have multiple components to the connection (like an ip and port), I mean you can encode that as a string of course but then that has to be parsed, if it where possible to have T as the "adress" It would open up to a lot of flexibility
T ConnectionId
makes it a bit generically nasty
public abstract class ConnectionContext<T>
{
public abstract T ConnectionId { get; set; }
public abstract IFeatureCollection Features { get; }
public abstract IPipe Transport { get; set; }
}
public interface IConnectionIdFeature<T>
{
T ConnectionId { get; set; }
}
public interface IConnectionTransportFeature
{
public abstract PipeFactory PipeFactory { get; set; }
public abstract IPipe Transport { get; set; }
}
public delegate Task ConnectionDelegate<T>(ConnectionContext<T> connection);
public interface IConnectionBuilder<T>
{
IServiceProvider ApplicationServices { get; }
IConnectionBuilder Use(Func<ConnectionDelegate<T>, ConnectionDelegate<T>> middleware);
ConnectionDelegate<T> Build();
}
Also there is no compile time enforcement making the T
in IConnectionIdFeature
agree with anything else; even though you now need it everywhere?
Also "other things of t" can be added via features like IIPAddressFeature
It's going to be a string. It's simpler and we already use strings for things like the request id.
If IConnectionTransportFeature
and IConnectionIdFeature
are required features of ConnectionContext
, why duplicate the properties ConnectionId
and Transport
?
See the design of HttpContext
. The properties that are hoisted to the top level are the most commonly used one that will apply to most connection implementations. It's a convenience, nothing more. Under the covers, the implementation of those properties directly expose the feature properties.
@NinoFloris
I really wouldn't mind a better name, shorter and without confusion to old full framework tech for AspNetCore. Especially if it's going to be the reference name for the server stack in general.
You meant for ASP.NET not, AspNetCore right? There's a point where you end up going from pure connection abstraction to ASP.NET Core's http stack (see the "ASP.NET Core HTTP running inside of ASP.NET Core Sockets" sample). What would you call the bridge package that is the HTTP "connection" middleware.
Maybe a brand name would solve the naming problem 馃槃.
@benaadams
Socket generally has a very focused use; could it be more general like Connection? (Also matching the ConnectionContext) of which Socket can be of of the many Connection types.
I like it. I'm not sure I like the assembly name yet though. Microsoft.AspNetCore.Connections
? It'll grow on me.
It's going to be a string. It's simpler and we already use strings for things like the request id.
Also makes it simpler to work with Activity of System.Diagnostics e.g. HttpCorrelationProtocol; byte[]
you'd have realloc back to string
I like it. I'm not sure I like the assembly name yet though. Microsoft.AspNetCore.Connections? It'll grow on me.
Its the interpreting layer, maybe:
Microsoft.AspNetCore.Protocols
?
Microsoft.AspNetCore.Protocols.Http1
- Specific Http1, Http1.1 protocol
Microsoft.AspNetCore.Protocols.Http2
- Specific Http2 protocol
Microsoft.AspNetCore.Protocols.Http
- Merged Http1+2 (negotiated)
Microsoft.AspNetCore.Protocols.Tls
- TLS SocketDelegate middleware
Microsoft.AspNetCore.Protocol.Abstractions
Microsoft.AspNetCore.Protocol.Http
Microsoft.AspNetCore.Protocol.Tls
@davidfowl I like that layout the best of all, but for consistency I think it should be "Protocols", like most other namespaces, e.g.
System.Collections
System.DirectoryServices.Protocols
System.Web.Services.Protocols
Some of the new libs have Protocol at the end, for a Protocol space for a singular purpose, but if we're going to have many here: plural feels far more correct to me. List for comparison: https://apisof.net/catalog
@davidfowl yes I meant ASP.NET is getting pretty overloaded. What's the actual web framework part of it called these days? The ASP.NET Core 2.0 Web Framework
?
Doing a search for ASP.NET 2.0 is great archaeological fun though:
https://www.google.com/search?q=asp.net+2.0
It bothers me the name ASP.NET Core is 2 parts platform identifier (.NET and Core) and just one part 'product name' which instead of actually being a good name for a server stack is just an acronym reference to ancient tech from the nineties, it's long and hard to type, age is showing.
Now we can all guess the marketing department loves the brand recognition ASP.NET has with the old guard (meaning no offence), and I get that by using the same name might help those people find the transition to .NET Core. However overloading it more and more is doing nobody a service.
I'm exactly missing the few brand/codenames I can reference to people that directly correspond to a specific piece of the bigger stack. Not always having to refer to the long overloaded umbrella brand name attached to a precise description of said piece of the stack.
Kestrel is a very successful example of exactly that.
Sorry for the hijack, is there any designated place where I can put this on the table?
Sorry for the hijack, is there any designated place where I can put this on the table?
Sure, file an issue on aspnet/Home, but I gotta be honest, I'm not sure it'll change anything. The fact that ASP.NET Core is even called ASP.NET Core should be a clear sign of that. It's possible we could move some things under the Microsoft.Extensions
umbrella since there's other prior art for that.
Sure, file an issue on aspnet/Home, but I gotta be honest, I'm not sure it'll change anything.
I won't have any illusions ;) I know a name change is never going to happen, all I'm asking for is a bit more specificity underneath that bulging umbrella.
Maybe ASP.NET (Core) can stay as the umbrella name, but assemblies can be called differently. Kestrel is a good example of that.
It is just difficult to find names like that, so you may end up defaulting to Microsoft.AspNetCore.XXX as a safe choice.
But I'm all for these unique names. They are distinctive and easy to research/reference.
Maybe ASP.NET (Core) can stay as the umbrella name, but assemblies can be called differently. Kestrel is a good example of that.
No disagreement there.
It is just difficult to find names like that, so you may end up defaulting to Microsoft.AspNetCore.XXX as a safe choice.
Likely, the latest suggestion of Protocols is what I like the most so far.
But I'm all for these unique names. They are distinctive and easy to research/reference.
You mean a name like kestrel but the represents these lower layers. Bedrock 馃槃 might be it, but that'll lead to too many Flintstones references.
I don't see any issue with the kestrel stuff continuing to remain in the AspNetCore nomenclature as it's very much owned by the ASP.NET team and part of their platform. This change might decouple the components of Kestrel a bit more to add another layer of abstraction, but it's still very much rooted in the same team/platform.
I see the Microsoft.Extensions nomenclature being something that spans usage by frameworks from multiple teams, whether its web, console, Windows app, or library.
My suggestion would be to move anything that is platform/framework agnostic into the Microsoft.Extensions.* nomenclature where possible and where it makes sense.
On a side note, I actually wish the host providers used to bootstrap web apps wasn't in the AspNetCore arena as there is a service host option, which to me seems more like a platform specific implementation as it solely requires a windows system to operate. Would be nice if it was a true abstraction were there could be systemd and upstartd implementations under them. Seems like those would be more relatable to the .NET ecosystem and be part of System.* instead. Feels weird using the service host for a Windows service when it's not web based.
On a side note, I actually wish the host providers used to bootstrap web apps wasn't in the AspNetCore arena as there is a service host option, which to me seems more like a platform specific implementation as it solely requires a windows system to operate. Would be nice if it was a true abstraction were there could be systemd and upstartd implementations under them. Seems like those would be more relatable to the .NET ecosystem and be part of System.* instead. Feels weird using the service host for a Windows service when it's not web based.
Microsoft.Extensions.Hosting is coming. But that's another spec and another code name (if I can think one up). See the tease as part of the 2.0 release https://github.com/aspnet/Hosting/tree/dev/src/Microsoft.Extensions.Hosting.Abstractions
I've updated the spec with the new names.
@davidfowl for hosting project codename/spec, I like Project Hostess. As in Hostess CupCake 馃槃
Where can I find the spec?
Based on the description: "OWIN for Connections", what about calling this OCIN?
"Open Connection/Communication Interface for .NET"?
Namespace: Microsoft.Ocin.
I almost left that part out but thought it was a good analogy. I'd rather not call it OWIN because ASP.NET Core has abstractions that aren't OWIN, and it'll be the same for this.
But I suggested "OCIN", that's a different name :)
ONIN (replace connection with networking) sounds better but I still don't like the connotation.
@davidfowl
Naming needs some work though, sockets isn't great.
We are talking about different kinds of client-server communication, so why not Microsoft.AspNetCore.Communication
.
Hi, you mentioned libuv/IOCP and obviously plain old socket, are you thinking of using RIO?
Thanks.
@mnns that is in the works, (though no official time plan) check out https://github.com/dotnet/corefxlab/tree/master/src/System.IO.Pipelines.Networking.Windows.RIO and https://github.com/dotnet/corefxlab/tree/master/samples/System.IO.Pipelines.Samples
@wholroyd What kind of abstractions do you want to better support systemd/upstart?
We have a guide that demonstrates how to use systemd to keep your asp.net core app running and manage logs. In 2.0.0, we added KestrelServerOptions.UseSystemd() to support systemd socket activation. As for graceful shutdown, systemd sends a SIGTERM AFAIK which is handled by Hosting.
I'm not trying to claim we couldn't do more or provide better abstractions. I'm just interested in what your ideas are.
@halter73 Wasn't aware of KestrelServerOptions.UseSystemd()
. The part I was referencing was the fact that there is a service host (at https://github.com/aspnet/Hosting/blob/dev/src/Microsoft.AspNetCore.Hosting.WindowsServices/WebHostService.cs), but it's framework specific (IWebHost
) and it's using ServiceBase
(Windows).
I like the hosting entrypoint concept used in the library, I just wish that it was abstracted enough to be framework agnostic (more like IHost
- AspNetCore could then abstract it further to IWebHost
) and become platform agnostic (non-Windows). I guess it would mean a change to .NET itself to make ServiceBase to be usable on non Windows systems - hook into Systemd/Upstartd/Windows as necessary.
Make sense?
I think that makes sense. Implementing methods like ServicBase.OnStop
or IHost.OnStop
seems a lot easier than writing stuff like this yourself.
I can open an issue to request it. Should it go to dotnet/netstandard? @halter73
@wholroyd give it a few days. I'm going to publish a spec soon.
@davidfowl do you think the Kestrel GitHub repo will be renamed to just KestrelServer after the new abstraction stuff is released?
@shaggygi sure
As a consumer, if I pull in Microsoft.AspNetCore.Protocols.Http
I would personally expect to have http 0.x through to http2 and beyond. Wouldn't mind it being a meta package to allow more advanced use cases (eg: my service only supports http2). Merging would make for a nicer experience to newbies (and less confusing), imo.
Looking forward to seeing how AMQP fits into this in the future (generically, not tied to RabbitMQ etc)
Naming needs some work though, sockets isn't great.
if it is about transport abstraction you should name it:
Microsoft.AspNetCore.Transport(s)
@aL3891 I now think we need to support clients as well.
I just noticed that this was moved to v2.2.
But how will this be compatible with the upcoming SignalR (with ASP.NET 2.1)?
There are a lot of overlaps between Bedrock and SignalR, so it would be ideal for them to share some abstraction layers.
Edit: For example, they both define a ConnectionContext
class which does basically the same thing.
And by "SignalR", I mean the lower-level libraries that are part of the SignalR repo, like Microsoft.AspNetCore.Sockets.Abstractions.
@MuleaneEve that's intentional. The plan is to use protocol abstractions in SignalR and remove sockets.abstractions.
We made some decisions today:
Microsoft.AspNetCore.Connections.Http - Has the HttpConnectionHandler (today this is internal in Kestrel)
Microsoft.AspNetCore.Connections.Tls - TLS connection middleware
Microsoft.AspNetCore.Connections.Logging - Logging connection middleware
Microsoft.AspNetCore.Protocol.Abstractions -> Microsoft.AspNetCore.Connections.Abstractions
Move EndPoint to Connections.Abstractions and rename it to ConnectionHandler.
C#
public abstract ConnectionHandler
{
Task OnConnectionAsync(ConnectionContext connectionContext);
}
Considering how close we are from the 2.1 release, this is probably the best solution.
To be clear, does that mean that the Connections layer here and Sockets layer in SignalR will also be internal for now?
By the way, I like the name _Connections_.
To be clear, does that mean that the Connections layer here and Sockets layer in SignalR will also be internal for now?
No, it will be public.
Ok. Have you looked at the peer-to-peer sample that I published?
I hope such scenarios will be supported.
@KPixel yea I've seen it but TBH I don't see how you plan to use the connection abstractions.
Are the Connections & Sockets layers (mostly) final?
I will rewrite this sample and my app using them to see where I get stuck.
Are the Connections & Sockets layers (mostly) final?
It's all connections now, and the client API isn't final. I feel pretty confident that the ConnectionContext API won't churn much. We're going to be adding more things to it and renaming packages and namespaces though.
@KPixel I took a deeper look and that looks pretty interesting, there are a couple of issues:
@davidfowl Thanks for taking a look.
I'm also investigating the new layers... Tomorrow, I will create a new issue to continue this discussion.
```C#
public abstract class ConnectionContext
{
public abstract string ConnectionId { get; set; }
public abstract IFeatureCollection Features { get; }
public abstract IDictionary<object, object> Items { get; set; }
public abstract IDuplexPipe Transport { get; set; }
}
public interface IConnectionBuilder
{
IServiceProvider ApplicationServices { get; }
IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware);
ConnectionDelegate Build();
}
public delegate Task ConnectionDelegate(ConnectionContext connection);
public abstract ConnectionHandler
{
Task OnConnectionAsync(ConnectionContext connectionContext);
}
### Remaining 2.1 work
- Figuring out how to merge use `ConnectionContext` as the client abstraction (SignalR needs this).
- Adding support for aborting the connection (a first class Abort method) semi related to the first bullet https://github.com/aspnet/KestrelHttpServer/issues/2054
### 2.2 and beyond
- Nothing specifically planned at this layer besides adding more feature interfaces
## Kestrel specific transport layer (pubternal in 2.1)
- **Microsoft.AspNetCore.Kestrel.Transport.Abstractions** - Required to implement a kestrel transport
- **Microsoft.AspNetCore.Kestrel.Transport.Libuv** - Libuv implementation
- **Microsoft.AspNetCore.Kestrel.Transport.Sockets** - Sockets implementation
3rd party implementations:
- **RedHatX.AspNetCore.Server.Kestrel.Transport.Linux** - https://github.com/tmds/kestrel-linux-transport - Native epoll transport for linux
The transport layer remains pubternal in 2.1 because we think there might be some bigger design
changes we want to make (see 2.2 and beyond for details).
## Remaining 2.1 work
We may add support for Abort on the `ConnectionContext` and will need to implement it at the transport layer.
## 2.2 and beyond
- Make the API public
- Support for clients (libuv client/sockets client)
- Potentially share abstractions for Kestrel's TCP transports and SignalR's HTTP based transports
- Design changes around who creates the Pipe (see https://github.com/aspnet/KestrelHttpServer/issues/2429)
## Kestrel Core (ASP.NET IServer implementation)
Even though the transport layer itself is pubternal in 2.1, consuming the IConnectionBuilder
from Kestrel is public. This is what our platform techempower benchmark is built on.
```C#
public class Program
{
public static void Main(string[] args)
{
var host = WebHostBuilder.CreateDefaultBuilder(args)
.UseKestrel(options =>
{
options.Listen(IPAddress.Loopback, 9001, builder =>
{
// Log all of the bytes as they are sent and received
builder.UseConnectionLogging();
// Connection builder API is exposed here
builder.UseConnectionHandler<ChatHandler>();
});
options.Listen(IPAddress.Any, 8004, builder =>
{
// Using hubs bound to TCP
builder.UseHub<Chat>();
});
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
These are the connection adapters that exists today in kestrel that need to be ported to middleware.
```C#
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddConnections();
}
public void Configure(IApplicationBuilder app)
{
app.UseConnections(routes =>
{
routes.MapConnections("/chat", builder =>
{
// Connection builder API is exposed here
builder.UseConnectionHandler<ChatHandler>();
});
routes.MapConnections("/mqtt", builder =>
{
// Log all of the bytes as they are sent and received
builder.UseConnectionLogging();
builder.UseConnectionHandler<MQTTHandler>(options =>
{
// Restrict to websockets only
options.Transports = TransportType.WebSockets;
// Specify the subprotocol
options.SubProtocol = "mqttv3.1";
});
});
// Shortcut to directly map a single connection handler
routes.MapConnectionHandler<NotificationHandler>("/notifictions");
});
}
}
```C#
var connection = new HttpConnection(new Uri("http://localhost:8001"));
await connection.StartAsync();
var result = await connection.Transport.Input.ReadAsync();
await connection.Transport.Output.WriteAsync(result.Buffer.ToArray());
await connection.DisposeAsync();
SignalR 2.2 -> First class TCP Support
id like to have that earlier to start a mqtt transport but looks like this has to wait a little bit longer
id like to have that earlier to start a mqtt transport but looks like this has to wait a little bit longer
Transport for what exactly? The SignalR TCP support is more an official statement, we're not explicitly working on it for 2.1 but it will work and there will be no client support (you can send payloads from a custom TCP client). However, we are shipping the APIs required to implement any server side protocol (client on the way).
I want to build a mqtt transport for signalr so i can use hub programming model as my mqtt broker
I want to build a mqtt transport for signalr so i can use hub programming model as my mqtt broker
Just to be clear, websockets or tcp is the transport right? You want to describe hub invocations using Mqtt packets? It sounds like you want to write an IHubProtocol
In SignalR speak, that's a custom hub protocol https://github.com/aspnet/SignalR/blob/2f9942e1f20ff6b76542900eadd5828a2b61957a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/IHubProtocol.cs. But if you could clarify further that would be great
@davidfowl I'm exited to see client (outgoing TCP) support on the 2.2 roadmap. I was pondering a bit on how to deal with client connections and making the Transport more usable outside of Kestrel.
Paper design:
C#
interface IIOService
{
Task<IDuplexPipe> ConnectTcpAsync(string host, int port);
IAsyncDisposable AcceptOnTcp(IPAddress address, int port, Action<IDuplexPipe> onAccept);
}
Related (from implementation perspective) is this open issue https://github.com/aspnet/KestrelHttpServer/issues/1587 to allow endpoints to be handled by the same LibuvThreads.
Sure since the API shape for the transport abstractions are still not set in stone (pubternal APIs are in this category) we can iterate on the design. That particular API shape I think is too minimal though, transports need to communicate more than just a duplex pipe.
I absolutely know I'm being dense here, but I'm a bit confused on what it means to have a TCP transport and/or custom protocol in Kestrel (since I've always thought of Kestrel as TCP/HTTP).
In that scenario, where I've decided to use the TCP transport and write a custom protocol (let's assume sans SignalR for the moment in this example), what work is Kestrel itself doing? Is that scenario similar to using the old TcpListener, or are these abstractions giving me a bit more than that?
Sorry for the dumb question, all.
In that scenario, where I've decided to use the TCP transport and write a custom protocol (let's assume sans SignalR for the moment in this example), what work is Kestrel itself doing?
Kestrel is the glue, it wires up the transport layer, handles connection management and timeouts, graceful and ungraceful shutdown of connections.
Is that scenario similar to using the old TcpListener, or are these abstractions giving me a bit more than that?
The connection abstractions decouple you from the underlying transport. Your protocol parsing just takes bytes from the pipeline and it doesn't matter where those bytes come from. You aren't bound to TCP, which means you can easily test your protocol parsing layer with a simple in memory pipe that manually pushes bytes (in memory transport basically).
Sounds awesome David, thanks!
@JanEggers wrote an MqttServer prototype implementation based on bedrock https://github.com/JanEggers/Playground/blob/SignalR/MQTT/Playground.core/Program.cs#L24 https://github.com/JanEggers/Playground/blob/SignalR/MQTT/Playground.core/Hubs/MqttHubConnectionHandler.cs
I was working on a tutorial for Pipelines and Connections, and I am stuck because it is currently difficult to explain the Connections library without tying it to either SignalR or Kestrel.
Currently, the TCP transport is in Kestrel, the WebSockets (and others) transport is in SignalR.
And they have their own internal dispatchers.
If I understand Project Bedrock correctly, the next step in 2.2 will be around refactoring these transports and dispatchers such that we can develop applications that use them without taking dependency on SignalR or Kestrel. Correct?
from my point of view kestrel will allways be required, but there will be a better layering on top of it. so you can do:
tcp > [TLS] > http > aspnet
tcp > [TLS] > http > signalr
tcp > [TLS] > mqtt > [signalr]
tcp > your own thingy
I was working on a tutorial for Pipelines and Connections, and I am stuck because it is currently difficult to explain the Connections library without tying it to either SignalR or Kestrel.
Those are the 2 hosts, what are you expecting? Dispatchers need to exist in order for you to actually run the framework built on top of connections. The 3rd type of dispatcher is the manual in memory test connection. Where you new up your connection handler and pass in a test ConnectionContext
.
Currently, the TCP transport is in Kestrel, the WebSockets (and others) transport is in SignalR.
And they have their own internal dispatchers.
That's correct an by design. There could be a pure websockets dispatcher as well but nobody needed it so it wasn't done.
If I understand Project Bedrock correctly, the next step in 2.2 will be around refactoring these transports and dispatchers such that we can develop applications that use them without taking dependency on SignalR or Kestrel. Correct?
Not quite, that's definitely lower priority than the other things. The main point of 2.2 is completing the transport abstraction for kestrel and making it properly public API (for both clients and servers).
@KPixel where are you getting hung up? Framework that rely on the abstraction don't care what dispatcher they run on. SignalR doesn't know what is hosting it and that why it works on TCP or on WebSockets, SSE, or long polling.
@JanEggers
from my point of view kestrel will allways be required, but there will be a better layering on top of it. so you can do:
tcp > [TLS] > http > aspnet
tcp > [TLS] > http > signalr
tcp > [TLS] > mqtt > [signalr]
tcp > your own thingy
Thats correct, we'll see if the Kestrel transport layer ends up being standalone or not by the time we're done designing it but that will be an added bonus of good design.
we'll see if the Kestrel transport layer ends up being standalone
That's basically what I meant.
So, you answered my question :)
now that Microsoft.AspNetCore.Connections.Abstractions is released I have question:
why does it depend on Microsoft.AspNetCore.Http.Features?
if it should be usable for plain tcp why do i need http features?
also is there any code for the tls middleware / what repo / whats the packagename?
and finally I wanted to use the new abstraction for mqttnet. The author of that library is concerned updating aspnetcore dependency to 2.1. So I thought about just depending on System.IO,Pipelines would be a good idea as that is backwards compatible to netstandard 1.3 and kestrel is not required at all. So the question is: will the tls layer depend just on System.IO.Piplines or will it sit on top of connection abstraction? And if it will depend on Connections is there a chance that Connection Abstractions could be NetStandard1.3 compatible as well maybe in a later version of itself?
why does it depend on Microsoft.AspNetCore.Http.Features?
IFeatureCollection. It's unfortunate but that was the lesser of all evils:
We chose 3. 2 is still possible to do in a mostly non-breaking way but it wouldn't fix the type name (namespace would be http).
also is there any code for the tls middleware / what repo / whats the packagename?
It doesn't exist yet. It will be in this repository.
and finally I wanted to use the new abstraction for mqttnet. The author of that library is concerned updating aspnetcore dependency to 2.1. So I thought about just depending on System.IO,Pipelines would be a good idea as that is backwards compatible to netstandard 1.3 and kestrel is not required at all.
By ASP.NET Core 2.1 the author means netstandard 2.0 right?
So the question is: will the tls layer depend just on System.IO.Piplines or will it sit on top of connection abstraction? And if it will depend on Connections is there a chance that Connection Abstractions could be NetStandard1.3 compatible as well maybe in a later version of itself?
Connection abstractions. Maybe, but we made a call to target netstandard 2.0 as a minimum.
By ASP.NET Core 2.1 the author means netstandard 2.0 right?
If I depend on Connection.Abstractions then the consumers of that package need to update kestrel to 2.1 otherwise there are no listenoptions to hook the connectionhandler or did I miss something? I cant do this on Kestrel 2.0 or can I?
https://github.com/JanEggers/MQTTnet/blob/732ede1f2475610b8a181635a571210716a3da9f/Tests/MQTTnet.TestApp.AspNetCore2/Program.cs#L16
thx for clarifiing!
You need ASP.NET Core 2.1 to use ConnectionHandler
with Kestrel.
I think about developing an FTP server using the API in Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
, because it seems like an (almost) perfect match. How will this API change in 2.2? Will it be less (or more) useful for the development of a non-HTTP server?
@fubar-coder I would use Kestrel directly for that, not the transport abstractions layer.
@davidfowl What would be the starting point for the development of a non-HTTP service? The reason I thought about M.ANC.S.K.Transport.Abstractions
was to avoid all those HTTP(S) specific code.
I'm trying to get a handle on exactly what you would need to implement to use the connection abstraction in Kestrel. Looking at @JanEggers MQTTnet it seems like you need to implement ConnectionHandler, and ConnectionContext. What else?
@b3nt0 thats it, everything else is up to your protocol or the library you are adapting. stictly you dont even need the ConnectionContext you could put all the code in the ConnectionHandler class. What I am missing the most is client support that is announced as 2.2 had to copy stuff from the signalr samples to polyfill
@davidfowl I want get some specific info from transport layer. For example some info about Socket.Handle and bring it to application layer. Can I do that with this model? Or I need create own http server with http parsers and a lot of other work?
Little more about application:
I want listen HttpRequests, get some specific info from incoming socket connection and depending on this info route request to different webapi applications, then get response from webapi and route them back to client.
I understand that it's very specific case, but it very important for me.
Pseudocode
var _incomingConnection = await HandleConnection();
var _info = GetSpecificInfo(incomingConnection.IncomingSocket.Handle);
while (true)
{
var httpRequest = await _incomingConnection.ReadHttpRequest();
switch (_info)
{
case _:
await SendHttpRequestToWebApi5001(httpRequest);
break;
case _:
await SendHttpRequestToWebApi5002(httpRequest);
break;
}
var response = await ReceiveResponse();
await SendHttpResponseToClient(response);
}
Sure, what information do you want to get off the handle?
@davidfowl very fast thanks for this :)
In our project we use debian like OS with custom security polices over standard Linux. It uses custom subsystem to set security labels on users, filesystem, socket, etc.
I use unmanaged library to get security label form Socket.Handle, on simple tcp test project it's work well. But I need correctly route httprequest and httpresponse to my webapi - it's more complex task.
If I can use this model, where I can put my routing logic?
@davidfowl I looked source code to understand how it's model works. Please correct me if I'm wrong.
Transport layer handle connection, then dispatcher process them and up to middleware. In Application code I can use this connection from HttpContext.Features.
If I'm correct then in my case I can get access to socket object in SocketTransport, then put my security label to socketconnection.
For that I need modify existing SocketTransport and SocketConnection. Routing logic put to custom middlware.
It is correct way? Or I can get access to incomig socket connection another way?
I'm sorry that I went beyond the discussion.
That's correct. We'd need to expose a new feature that exposed the socket handle. Then you could write the logic you wanted to write.
We'd need to expose a new feature that exposed the socket handle. Then you could write the logic you wanted to write.
It would be great. What is needed for this?
Can I somehow help?
@westfin Yes! You can file an issue specifying the same thing you did here and we can come up with a feature that exposes the underlying socket handle, then you can send a PR.
@davidfowl while I understand project #bedrock is the work to allow non HTTP protocol implementation to become part of the AspNetCore framework, is there a list of protocols that would/could be considered first class citizens ie. SFTP, FTP & FTPS
You can take a look my sample website: https://wsecho.azurewebsites.net/
what you can do here is you can connect/create hub dynamically on the fly, instead of static hub definition;
wss://wsecho.azurewebsites.net/hub/XYZ.....
instead of listening different ports you can use different hub for different connections.
SignalR v1 hub implementation was terrible, v2 improved but still hard to implement.
with Kestrel, I have created list for hub, basically it is a list. whenever it receives new hub it is adding in to the list, and I have modified all methods accordingly.
PS:Sometime Kestrel app crashes, because fo the bug in Kestrel, this site is uses first version of Kestrel. I'll upgrade it later.
@davidfowl any updates on this since 2.2 is out?
since 2.2 is out?
馃 Don't think it is yet?
https://github.com/aspnet/AspNetCore/releases/tag/2.2.0
isnt this final?
@JanEggers it looks like it, but it's just tagged as 2.2.0 can't find any release?
anyway I was just hoping for some news specificly about a client side implementation of Connections.Abstractions.
No we haven't made any progress in 2.2
It's very sad :( I was telling developers wait for 2.2 and you'll be able to remove that ugly code that works with sockets directly.
Well, actually, there's a public API that you can use today, it's just tied to Kestrel in it's current state.
@davidfowl I've tried to use KestrelServer class directly to implement something like a tcp echo server. The problem is that it's still coupled to HTTP. When I was sending a request from browser it kinda worked. But when using telnet it closes connection and doesn't keep it. I assume it's dropping it cause of some mandatory HTTP headers are not sent or just because it depends on a request -> response thing without keeping persistent connections. If you can share a sample with an implementation similar to what you have here https://github.com/davidfowl/TcpEcho but using Kestrel that would be great.
Any progress in 3.0?
I would like to port https://github.com/AceHack/MultiplexedWebSockets to use bedrock in whatever way makes most sense. I have a version I'm working on that uses https://github.com/Microsoft/bond any suggestions?
@davidfowl I really liked the simplicity of your example > See https://github.com/davidfowl/MultiProtocolAspNetCore
Any tips or hints as to how to implement TLS for something that's not coupled to HTTPS (for example, a TCP device that encrypts the delivery of its data using TLS)?
My WIP PR here replats Orleans' networking on top of the pubternal 'Bedrock' APIs and adds client support. Orleans has external clients, but silos also need to communicate with each other (most distributed systems have this requirement) so support for client networking is strongly desired.
Perhaps Bedrock could become a Microsoft.Extensions lib & TLS can be a piece of that pipeline (with client support), eg: Microsoft.Extensions.{Transport,Connection,Networking}.Abstractions.
Here are the core interfaces I'm using in addition to what @davidfowl specified above:
```C#
// Client side
public interface IConnectionFactory
{
Task
}
// Server side
public interface IConnectionListenerFactory
{
IConnectionListener Create(string endPoint, ConnectionDelegate connectionDelegate);
}
public interface IConnectionListener
{
Task BindAsync();
Task UnbindAsync();
Task StopAsync();
}
```
Those are subject to change & perhaps 'Transport' is more appropriate than 'Connection' in those names.
ASP.NET uses an IEndpointInformation
interface instead of the string
which my PR currently uses. I don't hold a strong opinion, but IEndpointInformation
felt awkward to me. We may change that before merging.
Is it correct that I, when I want to use TLS, have to do the following steps:
I hoped that I could avoid this pipe <-> stream <-> pipe conversion.
Closing this because the core of bedrock is in Kestrel. We still have a number of reactions we want to make (#4623 for example) but those should be tracked in separate issues.
Most helpful comment
It would be really cool to have something equivalent to Transports on the client side as well, so that you could basically have a more abstract HttpClient with a switchable underlying transport mechanism