Reputation: 547
I have a REST API built in .NET Framework WebAPI. I have created a custom parameter binding attribute for extracting a value from HTTP headers. There are scenarios where the header may or may not be present on the request, so I would like to be able to do something like the following to treat the header as an optional parameter.
public IHttpActionResult Register([FromBody] RegistrationRequest request, [FromHeaderAuthorization] string authorization = null)
{
This works fine when I call the endpoint with the authorization header included. When calling the endpoint without the header however I get the following error message:
The request is invalid.', MessageDetail='The parameters dictionary does not contain an entry for parameter 'authorization' of type 'System.String'
I have been searching to try and determine if it is possible to treat a parameter as optional in this way and have found some mixed results. It appears that in C# 8.0 I could achieve this using a nullable reference type, but Visual Studio indicates that 8.0 is currently in preview and thus not really an option for me.
That said, I haven't really been able to find anything else that indicates whether this type of thing is possible or not.
Is it possible to treat this header parameter as optional or do I need to go about this differently?
Upvotes: 1
Views: 1526
Reputation: 11
We had the similar situation (ASP .NET Core 6) where Header Parameter always considered as mandatory by the framework even though we assigned a default value (range
variable).
public async Task<IActionResult> GetMessages(
[EmailAddress(ErrorMessage = "Invalid Mailbox Address")][FromRoute][Required] string mailbox,
[FromRoute][Required] string folderId,
[FromQuery] GetMessageBodyParameter getMessageBodyParameter,
[FromHeader] string range = "0-9")
And we flagged the variable as nullable (string? range
) and it is working fine now.
public async Task<IActionResult> GetMessages(
[EmailAddress(ErrorMessage = "Invalid Mailbox Address")][FromRoute][Required] string mailbox,
[FromRoute][Required] string folderId,
[FromQuery] GetMessageBodyParameter getMessageBodyParameter,
[FromHeader] string? range = "0-9")
Upvotes: 1
Reputation: 547
I ended up abandoning the header parameter and going in a slightly different direction.
I had already created a class to extend HttpRequestMessage to do things like get the IP of the client calling the endpoint, I ended up adding a method to handle checking for the existence of the header and retrieving the necessary identity information as needed.
public static class HttpRequestMessageExtensions
{
private const string HttpContext = "MS_HttpContext";
private const string RemoteEndpointMessage = "System.ServiceModel.Channels.RemoteEndpointMessageProperty";
/* Method body excluded as irrelevant */
public static string GetClientIpAddress(this HttpRequestMessage request) { ... }
/** Added this method for handling the authorization header. **/
public static Dictionary<string, string> HandleAuthorizationHeader(this HttpRequestMessage request)
{
Tenant tenant = new Tenant();
IEnumerable<string> values;
request.Headers.TryGetValues("Authorization", out values);
string tenantConfig = ConfigurationUtility.GetConfigurationValue("tenantConfig");
if (null != values)
{
// perform actions on authorization header.
}
else if(!string.IsNullOrEmpty(tenantConfig))
{
// retrieve the tenant info based on configuration.
}
else
{
throw new ArgumentException("Invalid request");
}
return tenant;
}
}
Upvotes: 0