我创建了Web API服务。 我想要做的是从按钮单击后面的代码调用该API函数,即SaveSession(字符串数据),并以字符串格式传递整个表单集合数据作为参数。 当我通过webclient.uploadstring(url,string)调用api的uri时; 它正在调用Web服务,但参数未被传递。 请帮助。
答案 0 :(得分:3)
不是使用接受字符串的控制器操作方法,而是可以读取发布到控制器的form-url编码内容。
在下面的示例中,SessionController公开一个SaveSession()方法,该方法接受form-url编码内容的POST,然后将会话数据作为KeyValuePair实例的集合读取。
示例客户端构建键值对列表,然后使用HttpClient实例将FormUrlEncodedContent发布到Web API控制器方法。
示例SessionController:
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);
}
}
}
}
}
}
我通常将 IsFormUrlEncodedContent 和 ReadAsFormUrlEncodedContentAsync 方法作为HttpContent上的扩展方法,但为了本示例的目的将它们放在控制器中。