简单类型参数: url读取(string,bool,int...)
复杂类型参数:从message body用media-type formatter 读取
url读取route data(路由解析uri的时候得到)和URI query string
强制复杂类型从uri获取
public class GeoPoint { public double Latitude { get; set; } public double Longitude { get; set; } } public ValuesController : ApiController { public HttpResponseMessage Get([FromUri] GeoPoint location) { ... } }
http://localhost/api/values/?Latitude=47.678558&Longitude=-122.130989
强制简单类型从request body获取([FromBody]时webapi 会用Content-Type选择一个media type formatter)
public HttpResponseMessage Post([FromBody] string name) { ... } //只能用于一个参数的情况
POST http://localhost:5076/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:5076
Content-Type: application/json
Content-Length: 7
"Alice"
类型转换(实现类型转换后,会当做简单类型尝试从uri获取)
[TypeConverter(typeof(GeoPointConverter))] public class GeoPoint { public double Latitude { get; set; } public double Longitude { get; set; } public static bool TryParse(string s, out GeoPoint result) { result = null; var parts = s.Split(','); if (parts.Length != 2) { return false; } double latitude, longitude; if (double.TryParse(parts[0], out latitude) && double.TryParse(parts[1], out longitude)) { result = new GeoPoint() { Longitude = longitude, Latitude = latitude }; return true; } return false; } } class GeoPointConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) { return true; } return base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string) { GeoPoint point; if (GeoPoint.TryParse((string)value, out point)) { return point; } } return base.ConvertFrom(context, culture, value); } } public HttpResponseMessage Get(GeoPoint location) { ... } http://localhost/api/values/?location=47.678558,-122.130989
Model Binders
public class GeoPointModelBinder : IModelBinder { // List of known locations. private static ConcurrentDictionary<string, GeoPoint> _locations = new ConcurrentDictionary<string, GeoPoint>(StringComparer.OrdinalIgnoreCase); static GeoPointModelBinder() { _locations["redmond"] = new GeoPoint() { Latitude = 47.67856, Longitude = -122.131 }; _locations["paris"] = new GeoPoint() { Latitude = 48.856930, Longitude = 2.3412 }; _locations["tokyo"] = new GeoPoint() { Latitude = 35.683208, Longitude = 139.80894 }; } public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { if (bindingContext.ModelType != typeof(GeoPoint)) { return false; } ValueProviderResult val = bindingContext.ValueProvider.GetValue( bindingContext.ModelName); if (val == null) { return false; } string key = val.RawValue as string; if (key == null) { bindingContext.ModelState.AddModelError( bindingContext.ModelName, "Wrong value type"); return false; } GeoPoint result; if (_locations.TryGetValue(key, out result) || GeoPoint.TryParse(key, out result)) { bindingContext.Model = result; return true; } bindingContext.ModelState.AddModelError( bindingContext.ModelName, "Cannot convert value to Location"); return false; } }
使用
//1 public HttpResponseMessage Get([ModelBinder(typeof(GeoPointModelBinder))] GeoPoint location) //2 [ModelBinder(typeof(GeoPointModelBinder))] public class GeoPoint { // .... } //3 public static class WebApiConfig { public static void Register(HttpConfiguration config) { var provider = new SimpleModelBinderProvider( typeof(GeoPoint), new GeoPointModelBinder()); config.Services.Insert(typeof(ModelBinderProvider), 0, provider); // ... } } public HttpResponseMessage Get([ModelBinder] GeoPoint location) { ... }
value provider(解析参数返回字典对象)
例:
http://localhost/api/values/1?location=48,-122
会解析为字典
- id = "1"
- location = "48,122"
id,location对应ModelBindingContext.ModelName
"1","48,122" RawValue如果被正确转换会被设置到ModelBindingContext.Model
public class CookieValueProvider : IValueProvider { private Dictionary<string, string> _values; public CookieValueProvider(HttpActionContext actionContext) { if (actionContext == null) { throw new ArgumentNullException("actionContext"); } _values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (var cookie in actionContext.Request.Headers.GetCookies()) { foreach (CookieState state in cookie.Cookies) { _values[state.Name] = state.Value; } } } public bool ContainsPrefix(string prefix) { return _values.Keys.Contains(prefix); } public ValueProviderResult GetValue(string key) { string value; if (_values.TryGetValue(key, out value)) { return new ValueProviderResult(value, value, CultureInfo.InvariantCulture); } return null; } }
使用(查找值时会使用所有注册的value provider查找,得到第一个返回的值)
public class CookieValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(HttpActionContext actionContext) { return new CookieValueProvider(actionContext); } } public static void Register(HttpConfiguration config) { config.Services.Add(typeof(ValueProviderFactory), new CookieValueProviderFactory()); // ... } // 不使用其他value provider public HttpResponseMessage Get( [ValueProvider(typeof(CookieValueProviderFactory))] GeoPoint location)
HttpParameterBinding
url:http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api