morris295
morris295

Reputation: 547

.NET WebAPI parameter bound optional parameter

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

Answers (2)

Nithin
Nithin

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

morris295
morris295

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

Related Questions