【问题标题】:Programmatically invoking the ASP.NET Core request pipeline以编程方式调用 ASP.NET Core 请求管道
【发布时间】:2018-10-28 16:26:24
【问题描述】:

问题

如果我有一个 HTTP 动词、路由、标头和正文有效负载,有没有办法从我自己的应用程序中以编程方式调用 ASP.NET Core 请求管道?

背景

在某些用例中,我们的 ASP.NET Core 应用程序的 WebAPI 无法访问,因为该应用程序在防火墙后面运行或无法访问。

为了为这种情况提供解决方案,我们希望我们的应用程序轮询一些其他服务以获取“工作项”,然后将其转换为我们应用程序中的 API 调用。

我考虑的方法

  • 我可能只要求 DI 给我一个控制器实例,然后调用它的方法。这种方法的问题:
    • 不强制执行授权属性。但在我们的用例中,验证不记名令牌很重要。所以这里的问题是:如何以编程方式调用授权中间件?
    • 我必须自己将传入的工作项路由到正确的控制器/方法。
  • 使用Microsoft.AspNetCore.TestHost 包,我可以创建一个TestClient,它允许我向自己提出请求(参见here)。但这里有几个不确定性:
    • TestHost 的预期用例是用于集成测试。在生产环境中使用它是否安全?
    • 是否有可能让这样的TestServer 与常规主机一起运行?
    • 线程安全呢?我可以从单个 TestServer 实例创建多个 TestClients 并在不同线程中使用它们吗?

所以我确信必须有一种更简洁、更直接的方法来从我自己的应用程序中以编程方式调用请求管道...

【问题讨论】:

  • 恐怕我不明白你的问题。当您遇到防火墙问题时,您首先无法访问控制器,那么您如何让它直接调用自己?我在这里错过了什么吗?
  • 您可以使用HttpClient 发出新请求吗?这就是您向“外部”网站发出请求的方式,例如github
  • @SimplyGed,看起来我忽略了最明显的解决方案——老实说,这似乎有点骇人听闻。我还深入研究了 TestServer 源代码,发现了 IHttpApplication 接口,它有一个 ProcessRequestAsync 方法,显然允许通过请求管道推送请求。我可能会仔细研究一下,否则就按照您的建议使用 HttpClient 调用我自己的 API。
  • @RobertHegner,这个解决方案对你有用吗?如果是这样,我想知道您是否可以分享您的实现最终的样子,ProcessRequestAsync 方法看起来很有趣。我有一个类似的用例,最近要求提供一些指导stackoverflow.com/questions/56207115/…
  • @user991985 我最终使用了 Simply Ged 的建议(使用 HtttpClient 来调用我自己的端点)。

标签: asp.net-core middleware asp.net-core-testhost request-pipeline


【解决方案1】:

是的,这实际上相当容易。您可以在 Startup 类的 Configure 方法末尾获得对请求管道的引用。将其保存在静态字段/单例服务/等中。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  // ... usual configuration code

  AClass.PipelineStaticField = app.Build();
}

然后,在您希望注入请求的方法中,您必须构建一个 HttpContext 以传递到管道中。

var ctx = new DefaultHttpContext();

// setup a DI scope for scoped services in your controllers etc.
using var scope = _provider.CreateScope();
ctx.RequestServices = scope.ServiceProvider;

// prepare the request as needed
ctx.Request.Body = new MemoryStream(...);
ctx.Request.ContentType = "application/json";
ctx.Request.ContentLength = 1234;
ctx.Request.Method = "POST";
ctx.Request.Path = PathString.FromUriComponent("/mycontroller/action");

// you only need this if you are hosting in IIS (.UseIISIntegration())
ctx.Request.Headers["MS-ASPNETCORE-TOKEN"] = Environment.GetEnvironmentVariable("ASPNETCORE_TOKEN");

// setup a place to hold the response body
ctx.Response.Body = new MemoryStream();

// execute the request
await AClass.PipelineStaticField(ctx);

// interpret the result as needed, e.g. parse the body
ctx.Response.Body.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(ctx.Response.Body);
string body = await reader.ReadToEndAsync();

这样您的请求将遍历整个管道,包括身份验证和授权等所有中间件。

【讨论】:

  • 我没有测试它,因为我不再从事那个项目(问题来自 2018 年)。但它看起来不错,我相信它会帮助其他人。感谢您的回答!
猜你喜欢
  • 2010-11-21
  • 1970-01-01
  • 1970-01-01
  • 2018-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多