【问题标题】:PostAsync throwing IRandomAccessStream error when targeting windows 10 UWP针对 Windows 10 UWP 时 PostAsync 引发 IRandomAccessStream 错误
【发布时间】:2015-10-24 18:41:44
【问题描述】:

我正在将我的 Windows 8.1 应用程序移植到 Windows 10 UWP,但现在调用 PostAsync 会引发异常。

这个确切的代码在面向 8.1 时可以完美运行,但是当我面向 Windows 10 UWP 时,它会引发以下异常:

This IRandomAccessStream does not support the GetInputStreamAt method because it requires cloning and this stream does not support cloning.

代码

    public async void TestPost()
    {
        var parameters = GetParameters();
        var formattedData = new FormUrlEncodedContent(parameters);
        using (var clientHandler = new HttpClientHandler { Credentials = GetCredentials() })
        {
            using (var httpClient = new HttpClient(clientHandler))
            {
                var response = await httpClient.PostAsync(postUrl, formattedData);
            }
        }
    }

private Dictionary<string, string> GetParameters()
{
    var parameters = new Dictionary<string, string>();
    parameters["grant_type"] = "url";
    parameters["device_id"] = "unique key";
    parameters["redirect_uri"] = "redirect url";
    return parameters;
}

public static NetworkCredential GetCredentials()
{
    return new NetworkCredential("<secret key>", "");
}

堆栈跟踪

 at System.IO.NetFxToWinRtStreamAdapter.ThrowCloningNotSuported(String methodName)
   at System.IO.NetFxToWinRtStreamAdapter.GetInputStreamAt(UInt64 position)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpHandlerToFilter.<SendAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpClientHandler.<SendAsync>d__1.MoveNext()

【问题讨论】:

  • 您能提供您的GetParameters()GetCredentials() 实现吗?当服务器不需要认证时,错误是否重现?
  • @kiewic,当然。我已经添加了方法。他们没什么特别的。至于对不需要身份验证的服务器的请求。我没有一个好用的。我正在打一个安全的 api。
  • 有谁知道这是否有更新,所以我们可以使用System.Net.Http。我对Windows.Web.Http 的问题是,如果不提示用户进行无缝集成,我找不到发送当前 Windows 凭据的方法

标签: c# windows-runtime uwp


【解决方案1】:

您是否尝试过改用Windows.Web.Http.HttpClient

// using Windows.Web.Http;
// using Windows.Web.Http.Filters;

var parameters = GetParameters();
var formattedData = new HttpFormUrlEncodedContent(parameters);
using (var clientHandler = new HttpBaseProtocolFilter())
{
    clientHandler.ServerCredential = GetCredentials();

    using (var httpClient = new HttpClient(clientHandler))
    {
        var response = await httpClient.PostAsync(postUrl, formattedData);
    }
}

【讨论】:

  • 这不是编译。 HttpBaseProtocolFilter 没有属性“clientHandler”
  • 我的错,我想用ServerCredential
  • 知道了,我更新了那部分,但是 HttpClient 类没有采用 HttpBaseProtocolFilter 对象的构造函数。
  • 是的,它需要一个IHttpFilter 变量。
  • 好的,这样就可以了。我能够提出请求。但是我被提示在应用程序本身中输入我的服务器凭据。凭据只是一个用户名,没有密码。但是,Windows 安全凭证的构造函数要求将资源字符串作为第一个参数。我没有。所以我尝试使用空构造函数并将值分配给用户名属性。我仍然收到提示。
【解决方案2】:

这是一个错误。解决方法是使用 Windows.Web

using Windows.Web.Http;
using Windows.Web.Http.Filters;
using Windows.Web.Http.Headers;

    /// <summary>
    /// Performs the post asynchronous.
    /// </summary>
    /// <typeparam name="T">The generic type parameter.</typeparam>
    /// <param name="uri">The URI.</param>
    /// <param name="objectToPost">The object to post.</param>
    /// <returns>The response message.</returns>
    private static async Task<HttpResponseMessage> PerformPostAsync<T>string uri, object objectToPost)
    {
        HttpResponseMessage response = null;

        // Just add default filter (to enable enterprise authentication)
        HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();

        using (HttpClient client = HttpService.CreateHttpClient(filter))
        {
            // Now create the new request for the post
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(uri));

            if (objectToPost != null)
            {
                // Frist get the bytes
                byte[] bytes = UTF8Encoding.UTF8.GetBytes(JsonHelper.Serialize(objectToPost));

                // Now create the HttpBufferContent from the bytes and set the request content
                IHttpContent content = new HttpBufferContent(bytes.AsBuffer());
                content.Headers.ContentType = HttpMediaTypeHeaderValue.Parse(HttpService.JsonMediaType);
                request.Content = content;
            }

            // Now complete the request
            response = await client.SendRequestAsync(request);
        }

        return response;
    }

    /// <summary>
    /// Creates the HTTP client.
    /// </summary>
    /// <param name="filter">The filter.</param>
    /// <returns>HTTP client.</returns>
    private static HttpClient CreateHttpClient(HttpBaseProtocolFilter filter = null)
    {
        HttpClient client = new HttpClient(filter);
        client.DefaultRequestHeaders.Accept.Add(new HttpMediaTypeWithQualityHeaderValue(HttpService.JsonMediaType));
        return client;
    }
}

