ASP.NET MVC Потенциально опасное значение Request.Form было обнаружено от клиента при использовании пользовательского связывателя моделей
Получение ошибки здесь:
ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");
Как разрешить только выбор значений? т.е.
[ValidateInput(false)]
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");
ValueProviderResult value2 = bindingContext.ValueProvider.GetValue("ConfirmationMessage2");
}
4 ответа
Пытаться:
HttpRequestBase request = controllerContext.HttpContext.Request;
string re = request.Unvalidated.Form.Get("ConfirmationMessage")
У вас есть несколько вариантов.
В модели добавьте этот атрибут к каждому свойству, для которого нужно разрешить HTML - лучший выбор
using System.Web.Mvc;
[AllowHtml]
public string SomeProperty { get; set; }
В действии контроллера добавьте этот атрибут, чтобы разрешить все HTML
[ValidateInput(false)]
public ActionResult SomeAction(MyViewModel myViewModel)
Грубая сила в web.config - определенно не рекомендуется
В файле web.config в тегах вставьте элемент httpRuntime с атрибутом requestValidationMode="2.0". Также добавьте атрибут validateRequest="false" в элементе pages.
<configuration>
<system.web>
<httpRuntime requestValidationMode="2.0" />
</system.web>
<pages validateRequest="false">
</pages>
</configuration>
Дополнительная информация: http://davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx
Вышеуказанное работает для использования связующего устройства по умолчанию.
Custom ModelBinder
Похоже, что вызов метода bindingContext.ValueProvider.GetValue() в приведенном выше коде всегда проверяет данные независимо от каких-либо атрибутов. Копание источников ASP.NET MVC показывает, что DefaultModelBinder сначала проверяет, требуется ли проверка запроса, а затем вызывает метод bindingContext.UnvalidatedValueProvider.GetValue() с параметром, который указывает, требуется ли проверка.
К сожалению, мы не можем использовать какой-либо код инфраструктуры, потому что он запечатан, закрыт или что-то еще, чтобы защитить невежественных разработчиков от опасных действий, но не так уж сложно создать работающий пользовательский механизм связывания модели, который учитывает атрибуты AllowHtml и ValidateInput:
public class MyModelBinder: IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// First check if request validation is required
var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled;
// Get value
var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
if (valueProviderResult != null)
{
var theValue = valueProviderResult.AttemptedValue;
// etc...
}
}
}
Другая необходимая часть - это способ получения непроверенного значения. В этом примере мы используем метод расширения для класса ModelBindingContext:
public static class ExtensionHelpers
{
public static ValueProviderResult GetValueFromValueProvider(this ModelBindingContext bindingContext, bool performRequestValidation)
{
var unvalidatedValueProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;
return (unvalidatedValueProvider != null)
? unvalidatedValueProvider.GetValue(bindingContext.ModelName, !performRequestValidation)
: bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
}
}
Более подробная информация об этом на http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/
Расширяя ответ от @DW, в моем контроллере Edit при переборе значений формы мне пришлось заменить все экземпляры Request.Params.AllKeys
с Request.Unvalidated.Form.AllKeys
и все случаи Request[key]
с Request.Unvalidated.Form[key]
,
Это было единственное решение, которое сработало для меня.
Как писал Майк Годин, даже если вы установили атрибут [ValidateInput(false)], вам нужно использовать Request.Unvalidated.Form вместо Request.Form. Это сработало для меня с ASP.NET MVC 5
Вот шаги для кодирования на уровне клиента и декодирования его на уровне сервера:
Разместите форму, используя метод отправки jquery.
В jquery нажмите кнопку метода события, закодируйте поле, которое вы хотите опубликовать на сервере. Пример:
$("#field").val(encodeURIComponent($("#field").val())) $("#formid").submit();
На уровне контроллера получить доступ ко всем значениям идентификатора формы, используя
HttpUtility.UrlDecode(Request["fieldid"])
Пример примера:
Уровень контроллера:
public ActionResult Name(string id) { CheckDispose(); string start = Request["start-date"]; string end = Request["end-date"]; return View("Index", GetACPViewModel(HttpUtility.UrlDecode(Request["searchid"]), start, end)); }
Уровень клиента:
<% using (Html.BeginForm("Name", "App", FormMethod.Post, new { id = "search-form" })) { %> <div> <label for="search-text" style="vertical-align: middle" id="search-label" title="Search for an application by name, the name for who a request was made, or a BEMSID">App, (For Who) Name, or BEMSID: </label> <%= Html.TextBox("searchid", null, new {value=searchText, id = "search-text", placeholder = "Enter Application, Name, or BEMSID" })%> </div> <div> <input id="start-date" name="start-date" class="datepicker" type="text" placeholder="Ex: 1/1/2012"/> </div> <div> <input id="end-date" name="end-date" class="datepicker" type="text" placeholder="Ex: 12/31/2012"/> </div> <div> <input type="button" name="search" id="btnsearch" value="Search" class="searchbtn" style="height:35px"/> </div> <% } %>
В функции "Готовность документа":
$(function () {
$("#btnsearch").click(function () {
$("#search-text").val(encodeURIComponent($("#search-text").val()));
$("#search-form").submit();
});
});