Daily Knowledge Drop
When using minimal apis in C#, while query string values will automatically be extracted and send to the lambda expression, they are by "default", required values. Defaults can also not be supplied, as lambda expressions do not allow default values.
Either the minimal api needs to use a method (as opposed to a lambda expression) or the parameter needs to be nullable, with the default value being set in the lambda body if not passed in.
A few examples will make this clearer.
Lambda endpoint
First, lets look at a "default" minimal endpoint which uses a lambda expression. Here we expect the count parameter to be supplied in a query string.
app.MapGet("/getdata/lambda", (int count) =>
{
return count;
});
If the endpoint /getdata/lambda?count=5
is invoked, then the result return is 5.
However, if no parameter is supplied and /getdata/lambda
is invoked, or if a the parameter is incorrectly name (for example /getdata/lambda?counter=5
is invoked ) an exception will be thrown:
BadHttpRequestException: Required parameter "int count" was not provided from query string
Method endpoint
If the lambda is replaced with a method, the same exception will occur if no query string parameter is supplied:
// external method
int ExtMethod(int count)
{
return count;
}
app.MapGet("/getdata/extmethod", ExtMethod);
Invoking /getdata/extmethod?count=10
, will result in 10 being returned, while invoking /getdata/extmethod
will result in the exception:
BadHttpRequestException: Required parameter "int count" was not provided from query string
Default values
Once technique which partially works, is to set the parameter to have a default value - however this only works when using a method, and not when using a lambda
.
This is due to the fact that lambda parameters cannot have default values
- this applies generally to lambda expression, and not specific to minimal api lambdas.
// This is NOT VALID and will NOT compile
// The parameter count cannot have a default value
app.MapGet("/getdata/lambda", (int count = 5) =>
{
return count;
});
// ---
// This IS VALID and will WORK
int ExtMethod(int count = 5)
{
return count;
}
app.MapGet("/getdata/extmethod", ExtMethod);
However, now if the method endpoint is invoked, /getdata/extmethod?count=10
, 10 will be returned and if /getdata/extmethod
is invoked (with the parameter count set), the default value of 5 will be returned.
Nullable types
The solution for both cases, is to have the parameter type changed to a nullable type
and set it to a default value in the body, if null:
// int changed to int?
app.MapGet("/getdata/lambda", (int? count) =>
{
return count ?? 5;
});
// ---
// int changed to int?
int ExtMethod(int? count)
{
return count ?? 5;
}
app.MapGet("/getdata/extmethod", ExtMethod);
In both cases now, the parameter is allowed to be null, and if null, then the default value of 5 will be returned. If the parameter value is supplied, then it will be returned.
Notes
Thinking through the process in a general sense and comparing it to normal method invocations, it does make sense that this is how it would work - even if its not obvious initially:
- When invoking a traditional method which has a parameter of type
int
, the value has to be explicitly supplied - just like with minimal api. - When invoking a traditional method which has a parameter of type
int
with a default value, the value can optionally be supplied - just like with minimal api. - When working with a lambda outside of minimal api, default values are not allowed - just like with minimal api.
- When invoking a traditional method which has a parameter of
nullable int
(int?) - the value can optionally be supplied - just like with minimal api.
References
How to Access Query Strings in Minimal APIs
Daily Drop 88: 03-06-2022
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.