首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DelegatingHandler设置CurrentPrincipal

DelegatingHandler设置CurrentPrincipal
EN

Stack Overflow用户
提问于 2013-06-10 20:18:10
回答 2查看 1.9K关注 0票数 2

我正在尝试对DelegateHandler的一个实现进行单元测试。我的简化实现:

代码语言:javascript
复制
public class FooHandler
    : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Thread.CurrentPrincipal = new GenericPrincipal(
            new GenericIdentity("Vegard"), new[] { "A", "B" });

        return await base.SendAsync(request, cancellationToken);
    }
}

当我尝试对其进行单元测试时,我会这样做:

代码语言:javascript
复制
public class TestHandler : DelegatingHandler
{
    private readonly Func<HttpRequestMessage,
        CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
    public TestHandler()
    {
        _handlerFunc = (r, c) => Return(HttpStatusCode.OK);
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return _handlerFunc(request, cancellationToken);
    }

    public static Task<HttpResponseMessage> Return(HttpStatusCode status)
    {
        return Task.Factory.StartNew(
            () => new HttpResponseMessage(status));
    }
}

[TestMethod]
public async Task SendAsync_CorrectTokens_IsAuthorized()
{
    var message = new HttpRequestMessage(HttpMethod.Get, "http://www.test.com");

    var handler = new AuthorizationHeaderHandler
        {
            InnerHandler = new TestHandler()
        };

    var invoker = new HttpMessageInvoker(handler);
    var result = await invoker.SendAsync(message, new CancellationToken());

    Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
    Assert.IsTrue(Thread.CurrentPrincipal.Identity.IsAuthenticated); // fails
    Assert.AreEqual("Vegard", Thread.CurrentPrincipal.Identity.Name); // fails
}

我猜测这是因为HttpMessageInvoker在单独的线程上运行DelegateHandler。我可以强制它们在同一个线程上吗?

EN

回答 2

Stack Overflow用户

发布于 2013-06-10 21:43:23

我可以强制它们在同一个线程上吗?

你不能这么做。

一个更好的问题是“我如何将Thread.CurrentPrincipal流到正在执行请求的线程”?这个问题有一个答案。

Thread.CurrentPrincipal在ASP.NET中很奇怪,实际上,我建议您根本不要使用它,而是使用HttpContext.User。但如果你愿意,你可以通过理解以下几点来让它工作:

每当线程进入

  1. HttpContext.User请求SynchronizationContext.

时,ASP.NET都会传递HttpContext.User覆盖的ASP.NET

不幸的是,您当前的测试在几个关键点上存在缺陷:

  • 在请求完成后,Thread.CurrentPrincipal的值是当前运行测试的方式,没有HttpContext (或ASP.NET SynchronizationContext),这会干扰主要用户的流动。

要完全测试授权,您需要进行集成测试。

另请参阅my answer to this question

票数 3
EN

Stack Overflow用户

发布于 2013-06-10 21:39:14

您实际遇到的是await的行为。当您退出await时,Await会将主体重置为您进入await时的状态。因此,由于在调用await invoker.SendAsync时没有当前主体,因此在等待调用之后也不会有当前主体。

但是,您的测试处理程序应该看到正确的主体。您可以做的是让您的测试处理程序将当前主体存储在其SendAsync实现中,将其公开为公共属性,然后让您的测试断言测试处理程序看到了它应该看到的主体。这应该可以很好地工作,这应该是您关心的行为。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17023682

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档