【讨论】:

    【解决方案3】:

    我们需要使用跨平台的 PCL System.Net.Http 库,所以我们不能只是交换所有内容以使用特定于平台的库。对于特定的问题案例,我们最终使用了不同的 HttpMessageHandler。该处理程序将实际调用委托给 Windows.Web.Http 库。

    /// <summary>
    /// A System.Net.Http message handler that delegates out to Windows.Web.Http.HttpClient.
    /// </summary>
    public class WindowsHttpMessageHandler : HttpMessageHandler
    {
        private const string UserAgentHeaderName = "User-Agent";
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient();
    
            Windows.Web.Http.HttpRequestMessage webRequest = new Windows.Web.Http.HttpRequestMessage
            {
                Method = ConvertMethod(request.Method),
                RequestUri = request.RequestUri,
                Content = await ConvertRequestContentAsync(request.Content).ConfigureAwait(false),
            };
    
            CopyHeaders(request.Headers, webRequest.Headers);
    
            Windows.Web.Http.HttpResponseMessage webResponse = await client.SendRequestAsync(webRequest)
                .AsTask(cancellationToken)
                .ConfigureAwait(false);
    
            HttpResponseMessage response = new HttpResponseMessage
            {
                StatusCode = ConvertStatusCode(webResponse.StatusCode),
                ReasonPhrase = webResponse.ReasonPhrase,
                Content = await ConvertResponseContentAsync(webResponse.Content).ConfigureAwait(false),
                RequestMessage = request,
            };
    
            CopyHeaders(webResponse.Headers, response.Headers);
    
            return response;
        }
    
        private static void CopyHeaders(HttpRequestHeaders input, Windows.Web.Http.Headers.HttpRequestHeaderCollection output)
        {
            foreach (var header in input)
            {
                output.Add(header.Key, GetHeaderValue(header.Key, header.Value));
            }
        }
    
        private static void CopyHeaders(HttpContentHeaders input, Windows.Web.Http.Headers.HttpContentHeaderCollection output)
        {
            foreach (var header in input)
            {
                output.Add(header.Key, GetHeaderValue(header.Key, header.Value));
            }
        }
    
        private static void CopyHeaders(Windows.Web.Http.Headers.HttpContentHeaderCollection input, HttpContentHeaders output)
        {
            foreach (var header in input)
            {
                if (!string.Equals(header.Key, "Expires", StringComparison.OrdinalIgnoreCase) || header.Value != "-1")
                {
                    output.Add(header.Key, header.Value);
                }
            }
        }
    
        private static void CopyHeaders(Windows.Web.Http.Headers.HttpResponseHeaderCollection input, HttpResponseHeaders output)
        {
            foreach (var header in input)
            {
                output.Add(header.Key, header.Value);
            }
        }
    
        private static string GetHeaderValue(string name, IEnumerable<string> value)
        {
            return string.Join(string.Equals(name, UserAgentHeaderName, StringComparison.OrdinalIgnoreCase) ? " " : ",", value);
        }
    
        private static Windows.Web.Http.HttpMethod ConvertMethod(HttpMethod method)
        {
            return new Windows.Web.Http.HttpMethod(method.ToString());
        }
    
        private static async Task<Windows.Web.Http.IHttpContent> ConvertRequestContentAsync(HttpContent content)
        {
            if (content == null)
            {
                return null;
            }
    
            Stream contentStream = await content.ReadAsStreamAsync().ConfigureAwait(false);
            var result = new Windows.Web.Http.HttpStreamContent(contentStream.AsInputStream());
    
            CopyHeaders(content.Headers, result.Headers);
    
            return result;
        }
    
        private static async Task<HttpContent> ConvertResponseContentAsync(Windows.Web.Http.IHttpContent content)
        {
            var responseStream = await content.ReadAsInputStreamAsync();
            var result = new StreamContent(responseStream.AsStreamForRead());
    
            CopyHeaders(content.Headers, result.Headers);
    
            return result;
        }
    
        private static HttpStatusCode ConvertStatusCode(Windows.Web.Http.HttpStatusCode statusCode)
        {
            return (HttpStatusCode)(int)statusCode;
        }
    }
    

    虽然我们只需要它进行几次调用,但它并未针对所有用例进行 100% 测试。

    【讨论】:

      猜你喜欢
      • 2016-12-08
      • 2017-07-30
      • 2016-01-24
      • 2016-10-14
      • 1970-01-01
      • 2016-05-01
      • 2016-10-12
      • 2018-01-31
      • 2021-08-20
      相关资源
      最近更新 更多