-1

I'm writing a generic report web api in C# and I want to have an optional parameter because some reports require only a report id and primary id and sometimes I need report id, primary id and secondary id.

However currently this works: http://localhost:50505/api/report/4/9981/0

But this doesn't: http://localhost:50505/api/report/4/9981

I don't want to pass a zero because the parameter is not used for report of id 4.

This is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Description;
using IPD_Report.Api.Interfaces.Factories;
using IPD_Report.Dtos.RequestModels;
using IPD_Report.Dtos.ResponseModels;
using IPD_Report.SoapService.Attributes;
using IPD_Report.SoapService.Commands;
using IPD_Report.SoapService.Interfaces.Commands;

namespace IPD_Report.Api.Controllers
{
    /// <summary>
    /// This controller is used to generate reports based on report ID.
    /// </summary>
    [RoutePrefix("api/report")]
    public class ReportController : ApiController
    {
        private readonly IReportCommands _reportCommands;
        private readonly IDtoFactory _dtoFactory;

        public ReportController(IReportCommands reportCommands, IDtoFactory dtoFactory)
        {
            _reportCommands = reportCommands;
            _dtoFactory = dtoFactory;
        }

        /// <summary>
        /// Generic GET request for returning report.
        /// </summary>
        /// <param name="reportId"></param>
        /// <param name="primaryId"></param>
        /// <param name="secondaryId"></param>
        /// byte[]
        [Route("{reportId}/{primaryId}/{secondaryId}")]
        [ResponseType(typeof(byte[]))]
        [HttpGet]
        public IHttpActionResult Get(int reportId, int primaryId, int? secondaryId = 0)
        {
            var dto = _dtoFactory.GenerateModel(reportId, primaryId, secondaryId);

            var stuff = GetAttribute(reportId, dto);

            return Ok(stuff);
        }

        /// <summary>
        /// Returns a list of available methods as a string list containing the method ID, method name, and returned filetype
        /// </summary>
        /// <returns>List&lt;List&lt;string&gt;&gt;</returns>
        [Route("getReportList")]
        [ResponseType(typeof(IEnumerable<ReportTypeModel>))]
        [HttpGet]
        public IHttpActionResult GetReportList()
        {
            var methodInfo = typeof(ReportCommands).GetMethods()
                .Where(x => x.GetCustomAttributes(false).OfType<MethodId>().Any())
                .Select(x => x.GetCustomAttributesData().Select(y => y.ConstructorArguments)).ToList();


            var methodList = new List<ReportTypeModel>();
            for(var i =0;i<methodInfo.Count;i++)
            {
                var annotation = (methodInfo.ToList()[i]?.ToList().FirstOrDefault() ?? throw new InvalidOperationException()).ToList();

                methodList.Add(new ReportTypeModel
                {
                    Id = int.Parse(annotation[0].Value.ToString()),
                    Name = annotation[1].Value.ToString(),
                    Format = annotation[2].Value.ToString()

                });
            }

            return Ok(methodList);
        }

        private object GetAttribute(int id, BaseModel baseModel)
        {
            var methodInfo = typeof(ReportCommands).
                GetMethods()
                .Where(x => x.GetCustomAttributes(false).OfType<MethodId>().Any())
                .First(x => x.GetCustomAttributes(false).OfType<MethodId>().First().Id == id);


            return methodInfo.Invoke(_reportCommands, new object[] { baseModel });
        }
    }
}

I need some help advise for this:

public IHttpActionResult Get(int reportId, int primaryId, int? secondaryId = 0)

I've writing secondary ID as an optional parameter but if I try to call this url: http://localhost:50505/api/report/4/9981

I get a 404.

Any advice?

Nick

4
  • 1
    Make it optional in the route template [Route("{reportId}/{primaryId}/{secondaryId?}")] Commented Jan 3, 2018 at 11:50
  • @Nkosi I didn't realise you could add a question mark to route parameter in the route attribute to denote it as optional. That worked. Commented Jan 3, 2018 at 11:53
  • Reference Attribute Routing in ASP.NET Web API 2 Commented Jan 3, 2018 at 11:54
  • More specifically Optional URI Parameters and Default Values Commented Jan 3, 2018 at 11:55

1 Answer 1

0

Just change the route parameter and make it nullable;

[Route("{reportId}/{primaryId}/{secondaryId?}")]
Sign up to request clarification or add additional context in comments.

2 Comments

This was an obvious duplicate...
@Rainman this worked. It's the same as Nkosi suggestions.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.