.net core 路由,用通用路由了解什么应用程序调用

.net core routing, understand what application called with a generic route

所以我有一个基本控制器,下面的 [Route] 定义

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

}

我当前的所有控制器都继承自 BaseController

我想要实现的是两个不同的应用程序可以调用我的控制器和我的代码以了解 'application' 调用它的内容。

应用程序 1 应该可以调用 /Application1/Api/MyController
应用程序 2 应该能够调用 /Application2/Api/MyController

这两个请求应该发送到同一个控制器,但我的代码应该知道调用它的是哪个应用程序。

我考虑过使用某种中间件,然后从 Request.Path 中构建应用程序,然后将其存储在 HttpContext.Current.Items 之类的东西中,但这似乎不是正确的方法做吧。

您可以将路由模板移动到操作中,然后每个操作在技术上都会根据您提议的约定了解其调用者上下文:

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

当然,这是您建议的约定,它不会以任何方式通过某些自定义应用程序身份验证强制执行,因此您必须相信您的调用者会通过此约定正确识别自己。

另一种方法,可能是有一个基础 class 变量并在检查路线后设置它。

[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);
    }
}

我个人的偏好是将值作为 HTTP header 而不是路由参数传递,尤其是当您希望它无处不在时。这意味着您不需要 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
{
}

方法一用法:

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

方法二用法:

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

方法三用法:

首先,创建一个包含 属性:

的基本控制器
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]")]

现在您应该在控制器设置上设置 属性 值。