Documentation
Getting started
Add the dependency:
dotnet add package Bemol
or copy to csproj:
<ItemGroup>
<PackageReference Include="Bemol" Version="1.0.0-alpha" />
</ItemGroup>
Start coding:
using Bemol;
class HelloWorld {
static void Main() {
App app = new App().Start(7000);
app.Get("/", (ctx) => ctx.Result("Hello World!"));
}
}
You can run the development server with:
dotnet watch run
Routing
A route is made up of three simple pieces:
- A method (
get
,post
,put
,delete
,head
, etc.) - A path (
/hello
,/users/:name
,/path/*
, etc.) - A context
(ctx) => { }
app.Get("/", ctx => {
// Show something
});
app.Post("/", ctx => {
// Create something
});
app.Put("/", ctx => {
// Update something
});
app.Delete("/", ctx => {
// Annihilate something
});
app.Head("/", ctx => {
// Show header
});
Methods
There exists two special methods, before
and after
.
A before
method is matched before every request.
app.Before(ctx => {
// runs before all requests
});
app.Before("/path/*", ctx => {
// runs before request to /path/*
});
An after
method is matched after every request (even if an exception occurred).
app.After(ctx => {
// run after all requests
});
app.After("/path/*", ctx => {
// runs after request to /path/*
});
You can also add your own custom methods:
app.Custom("TRACE", "/", ctx => {
// Trace something
});
Paths
Paths are matched in the order they are defined.
Paths can include named parameters, accessible via ctx.PathParam("key")
:
app.Get("/hello/:name", ctx => {
ctx.Result("Hello: " + ctx.PathParam("name"));
});
Paths can also include wildcard parameters, which are like unnamed path-parameters:
app.Get("/hello/*", ctx => {
// capture all request to sub-paths of /hello/
});
Context (ctx)
The Context
object provides you with everything you need to handle a http-request.
// Request methods
ctx.Body() // get body as string
ctx.Body<T>() // get body as type
ctx.BodyAsBytes() // get body as bytes
ctx.UploadedFile(name) // get uploaded file by name
ctx.FormParam(key) // get form parameter
ctx.FormParam<T>(key) // get form parameter as type
ctx.FormParam(key, default) // get form parameter (or default value)
ctx.FormParam() // get form parameter collection
ctx.PathParam(key) // get path parameter
ctx.PathParam<T>(key) // get path parameter as type
ctx.ContentLength() // get request content length
ctx.ContentType() // get request content type
ctx.Cookie(name) // get request cookie
ctx.Header(header) // get request header
ctx.Header() // get request header collection
ctx.Ip() // get request ip address
ctx.Method() // get request method
ctx.Path() // get request path
ctx.QueryParam() // get request query parameter
ctx.QueryParam<T>() // get request query parameter as type
ctx.QueryMap() // get request query paramaeter as collection
ctx.QueryString() // get query string
ctx.UserAgent() // get user agent
// Response methods
ctx.Result(resultString) // set a string result that will be sent to the client
ctx.ResultString() // get the string result that will be sent to the client
ctx.Result(byteArray) // set a byte[] result that will be sent to the client
ctx.ResultBytes() // get the byte[] result that will be sent to the client
ctx.ResultStream() // get the stream that will be sent to the client
ctx.ContentType(contentType) // set the response content type
ctx.Header(name, value) // set a response header
ctx.Status(statusCode) // set response status
ctx.Status() // get response status
ctx.Redirect(path) // redirect to path
ctx.Redirect(path, statusCode) // redirect to path with specific HTTP 3XX status code
ctx.Cookie(name, value) // set cookie by name and value
ctx.Cookie(cookie) // set cookie
ctx.RemoveCookie(name) // remove cookie
ctx.Html(html) // call Result(string).ContentType("text/html")
ctx.Json(obj) // call Result(JsonSerializer.Serialize(obj)).ContentType("application/json")
ctx.Render(filePath, model) // call Html(BemolRenderer.Render(filePath, model))
Error Mapping
All handlers (before, path, after) can throw HttpException
(and any subclass of HttpException
):
using Bemol.Http.Exception;
app.Get("/error", ctx => {
throw new NotFoundException();
});
The app.Error()
method gives you a way to handle those:
app.Error(404, ctx => {
ctx.Result("Generic 404 message");
});
Configuration
You can pass a config object when creating a new instance of App
. The below snippets shows all the available config options:
App(config => {
config.PublicFolder = publicFolder // public folder used to serve static files (default is "/public")
config.ContextPath = contextPath // context path for the http server (default is "/")
condig.DefaultContentType = contentType // content type to use if no content type is set (default is "text/plain")
config.IgnoreTrailingSlashes = true/false // default is true
condig.EnableCorsForAllOrigins = true/false // enable cors for all origins
// DotLiquid
config.ResourcesFolder = resourcesFolder // resources folder for DotLiquid (default is "/resources")
config.PartialsFolder = partialsFolder // partials folder for DotLiquid (default is "/partials")
})
Static Files
To include static files in your build:
<ItemGroup>
<Watch Include="public/**" />
<None Include="public/**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Static resource handling is done after endpoint matching, meaning your self-defined endpoints have higher priority. The process looks like this:
before handlers
endpoint handler
if no endpoint handler found
static file handler
if no static file found
response is 404
after handlers
If you do config.PublicFolder = "/public"
. Your index.html
file at /public/index.html
will be available at http://{host}:{port}/index.html
and http://{host}:{port}/
.