1

我创建了 Web API 服务。我要做的是从按钮单击后面的代码中调用该 API 函数,即 SaveSession(string data),并将整个表单集合数据作为字符串格式的参数传递。当我通过 webclient.uploadstring(url,string); 调用 api 的 uri 时 它正在调用 Web 服务,但未传递参数。请帮忙。

4

1 回答 1

3

代替使用接受字符串的控制器操作方法,您可以改为读取发布到控制器的 form-url-encoded 内容。

在下面的示例中,SessionController 公开了一个 SaveSession() 方法,该方法接受表单 URL 编码内容的 POST,然后将会话数据作为 KeyValuePair 实例的集合读取。

示例客户端构建一个键值对列表,然后使用 HttpClient 实例将 FormUrlEncodedContent 发布到 Web API 控制器方法。

会话控制器示例:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace MvcApplication1.Controllers
{
    public class SessionController : ApiController
    {
        /// <summary>
        /// Saves specified the session data.
        /// </summary>
        /// <returns>
        /// A <see cref="HttpResponseMessage"/> that represents the response to the requested operation.
        /// </returns>
        [HttpPost()]
        public HttpResponseMessage SaveSession()
        {
            // Ensure content is form-url-encoded
            if(!IsFormUrlEncodedContent(this.Request.Content))
            {
                return this.Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            // Read content as a collection of key value pairs
            foreach (var parameter in ReadAsFormUrlEncodedContentAsync(this.Request.Content).Result)
            {
                var key     = parameter.Key;
                var value   = parameter.Value;

                if(!String.IsNullOrEmpty(key))
                {
                    // Do some work to persist session data here
                }
            }

            return this.Request.CreateResponse(HttpStatusCode.OK);
        }

        /// <summary>
        /// Determines whether the specified content is form URL encoded content.
        /// </summary>
        /// <param name="content">
        /// The type that the <see cref="IsFormUrlEncodedContent(HttpContent)"/> method operates on.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the specified content is form URL encoded content; otherwise, <see langword="false"/>.
        /// </returns>
        public static bool IsFormUrlEncodedContent(HttpContent content)
        {
            if (content == null || content.Headers == null)
            {
                return false;
            }

            return String.Equals(
                content.Headers.ContentType.MediaType, 
                FormUrlEncodedMediaTypeFormatter.DefaultMediaType.MediaType, 
                StringComparison.OrdinalIgnoreCase
            );
        }

        /// <summary>
        /// Write the HTTP content to a collection of name/value pairs as an asynchronous operation.
        /// </summary>
        /// <param name="content">
        /// The type that the <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent)"/> method operates on.
        /// </param>
        /// <returns>The <see cref="Task"/> object representing the asynchronous operation.</returns>
        /// <remarks>
        /// The <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent, CancellationToken)"/> method 
        /// uses the <see cref="Encoding.UTF8"/> format (or the character encoding of the document, if specified) 
        /// to parse the content. URL-encoded characters are decoded and multiple occurrences of the same form 
        /// parameter are listed as a single entry with a comma separating each value.
        /// </remarks>
        public static Task<IEnumerable<KeyValuePair<string, string>>> ReadAsFormUrlEncodedContentAsync(HttpContent content)
        {
            return ReadAsFormUrlEncodedContentAsync(content, CancellationToken.None);
        }

        /// <summary>
        /// Write the HTTP content to a collection of name/value pairs as an asynchronous operation.
        /// </summary>
        /// <param name="content">
        /// The type that the <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent, CancellationToken)"/> method operates on.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token used to propagate notification that the operation should be canceled.
        /// </param>
        /// <returns>The <see cref="Task"/> object representing the asynchronous operation.</returns>
        /// <remarks>
        /// The <see cref="ReadAsFormUrlEncodedContentAsync(HttpContent, CancellationToken)"/> method 
        /// uses the <see cref="Encoding.UTF8"/> format (or the character encoding of the document, if specified) 
        /// to parse the content. URL-encoded characters are decoded and multiple occurrences of the same form 
        /// parameter are listed as a single entry with a comma separating each value.
        /// </remarks>
        public static Task<IEnumerable<KeyValuePair<string, string>>> ReadAsFormUrlEncodedContentAsync(HttpContent content, CancellationToken cancellationToken)
        {
            return Task.Factory.StartNew<IEnumerable<KeyValuePair<string, string>>>(
                (object state) =>
                {
                    var result  = new List<KeyValuePair<string, string>>();

                    var httpContent = state as HttpContent;

                    if (httpContent != null)
                    {
                        var encoding    = Encoding.UTF8;
                        var charSet     = httpContent.Headers.ContentType.CharSet;

                        if (!String.IsNullOrEmpty(charSet))
                        {
                            try
                            {
                                encoding    = Encoding.GetEncoding(charSet);
                            }
                            catch (ArgumentException)
                            {
                                encoding    = Encoding.UTF8;
                            }
                        }

                        NameValueCollection parameters = null;

                        using (var reader = new StreamReader(httpContent.ReadAsStreamAsync().Result, encoding))
                        {
                            parameters = HttpUtility.ParseQueryString(reader.ReadToEnd(), encoding);
                        }

                        if (parameters != null)
                        {
                            foreach(var key in parameters.AllKeys)
                            {
                                result.Add(
                                    new KeyValuePair<string, string>(key, parameters[key])
                                );
                            }
                        }
                    }

                    return result;
                },
                content,
                cancellationToken
            );
        }
    }
}

调用客户端示例:

using System;
using System.Collections.Generic;
using System.Net.Http;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var client = new HttpClient())
            {
                // Initialize HTTP client
                client.BaseAddress  = new Uri("http://localhost:26242/api/", UriKind.Absolute);
                client.Timeout      = TimeSpan.FromSeconds(10);

                // Build session data to send
                var values          = new List<KeyValuePair<string, string>>();

                values.Add(new KeyValuePair<string, string>("Item1", "Value1"));
                values.Add(new KeyValuePair<string, string>("Item2", "Value2"));
                values.Add(new KeyValuePair<string, string>("Item3", "Value3"));

                // Send session data via POST using form-url-encoded content
                using (var content = new FormUrlEncodedContent(values))
                {
                    using (var response = client.PostAsync("session", content).Result)
                    {
                        Console.WriteLine(response.StatusCode);
                    }
                }
            }
        }
    }
}

我通常将IsFormUrlEncodedContentReadAsFormUrlEncodedContentAsync方法作为 HttpContent 的扩展方法,但出于本示例的目的将它们放置在控制器中。

于 2012-10-18T16:54:04.993 回答