Как я могу создать пользовательские маршруты WebAPI, такие как «package / {packageName} / {controller}», для маршрутизации к частям приложения в отдельной сборке?

#c# #asp.net-core #asp.net-core-webapi #asp.net-core-2.2

#c# #asp.net-core #asp.net-core-webapi #asp.net-core-2.2

Вопрос:

Наше приложение загружает контроллеры во внешние сборки, которые мы называем пакетами. Я хочу создать маршрут, который перенаправляет к пакету, используя URL-адреса, подобные package/BillingPackage/Invoice , а не api/BillingPackage/Invoice . Вот что я сделал:

Startup.cs

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseEndpointRouting()
        .UseMvc(routes =>
    {
        routes.MapRoute(
            name: "package", 
            template: "package/{package}/{controller}/{id?}");
        routes.MapRoute("api", "api/{controller}/{action=Get}/{id?}");            
        routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
    app.UseStaticFiles();
}

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var source = new PackageAssemblySource(Configuration);
    var packageAssemblies = source.Load();
    var builder = new ContainerBuilder();
    builder.RegisterModule(new WebApiModule(packageAssemblies));

    services
        .AddMvc()
        .ConfigureApplicationPartManager(manager =>
        {
            // Add controllers and parts from package assemblies.
            foreach (var assembly in packageAssemblies)
            {
                manager.ApplicationParts.Add(new AssemblyPart(assembly));
            }
        });
        .AddControllersAsServices() // Now that AssemblyParts are loaded.
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);;

    builder.Populate(services);
    ApplicationContainer = builder.Build();

    return new AutofacServiceProvider(ApplicationContainer);
}
  

Затем я определяю контроллер следующим образом:

 [Route("package/BillingPackage/[controller]", Name = "Invoice")]
public class InvoiceController : ControllerBase
{
    [HttpGet()]
    public ActionResult<Invoice> Get()
    {
        return new SampleInvoice();
    }
}
  

Даже при всем этом package/BillingPackage/Invoice выдает значение 404, тогда api/BillingPackage/Invoice как нет. Как мне заставить мой WebAPI обслуживать конечные точки package , а не api ?

Комментарии:

1. конфликт маршрута с template: "package/{package}/{controller}/{id?}" . Если вы используете атрибутивную маршрутизацию на контроллере, удалите этот маршрут на основе соглашения

2. Интересно, но тогда как мне указать имя пакета «BillingPackage», если не с маршрутом на контроллере?

3. Вы уже жестко запрограммировали имя пакета в шаблоне маршрута атрибута package/BillingPackage/[controller]

4. Да, я понимаю вашу точку зрения, но как контроллеры в пакете могут указывать имя пакета, если не по атрибутам? Как эти контроллеры могут быть связаны с этим именем пакета? Кроме того, RouteData всегда содержит только {"action":"Get","controller":"Customer"} вместо значения для package . Что мне нужно написать, чтобы извлечь это из URL?

5. вам нужно будет включить параметр шаблона [Route("package/{package}/[controller]", Name = "Invoice")] вместе с аргументом метода / действия public ActionResult<Invoice> Get(string package) , который будет заполняться из соответствующего значения из URL.

Ответ №1:

Вероятно, у вас возник конфликт маршрутов с template: "package/{package}/{controller}/{id?}" .

Если вы используете атрибутивную маршрутизацию на контроллере, удалите этот маршрут на основе соглашения

Чтобы получить желаемое поведение, вам нужно будет включить параметр шаблона [Route("package/{package}/[controller]", Name = "Invoice")] вместе с аргументом метода / действия public ActionResult<Invoice> Get(string package) , который будет заполнен из соответствующего значения из URL.

Например

 [Route("package/{package}/[controller]", Name = "Invoice")]
public class InvoiceController : ControllerBase {

    //GET package/BillingPackage/Invoice
    [HttpGet()]
    public ActionResult<Invoice> Get(string package) {
        return new SampleInvoice();
    }
}
  

Ссылочная маршрутизация на действия контроллера в ASP.NET Ядро