Skip to content
This repository has been archived by the owner on Dec 19, 2018. It is now read-only.

WIP: Simplify hosting configuration with some extension methods #991

Closed
wants to merge 4 commits into from

Conversation

davidfowl
Copy link
Member

@davidfowl davidfowl commented Mar 27, 2017

  • Added WaitForShutdown method to IWebHost
  • Added Run and RunApplication to IWebHostBuilder to Build and
    Start the application in a single method.

After a discussion about what could be done to further simplify some of the startup logic with the WebHostBuilder a few things came up. These were some of the methods that we could add to make the startup logic more approachable while not completely diverging from the original API.

Further simplification requires picking kestrel to to be the default server but that won't happen as part of this PR and requires further discussion.

/cc @glennc @Tratcher @DamianEdwards

- Added WaitForShutdown method to IWebHost
- Added Run and RunWith to IWebHostBuilder to Build and
Start the application in a single method.
@davidfowl davidfowl changed the title Simplify hosting configuration with some extension methods WIP: Simplify hosting configuration with some extension methods Mar 27, 2017
/// </summary>
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to run.</param>
/// <param name="configure">The delegate that configures the <see cref="IApplicationBuilder"/>.</param>
public static IWebHost RunWith(this IWebHostBuilder hostBuilder, Action<IApplicationBuilder> configure)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name isn't really good. RunAndConfigure? ConfigureAndRun? RunWithConfiguration?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once an IApplicationBuilder is needed it's probably alright to call Configure and Build separately. If another Run API then maybe one that takes Run(handler, port) to avoid the extra UseUrls. Also like the idea of having Kestrel as a default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, I'd like to play around with it a little before dumping it. Needing middleware isn't an advanced scenario, it's what you do after you get hello world working.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the port, overload, the assumption would be that it binds to * and not localhost (we've had these debates over and over). I'll add it and see what the feedback is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love these methods. I added port as the first argument but multiple arguments with one being a delegate is always ugly IMO.

foo.Run(app => { }, 8080);
foo.Run(8080, app=> { });
foo.Listen(8080).Run(app => { });

var hostingEnvironment = host.Services.GetService<IHostingEnvironment>();
var applicationLifetime = host.Services.GetService<IApplicationLifetime>();

Console.WriteLine($"Hosting environment: {hostingEnvironment.EnvironmentName}");
Copy link
Member

@lutzroeder lutzroeder Mar 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be implemented without always writing to Console?

Copy link
Member Author

@davidfowl davidfowl Mar 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a whole discussion on this too. I think the default should use the console. Having an options to turn it off would be fine though. See #979

/// <param name="token">The token to trigger shutdown.</param>
public static void WaitForShutdown(this IWebHost host, CancellationToken token)
{
host.WaitForShutdown(token, shutdownMessage: null);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this dispose the host? Part of the API is about simplicity but it's also generally useful outside of that use case.

/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to run.</param>
/// <param name="port">The port to bind to.</param>
/// <param name="handler">A delegate that handles the request.</param>
public static IWebHost Run(this IWebHostBuilder hostBuilder, int port, RequestDelegate handler)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there some FxCop rule that says keep adding new parameters at the end of the method if name stays the same (agree having the port first makes more sense otherwise).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use FXCop 😄

await context.Response.WriteAsync("Hello World!");
});
var host = new WebHostBuilder()
.Run(async context =>
Copy link
Member

@Tratcher Tratcher Mar 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildAndStart?

Copy link
Member Author

@davidfowl davidfowl Mar 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too ugly. It's really BuildRunStart so no...

public static void MainWithPort()
{
var host = new WebHostBuilder()
.Run(8080, async context =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've avoided specifying just a port because of the ambiguity over what the IP/Host is. Localhost? */Any? Loopack? IPv6Loopback? There's never been agreement for what the default host/ip should be.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't see this extension being used outside of demoware, no real app is this simple. I'd rather have the RunApplication variant as Run.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've avoided specifying just a port because of the ambiguity over what the IP/Host is. Localhost? */Any? Loopack? IPv6Loopback? There's never been agreement for what the default host/ip should be.

I know, I was there, I'm forcing the discussion by picking Any.

I also don't see this extension being used outside of demoware, no real app is this simple. I'd rather have the RunApplication variant as Run.

Agreed. Or very simple applications.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea this is dangerous. to me it reads like "bind to any nic, on any IP I have". That's going to be a nasty surprise for someone. Be specific here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a required hostname.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

url instead of port is probably ok. UseUrls is a little bit more but having Run(...) or some similar method just take the handler instead of calling Configure is a great simplification.

/// <param name="token">The token to trigger shutdown.</param>
public static void Run(this IWebHost host, CancellationToken token)
{
host.Run(token, shutdownMessage: null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No default shutdown message?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hasn't changed.

/// <param name="handler">A delegate that handles the request.</param>
public static IWebHost Run(this IWebHostBuilder hostBuilder, int port, RequestDelegate handler)
{
var host = hostBuilder.UseUrls($"http://*:{port}/")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, @blowdart has killed this before. Too many localhost test servers being publicly exposed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No no no no no. Don't make me cry.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it has to be this way for compat with other frameworks.

golang:

For TCP and UDP, the syntax of laddr is "host:port", like "127.0.0.1:8080". If host is omitted, as in ":8080", Listen listens on all available interfaces instead of just the interface with the given host address.

nodejs

Begin accepting connections on the specified port and hostname. If the hostname is omitted, the server will accept connections directed to any IPv4 address (INADDR_ANY).

As a compromise, we could require both host and port.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already require host and port (and scheme). Unless you're going to accept them a separate parameters I don't see this extension adding much value over UseUrls.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't but others do. Everything here is doable already this isn't about functionality. If it was we wouldn't make new APIs. It's about ease of use, API design, the right nomenclature and common parameters used to Start, Listen, Run a simple server.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tend to agree. Taking url instead of just the port makes sense given it's consistent overall.

/// </summary>
/// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to run.</param>
/// <param name="handler">A delegate that handles the request.</param>
public static IWebHost Run(this IWebHostBuilder hostBuilder, RequestDelegate handler)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't these extensions named Start? the IWebHost.Run extensions all block but these call Start and return.

@davidfowl davidfowl closed this Apr 4, 2017
@davidfowl
Copy link
Member Author

Will revisit.

@DamianEdwards
Copy link
Member

We're looking at doing something in the meta-package: aspnet/MetaPackages#24

@davidfowl davidfowl deleted the davidfowl/simplify-bootup branch April 18, 2017 07:39
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants