Search code examples
asp.net-web-apiasp.net-web-api2asp.net-web-api-routing

.Net Framework API Controller won't recognize Route attributes


I have created an API Controller using .Net Framework as follows:

public class ApplicationUsersController : ApiController
{

    [Route("api/ApplicationUser/{username}/{password}")]
    [ResponseType(typeof(ApplicationUser))]
    public IHttpActionResult GetApplicationUser(string username, string password)
    {
        ApplicationUser user = new ApplicationUser()

        //Code to populate user.

        return Ok(user);
    }

    [Route("api/ApplicationUser/{username}")]
    [ResponseType(typeof(ApplicationUser))]
    public IHttpActionResult GetApplicationUser(string username)
    {
        ApplicationUser user = new ApplicationUser()

        //Code to populate user.

        return Ok(user);
    }

    // PUT: api/ApplicationUsers/5
    [Route("api/ApplicationUser/{username}")]
    [ResponseType(typeof(void))]
    public IHttpActionResult PutApplicationUser(string username, ApplicationUser ApplicationUser)
    {
        //Code to update user
        return StatusCode(HttpStatusCode.NoContent);
    }

    // POST: api/ApplicationUsers
    [Route("api/ApplicationUser")]
    [ResponseType(typeof(ApplicationUser))]
    public IHttpActionResult PostApplicationUser(ApplicationUser ApplicationUser)
    {
        //Code to create new user

        return Ok(ApplicationUser);

        //    return CreatedAtRoute("api/ApplicationUser/{username}", new { username = ApplicationUser.UserName }, ApplicationUser);
    }

    // DELETE: api/ApplicationUsers/5
    [Route("api/ApplicationUser/{username}")]
    [ResponseType(typeof(ApplicationUser))]
    public IHttpActionResult DeleteApplicationUser(string username)
    {
        //Code to populate user then delete the record.

        return Ok(user);
    }

}

When I make a Get call to api/ApplicationUser/{username}/{password}, it works fine. If I make a Post call to api/ApplicationUser, it works fine. If I make a Get, Put or Delete call to api/ApplicationUser/{username}, I get a "not found" error. Is there something else I need to do to make it recognize the route?

Thanks, Jim

**** Update ****

I have discovered that it will recognize the route as long as the username doesn't end with .something such as .com. The thing is, I am using email addresses as the username. Is there a rule somewhere that a REST url can't end with .somthing? Is there a way around this?


Solution

  • The problem was the format of the parameters. Apparently a url can't end with a .com or other domain suffix. What I did was to convert the parameters to Base64. I created these two extension functions.

        public static string ToBase64(this string value)
        {
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(value);
                return Convert.ToBase64String(bytes);
            }
            catch (Exception)
            {
                return value;
            }
        }
    
        public static string FromBase64(this string value)
        {
            try
            {
                byte[] bytes = Convert.FromBase64String(value);
                return Encoding.UTF8.GetString(bytes);
            }
            catch(Exception)
            {
                return value;
            }
        }
    

    In the controller, I did something like:

    [Route("api/ApplicationUser/{username}")]
    [ResponseType(typeof(ApplicationUser))]
    public IHttpActionResult GetApplicationUser(string username)
    {
    
        username = username.FromBase64();
    
        ApplicationUser user = new ApplicationUser()
    
        //Code to populate user.
    
        return Ok(user);
    }
    

    In the client, I did something like:

        async Task<ApplicationUser> IApplicationUserService.GetApplicationUser(string username)
        {
    
            username = username.ToBase64();
    
            ApplicationUser ret = null;
    
                var response = await _httpClient.GetAsync($"api/ApplicationUser/{username}");
    
                if (response.IsSuccessStatusCode)
                {
                    ret = await JsonSerializer.DeserializeAsync<ApplicationUser>
                                  (await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
                }
    
            return ret; ;
        }
    

    Cheers, Jim