0

我正在将 OAuth 身份验证分解为IHttpFilter以与HttpClient一起使用。我正在使用以下代码进行测试,期望它将所有请求简单地转发到HttpBaseProtocolFilter

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Filters.h>

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Http;
using namespace Windows::Web::Http::Filters;

struct TestHttpFilter : implements<TestHttpFilter, IHttpFilter>
{
    TestHttpFilter(IHttpFilter inner_filter) : inner_filter_{ inner_filter } {}
    IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage const& request) const
    {
        auto const result{ co_await inner_filter_.SendRequestAsync(request) };
        co_return result;
    }
private:
    IHttpFilter inner_filter_{ nullptr };
};

int main()
{
    init_apartment();

    IHttpFilter const base_filter{ HttpBaseProtocolFilter{} };
    IHttpFilter const test_filter{ TestHttpFilter{ base_filter } };
    HttpClient const http_client{ test_filter };

    auto const result{ http_client.GetStringAsync({ L"http://aka.ms/cppwinrt" }).get() };

    printf("Response: %ls!\n", result.c_str());
}

过滤器链已正确创建,并传递给HttpClientc'tor。发出GetStringAsync调用时,代码内部崩溃TestHttpFilter::SendRequestAsync并出现以下错误:

Exception thrown at <address> in <app>.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

put_abi这看起来是在 SDK 头文件<Windows.Web.Http.Filters.h>内的调用中取消引用的 NULL 指针(为简洁起见,省略了命名空间):

template <typename D> IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> consume_Windows_Web_Http_Filters_IHttpFilter<D>::SendRequestAsync(HttpRequestMessage const& request) const
{
    IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> operation{ nullptr };
    check_hresult(WINRT_SHIM(IHttpFilter)->SendRequestAsync(get_abi(request), put_abi(operation)));
    return operation;
}

我不明白,我哪里做错了。我希望通过回答以下问题来深入了解它的核心:

  • 执行有什么问题TestHttpFilter吗?
  • HTTP过滤器可以与HttpClient(例如)的便捷实现一起使用,还是我们在使用过滤器时GetStringAsync需要通过接口?SendRequestAsync
  • 极不可能,但这可能是生成的 SDK 标头的问题,为本地operation对象选择了不合适的 c'tor?

我可以使用官方 Windows SDK 版本 10.0.17134.0 重现该问题。

4

1 回答 1

0

C++/WinRT投影带有一点类型对偶性1:有提供运行时类的实现的实现类型,也有包含Windows 运行时所需的脚手架的投影类型,并充当实现的代理类型。

当您创作将由 Windows 运行时 API 使用的运行时类时,这种区别变得很重要。有问题的代码实现了一个类型,但未能构造相应的投影类型。错误出现在以下代码行中:

IHttpFilter const test_filter{ TestHttpFilter{ base_filter } };
HttpClient const http_client{ test_filter };

第一行构造一个实现类型的实例。第二行将它传递给HttpClientc'tor,它需要一个投影类型2。解决方法是为TestHttpFilter代替构造投影类型,这可以使用make函数模板方便地完成:

IHttpFilter const test_filter{ make<TestHttpFilter>(base_filter) };
HttpClient const http_client{ test_filter };

一般建议:

  • 始终确保您了解您正在使用的类型。建立命名约定以区分实现类型和预计类型。
  • 通过 ABI 时,(通常)需要通过投影类型。在调用 Windows 运行时 API 或从实现类型返回值时,通常会跨越 ABI。
  • 无论你做什么,都不要让它在运行时失败。当你到达那里时,这个宇宙中最多只有一个人可以帮助你。

1 请参阅投影类型和实现类型是什么意思?

2 理想情况下,这应该无法编译,尽管我不知道如何在不(过度)限制通用库的多功能性的情况下实现它。

于 2018-05-25T11:56:33.800 回答