web-dev-qa-db-ja.com

コントローラーが異なるが同じアクション名のルートは、必要なURLを生成できません

私はMVC WebアプリのAPIをセットアップしようとしていますが、これには多くのルートがありますが、それぞれに同じ部分があります。基本的に各エリアのCRUD。また、バージョン対応に設定しています。私は2つのコントローラーをそれぞれセットアップし、簡単なアクションで開始してすぐに競合を受け取ります。私が得るエラーは

私はこれらのURLの後にいます

MVCを使用すると、

だから私はcontacts_deleteおよびlocations_deleteのようなURLを生成する

https://foo.bar/aim/v1/contacts_delete/11111しかし、それは私にはあまり意味がありません。 MVCがそれを実行できる場合、これを実現する方法があると私は信じる必要があります。

私が得るエラーは:

同じ名前「delete」の属性ルートには同じテンプレートが必要です。

アクション: 'rest.fais.foo.edu.Controllers.aimContactsController.delete(rest.fais.foo.edu)'-テンプレート: 'aim/v1/contacts/delete/{id}'

アクション: 'rest.fais.foo.edu.Controllers.aimLocationsController.delete(rest.fais.foo.edu)'-テンプレート: 'aim/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?}");
        });
    }
}

私がこれを回避する方法の答えをググるように思えないこと。差し迫った問題を修正したいのですが、どんな提案も歓迎します。

11
jeremy.bass

両方のルートに同じ名前が付けられています。これはASP.NET Core MVCでは機能しません。

メソッドの命名についてではなく、ルートの命名について話しています。 HttpPost属性内で同じ識別子Name = "delete"を使用して両方のルートを呼び出しました。 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 ...
    }
}
13
Federico Dipuma

別の可能な解決策は次のとおりです。

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

アクション名を動的に使用した例:

[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 -> madridのデータを英語で取得します

https://example.domain.com/api/es/spatial/get50k/madrid ->スペイン語でマドリードのデータを取得

(ルートのアクションと言語を使用)

0
sanmolhec