Asp.net Web Api に次の問題があります。次のオブジェクトをアクションのパラメーターとして使用しようとしています
[DataContract]
public class MyObject
{
[DataMember]
public object MyIdProperty {get;set;}
}
プロパティ MyIdProperty には、Guid または Int32 を含めることができます
MVC では ModelBinder を作成しましたが、これは魅力的に機能するので、このように WebApi 用に作成しました
public class HttpObjectIdPropertyModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != ObjectType
|| (bindingContext.ModelName.TrimHasValue()
&& !bindingContext.ModelName.EndsWith("Id", StringComparison.OrdinalIgnoreCase)))
{
return false;
}
ValueProviderResult result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (result == null || result.RawValue == null || result.RawValue.GetType() == ObjectType)
{
bindingContext.Model = null;
return true;
}
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, result);
string stringValue = result.RawValue as string;
if (stringValue == null)
{
string[] stringValues = result.RawValue as string[];
if (stringValues != null && stringValues.Length == 1)
{
stringValue = stringValues[0];
}
if (stringValue == null)
{
return false;
}
}
Guid guid;
int integer;
if (Guid.TryParse(stringValue, out guid))
{
bindingContext.Model = guid;
}
else if (int.TryParse(stringValue, out integer))
{
bindingContext.Model = integer;
}
else
{
return false;
}
return true;
}
private static readonly Type ObjectType = typeof(object);
private static HttpParameterBinding EvaluateRule(HttpObjectIdPropertyModelBinder binder, HttpParameterDescriptor parameter)
{
if (parameter.ParameterType == ObjectType
&& parameter.ParameterName.EndsWith("Id", StringComparison.OrdinalIgnoreCase))
{
return parameter.BindWithModelBinding(binder);
}
return null;
}
public static void Register()
{
var binder = new HttpObjectIdPropertyModelBinder();
GlobalConfiguration.Configuration.Services.Insert(typeof(ModelBinderProvider), 0, new SimpleModelBinderProvider(typeof(object), binder));
GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, param => EvaluateRule(binder, param));
}
}
WebApi のモデル バインダーを作成するのは初めてなので、それがうまくできているかどうか、この問題を解決する良い方法であるかどうかさえわかりません。
とにかくこのモデルバインダーでこんなアクションがあれば
public IEnumerable<MyObject> Get(object id)
{
// code here...
}
パラメーター id は、Json フォーマッターまたは Xml フォーマッターとモデル バインダーを使用して適切に逆シリアル化されます。
しかし、次のアクションを使用すると
public void Post(MyObject myObject)
{
// code here...
}
パラメータ myObject は、Xml フォーマッタを使用すると完全に逆シリアル化されますが、Json フォーマッタを使用すると、プロパティ MyIdProperty には Guid または Int32 ではなく文字列が含まれます。どちらの場合も、モデル バインダーはまったく使用されません。複合型のプロパティごとにモデル バインダーを使用する MVC と比較して、アクション パラメーターでモデルの評価を停止するようなものです。
注:私は真のタイプを使用したり、内部または保護されたプロパティを真のタイプで使用したりしたくありません。これは、この種のプロパティがさまざまなオブジェクトにあり、複製する必要がある場合、コードを維持するのが非常に難しくなるためです。それらを毎回