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 #1980

Open
davidfowl opened this Issue Aug 3, 2017 · 110 comments

Comments

Projects
None yet
@davidfowl
Member

davidfowl commented Aug 3, 2017

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:

  • Applications/Middleware/Frameworks - The application code that handles connections and implement protocol parsing logic or other logic that modifies the stream of data (http, TLS as an example)
  • Transports - Transports provide an implementation of an 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.
  • Dispatchers - The dispatcher is the component that brings the transport layer and application layer together. Its job is to manage the lifetime of the transport connection and application running on top. The dispatcher will expose the 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.

Applications/Middleware/Frameworks

At the center of this work is a new set of primitives that represent an underlying connection:

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; }
}
public interface IConnectionIdFeature
{
    string ConnectionId { get; set; }
}
public interface IConnectionTransportFeature
{
    IDuplexPipe Transport { get; set; }
}
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.

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.

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:

  • Kestrel's ASP.NET Core implementation will be re-platted on top of this new infrastructure which means it will be fully decoupled from Kestrel.
  • Kestrel's connection adapter pipeline will be changed to use the IConnectionBuilder instead. This means that things like TLS , windows auth and connection logging can be separate middleware components.
  • SignalR will be built on top of this making it possible to run SignalR on any connection based infrastructure.

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.

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:

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();
@aL3891

This comment has been minimized.

aL3891 commented Aug 3, 2017

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

@dopare

This comment has been minimized.

dopare commented Aug 3, 2017

@davidfowl what do you think about performance hit after introducing such an abstraction?

@galvesribeiro

This comment has been minimized.

galvesribeiro commented Aug 4, 2017

@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! :)

@dls314

This comment has been minimized.

dls314 commented Aug 4, 2017

Similarly, Microsoft.AspNetCore.Sockets.Tls => Microsoft.Sockets.Tls would make sense, but I want the feature more than a name.

@shaggygi

This comment has been minimized.

shaggygi commented Aug 4, 2017

@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?

@galvesribeiro

This comment has been minimized.

galvesribeiro commented Aug 4, 2017

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

@no1melman

This comment has been minimized.

no1melman commented Aug 4, 2017

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

@davidfowl

This comment has been minimized.

Member

davidfowl commented Aug 4, 2017

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

@no1melman

This comment has been minimized.

no1melman commented Aug 4, 2017

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.

@galvesribeiro

This comment has been minimized.

galvesribeiro commented Aug 4, 2017

@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! :)

@wholroyd

This comment has been minimized.

wholroyd commented Aug 4, 2017

I am thoroughly upset by the complete lack of references to The Flintstones in this issue.

@benaadams

This comment has been minimized.

Contributor

benaadams commented Aug 4, 2017

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

@davidfowl

This comment has been minimized.

Member

davidfowl commented Aug 4, 2017

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

@markrendle

This comment has been minimized.

Contributor

markrendle commented Aug 4, 2017

@davidfowl

Naming needs some work though, sockets isn't great.

Microsoft.AspNetCore.Bungholes

@NinoFloris

This comment has been minimized.

NinoFloris commented Aug 4, 2017

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.

@KPixel

This comment has been minimized.

KPixel commented Aug 4, 2017

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" :)

@benaadams

This comment has been minimized.

Contributor

benaadams commented Aug 4, 2017

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

@aL3891

This comment has been minimized.

aL3891 commented Aug 4, 2017

Microsoft.Bedrock? :)
Its a cool name imo

It could also be Microsoft.Transport, also fits pretty well conceptually

@KPixel

This comment has been minimized.

KPixel commented Aug 4, 2017

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.

@dls314

This comment has been minimized.

dls314 commented Aug 4, 2017

It may be nice to identify connections by T instead of string. Perhaps IConnectionIdFeature w/ properly comparable T?

@KPixel

This comment has been minimized.

KPixel commented Aug 4, 2017

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?

