ASP.net Web Api 版本控制

3
我有一个ASP.net Web Api项目,决定支持版本控制。我使用微软官方Nuget来支持版本控制(更多信息请参见 这里),并且我决定按命名空间进行版本控制(例如 这里)。
不幸的是,我无法让代码正常工作。如果我像这样调用我的方法:
http://localhost:7291/api/Saved/GetNumberOfSavedWorkoutsForUser?api-version=2.0

我遇到了一个错误:
Multiple types were found that match the controller named 'Saved'. This can happen if the route that services this request ('api/{controller}/{action}/{id}') found multiple controllers defined with the same name but differing namespaces, which is not supported.

如果我这样调用它:http://localhost:7291/v2/Saved/GetNumberOfSavedWorkoutsForUser,会出现404错误。该接口与用户保存的锻炼计划相关。
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

我不确定我做错了什么。这是我的代码:

Startup.cs

public void Configuration(IAppBuilder app)
    {
        var configuration = new HttpConfiguration();
        var httpServer = new HttpServer(configuration);


        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

        // reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
        configuration.AddApiVersioning(o => 
        {
            o.AssumeDefaultVersionWhenUnspecified = true;
            o.ReportApiVersions = true; 
            o.DefaultApiVersion = ApiVersion.Default;
        });


        configuration.Routes.MapHttpRoute(
            "VersionedUrl",
            "v{apiVersion}/{controller}/{action}/{id}",
            defaults: null,
            constraints: new { apiVersion = new ApiVersionRouteConstraint() });

        configuration.Routes.MapHttpRoute(
            "VersionedQueryString",
            "api/{controller}/{action}/{id}",
            defaults: null);


        app.UseWebApi(httpServer);

        ConfigureAuth(app);
    }

保存的控制器(v1)

namespace Master.Infrastructure.Api.Controllers
{

    [Authorize]
    [RoutePrefix("api/Saved")]
    [ApiVersion("1.0")]
    public class SavedController : ApiController
    {

        private readonly IUserService _userService;

        public SavedController(IUserService userService)
        {
            _userService = userService;

        }


        [HttpGet]
        [ActionName("GetNumberOfSavedWorkouts")]
        public async Task<NumberOfSavedWorkouts> GetNumberOfSavedWorkouts()
        {
            var numOfSavedWorkouts = new NumberOfSavedWorkouts
            {
                CurrentNumberOfSavedWorkouts =
                    await _userService.GetNumberOfSavedWorkoutsForUserAsync(User.Identity.GetUserId())
            };

            return numOfSavedWorkouts;
        }

    }
}

Saved Controller (v2)

namespace Master.Infrastructure.Api.V2.Controllers
{
    [Authorize]
    [ApiVersion("2.0")]
    [RoutePrefix("v{version:apiVersion}/Saved")]
    public class SavedController : ApiController
    {

        private readonly ISavedWorkoutService _savedWorkoutService;


        public SavedController(ISavedWorkoutService savedWorkoutService)
        {       
            _savedWorkoutService = savedWorkoutService;
        }


        [ActionName("GetNumberOfSavedWorkoutsForUser")]
        public async Task<IHttpActionResult> GetNumberOfSavedWorkoutsForUser()
        {
            var cnt = await _savedWorkoutService.CountNumberOfSavedWorkoutsForUser(User.Identity.GetUserId());

            return Ok(cnt);
        }
    }
}
1个回答

7
您的路由配置有误。我强烈建议您不要混合使用路由风格,除非您确实需要这样做。它会让故障排除变得非常困难。
这里有几件事情需要注意:
  1. 您同时使用了查询字符串和URL段版本的配置,您想要哪一个呢?我建议只选择一个。默认和我的建议是使用查询字符串方法。
  2. 您的约定式路由与属性式路由不同。
  3. 由于您定义了RoutePrefixAttribute,看起来您更喜欢属性式路由风格。我建议删除所有的约定式路由(例如:configuration.Routes.MapHttpRoute)。
在您的约定中,路由模板为: v{apiVersion}/{controller}/{action}/{id} 但在您的属性中,路由模板为: api/Saved 这两个都不符合您期望的路由: http://localhost:7291/api/Saved/GetNumberOfSavedWorkoutsForUser http://localhost:7291/v2/Saved/GetNumberOfSavedWorkoutsForUser 对于使用路由属性的查询字符串方法,应该像这样:
configuration.AddApiVersioning(o => o.ReportApiVersions = true);

namespace Master.Infrastructure.Api.Controllers
{
    [Authorize]
    [ApiVersion("1.0")]
    [RoutePrefix("api/Saved")]
    public class SavedController : ApiController
    {
       private readonly IUserService _userService;
       public SavedController(IUserService userService) => _userService = userService;

       [HttpGet]
       [Route("GetNumberOfSavedWorkouts")]
       public async Task<IHttpActionResult> GetNumberOfSavedWorkouts()
       {
            var userId = User.Identity.GetUserId();
            var count = await _userService.GetNumberOfSavedWorkoutsForUserAsync(userId);
            return Ok(new NumberOfSavedWorkouts(){ CurrentNumberOfSavedWorkouts = count });
       }
    }
}

namespace Master.Infrastructure.Api.V2.Controllers
{
    [Authorize]
    [ApiVersion("2.0")]
    [RoutePrefix("api/Saved")]
    public class SavedController : ApiController
    {
       private readonly ISavedWorkoutService _savedWorkoutService;
       public SavedController(ISavedWorkoutService savedWorkoutService) => _savedWorkoutService = savedWorkoutService;

       [HttpGet]
       [Route("GetNumberOfSavedWorkoutsForUser")]
       public async Task<IHttpActionResult> GetNumberOfSavedWorkoutsForUser()
       {
            var userId = User.Identity.GetUserId();
            var count = await _savedWorkoutService.CountNumberOfSavedWorkoutsForUser(userId);
            return Ok(count);
       }
    }
}

以下应该就可以工作了: http://localhost:7291/api/Saved/GetNumberOfSavedWorkouts?api-version=1.0 http://localhost:7291/api/Saved/GetNumberOfSavedWorkoutsForUser?api-version=2.0 希望这有所帮助。

1
刚刚意识到我忘了一件事。你还需要在配置中加入以下内容才能使用基于属性的路由:configuration.MapHttpAttributeRoutes() - Chris Martinez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接