具有不同控制器但具有相同操作名称的路由无法生成所需的URL

时间:2017-07-24 21:28:52

标签: c# rest asp.net-core routes asp.net-core-mvc

我正在尝试为我的MVC网络应用程序设置一个API,该应用程序将包含很多路由,但每个路由都有很多相同的部分。基本上每个区域的CRUD。我也将它设置为版本。我已经设置了两个控制器,每个控制器都有一个简单的操作来启动并立即接收冲突。我得到的错误是

我正在追踪这些网址

MVC会让你有一个

所以我正在寻找一个不必要地命名诸如contacts_deletelocations_delete之类的东西,产生像

这样的网址

我也可以做https://foo.bar/aim/v1/contacts_delete/11111,但这对我来说似乎毫无意义。如果MVC可以做到这一点,我必须相信有一种方法可以实现这一点。

我得到的错误是:

  

具有相同名称的属性路线'删除'必须具有相同的模板:

     

行动:' rest.fais.foo.edu.Controllers.aimContactsController.delete(rest.fais.foo.edu)' - 模板:'目标/ v1 / contacts / delete / {id}'

     

行动:' rest.fais.foo.edu.Controllers.aimLocationsController.delete(rest.fais.foo.edu)' - 模板:'目标/ v1 / locations / delete / {id}'

对于我设置的控制器

[EnableCors("SubDomains")]
[ResponseCache(NoStore = true, Duration = 0)]
[Produces("application/json")]
[Route("aim/v1/contacts/[action]")]
[ProducesResponseType(typeof(errorJson), 500)]
public class aimContactsController : Controller
{
    private readonly IHostingEnvironment _appEnvironment;
    private readonly AimDbContext _aim_context;
    private readonly UserManager<ApplicationUser> _userManager;

    public aimContactsController(IHostingEnvironment appEnvironment,
        AimDbContext aim_context,
        UserManager<ApplicationUser> userManager)
    {
        _appEnvironment = appEnvironment;
        _userManager = userManager;
        _aim_context = aim_context;
    }



    [HttpPost("{id}", Name = "delete")]
    public IActionResult delete(string id)
    {

        return Json(new
        {
            results = "deleted"
        });
    }

}


[EnableCors("SubDomains")]
[ResponseCache(NoStore = true, Duration = 0)]
[Produces("application/json")]
[Route("aim/v1/locations/[action]")]
[ProducesResponseType(typeof(errorJson), 500)]
public class aimLocationsController : Controller
{
    private readonly IHostingEnvironment _appEnvironment;
    private readonly AimDbContext _aim_context;
    private readonly UserManager<ApplicationUser> _userManager;

    public aimLocationsController(IHostingEnvironment appEnvironment,
        AimDbContext aim_context,
        UserManager<ApplicationUser> userManager)
    {
        _appEnvironment = appEnvironment;
        _userManager = userManager;
        _aim_context = aim_context;
    }



    [HttpPost("{id}", Name = "delete")]
    public IActionResult delete(string id)
    {

        return Json(new
        {
            results = "deleted"
        });
    }

}

对于 Startup.cs 我有

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
        //RolesData.SeedRoles(app.ApplicationServices).Wait();

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            //app.UseExceptionHandler("/Home/Error");
        }

        app.UseIdentity();
        app.UseDefaultFiles();
        app.UseStaticFiles();

        //app.UseResponseCompression();

        // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
        app.UseSession();

        // custom Authentication Middleware
        app.UseWhen(x => (x.Request.Path.StartsWithSegments("/aim_write", StringComparison.OrdinalIgnoreCase) || x.Request.Path.StartsWithSegments("/rms", StringComparison.OrdinalIgnoreCase)),
        builder =>
        {
            builder.UseMiddleware<AuthenticationMiddleware>();
        });

        // Enable middleware to serve generated Swagger as a JSON endpoint.
        app.UseSwagger();

        // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
        app.UseSwaggerUI(c =>
        {
            c.RoutePrefix = "docs";
            //c.SwaggerEndpoint("/docs/v1/wsu_restful.json", "v1.0.0");swagger
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1.0.0");
        });


        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "javascript",
                template: "javascript/{action}.js",
                defaults: new { controller = "mainline" });
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
            routes.MapRoute(
                name: "AIMApi",
                template: "aim/v1/{action}/{id?}",
                defaults: new { controller = "aim" });
            routes.MapRoute(
                name: "AIMContactsApi",
                template: "aim/v1/contacts/{action}/{id?}",
                defaults: new { controller = "aimContactsController" }
            );
            routes.MapRoute(
                name: "AIMLocationsApi",
                template: "aim/v1/locations/{action}/{id?}",
                defaults: new { controller = "aimLocationsController" }
            );
            routes.MapRoute(
                name: "RMSApi",
                template: "{controller=rms}/v1/{action}/{id?}");
        });
    }
}

我似乎无法解决如何解决此问题的答案。我想解决当前的问题,但欢迎任何建议。

3 个答案:

答案 0 :(得分:12)

两个路由的名称相同,这在ASP.NET Core MVC中无效。

我不是在谈论命名的方法,而是关于路由命名。您在Name = "delete"属性中调用了两个标识为HttpPost的路由。 MVC中的路由名称唯一标识路由模板。

从我所看到的,你并不需要确定你的路线,只是为了区分不同的URI。因此,您可以自由删除操作方法的Name属性的HttpPost属性。这应该足以让ASP.NET Core路由器匹配您的操作方法。

如果您只使用属性路由进行还原,则最好将控制器更改为以下内容:

// other code omitted for clarity
[Route("aim/v1/contacts/")]
public class aimContactsController : Controller
{
    [HttpPost("delete/{id}")]
    public IActionResult delete(string id)
    {
        // omitted ...
    }
}

答案 1 :(得分:0)

另一个可能的解决方案是:

// other solution
[Route("aim/v1/contacts/[Action]")]
public class aimContactsController : Controller
{
    [HttpPost("{id}")]
    public IActionResult delete(string id)
    {
        // omitted ...
    }
}

答案 2 :(得分:0)

具有动态名称的示例:

[Route("api/{lang}/[controller]/[Action]")]
    [ApiController]
    public class SpatiaController : ControllerBase
    {
        private readonly ISpatialService _service;
        private readonly ILogger<SpatialController> _logger;

        public SpatialUnitsIGMEController(ILogger<SpatialController> logger, ISpatialService service) 
        {
            _service = service;
            _logger = logger;
        }


        [HttpGet]
        public async Task<ActionResult<IQueryable<ItemDto>>> Get50k(string lang)
        {
            var result = await _service.GetAll50k(lang);
            return Ok(result);
        }

        [HttpGet("{name}")]
        public async Task<ActionResult<ItemDto>> Get50k(string lang, string name)
        {
            var result = await _service.Get50k(lang, name);
            return Ok(result);
        }
    }

要调用这些端点,将使用以下调用:

https://example.domain.com/api/en/spatial/get50k->我们用英语获取所有数据

https://example.domain.com/api/en/spatial/get50k/madrid->我们获得了英语的马德里数据

https://example.domain.com/api/es/spatial/get50k/madrid->我们获得了西班牙语的马德里数据

(使用路线中的动作和语言)