.NET Core路由:了解使用通用路由调用的应用程序

4

我有一个基本控制器,以下是[Route]定义。

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

}

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

我的目标是让两个不同的应用程序可以调用我的控制器,并让我的代码知道是哪个“应用程序”在调用它。

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

这两个请求都应该指向同一个控制器,但我的代码应该知道哪个应用程序调用了它。

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


“应用程序”是什么意思?你是指客户端通过HTTP调用它吗? - DavidG
你不觉得最好通过HTTP头传递这种信息而不是URL吗?或者使用一些映射到应用程序的API密钥? - DavidG
我并没有真正考虑使用HTTP头。这是可能的,但客户端通过路由来完成会更容易。 - Jamie Rees
这是我的最初想法,但我似乎无法通过谷歌搜索正确的词来得到答案@DavidG :) - Jamie Rees
我添加了一个答案,如果没有其他方法可以避免使用动态路由,它应该会给你提供如何根据你的要求继续进行的想法。 - DavidG
显示剩余5条评论
2个回答

3

就我个人而言,如果您希望在各处使用该值,那么我的首选是将其作为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
}

方法二使用说明:

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路由值,使用第三种方法中的基本控制器,将属性修改为以下内容:

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
您可以将路由模板移动到动作中,然后按照您提出的约定,每个动作在技术上都能意识到其调用者上下文:
[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);
    }
}

将其作为操作方法的一部分存在的问题是我必须在每个操作方法上都加上它。理想情况下,我希望在一个地方完成所有操作,这样任何人都可以添加更多的API而不必担心调用应用程序。 - Jamie Rees
你能否在基类构造函数中检查路由并根据约定设置一些字符串变量来标识调用者上下文,而不是简单地检查吗? - Vidmantas Blazevicius
你会如何建议在基类构造函数中访问那个路由变量? - Jamie Rees
@JamieRees 我已经为你添加了一个示例,展示如何完成它。 - Vidmantas Blazevicius
谢谢@DavidG,我最初认为可以在构造函数中完成,因此使用了readonly,但后来意识到在调用构造函数时HttpContext将不可用。 - Vidmantas Blazevicius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接