原文地址

由于工作原因,要使用ASP.NET WEBAPI(非mvc webapi),前几天时间一直很紧张,所以webapi一直将就用,今天下午好不容易有时间终于看了下,解决了自己一直疑惑的问题,在此特贴出,给大家分享。

Here’s an overview of how WebAPI binds parameters to an action method.  I’ll describe how parameters can be read, the set of rules that determine which technique is used, and then provide some examples.

[update] Parameter binding is ultimately about taking a HTTP request and converting it into .NET types so that you can have a better action signature.

The request message has everything about the request, including the incoming URL with query string, content body, headers, etc.  Eg, without parameter binding, every action would have to take the request message and manually extract the parameters, kind of like this:

public object MyAction(HttpRequestMessage request)
{
// make explicit calls to get parameters from the request object
int id = int.Parse(request.RequestUri.ParseQueryString().Get("id")); // need error logic!
Customer c = request.Content.ReadAsAsync<Customer>().Result; // should be async!
// Now use id and customer
}

That’s ugly, error prone, repeats boiler plate code, is missing corner cases, and hard to unit test. You want the action signature to be something more relevant like:

public object MyAction(int id, Customer c) { }

So how does WebAPI convert from a request message into real parameters like id and customer?

Model Binding vs. Formatters

There are 2 techniques for binding parameters: Model Binding and Formatters. In practice, WebAPI uses model binding to read from the query string and Formatters to read from the body.

(1) Using Model Binding:

ModelBinding is the same concept as in MVC, which has been written about a fair amount (such as here). Basically, there are “ValueProviders” which supply pieces of data such as query string parameters, and then a model binder assembles those pieces into an object.

(2) Using Formatters:

Formatters (see the MediaTypeFormatter class) are just traditional serializers with extra metadata such as the associated content type. WebAPI gets the list of formatters from the HttpConfiguration, and then uses the request’s content-type to select an appropriate formatter. WebAPI has some default formatters. The default JSON formatter is JSON.Net. There is an Xml formatter and a FormUrl formatter that uses JQuery’s syntax.

The key method is MediaTypeFormatter.ReadFromStreayAsync, which looks :

public virtual Task<object> ReadFromStreamAsync(
Type type,
Stream stream,
HttpContentHeaders contentHeaders,
IFormatterLogger formatterLogger)

Type is the parameter type being read, which is passed to the serializer. Stream is the request’s content stream. The read function then reads the stream, instantiates an object, and returns it.

HttpContentHeaders are just from the request message. IFormatterLogger is a callback interface that a formatter can use to log errors while reading (eg, malformed data for the given type).

Both model binding and formatters support validation and log rich error information.  However, model binding is significantly more flexible.

When do we use which?

Here are the basic rules to determine whether a parameter is read with model binding or a formatter:

  1. If the parameter has no attribute on it, then the decision is made purely on the parameter’s .NET type.“Simple types” uses model binding. Complex types uses the formatters. A “simple type” includes:primitives, TimeSpan, DateTime, Guid, Decimal, String, or something with a TypeConverter that converts from strings.
  2. You can use a [FromBody] attribute to specify that a parameter should be from the body.
  3. You can use a [ModelBinder] attribute on the parameter or the parameter’s type to specify that a parameter should be model bound. This attribute also lets you configure the model binder.  [FromUri] is a derived instance of [ModelBinder] that specifically configures a model binder to only look in the URI.
  4. The body can only be read once.  So if you have 2 complex types in the signature, at least one of them must have a [ModelBinder] attribute on it.

It was  a key design goal for these rules to be static and predictable.

Only one thing can read the body

A key difference between MVC and WebAPI is that MVC buffers the content (eg, request body). This means that MVC’s parameter binding can repeatedly search through the body to look for pieces of the parameters. Whereas in WebAPI, the request body (an HttpContent) may be a read-only, infinite, non-buffered, non-rewindable stream.

That means that parameter binding needs to be very careful about not reading the stream unless it’s guaranteeing to bind a parameter.  The action body may want to read the stream directly, and so WebAPI can’t assume that it owns the stream for parameter binding.  Consider this example action:

        // Action saves the request’s content into an Azure blob
public Task PostUploadfile(string destinationBlobName)
{
// string should come from URL, we’ll read content body ourselves.
Stream azureStream = OpenAzureStorage(destinationBlobName); // stream to write to azure
return this.Request.Content.CopyToStream(azureStream); // upload body contents to azure.
}

The parameter is a simple type, and so it’s pulled from the query string. Since there are no complex types in the action signature, webAPI never even touches the request content stream, and so the action body can freely read it.

Some examples

Here are some examples of various requests and how they map to action signatures.

/?id=123&name=bob 
void Action(int id, string name) // both parameters are simple types and will come from url

/?id=123&name=bob 
void Action([FromUri] int id, [FromUri] string name) // paranoid version of above.

void Action([FromBody] string name); // explicitly read the body as a string.

public class Customer {   // a complex object 
  public string Name { get; set; } 
  public int Age { get; set; } 
}

/?id=123 
void Action(int id, Customer c) // id from query string, c is a complex object, comes from body via a formatter.

void Action(Customer c1, Customer c2) // error! multiple parameters attempting to read from the body

void Action([FromUri] Customer c1, Customer c2) // ok, c1 is from the URI and c2 is from the body

void Action([ModelBinder(MyCustomBinder)] SomeType c) // Specifies a precise model binder to use to create the parameter.

