1

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?

5
  • Maybe you could try to create a custom ModelBinder for that parameter, and check for nul values Commented Jun 21, 2019 at 19:50
  • @carloschourio, the use case I'm dealing with is that the header would not be present, neither key nor value. In that case would a custom ModelBinder be of any use? It seems like in this scenario checking for a null value wouldn't work just because the key or value wouldn't exist at all. Commented Jun 21, 2019 at 20:00
  • 1
    Is it obligatory that you have to perform the logic with the header inside the controller? I think you could be using a filter to get the value from the header and it wouldn't matter if it's present or not. But maybe you have to put the logic inside the controller and not in the filter. Commented Jun 21, 2019 at 20:26
  • 1
    It's not necessarily obligatory, no. This REST API is the front-end of a multi-tenant server. There are two deployment scenarios; cloud and locally hosted. This header helps to identify what tenant is making the call when using the cloud. For locally hosted, whoever is hosting is considered the sole tenant. That's the use case I'm dealing with. All of that said, it looks like a filter could be useful here, since I could check for the presence of the header and do whatever I need to if it's present or not. I'll take a look at moving in that direction. Commented Jun 21, 2019 at 20:39
  • Does it work when you define a second overload without the parameter explicitly? Like this: public IHttpActionResult Register([FromBody] RegistrationRequest request) => Register(RegistrationRequest, null); Commented Jun 21, 2019 at 21:52

2 Answers 2

1

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")
Sign up to request clarification or add additional context in comments.

Comments

0

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;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.