Маршрутизация ядра .net, понять, какое приложение вызывается с помощью общего маршрута - PullRequest
4 голосов
/ 10 июня 2019

Итак, у меня есть базовый контроллер, который следующее [Route] определение

[Route("{application}/api/[controller]")]
public class BaseController
{

}

Все мои текущие контроллеры наследуют от BaseController.

Чего я пытаюсь достичьв том, что два разных приложения могут вызывать мои контроллеры и мой код, чтобы знать, что его называет «приложение».

Приложение 1 должно иметь возможность вызывать /Application1/Api/MyController
Приложение 2 должно иметь возможность вызывать/Application2/Api/MyController

и оба запроса должны идти к одному и тому же контроллеру, но мой код должен знать, какое приложение вызвало его.

Я думал о наличии некоторого промежуточного программного обеспечения, а затем работал над приложениемиз Request.Path, а затем сохраните его в чем-то вроде HttpContext.Current.Items, но это не похоже на правильный способ сделать это.

Ответы [ 2 ]

3 голосов
/ 10 июня 2019

Здесь я предпочитаю передавать значение в виде заголовка HTTP, а не параметра маршрута, особенно если вы хотите его везде. Это означает, что вам не нужен атрибут Route и другой URL для каждого приложения. Используя пользовательский ActionFilterAttribute, есть множество способов передать эту деталь в ваши действия. Например:

public class ApplicationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.HttpContext.Request.Headers.TryGetValue("Application", out var values))
        {
            // Method 1: This allows you to specify a parameter on your action
            context.ActionArguments.Add("application", values.First());

            // Method 2: This adds the value into the route data
            context.RouteData.Values.Add("Application", values.First());

            // Method 3: This will set a property on your controller
            if (context.Controller is BaseApplicationController baseController)
            {
                baseController.Application = values.First();
            }
        }

        base.OnActionExecuting(context);
    }
}

И примените его к методам действий или вашему контроллеру:

[Application]
public class FooController : Controller
{
}

Способ 1 Использование:

public IActionResult Index(string application)
{
    // do something with the parameter passed in
}

Способ 2 Использование:

public IActionResult Index(string application)
{
    var application = (string)RouteData.Values["Application"];
}

Способ 3 Использование:

Сначала создайте базовый контроллер, содержащий свойство:

public abstract class BaseApplicationController : Controller
{
    public string Application { get; set; }
}

Затем убедитесь, что ваш контроллер наследует от него:

[Application]
public class FooController : BaseApplicationController
{
}

Теперь вы можете получить доступ к свойству на вашем контроллере:

public IActionResult Index(string application)
{
    var application = this.Application;
}

Бонусный метод 4:

Кроме того, вы можете использовать этот метод для использования значения маршрута URL, используя базовый контроллер из метода 3, изменив атрибут так, чтобы он выглядел следующим образом:

public class ApplicationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.Controller is BaseApplicationController baseController)
        {
            baseController.Application = (string)context.RouteData.Values["application"];
        }

        base.OnActionExecuting(context);
    }
}

Добавить атрибут маршрута в ваш контроллер:

[Route("{application}/api/[controller]/[action]")]

А теперь у вас должно быть значение свойства в наборе контроллера.

1 голос
/ 10 июня 2019

Вы можете переместить шаблон маршрута в действие, и тогда каждое действие будет технически осведомлено о контексте вызывающего абонента в соответствии с предложенным соглашением:

[Route("api/[controller]")]
public class YourController : BaseController
{
    [HttpGet("{application}")]
    public IActionResult Get(string application)
    {
        if (application == "Application1")
        {
            ...Application1 called
        }
        if (application == "Application2")
        {
            ...Application2 called
        }
        ...        
    } 
}

Конечно, это ваше предлагаемое соглашение, и оно никоим образом не применяется посредством какой-либо пользовательской аутентификации приложения, поэтому вам придется верить, что ваши абоненты правильно идентифицируют себя в этом соглашении.

Другой подход может состоять в том, чтобы иметь переменную базового класса и установить ее после проверки маршрута.

[Route("{application}/api/[controller]")
public class BaseController: Controller
{
    protected string CallingApp { get; set; }

    public override void OnActionExecuting(ActionExecutingContext ctx)
    {
        CallingApp  = ctx.RouteData.Values["application"];
        base.OnActionExecuting(ctx);
    }
}
...