C# – ASP.NET MVC Attribute-Routing with Null Values

asp.netasp.net-mvcc

Here is a paste of the action method MovieCustomer in the EverythingController.
The Viewmodel is used to Combine two Models: Customer & Movies, and is populated with information from the Database via the ApplicationDbContext (_context).

The Routeing works successfully and renders the page when there are values for MovieId and CustomerId

e.g. /Everything/MovieCustomer/1/1

I want the page to also load if one or both of the values are null. So far both of the int parameters were made nullable and there is an if statement in the method to change the parameters to 1 if either is null.
So far if the values are null the browser returns a 404 error.

How can I get the page to function when one or either of the parameters are null? Thanks

[Route("Everything/MovieCustomer/{movieId}/{customerId}")]
public ActionResult MovieCustomer(int? movieId, int? customerId)
{
    var viewmodel = new ComboViewModel
    {
        _Customers = new List<Customer>(),
        _Movies = new List<Movies>(),
        _customer = new Customer(),
        _movie =  new Movies()
    };
    viewmodel._Customers = _context.Customers.ToList();
    viewmodel._Movies = _context.Movies.ToList();

    if (!movieId.HasValue)
        movieId = 1;

    if (!customerId.HasValue)
        customerId = 1;

    viewmodel._customer = viewmodel._Customers.SingleOrDefault(a => a.Id == customerId);
    viewmodel._movie = viewmodel._Movies.SingleOrDefault(a => a.Id == movieId);

    return View(viewmodel);
}

Best Answer

You can achieve this using separate routes, or change your parameters to be optional.

When using 3 attributes, you add separate routes for each of the options that you have - when no parameters are specified, when only movieId is specified, and when all 3 parameters are specified.

[Route("Everything/MovieCustomer/")]
[Route("Everything/MovieCustomer/{movieId}")]
[Route("Everything/MovieCustomer/{movieId}/{customerId}")]
public ActionResult MovieCustomer(int? movieId, int? customerId)
{
    // the rest of the code
}

Alternatively you an combine change your route parameters to optional (by adding ? in route definition) and this should cover all 3 cases that you have:

[Route("Everything/MovieCustomer/{movieId?}/{customerId?}")]
public ActionResult MovieCustomer(int? movieId, int? customerId)
{
    // the rest of the code
}

Keep in mind that neither sample supports the case where you provide only customerId.