-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Project Bedrock #4772
Comments
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 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? |
Me too. But I would like to have the package semantics more clear. Better to suggest it now then after the release :)
I guess that is the purpose of the transports. At least that is what I understood from this part:
|
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'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.
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.
Yes that would be a transport.
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. |
Async Serving Power |
SignalR didn't make a message queue the transport, those were fundamentally different abstractions. |
|
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". |
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? :) 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." |
It may be nice to identify connections by T instead of string. Perhaps IConnectionIdFeature w/ properly comparable T? |
My guess is that the ConnectionId is a string to simplify passing it around. |
Make sense... Would avoid allocations with unnecessary |
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? |
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 If not T how about going to int? |
Avoid the eponymous namespace's class ambiguity with System.IO.Connections? |
and
If you are going to use a Hash function with this value and you are using your own Why don't let the user use whatever type they want? |
Also yeah, @benaadams suggestion looks great. By using |
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 |
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 |
@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: // Client side
public interface IConnectionFactory
{
Task<ConnectionContext> ConnectAsync(string endPoint);
}
// 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 |
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. |
Project Bedrock
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 theConnectionContext
that flows through the dispatcher to the application.IConnectionBuilder
for a particular binding relevant to the transport. For example, the http dispatcher will expose theIConnectionBuilder
based on a particular route, while the TCP dispatcher will expose anIConnectionBuilder
based on an ip address and port.Applications/Middleware/Frameworks
At the center of this work is a new set of primitives that represent an underlying connection:
The
ConnectionContext
is the "HttpContext" of the connection universe. It's an abstraction that represents a persistent connection of some form. This couldbe 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 featuresfrom the connection which can enrich the underlying abstraction. The 2 required features are the
IConnectionTransportFeature
and theIConnectionIdFeature
.Next, we introduce the abstraction for executing a connection.
The
ConnectionDelegate
represents a function that executes some logic per connection. ThatTask
return represents theconnection 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 theIApplicationBuilder
) representsa sockets pipeline. The middleware signature is
Func<ConnectionDelegate, ConnectionDelegate>
so callers can decorate the nextConnectionDelegate
in the chain similar to http middleware in ASP.NET Core.
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
Transports are responsible for providing the initial
IFeatureCollection
implementation for the connection and providing a stream of bytes to the application.Libuv and System.Net.Sockets
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)
WebSockets
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.
Other HTTP transports
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
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.
Dispatchers
ASP.NET Core
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.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:
We should introduce the following packages:
ConnectionDelegate
middlewareConnectionDelegate
middleware (do we merge Http and Http2?)ConnectionDelegate
middlewareHere's what the Kestrel for TCP could look like wired up to the generic host:
The text was updated successfully, but these errors were encountered: