ASP.NET Отклонение MVC по дополнительным полям

#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;
}