Skip to content
This repository was archived by the owner on Nov 27, 2018. It is now read-only.

Commit

Permalink
[Fixes #367] Add extensions on WebHostBuilder for super simple HTTP s…
Browse files Browse the repository at this point in the history
…ervice application building
  • Loading branch information
kichalla committed Dec 12, 2016
1 parent 54297fb commit 2702a9a
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 10 deletions.
20 changes: 10 additions & 10 deletions samples/RoutingSample.Web/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ public void Configure(IApplicationBuilder app)
});
}

public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();

host.Run();
}
//public static void Main(string[] args)
//{
// var host = new WebHostBuilder()
// .UseKestrel()
// .UseIISIntegration()
// .UseStartup<Startup>()
// .Build();

// host.Run();
//}
}
}
30 changes: 30 additions & 0 deletions samples/RoutingSample.Web/TestHttpServices.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Builder;

namespace RoutingSample.Web
{
public class TestHttpServices
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseRouter(routeBuilder =>
{
routeBuilder
.MapGet("hello/{*name}", (req, resp, routeData) => resp.WriteAsync($"Hello, {routeData.Values["name"]}!"))
.MapGet("goodbye/{*name}", (httpContext) =>
{
return httpContext.Response.WriteAsync($"Goodbye, {httpContext.GetRouteData().Values["name"]}!");
})
.MapGet("{*name}", (req, resp, routeData) => resp.WriteAsync($"Welcome, {routeData.Values["name"]}!"));
})
.Build();

host.Run();

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Constraints;
Expand Down Expand Up @@ -74,6 +75,22 @@ public static IRouteBuilder MapDelete(this IRouteBuilder builder, string templat
return builder.MapVerb("DELETE", template, action);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapDelete(
this IRouteBuilder builder,
string template,
Func<HttpRequest, HttpResponse, RouteData, Task> handler)
{
return builder.MapVerb("DELETE", template, handler);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP GET requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
Expand All @@ -100,6 +117,22 @@ public static IRouteBuilder MapGet(this IRouteBuilder builder, string template,
return builder.MapVerb("GET", template, action);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP GET requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapGet(
this IRouteBuilder builder,
string template,
Func<HttpRequest, HttpResponse, RouteData, Task> handler)
{
return builder.MapVerb("GET", template, handler);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP POST requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
Expand All @@ -126,6 +159,22 @@ public static IRouteBuilder MapPost(this IRouteBuilder builder, string template,
return builder.MapVerb("POST", template, action);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP POST requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapPost(
this IRouteBuilder builder,
string template,
Func<HttpRequest, HttpResponse, RouteData, Task> handler)
{
return builder.MapVerb("POST", template, handler);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP PUT requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
Expand All @@ -152,6 +201,45 @@ public static IRouteBuilder MapPut(this IRouteBuilder builder, string template,
return builder.MapVerb("PUT", template, action);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP PUT requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapPut(
this IRouteBuilder builder,
string template,
Func<HttpRequest, HttpResponse, RouteData, Task> handler)
{
return builder.MapVerb("PUT", template, handler);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP requests for the given
/// <paramref name="verb"/>, <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="verb">The HTTP verb allowed by the route.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapVerb(
this IRouteBuilder builder,
string verb,
string template,
Func<HttpRequest, HttpResponse, RouteData, Task> handler)
{
RequestDelegate requestDelegate = (httpContext) =>
{
return handler(httpContext.Request, httpContext.Response, httpContext.GetRouteData());
};

return builder.MapVerb(verb, template, requestDelegate);
}

/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP requests for the given
/// <paramref name="verb"/>, <paramref name="template"/>, and <paramref name="handler"/>.
Expand Down
37 changes: 37 additions & 0 deletions src/Microsoft.AspNetCore.Routing/WebHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Hosting
{
public static class WebHostExtensions
{
/// <summary>
/// Adds routing related services and a <see cref="RouterMiddleware"/> middleware.
/// </summary>
/// <param name="builder">The <see cref="IWebHostBuilder"/>.</param>
/// <param name="configureRoutes">An <see cref="Action{RouteBuilder}"/> to configure the provided <see cref="RouteBuilder"/>.</param>
/// <returns></returns>
public static IWebHostBuilder UseRouter(this IWebHostBuilder builder, Action<RouteBuilder> configureRoutes)

This comment has been minimized.

Copy link
@davidfowl

davidfowl Dec 12, 2016

Member

This should be on IAppBuilder.

{
if (configureRoutes == null)
{
throw new ArgumentNullException(nameof(configureRoutes));
}

return builder
.ConfigureServices(services => services.AddRouting())
.Configure(app =>
{
var routeBuilder = new RouteBuilder(app);
configureRoutes(routeBuilder);
app.UseRouter(routeBuilder.Build());
});
}
}
}
1 change: 1 addition & 0 deletions src/Microsoft.AspNetCore.Routing/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"xmlDoc": true
},
"dependencies": {
"Microsoft.AspNetCore.Hosting": "1.2.0-*",

This comment has been minimized.

Copy link
@davidfowl

davidfowl Dec 12, 2016

Member

You should be able to remove this as a result.

"Microsoft.AspNetCore.Http.Extensions": "1.2.0-*",
"Microsoft.AspNetCore.Routing.Abstractions": {
"target": "project"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Xunit;

namespace Microsoft.AspNetCore.Routing.FunctionalTests
{
public class WebHostBuilderExtensionsTest
{
public static TheoryData<Action<RouteBuilder>, HttpRequestMessage, string> MatchesRequest
{
get
{
return new TheoryData<Action<RouteBuilder>, HttpRequestMessage, string>()
{
{
(rb) => rb.MapGet("greeting/{name}", (req, resp, routeData) => resp.WriteAsync($"Hello! {routeData.Values["name"]}")),
new HttpRequestMessage(HttpMethod.Get, "greeting/James"),
"Hello! James"
},
{
(rb) => rb.MapPost(
"greeting/{name}",
async (req, resp, routeData) =>
{
var streamReader = new StreamReader(req.Body);
var data = await streamReader.ReadToEndAsync();
await resp.WriteAsync($"{routeData.Values["name"]} {data}");
}),
new HttpRequestMessage(HttpMethod.Post, "greeting/James") { Content = new StringContent("Biography") },
"James Biography"
},
{
(rb) => rb.MapPut(
"greeting/{name}",
async (req, resp, routeData) =>
{
var streamReader = new StreamReader(req.Body);
var data = await streamReader.ReadToEndAsync();
await resp.WriteAsync($"{routeData.Values["name"]} {data}");
}),
new HttpRequestMessage(HttpMethod.Put, "greeting/James") { Content = new StringContent("Biography") },
"James Biography"
},
{
(rb) => rb.MapDelete("greeting/{name}", (req, resp, routeData) => resp.WriteAsync($"Hello! {routeData.Values["name"]}")),
new HttpRequestMessage(HttpMethod.Delete, "greeting/James"),
"Hello! James"
},
{
(rb) => rb.MapVerb(
"POST",
"greeting/{name}",
async (req, resp, routeData) =>
{
var streamReader = new StreamReader(req.Body);
var data = await streamReader.ReadToEndAsync();
await resp.WriteAsync($"{routeData.Values["name"]} {data}");
}),
new HttpRequestMessage(HttpMethod.Post, "greeting/James") { Content = new StringContent("Biography") },
"James Biography"
},
};
}
}

[Theory]
[MemberData(nameof(MatchesRequest))]
public async Task UseRouter_MapGet_MatchesRequest(Action<RouteBuilder> routeBuilder, HttpRequestMessage request, string expected)
{
// Arrange
var webhostbuilder = new WebHostBuilder();
webhostbuilder.UseRouter(routeBuilder);
var testServer = new TestServer(webhostbuilder);
var client = testServer.CreateClient();

// Act
var response = await client.SendAsync(request);

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var actual = await response.Content.ReadAsStringAsync();
Assert.Equal(expected, actual);
}
}
}

1 comment on commit 2702a9a

@davidfowl
Copy link
Member

Choose a reason for hiding this comment

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

@kichalla UseRouter should not be on IWebHostBuilder.

Please sign in to comment.