Una solucion que no he encontrado por ahí para mi problema es HttpContext.Current.Request.Unvalidated[«nombre»]
Os comento:
Resuta que estoy enviando un formulario con React que integra el editor react-draft-wysiwyg y estoy usando fetch API con formData porque el formularia envia también ficheros adjuntos.
El servidor es una API hecha con C# con el framework 4.5
Todo muy bien, pero cuando a la webapi le llega el html del campo en este caso «description», nos peta con el típico error:
A potentially dangerous Request.Form value was detected from the client.
Eso está bien, porque significa que nuestro framework nos previene de ataques XSS (Cross Site Scripting)
Para solucionar esto os encontraréis por ahí con las soluciones clásicas.
- Poner el requestValidationMode=2.0 en el web.config.
Esto deja todas las request a la API desprotejidas.
Proteje a las páginas y permite sobrecargar la validacion para que no valide las páginas que pongas en en el web.config o usando @page a nivel de página individual.
Muy bien… pero lo nuestro es una web api… así que… no sirve. - [System.Web.Mvc.ValidateInput(false)]
Esto tampoco nos vale ya que los parámetros los estamos pillando directamente de la request.
Como tenemos ficheros y valores mezlados en un form data, pues no nos vale un modelo y nos lo hacemos a mano.
* mirar código un poco más abajo - [AllowHtml] en el modelo.
Molaría, pero ya sabéis… no tenemos modelo, o mejor dicho, no lo podemos autorellenar de la request por la problemática anterior.
Este era el código con el que recogía lo que llegaba por la request y lo chutaba dentro del modelo:
var emailModel = new ActivityEmailModel(); emailModel.Files = new List<FileItem>(); foreach (string file in HttpContext.Current.Request.Files) { var postedFile = HttpContext.Current.Request.Files[file]; var memStream = new MemoryStream(); postedFile.InputStream.CopyTo(memStream); emailModel.Files.Add(new FileItem { FileName = postedFile.FileName, Content = memStream }); } emailModel.Subject = HttpContext.Current.Request["Subject"]; emailModel.Description = HttpContext.Current.Request["Description"];
Acertáis todos los que penséis que la última linia es la que peta.
Pues solo encontraba estas opciones, y no me daba la gana poner el modo de validación del 2.0 y dejar mi api en bragas así que mire con el intelisense que opciones había dentro de la request y me topo justo con «Unvalidated«.
Eureka! Justo lo que necesitaba!
emailModel.Description = HttpContext.Current.Request.Unvalidated["Description"];
Ahora ya puedo seguir con mi api protejida y solo hacer la concesión para este parámetro en contreto.
Como extra, os dejo también la parte del servicio javascript en react que envía la petición que también puede tener algo de miga por lo mismo… lo de enviar por post varios ficheros, junto con datos, con fetch y post data.
const PUBLIC_KEY = 'XXXX'; export const saveEmailService = (emailData) => { const url = `${API_BASE_URL}activities/emails`; emailData.email_from = JSON.parse(localStorage.getItem("sessionData")).UserId; emailData.email_to = JSON.parse(localStorage.getItem("sessionData")).ToId; const options = { method: 'POST', body: emailToFormData(emailData), headers: { "Authorization": 'Basic ' + btoa('usr:' + PUBLIC_KEY) } }; return isMock ? new Promise((response, reject) => { return response(true); }) : fetch(url, options) .then(response => response) } function emailToFormData(email){ const dataToSend = new FormData(); dataToSend.append("From", email.email_from); dataToSend.append("To", email.email_to); dataToSend.append("Subject", email.email_subject); dataToSend.append("Description", email.email_text); dataToSend.append("Files", email.files); for (var i=0; i < email.files.length; i++){ dataToSend.append("File_" + i, email.files[i], email.files[i].name); } return dataToSend; }
Ale! Espero que os sirva!