#c# #asp.net-mvc #model-binding
#c# #asp.net-mvc #Привязка к модели
Вопрос:
В ASP.NET MVC, у меня есть HTTP-метод
[HttpPost]
public JsonResult SampleMethod(LoginModel prmModel)
{
}
И LoginModel похож:
public class LoginModel
{
public string Username { get; set; }
public string Password { get; set; }
}
Я хочу, чтобы запрос завершился с ошибкой, если в теле запроса больше полей, чем ожидалось (имя пользователя и пароль)
Если тело HTTP-запроса является {Username: 'U', Password: 'P', Dummy:'D' }
, запрос должен завершиться неудачей из-за «фиктивного» поля в моем случае. (Исключение или неверный ответ на запрос)
Как я могу ограничить MVC Model Binder таким образом только для определенных методов? Это требование не для всех методов, для определенных моделей в проекте.
Комментарии:
1. Если кто-то отправит сообщение
{Username: 'U', Password: 'P', Dummy:'D' }
, то ASP.NET Привязка модели MVC автоматически пропуститDummy
и привяжет к модели только имя пользователя и парольLoginModel
. Тогда в чем ваша проблема?2. Чего вы хотите достичь? Связующее устройство модели по умолчанию в любом случае игнорировало бы фиктивное свойство.
3. Я НЕ хочу игнорировать и продолжать работу с привязываемыми полями. Я хочу, чтобы MVC генерировал ошибку и сбой, если в теле встречаются неожиданные поля.
4. вы можете проверить
Request.Form["Username "]
и запросить. Сформируйте [«Пароль»] в действиях вашего контроллера, если найден ключ, отличный от этой формы, тогда вы можете создать исключение и обработать его, какRequest.Form["Dummy"]
затем выбросить исключение5. @LaljiDhameliya Конечно, я могу это сделать, но я ищу встроенные общие подходы.
Ответ №1:
Если вы можете использовать Newtonsoft.Библиотека JSON, в которой отсутствует свойство JsonSerializerSettings
MissingMemberHandling . Вы можете написать пользовательскую привязку модели для десериализации объекта из json, используя это свойство, например:
public class StrictJsonBodyModelBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(string))
{
if (bindingContext.HttpContext.Request.ContentType != "application/json")
{
throw new Exception("invalid content type, application/json is expected");
}
using (var bodyStreamReader = new StreamReader(bindingContext.HttpContext.Request.Body))
{
var jsonBody = await bodyStreamReader.ReadToEndAsync().ConfigureAwait(false);
var jsonSerializerSettings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error,
};
var model = JsonConvert.DeserializeObject(jsonBody, bindingContext.ModelType, jsonSerializerSettings);
bindingContext.Result = ModelBindingResult.Success(model);
}
}
}
}
Тогда вы могли бы использовать эту модель binder с ModelBinderAttribute
аргументом for specific action:
[HttpPost]
public JsonResult SampleMethod([ModelBinder(typeof(StrictJsonBodyModelBinder))] LoginModel prmModel)
{
}
Теперь, когда будут переданы недопустимые свойства, JsonConvert
будет выдана ошибка (будет HTTP 500 для пользователей, если ошибка не будет обработана).
Ответ №2:
Самый простой способ реализовать это требование — проверить Request.Form.Keys.Count != 2 or > 2
if (Request.Form.Keys.Count > 2)
{
return View("Error"); // handle error
}
else
{
// handle logic here
}
Комментарии:
1. Это должно быть
Request.Form.Keys.Count>3
потому, что есть скрытоеAntiForegeryToken
поле
Ответ №3:
Решения:
[HttpPost]
public JsonResult SampleMethod()
{
dynamic prmModel= System.Web.Helpers.Json.Decode((new StreamReader(Request.InputStream).ReadToEnd()));
Newtonsoft.Json.Schema.JsonSchema schema = JsonSchema.Parse(Jsonschema());
Newtonsoft.Json.Linq.JObject user = JObject.Parse(Newtonsoft.Json.JsonConvert.SerializeObject(prmModel));
if (!user.IsValid(schema) || user.Count > 2)
return Json("Bad Request");
}
public string Jsonschema()
{
string schemaJson = @"{
'description': 'A',
'type': 'object',
'properties': {
'UserName':{'type':'string'},
'Password':{'type':'string'}
}
}";
return schemaJson;
}