[ModelBinder(MyCustomBinder)] public class SomeType { } // place attribute on type declaration to apply to all parameter instances 
void Action(SomeType c) // attribute on c’s declaration means it uses model binding.

Differences with MVC

Here are some differences between MVC and WebAPI’s parameter binding:

    1. MVC only had model binders and no formatters. That’s because MVC would model bind over the request’s body (which it commonly expected to just be FormUrl encoded), whereas WebAPI uses a serializer over the request’s body.
    2. MVC buffered the request body, and so could easily feed it into model binding. WebAPI does not buffer the request body, and so does not model bind against the request body by default.
    3. WebAPI’s binding can be determined entirely statically based off the action signature types. For example, in WebAPI, you know statically whether a parameter will bind against the body or the query string. Whereas in MVC, the model binding system would search both body and query string.

webapi是如何绑定参数的(How WebAPI does Parameter Binding)的更多相关文章

  1. webapi 控制器接收POST参数时必须以对象的方式接收

    webapi    控制器接收POST参数时必须以对象的方式接收

  2. ASP.NET Core WebApi 返回统一格式参数(Json 中 Null 替换为空字符串)

    相关博文:ASP.NET Core WebApi 返回统一格式参数 业务场景: 统一返回格式参数中,如果包含 Null 值,调用方会不太好处理,需要替换为空字符串,示例: { "respon ...

  3. WebApi接口 - 如何在应用中调用webapi接口

    很高兴能再次和大家分享webapi接口的相关文章,本篇将要讲解的是如何在应用中调用webapi接口:对于大部分做内部管理系统及类似系统的朋友来说很少会去调用别人的接口,因此可能在这方面存在一些困惑,希 ...

  4. Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)

    导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html. 本文主要来讲解以下内容: ...

  5. Parameter Binding in ASP.NET Web API(参数绑定)

    Parameter Binding in ASP.NET Web API(参数绑定) 导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnbl ...

  6. 【WebApi系列】浅谈HTTP在WebApi开发中的运用

    WebApi系列文章 [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi参数的传递 [04]详解WebApi测试和PostMan [05]浅谈W ...

  7. [PDO绑定参数]使用PHP的PDO扩展进行批量更新操作

    最近有一个批量更新数据库表中某几个字段的需求,在做这个需求的时候,使用了PDO做参数绑定,其中遇到了一个坑. 方案选择 笔者已知的做批量更新有以下几种方案: 1.逐条更新 这种是最简单的方案,但无疑也 ...

  8. Yii 1.1 DAO绑定参数实例

    <?php $sql = "SELECT * FROM admin_user WHERE user_name=:uname AND password LIKE :c"; $c ...

  9. Hibernate绑定参数

    使用绑定参数的优势: 我们为什么要使用绑定命名参数?任何一个事物的存在都是有其价值的,具体到绑定参数对于HQL查询来说,主要有以下两个主要优势:①. 可以利用数据库实施性能优化 因为对Hibernat ...

随机推荐

  1. PHP流程控制之goto语句

    goto 操作符可以用来跳转到程序中的另一位置.该目标位置可以用目标名称加上冒号来标记,而跳转指令是 goto 之后接上目标位置的标记.PHP 中的 goto 有一定限制,目标位置只能位于同一个文件和 ...

  2. Composite Design Pattern in Java--转

    https://dzone.com/articles/composite-design-pattern-in-java-1 The composite pattern is meant to &quo ...

  3. [转] CentOS下添加用户并且让用户获得root权限

    http://www.centoscn.com/CentOS/config/2014/0810/3471.html 1.添加用户,首先用adduser命令添加一个普通用户,命令如下: #adduser ...

  4. 在Android源码中如何吧so库打包编译进入apk, 集成第三方库(jar和so库)

    集成第三方so和jar包 include $(CLEAR_VARS) #jar包编译            LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES :=securit ...

  5. [JAVA小项目]GUI界面的局域网聊天室

    思路: 1.服务端: 1.1 创建ServerSocket 监听本地端口 1.2 循环接收多个客户端的连接,并且把多个客户端连接的每个管道都为其创建线程. 服务端类的成员:链表--每个成员都是线程类- ...

  6. JavaScript写的随机选人真实案例

    JavaScript写的随机选人真实案例 因工作需要,写了一个随机选人的小网页,先看效果图. 背景也是动态的,只不过在写的时候碰到个问题,就是如果把生成动态流星雨的画布放到上生成随机数的操作界面之上的 ...

  7. 1729 单词查找树 2000年NOI全国竞赛

    1729 单词查找树 2000年NOI全国竞赛 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master         题目描述 Description 在进行文法分析的 ...

  8. IOS微信浏览器点击事件不起作用问题

    问题: $(document).on("click",".btn",function(){alert("1")}); 在微信浏览器上点击不起 ...

  9. linux漏洞分析入门笔记-栈溢出

    ida7.0 ubuntu16.04 lts 0x00:环境配置 使用IDA远程调试Linux程序步骤如下: 1. 在进行远程调试之前需要对Linux平台进行一些准备工作.在IDA的安装目录中的dbg ...

  10. cocos2d-x 学习笔记之 CCMenuItemToggle用法

    想做用cocos2d-x做一个登陆界面,界面有有个记住账号的功能,但是该引擎我没有找到类似checkbox的类,考虑到Toggle也是开关即0和1,故考虑用这个类来实现. CCMenuItemImag ...