locked
ASP:NET web API route attribute question RRS feed

  • Question

  • User-1104215994 posted

    Hello,

    I have a web API and at first I had only one controller (api/v2/game) as follows;

    [System.Web.Http.RoutePrefix("api/v2/game")]
        public class LoadTestController : ApiController
        {
            private readonly IGameServicesTest _gameServices;
            
            #region Public Constructor  
    
            /// <summary>  
            /// Public constructor to initialize game service instance  
            /// </summary>  
            public LoadTestController(IGameServicesTest gameServices)
            {
                _gameServices = gameServices;
            }
    
    
            #endregion
    
    
            // POST: api/Game
            //[RequireHttps] For Prod Only
            [ValidTimeFilter]
            [ValidProductCodeFilter]
            [ValidIntervalFilter]
            [ValidTotalDailySale]
            [ValidTerminalFilter]
            [HttpPost, Route("purchase")]
            public async Task<IHttpActionResult> PurchaseGame(RequestDto game){
    ...

    Now I added one more controller (api/v2/web/game) but requests couldn't hit this new controller;

    [System.Web.Http.RoutePrefix("api/v2/web/game")]
        public class PalasController : ApiController
        {
            private readonly IGameServicesWeb _gameServices;
    
            #region Public Constructor  
    
            /// <summary>  
            /// Public constructor to initialize game service instance  
            /// </summary>  
            public PalasController(IGameServicesWeb gameServices)
            {
                _gameServices = gameServices;
            }
    
    
            #endregion
            [ValidProductCodeFilter]
            [HttpPost, Route("purchase")]
            public async Task<IHttpActionResult> PurchaseGame(RequestDto game)
            {
    ...

    Here is the webapiconfig;

    public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
                config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling =
                    Newtonsoft.Json.DateTimeZoneHandling.Local;
                // Web API routes
                config.MapHttpAttributeRoutes();
                
                
                //Registering RequestResponseHandler
                config.MessageHandlers.Add(new RequestResponseHandler());
                //Registering CustomExceptionFilter
                config.Filters.Add(new CustomExceptionFilter());
                
                var resolver = config.DependencyResolver;
                var basicAuth = resolver.GetService(typeof(BasicAuthenticationAttribute)) as BasicAuthenticationAttribute;
                // Web API configuration and services
                config.Filters.Add(basicAuth);
    
                
            }

    I am trying with postman but requests don't reach the controller. What is missing?

    Sunday, August 2, 2020 12:28 PM

Answers

  • User475983607 posted

    There is not enough information to reproduce this issue. 

    I built a very basic RoutePrefix and Route test and the attributes work exactly as written in the reference documentation.  Please take a few moments to debug your code.

    URLs

    https://localhost:44371/api/v2/game/purchase
    https://localhost:44371/api/v2/web/game/purchase
        [System.Web.Http.RoutePrefix("api/v2/web/game")]
        public class PalasController : ApiController
        {
            // api/v2/web/game/purchase
            [HttpGet, Route("purchase")]
            public string PurchaseGame()
            {
                return "PalasController";
            }
        }
        // api/v2/game/
        [RoutePrefix("api/v2/game")]
        public class LoadTestController : ApiController
        {
            // api/v2/game/purchase
            [HttpGet, Route("purchase")]
            public string PurchaseGame()
            {
                return "LoadTestController";
            }
        }

    API Route configuration

            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, August 2, 2020 1:07 PM
  • User1686398519 posted

    Hi cenk1536,

    Has the problem you encountered at first been resolved?I have other solutions you can refer to it.

    1. Because you have defined the default routeTemplate, when you use RoutePrefix, it will look for a matching routeTemplate. If you don't define it, you won't be able to find it.You need to define routeTemplate in WebApiConfig.cs.
    2. The order in which the routes are registered in the route table is important. Register more specific routes first, and then register more general routes to avoid false matches.

    WebApiConfig.cs

                config.Routes.MapHttpRoute(
                     name: "webgameApi",
                     routeTemplate: "api/v2/web/game/{controller}/{id}",
                     defaults: new { id = RouteParameter.Optional }
                 );
                config.Routes.MapHttpRoute(
                    name: "gameApi",
                    routeTemplate: "api/v2/game/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 3, 2020 8:54 AM

All replies

  • User475983607 posted

    There is not enough information to reproduce this issue. 

    I built a very basic RoutePrefix and Route test and the attributes work exactly as written in the reference documentation.  Please take a few moments to debug your code.

    URLs

    https://localhost:44371/api/v2/game/purchase
    https://localhost:44371/api/v2/web/game/purchase
        [System.Web.Http.RoutePrefix("api/v2/web/game")]
        public class PalasController : ApiController
        {
            // api/v2/web/game/purchase
            [HttpGet, Route("purchase")]
            public string PurchaseGame()
            {
                return "PalasController";
            }
        }
        // api/v2/game/
        [RoutePrefix("api/v2/game")]
        public class LoadTestController : ApiController
        {
            // api/v2/game/purchase
            [HttpGet, Route("purchase")]
            public string PurchaseGame()
            {
                return "LoadTestController";
            }
        }

    API Route configuration

            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, August 2, 2020 1:07 PM
  • User-1104215994 posted

    Hi,

    Thanks but I did add this;

    config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );

    still no-hit to the new controller.

    Sunday, August 2, 2020 5:19 PM
  • User-1104215994 posted

    I got this error:

    {
        "Message": "An error has occurred.",
        "ExceptionMessage": "An error occurred when trying to create a controller of type 'OyunPalasController'. Make sure that the controller has a parameterless public constructor.",
        "ExceptionType": "System.InvalidOperationException",
        "StackTrace": "   konum: System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   konum: System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   konum: System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()",
        "InnerException": {
            "Message": "An error has occurred.",
            "ExceptionMessage": "Resolution failed with error: No public constructor is available for type BusinessService.IGameServicesWeb.\n\nFor more detailed information run Unity in debug mode: new UnityContainer(ModeFlags.Diagnostic)",
            "ExceptionType": "Unity.ResolutionFailedException",
            "StackTrace": "   konum: Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)\r\n   konum: Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)\r\n   konum: Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)\r\n   konum: Unity.AspNet.WebApi.UnityDependencyResolver.SharedDependencyScope.GetService(Type serviceType)\r\n   konum: System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   konum: System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)",
            "InnerException": {
                "Message": "An error has occurred.",
                "ExceptionMessage": "No public constructor is available for type BusinessService.IGameServicesWeb.",
                "ExceptionType": "System.InvalidOperationException",
                "StackTrace": "   konum: Unity.Processors.ConstructorProcessor.<>c.<GetResolver>b__15_1(BuilderContext& c)\r\n   konum: Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)\r\n   konum: Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)\r\n   konum: Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)\r\n   konum: Unity.UnityContainer.<>c__DisplayClass111_0.<OptimizingFactory>b__0(BuilderContext& c)\r\n   konum: Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)\r\n   konum: Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)\r\n   konum: Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)\r\n   konum: Unity.Builder.BuilderContext.Resolve(Type type, String name)\r\n   konum: Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)\r\n   konum: Unity.Processors.ParametersProcessor`1.<>c__DisplayClass7_0.<CreateParameterResolvers>b__0(BuilderContext& context)\r\n   konum: Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)\r\n   konum: Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)\r\n   konum: Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)\r\n   konum: Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)\r\n   konum: Unity.UnityContainer.<>c__DisplayClass111_0.<OptimizingFactory>b__0(BuilderContext& c)\r\n   konum: Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)\r\n   konum: Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)",
                "InnerException": {
                    "Message": "An error has occurred.",
                    "ExceptionMessage": "'Unity.Exceptions.InvalidRegistrationException' türünde özel durum oluşturuldu.",
                    "ExceptionType": "Unity.Exceptions.InvalidRegistrationException",
                    "StackTrace": null
                }
            }
        }
    }

    Sunday, August 2, 2020 5:24 PM
  • User475983607 posted

    The error message is very clear, OyunPalasController does not have a parameterless constructor.  Add a parameterless constructor to OyunPalasController. 

    I think it is important to point out that your original post did not even mention OyunPalasController.  

    Sunday, August 2, 2020 9:39 PM
  • User-1104215994 posted

    I added this;

    container.RegisterType<IGameServicesWeb, GameServicesWeb>().RegisterType<UnitOfWork>(new TransientLifetimeManager());

    and it is OK.

    Monday, August 3, 2020 8:00 AM
  • User1686398519 posted

    Hi cenk1536,

    Has the problem you encountered at first been resolved?I have other solutions you can refer to it.

    1. Because you have defined the default routeTemplate, when you use RoutePrefix, it will look for a matching routeTemplate. If you don't define it, you won't be able to find it.You need to define routeTemplate in WebApiConfig.cs.
    2. The order in which the routes are registered in the route table is important. Register more specific routes first, and then register more general routes to avoid false matches.

    WebApiConfig.cs

                config.Routes.MapHttpRoute(
                     name: "webgameApi",
                     routeTemplate: "api/v2/web/game/{controller}/{id}",
                     defaults: new { id = RouteParameter.Optional }
                 );
                config.Routes.MapHttpRoute(
                    name: "gameApi",
                    routeTemplate: "api/v2/game/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 3, 2020 8:54 AM