IHttpFilter 实现导致 HttpClient::GetStringAsync 调用的访问冲突
IHttpFilter implementation causes access violation for HttpClient::GetStringAsync call
我正在将 OAuth 身份验证分解为 IHttpFilter for use with an HttpClient. I'm using the following code for testing, expecting that it would simply forward all requests to the 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());
}
过滤器链已正确创建,并传递到 HttpClient
c'tor。发出 GetStringAsync
调用时,代码在 TestHttpFilter::SendRequestAsync
内崩溃并出现以下错误:
Exception thrown at <address> in <app>.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
这看起来是在 SDK header 文件 (命名空间为简洁起见省略):
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 headers 的问题,为本地选择了不合适的 c'tor
operation
object?
我可以使用官方 Windows SDK 版本 10.0.17134.0.
重现问题
C++/WinRT projection comes with a bit of type duality1: There are implementation types that provide the implementation of a runtime class, as well as projected types 包含 Windows 运行时所需的脚手架,并充当实现类型的代理。
当您编写要由 Windows 运行时 API 使用的运行时 class 时,这种区别变得很重要。有问题的代码实现了一个类型,但未能构造相应的投影类型。错误在以下代码行中:
IHttpFilter const test_filter{ TestHttpFilter{ base_filter } };
HttpClient const http_client{ test_filter };
第一行构造了一个实现类型的实例。第二行将它传递给 HttpClient
c'tor,它需要一个 projected type2。解决方法是为 TestHttpFilter
构造投影类型,这可以使用 make 函数模板方便地完成:
IHttpFilter const test_filter{ make<TestHttpFilter>(base_filter) };
HttpClient const http_client{ test_filter };
一般建议:
- 始终确保您了解您使用的是哪种类型。建立命名约定以区分实现类型和投影类型。
- 当跨越 ABI 时,(通常)需要传递一个投影类型。您通常会在调用 Windows 运行时 API 或 return 来自实现类型的值时跨越 ABI。
- 无论你做什么,都不要让它在运行时失败。很可能在这个宇宙中最多只有一个人可以在你到达那里时帮助你。
1 见What do the projected type and the implementation type mean?
2 理想情况下,这应该无法编译,尽管我不知道如何在不(过度地)限制通用的多功能性的情况下实现它图书馆.
我正在将 OAuth 身份验证分解为 IHttpFilter for use with an HttpClient. I'm using the following code for testing, expecting that it would simply forward all requests to the 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());
}
过滤器链已正确创建,并传递到 HttpClient
c'tor。发出 GetStringAsync
调用时,代码在 TestHttpFilter::SendRequestAsync
内崩溃并出现以下错误:
Exception thrown at <address> in <app>.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
这看起来是在 SDK header 文件
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 headers 的问题,为本地选择了不合适的 c'tor
operation
object?
我可以使用官方 Windows SDK 版本 10.0.17134.0.
重现问题C++/WinRT projection comes with a bit of type duality1: There are implementation types that provide the implementation of a runtime class, as well as projected types 包含 Windows 运行时所需的脚手架,并充当实现类型的代理。
当您编写要由 Windows 运行时 API 使用的运行时 class 时,这种区别变得很重要。有问题的代码实现了一个类型,但未能构造相应的投影类型。错误在以下代码行中:
IHttpFilter const test_filter{ TestHttpFilter{ base_filter } };
HttpClient const http_client{ test_filter };
第一行构造了一个实现类型的实例。第二行将它传递给 HttpClient
c'tor,它需要一个 projected type2。解决方法是为 TestHttpFilter
构造投影类型,这可以使用 make 函数模板方便地完成:
IHttpFilter const test_filter{ make<TestHttpFilter>(base_filter) };
HttpClient const http_client{ test_filter };
一般建议:
- 始终确保您了解您使用的是哪种类型。建立命名约定以区分实现类型和投影类型。
- 当跨越 ABI 时,(通常)需要传递一个投影类型。您通常会在调用 Windows 运行时 API 或 return 来自实现类型的值时跨越 ABI。
- 无论你做什么,都不要让它在运行时失败。很可能在这个宇宙中最多只有一个人可以在你到达那里时帮助你。
1 见What do the projected type and the implementation type mean?
2 理想情况下,这应该无法编译,尽管我不知道如何在不(过度地)限制通用的多功能性的情况下实现它图书馆.