@galvesribeiro

This comment has been minimized.

galvesribeiro commented Aug 4, 2017

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.

@benaadams

This comment has been minimized.

Contributor

benaadams commented Aug 4, 2017

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();
}
@shaggygi

This comment has been minimized.

shaggygi commented Aug 4, 2017

I like @benaadams Connection suggestion. What about namespace System.IO.Connection?

@dls314

This comment has been minimized.

dls314 commented Aug 4, 2017

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?

@dls314

This comment has been minimized.

dls314 commented Aug 4, 2017

I like @benaadams Connection suggestion. What about namespace System.IO.Connection?

Avoid the eponymous namespace's class ambiguity with System.IO.Connections?

@galvesribeiro

This comment has been minimized.

galvesribeiro commented Aug 4, 2017

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?

@galvesribeiro

This comment has been minimized.

galvesribeiro commented Aug 4, 2017

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.

@aL3891

This comment has been minimized.

aL3891 commented Aug 4, 2017

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

@benaadams

This comment has been minimized.

Contributor

benaadams commented Aug 5, 2017

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?

@davidfowl

This comment has been minimized.

Member

davidfowl commented Apr 27, 2018

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.

@KPixel

This comment has been minimized.

KPixel commented Apr 27, 2018

we'll see if the Kestrel transport layer ends up being standalone

That's basically what I meant.
So, you answered my question :)

@JanEggers

This comment has been minimized.

Contributor

JanEggers commented Jun 1, 2018

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?

@davidfowl

This comment has been minimized.

Member

davidfowl commented Jun 1, 2018

why does it depend on Microsoft.AspNetCore.Http.Features?

IFeatureCollection. It's unfortunate but that was the lesser of all evils:

  1. Make a new abstraction that is feature collection but isn't IFeatureCollection
  2. Type forward to another assembly (this is still an option), but it wouldn't fix the namespace
  3. Just reference the assembly.

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.

@JanEggers

This comment has been minimized.

Contributor

JanEggers commented Jun 1, 2018

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

https://github.com/JanEggers/MQTTnet/blob/732ede1f2475610b8a181635a571210716a3da9f/Frameworks/MQTTnet.AspnetCore/ConnectionBuilderExtensions.cs#L7-L9

thx for clarifiing!

@davidfowl

This comment has been minimized.

Member

davidfowl commented Jun 1, 2018

You need ASP.NET Core 2.1 to use ConnectionHandler with Kestrel.

@fubar-coder

This comment has been minimized.

fubar-coder commented Jun 15, 2018

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?

@davidfowl

This comment has been minimized.

Member

davidfowl commented Jun 15, 2018

@fubar-coder I would use Kestrel directly for that, not the transport abstractions layer.

@fubar-coder

This comment has been minimized.

fubar-coder commented Jun 18, 2018

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

@b3nt0

This comment has been minimized.

b3nt0 commented Jul 2, 2018

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?

@JanEggers

This comment has been minimized.

Contributor

JanEggers commented Jul 3, 2018

@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

@westfin

This comment has been minimized.

westfin commented Sep 11, 2018

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

scheme

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);
}
@davidfowl

This comment has been minimized.

Member

davidfowl commented Sep 11, 2018

Sure, what information do you want to get off the handle?

@westfin

This comment has been minimized.

westfin commented Sep 11, 2018

@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?

@westfin

This comment has been minimized.

westfin commented Sep 13, 2018

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

image

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.

@davidfowl

This comment has been minimized.

Member

davidfowl commented Sep 14, 2018

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.

@westfin

This comment has been minimized.

westfin commented Sep 14, 2018

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?

@davidfowl

This comment has been minimized.

Member

davidfowl commented Sep 14, 2018

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

@grahamehorner

This comment has been minimized.

grahamehorner commented Oct 2, 2018

@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

@karayakar

This comment has been minimized.

karayakar commented Oct 4, 2018

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment