ASP.Net l'API Web personnalisé modèle de liaison avec x-www-form-urlencoded données publiées - rien ne semble fonctionner
Je vais avoir beaucoup de mal à faire la coutume de la liaison de modèle de travail lors de la publication x-www-form-urlencoded
de données. J'ai essayé tous les moyens, je pense, et rien ne semble pour produire le résultat désiré. Remarque lors de la publication des données JSON, mon JsonConverters et ainsi de suite tout le travail tout aussi bien. C'est quand je poste comme x-www-form-urlencoded
que le système n'arrive pas à comprendre comment lier mon modèle.
Mon cas de test, c'est que j'aimerais lier un TimeZoneInfo objet dans le cadre de mon modèle.
Voici mon modèle de classeur:
public class TimeZoneModelBinder : SystemizerModelBinder
{
protected override object BindModel(string attemptedValue, Action<string> addModelError)
{
try
{
return TimeZoneInfo.FindSystemTimeZoneById(attemptedValue);
}
catch(TimeZoneNotFoundException)
{
addModelError("The value was not a valid time zone ID. See the GetSupportedTimeZones Api call for a list of valid time zone IDs.");
return null;
}
}
}
Voici la classe de base que j'utilise:
public abstract class SystemizerModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var name = GetModelName(bindingContext.ModelName);
var valueProviderResult = bindingContext.ValueProvider.GetValue(name);
if(valueProviderResult == null || string.IsNullOrWhiteSpace(valueProviderResult.AttemptedValue))
return false;
var success = true;
var value = BindModel(valueProviderResult.AttemptedValue, s =>
{
success = false;
bindingContext.ModelState.AddModelError(name, s);
});
bindingContext.Model = value;
bindingContext.ModelState.SetModelValue(name, new System.Web.Http.ValueProviders.ValueProviderResult(value, valueProviderResult.AttemptedValue, valueProviderResult.Culture));
return success;
}
private string GetModelName(string name)
{
var n = name.LastIndexOf(".", StringComparison.Ordinal);
return n < 0 || n >= name.Length - 1 ? name : name.Substring(n + 1);
}
protected abstract object BindModel(string attemptedValue, Action<string> addModelError);
}
J'ai utilisé une classe de base de ce genre pour le rendre simple pour créer des modèles personnalisés liants.
Voici mon modèle de classeur fournisseur. Notez que c'est chargé correctement de mon conteneur IoC, donc je ne vais pas la peine de montrer cet aspect de mon code.
public class SystemizerModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
{
if(modelType == typeof(TimeZoneInfo))
return new TimeZoneModelBinder();
return null;
}
}
Enfin, voici la méthode de l'action et de la classe du modèle:
[DataContract)]
public class TestModel
{
[DataMember]
public TimeZoneInfo TimeZone { get; set; }
}
[HttpPost]
public HttpResponseMessage Test(TestModel model)
{
return Request.CreateResponse(HttpStatusCode.OK, model);
}
Pour la méthode de l'action, j'ai essayé:
public HttpResponseMessage Test([FromBody] TestModel model)
Ce invoque le FormUrlEncodedMediaFormatter
, qui semble l'ignorer mon classeur de modèles personnalisées tout simplement.
public HttpResponseMessage Test([ModelBinder] TestModel model)
C'est mon modèle de liaison personnalisé, comme prévu, mais il ne fournit ValueProviders pour RouteData
et QueryString
et pour quelque raison n'est pas de fournir quoi que ce soit pour le contenu du corps. Voir ci-dessous:
J'ai aussi essayé la décoration de la classe elle-même avec ModelBinder(typeof(SystemizerModelBinderProvider))
Pourquoi la liaison de modèle se produire UNIQUEMENT lorsque j'utilise le [ModelBinder] attribut, et pourquoi est-ce SEULEMENT essayer de lire la route et de la chaîne de recherche de valeurs et d'ignorer le contenu du corps? Pourquoi ne FromBody
ignorer mon modèle de liaison personnalisé fournisseur?
Comment puis-je créer un scénario où je peux recevoir POSTÉ x-www-form-urlencoded
de données et de réussir à lier les propriétés du modèle à l'aide de la logique personnalisée?
OriginalL'auteur Nathan Ridley | 2013-02-13
Vous devez vous connecter pour publier un commentaire.
Je vous recommande la lecture de la
blog suivant
dans lequel Mike Étal de explique en détails comment la liaison de modèle fonctionne dans l'API Web:Donc, si la source de vos données est le corps de la requête, alors vous pouvez créer un MediaTypeFormatter plutôt que d'un modèle de classeur.
Le
FormUrlEncodedMediaTypeFormatter
lit le corps de la demande et utilise un parseur personnalisé pour analyser lesapplication/x-www-form-urlencoded
demande dans une collection deKeyValuePair<string, string>
qui est ensuite utilisée pour construire le modèle.L'attribut avez-vous utilisé votre méthode d'action avec la MediaTypeFormatter,
[ModelBinder]
,[FromBody]
ou[ModelBinder(typeof(x))]
?OriginalL'auteur Darin Dimitrov
ModelBinder semblent relativement mieux que les MediaTypeFormatter. Vous n'avez pas besoin de s'inscrire à l'échelle mondiale.
J'ai trouvé une autre alternative à l'utilisation de modèle de liaison pour lier complexe des types d'objet dans l'API Web. Dans le modèle de classeur, je suis à la lecture du corps de la requête en tant que chaîne et ensuite à l'aide d'JSON.NET pour désérialiser requis type d'objet. Il peut être utilisé pour la carte de matrice complexe de types d'objets.
J'ai ajouté un modèle de classeur comme suit:
Et puis je suis à l'aide de l'API Web de contrôleur comme suit:
JSON.NET fournit la validation de certains avec JsonProoperty Attribut (newtonsoft.com/json/help/html/...). Vous pouvez définir des "Nécessaire" de la propriété de faire Requis, AllowNull etc.
OriginalL'auteur Tushar Kesare