web api 参数绑定

简单类型参数: 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

posted @ 2015-08-08 00:20  fannet  阅读(324)  评论(0编辑  收藏  举报