mvc web api 关于post参数怎么mvc4接收post数据,求教

mvc web api 关于post参数怎么接收,求教_百度知道
mvc web api 关于post参数怎么接收,求教
提问者采纳
// POST api&#47public class ValuesCvalues
public void Post(string value)
&#47, string value)
/ GET api/ DELETE api/string&value2&; }: ApiController
/value&values/ PUT api/
/value1&quot, &/
public IEnumerable&5
public string Get(int id)
public void Put(; GET api/values/values/// Get()
return new string[] { &quot
来自团队:
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Posts - 201,
Articles - 0,
Comments - 1233
12:07 by 贺臣, ... 阅读,
& 1. HttpClient简单介绍&
依稀还记得那个时候用WebClient,HttpWebRequest来发送一个请求,现在ASP.NET MVC4中自带了一个类HttpClient,用于接收HttpResponseMessage和发送HttpRequestMesssage。
问题在于既然WebClient,HttpWebRequest可以完成相应的功能,为什么还要使用HttpClient类,.NET Framework中既然提出了这样一个类肯定是有其特别之处的,这里罗列几个不同之处:
(1) 可以在HttpClient实例上配置扩展,设置默认的头部,取消未完成的的请求和设置
(2) HttpClient有自己的连接池
(3)&HttpClient 不与特定的服务器绑定,可以访问任何Http请求
(4) HttpClient采用异步请求处理&& 2. HttpClient备注说明
HttpClient包含在System.net.Http.dll 程序集中,用户接受和发送http请求,该类适用于.NET4.0以上版本。
更多说明可以参考微软官方网站:
& 3. HttpClient基本操作static&void&BasicMethod(){&&&&&&&&&&&&string&url&=&"";&&&&&&&&&&&&HttpClient&client&=&new&HttpClient();&&&&&&&&&&&&string&content&=&client.GetStringAsync(url).R&&&&&&&&&&&&Console.WriteLine(content);&&}
以上是使用HttpClient请求百度主页,貌似操作起来也挺方便的,运行输出请求得到的结果如下图:
控制台输出的为请求URL的内容。
HttpClient除了上面提到的GetStringAsync()方法之外,还提供了如下Get方法,详细可以参考MSDN:
&& 4. 自定义请求头
如果要自定义请求头,我们需要继承一个类:HttpClientHandler&&&&&&public&class&GitHttpClientHandler:HttpClientHandler&&&&{&&&&&&&&protected&override&Task&HttpResponseMessage&&SendAsync(HttpRequestMessage&request,&CancellationToken&cancellationToken)&&&&&&&&{&&&&&&&&&&&&request.Headers.Referrer&=&new&Uri("/");&&&&&&&&&&&&request.Headers.Add("UserAgent",&"Mozilla/4.0&(&MSIE&7.0;&Windows&NT&6.1;&WOW64;&Trident/5.0;&SLCC2;&.NET&CLR&2.0.50727)");&&&&&&&&&&&&&&&&&&&&&&&&Task&HttpResponseMessage&&task&=&base.SendAsync(request,&cancellationToken);&&&&&&&&&&&&HttpResponseMessage&response&=&task.R&&&&&&&&&&&&MediaTypeHeaderValue&contentType&=&response.Content.Headers.ContentT&&&&&&&&&&&&if&(string.IsNullOrEmpty(contentType.CharSet))&&&&&&&&&&&&{&&&&&&&&&&&&&&&&contentType.CharSet&=&"GBK";&&&&&&&&&&&&}&&&&&&&&&&&&return&&&&&&&&&}&&&&}&
HttpClientHandler就是常见的代理模式,在HttpClient.GetStringAsync()加了一层封装,拦截了HttpClient的输入和输出,从而实现一些自定义的操作,这种方式我们在MVC 中非常常见,就是MVC中的过滤器。& 5. 请求内容过长
HttpClient有一个属性
我们可以人工设置这个属性的大小:
HttpClient&client&=&new&HttpClient()&{&MaxResponseContentBufferSize&=&1024&*&1024&};&&
使用如上方式处理即可。& 6. 中文问题&&
中文问题总是令人头疼,很多时候会出现乱码。上面提到的自定义请求头也可以处理,这里贴出一段代码作参考,中文问题有点复杂需要根据具体情况处理:HttpResponseMessage&response&=&task.RMediaTypeHeaderValue&contentType&=&response.Content.Headers.ContentTif(string.IsNullOrEmpty(contentType.CharSet)){&&&contentType.CharSet&=&"GBK";}&& 7. 友情链接&&13800人阅读
刚开始创建MVC与Web API的混合项目时,碰到好多问题,今天拿出来跟大家一起分享下。有朋友私信我问项目的分层及文件夹结构在我的第一篇博客中没说清楚,那么接下来我就准备从这些文件怎么分文件夹说起。问题大概有以下几点: 1、项目层的文件夹结构 2、解决MVC的Controller和Web API的Controller类名不能相同的问题 3、给MVC不同命名空间的Area的注册不同的路由 4、让Web API路由配置也支持命名空间参数 5、MVC及Web API添加身份验证及错误处理的过滤器 6、MVC添加自定义参数模型绑定ModelBinder 7、Web API添加自定义参数绑定HttpParameterBinding 8、让Web API同时支持多个Get方法
一、项目层的文件夹结构 这里的结构谈我自己的项目仅供大家参考,不合理的地方欢迎大家指出。第一篇博客中我已经跟大家说了下框架的分层及简单说了下项目层,现在我们再仔细说下。新建MVC或Web API时微软已经给我们创建好了许多的文件夹,如App_Start放全局设置,Content放样式等、Controller放控制器类、Model数据模型、Scripts脚本、Views视图。有些人习惯了传统的三层架构(有些是N层),喜欢把Model文件夹、Controller文件夹等单独一个项目出来,我感觉是没必要,因为在不同文件夹下也算是一种分层了,单独出来最多也就是编译出来的dll是独立的,基本没有太多的区别。所以我还是从简,沿用微软分好的文件夹。先看我的截图
我添加了区域Areas,我的思路是最外层的Model(已删除)、Controllers、Views都只放一些共通的东西,真正的项目放在Areas中,比如上图中Mms代表我的材料管理系统,Psi是另外一个系统,Sys是我的系统管理模块。这样就可以做到多个系统在一个项目中,框架的重用性不言而喻。再具体看区域中一个项目
这当中微软生成的文件夹只有Controllers、Models、Views。其它都是我建的,比如Common放项目共通的一些类,Reports准备放报表文件、ViewModels放Knouckoutjs的ViewModel脚本文件。 接下来再看看UI库脚本库引入的一些控件要放置在哪里。如下图
我把框架的css images js themes等都放置在Content下,css中放置项目样式及960gs框架,js下面core是自已定义的一些共通的js包括utils.js、common.js及easyui的knouckout绑定实现knouckout.bindings.js,其它一看就懂基本不用介绍了。&
二、解决MVC的Controller和Web API的Controller类名不能相同的问题 回到区域下的一个项目文件夹内,在Controller中我们要创建Mvc Controller及Api Controller,假如一个收料的业务(receive) mvc路由注册为~/{controller}/{action},我希望的访问地址应该是 ~/receive/action api中由注册为~/api/{controller},我希望的访问地址应该是 ~/api/receive 那么问题就产生了,微软设计这个框架是通过类名去匹配的 mvc下你创建一个 receiveController继承Controller,就不能再创建一个同名的receiveController继承ApiController,这样的话mvc的访问地址和api的访问地址必须要有一个名字不能叫receive,是不是很郁闷。 通过查看微软System.Web.Http的源码,我们发现其实这个问题也很好解决,在这个DefaultHttpControllerSelector类中,微软有定义Controller的后缀,如图
我们只要把ApiController的后缀改成和MVC不一样,就可以解决问题了。这个字段是个静态只读的Field,我们只要把它改成ApiContrller就解决问题了。我们首先想到的肯定是反射。好吧,就这么做,在注册Api路由前添加以下代码即可完成
var suffix = typeof(DefaultHttpControllerSelector).GetField(&ControllerSuffix&, BindingFlags.Static | BindingFlags.Public);
if (suffix != null) suffix.SetValue(null, &ApiController&);
三、给MVC不同命名空间的Area的注册不同的路由 这个好办,MVC路由配置支持命名空间,新建区域时框架会自动添加{区域名}AreaRegistration.cs文件,用于注册本区域的路由
在这个文件中的RegisterArea方法中添加以下代码即可&
context.MapRoute(
this.AreaName + &default&,
this.AreaName + &/{controller}/{action}/{id}&,
new { controller = &Home&, action = &Index&, id = UrlParameter.Optional },
new string[] { &Zephyr.Areas.&+ this.AreaName + &.Controllers& }
其中第四个参数是命名空间参数,表示这个路由设置只在此命名空间下有效。
四、让Web API路由配置也支持命名空间参数 让人很头疼的是Web Api路由配置竟然不支持命名空间参数,这间接让我感觉它不支持Area,微软真会开玩笑。好吧我们还是自己动手。在google上找到一篇文章 貌似被墙了,这里有介绍一种方法替换HttpControllerSelector服务。 我直接把我的代码贴出来,大家可以直接用,首先创建一个新的HttpControllerSelector类
using System.L
using System.Collections.C
using System.Collections.G
using System.Net.H
using System.Web.H
using System.Web.Http.C
using System.Web.Http.D
using System.N
namespace Zephyr.Web
public class NamespaceHttpControllerSelector : DefaultHttpControllerSelector
private const string NamespaceRouteVariableName = &namespaceName&;
private readonly HttpConfiguration _
private readonly Lazy&ConcurrentDictionary&string, Type&& _apiControllerC
public NamespaceHttpControllerSelector(HttpConfiguration configuration)
: base(configuration)
_configuration =
_apiControllerCache = new Lazy&ConcurrentDictionary&string, Type&&(
new Func&ConcurrentDictionary&string, Type&&(InitializeApiControllerCache));
private ConcurrentDictionary&string, Type& InitializeApiControllerCache()
IAssembliesResolver assembliesResolver = this._configuration.Services.GetAssembliesResolver();
var types = this._configuration.Services.GetHttpControllerTypeResolver()
.GetControllerTypes(assembliesResolver).ToDictionary(t =& t.FullName, t =& t);
return new ConcurrentDictionary&string, Type&(types);
public IEnumerable&string& GetControllerFullName(HttpRequestMessage request, string controllerName)
object namespaceN
var data = request.GetRouteData();
IEnumerable&string& keys = _apiControllerCache.Value.ToDictionary&KeyValuePair&string, Type&, string, Type&(t =& t.Key,
t =& t.Value, StringComparer.CurrentCultureIgnoreCase).Keys.ToList();
if (!data.Values.TryGetValue(NamespaceRouteVariableName, out namespaceName))
return from k in keys
where k.EndsWith(string.Format(&.{0}{1}&, controllerName,
DefaultHttpControllerSelector.ControllerSuffix), StringComparison.CurrentCultureIgnoreCase)
string[] namespaces = (string[])namespaceN
return from n in namespaces
join k in keys on string.Format(&{0}.{1}{2}&, n, controllerName,
DefaultHttpControllerSelector.ControllerSuffix).ToLower() equals k.ToLower()
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
if (request == null)
throw new ArgumentNullException(&request&);
string controllerName = this.GetControllerName(request);
if (string.IsNullOrEmpty(controllerName))
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format(&No route providing a controller name was found to match request URI '{0}'&,
new object[] { request.RequestUri })));
IEnumerable&string& fullNames = GetControllerFullName(request, controllerName);
if (fullNames.Count() == 0)
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format(&No route providing a controller name was found to match request URI '{0}'&,
new object[] { request.RequestUri })));
if (this._apiControllerCache.Value.TryGetValue(fullNames.First(), out type))
return new HttpControllerDescriptor(_configuration, controllerName, type);
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format(&No route providing a controller name was found to match request URI '{0}'&,
new object[] { request.RequestUri })));
然后在WebApiConfig类的Register中替换服务即可实现
config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
好吧,现在看看如何使用,还是在区域的{AreaName}AreaRegistration类下的RegisterArea方法中注册Api的路由:
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
this.AreaName + &Api&,
&api/& + this.AreaName + &/{controller}/{action}/{id}&,
new { action = RouteParameter.Optional, id = RouteParameter.Optional,
namespaceName = new string[] { string.Format(&Zephyr.Areas.{0}.Controllers&,this.AreaName) } },
new { action = new StartWithConstraint() }
第三个参数defaults中的namespaceName,上面的服务已实现支持。第四个参数constraints我在第8个问题时会讲到,这里先略过。
五、MVC及Web API添加身份验证及错误处理的过滤器 先说身份验证的问题。无论是mvc还是api都有一个安全性的问题,未通过身份验证的人能不能访问的问题。我们新一个空项目时,默认是没有身份验证的,除非你在控制器类或者方法上面加上Authorize属性才会需要身份验证。但是我的控制器有那么多,我都要给它加上属性,多麻烦,所以我们就想到过滤器了。过滤器中加上后,控制器都不用加就相当于有这个属性了。 Mvc的就直接在FilterConfig类的RegisterGlobalFilters方法中添加以下代码即可
filters.Add(new System.Web.Mvc.AuthorizeAttribute());
Web Api的过滤器没有单独一个配置类,可以写在WebApiConfig类的Register中
config.Filters.Add(new System.Web.Http.AuthorizeAttribute());
Mvc错误处理默认有添加HandleErrorAttribute默认的过滤器,但是我们有可能要捕捉这个错误并记录系统日志那么这个过滤器就不够用了,所以我们要自定义Mvc及Web Api各自的错误处理类,下面贴出我的错误处理,MvcHandleErrorAttribute
using System.W
using System.Web.M
using log4
namespace Zephyr.Web
public class MvcHandleErrorAttribute : HandleErrorAttribute
public override void OnException(ExceptionContext filterContext)
ILog log = LogManager.GetLogger(filterContext.RequestContext.HttpContext.Request.Url.LocalPath);
log.Error(filterContext.Exception);
base.OnException(filterContext);
Web API的错误处理
using System.N
using System.Net.H
using System.W
using System.Web.Http.F
using log4
namespace Zephyr.Web
public class WebApiExceptionFilter : ExceptionFilterAttribute
public override void OnException(HttpActionExecutedContext context)
ILog log = LogManager.GetLogger(HttpContext.Current.Request.Url.LocalPath);
log.Error(context.Exception);
var message = context.Exception.M
if (context.Exception.InnerException != null)
message = context.Exception.InnerException.M
context.Response = new HttpResponseMessage() { Content = new StringContent(message) };
base.OnException(context);
然后分别注册到过滤器中,在FilterConfig类的RegisterGlobalFilters方法中
filters.Add(new MvcHandleErrorAttribute());
在WebApiConfig类的Register中
config.Filters.Add(new WebApiExceptionFilter());
&这样过滤器就定义好了。
六、MVC添加自定义模型绑定ModelBinder 在MVC中,我们有可能会自定义一些自己想要接收的参数,那么可以通过ModelBinder去实现。比如我要在MVC的方法中接收JObject参数
public JsonResult DoAction(dynamic request)
直接这样写的话接收到的request为空值,因为JObject这个类型参数Mvc未实现,我们必须自己实现,先新建一个JObjectModelBinder类,添加如下代码实现
using System.IO;
using System.Web.M
using Newtonsoft.J
namespace Zephyr.Web
public class JObjectModelBinder : IModelBinder
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
var stream = controllerContext.RequestContext.HttpContext.Request.InputS
stream.Seek(0, SeekOrigin.Begin);
string json = new StreamReader(stream).ReadToEnd();
return JsonConvert.DeserializeObject&dynamic&(json);
然后在MVC注册路由后面添加
ModelBinders.Binders.Add(typeof(JObject), new JObjectModelBinder()); //for dynamic model binder
添加之后,在MVC控制器中我们就可以接收JObject参数了。
七、Web API添加自定义参数绑定HttpParameterBinding
不知道微软搞什么鬼,Web Api的参数绑定机制跟Mvc的参数绑定有很大的不同,首先Web Api的绑定机制分两种,一种叫Model Binding,一种叫Formatters,一般情况下Model Binding用于读取query string中的值,而Formatters用于读取body中的值,这个东西要深究还有很多东西,大家有兴趣自己再去研究,我这里就简单说一下如何自定义ModelBinding,比如在Web API中我自己定义了一个叫RequestWrapper的类,我要在Api控制器中接收RequestWrapper的参数,如下
public dynamic Get(RequestWrapper query)
//do something
那么我们要新建一个RequestWrapperParameterBinding类
using System.Collections.S
using System.T
using System.Threading.T
using System.Web.Http.C
using System.Web.Http.M
using Zephyr.C
namespace Zephyr.Web
public class RequestWrapperParameterBinding : HttpParameterBinding
private struct AsyncVoid { }
public RequestWrapperParameterBinding(HttpParameterDescriptor desc) : base(desc) { }
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
HttpActionContext actionContext, CancellationToken cancellationToken)
var request = System.Web.HttpUtility.ParseQueryString(actionContext.Request.RequestUri.Query);
var requestWrapper = new RequestWrapper(new NameValueCollection(request));
if (!string.IsNullOrEmpty(request[&_xml&]))
var xmlType = request[&_xml&].Split('.');
var xmlPath = string.Format(&~/Views/Shared/Xml/{0}.xml&, xmlType[xmlType.Length – 1]);
if (xmlType.Length & 1)
xmlPath = string.Format(&~/Areas/{0}/Views/Shared/Xml/{1}.xml&, xmlType);
requestWrapper.LoadSettingXml(xmlPath);
SetValue(actionContext, requestWrapper);
TaskCompletionSource&AsyncVoid& tcs = new TaskCompletionSource&AsyncVoid&();
tcs.SetResult(default(AsyncVoid));
return tcs.T
接下来要把这个绑定注册到绑定规则当中,还是在WebApiConfig中添加
config.ParameterBindingRules.Insert(0, param =& {
if (param.ParameterType == typeof(RequestWrapper))
return new RequestWrapperParameterBinding(param);
return null;
&&此时RequestWrapper参数绑定已完成,可以使用了
八、让Web API同时支持多个Get方法 先引用微软官方的东西把存在的问题跟大家说明白,假如Web Api在路由中注册的为
routes.MapHttpRoute(
name: &API Default&,
routeTemplate: &api/{controller}/{id}&,
defaults: new { id = RouteParameter.Optional }
然后我的控制器为
public class ProductsController : ApiController
public void GetAllProducts() { }
public IEnumerable&Product& GetProductById(int id) { }
public HttpResponseMessage DeleteProduct(int id){ }
那么对应的地址请求到的方法如下
看到上面不知道到大家看到问题了没,如果我有两个Get方法(我再加一个GetTop10Products,这种情况很常见),而且参数也相同那么路由就没有办法区分了。有人就想到了修改路由设置,把routeTemplate:修改为&api/{controller}/{action}/{id}&,没错,这样是能解决上述问题,但是你的api/products无论是Get Delete Post Input方式都无法请求到对应的方法,你必须要api/products/GetAllProducts、api/products/DeleteProduct/4 ,action名你不能省略。现在明白了问题所在了。我就是要解决这个问题。
还记得我在写第四点的时候有提到这里,思路就是要定义一个constraints去实现: 我们先分析下uri path: api/controller/x,问题就在这里的x,它有可能代表action也有可能代表id,其实我们就是要区分这个x什么情况下代表action什么情况下代表id就可以解决问题了,我是想自己定义一系统的动词,如果你的actoin的名字是以我定义的这些动词中的一个开头,那么我认为你是action,否则认为你是id。
好,思路说明白了,我们开始实现,先定义一个StartWithConstraint类
using System.Collections.G
using System.L
using System.W
using System.Web.Http.R
namespace Zephyr.Web
/// &summary&
/// 如果请求url如: api/area/controller/x
x有可能是actioin或id
/// 在url中的x位置出现的是以 get put delete post开头的字符串,则当作action,否则就当作id
/// 如果action为空,则把请求方法赋给action
/// &/summary&
public class StartWithConstraint : IHttpRouteConstraint
public string[] array { get; set; }
public bool match { get; set; }
private string _id = &id&;
public StartWithConstraint(string[] startwithArray = null)
if (startwithArray == null)
startwithArray = new string[] { &GET&, &PUT&, &DELETE&, &POST&, &EDIT&, &UPDATE&, &AUDIT&, &DOWNLOAD& };
this.array = startwithA
public bool Match(System.Net.Http.HttpRequestMessage request, IHttpRoute route, string parameterName,
IDictionary&string, object& values, HttpRouteDirection routeDirection)
if (values == null) // shouldn't ever hit this.
return true;
if (!values.ContainsKey(parameterName) || !values.ContainsKey(_id)) // make sure the parameter is there.
return true;
var action = values[parameterName].ToString().ToLower();
if (string.IsNullOrEmpty(action)) // if the param key is empty in this case &action& add the method so it doesn't hit other methods like &GetStatus&
values[parameterName] = request.Method.ToString();
else if (string.IsNullOrEmpty(values[_id].ToString()))
var isidstr = true;
array.ToList().ForEach(x =&
if (action.StartsWith(x.ToLower()))
isidstr = false;
if (isidstr)
values[_id] = values[parameterName];
values[parameterName] = request.Method.ToString();
return true;
然后在对应的API路由注册时,添加第四个参数constraints
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
this.AreaName + &Api&,
&api/& + this.AreaName + &/{controller}/{action}/{id}&,
new { action = RouteParameter.Optional, id = RouteParameter.Optional,
namespaceName = new string[] { string.Format(&Zephyr.Areas.{0}.Controllers&,this.AreaName) } },
new { action = new StartWithConstraint() }
&这样就实现了,Api控制器中Action的取名就要注意点就是了,不过还算是一个比较完美的解决方案。
这次Mvc框架上的问题说的差不多,下次可能就开始写一些具体页面及细节了,如果大家对我的框架有兴趣,我会继续写下去的。不过从前天开始,我已经写了三天的博客了,连续熬了几个晚上到这么晚,我决定我要休息几天了。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5106201次
积分:61839
积分:61839
排名:第16名
原创:435篇
转载:4678篇
译文:22篇
评论:1483条
文章:21篇
阅读:36496
文章:15篇
阅读:27867
文章:22篇
阅读:184249
(4)(8)(28)(21)(47)(1)(1)(8)(170)(814)(1012)(1351)(969)(262)(207)(2)(3)(2)(61)(19)(2)(28)(22)(37)(1)(3)(4)(6)(9)(10)(26)mvc web api 关于post参数怎么接收,求教_百度知道
mvc web api 关于post参数怎么接收,求教
提问者采纳
public class ValuesController : ApiController
// GET api/values
public IEnumerable&string& Get()
return new string[] { &value1&, &value2& };
// GET api/values/5
public string Get(int id)
return &value&;
// POST api/values
public void Post(string value)
// PUT api/values/5
public void Put(int id, string value)
// DELETE api/values/5
public void Delete(int id)
来自团队:
其他类似问题
为您推荐:
mvc的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 mvc web api post 的文章

 

随机推荐