Este producto no es compatible con el sitio Datadog seleccionado. ().
Esta página aún no está disponible en español. Estamos trabajando en su traducción.
Si tienes alguna pregunta o comentario sobre nuestro actual proyecto de traducción, no dudes en ponerte en contacto con nosotros.

Metadata

ID: csharp-best-practices/use-model-binding

Language: C#

Severity: Notice

Category: Best Practices

Description

This rule encourages developers to use model binding instead of directly accessing data from the request object, such as Request.Form or Request.Headers. Model binding provides a clean and declarative way to receive input data by mapping HTTP request data to strongly typed parameters or models in controller actions.

Using model binding improves code readability, reduces boilerplate parsing and validation logic, and leverages built-in framework features like automatic type conversion and validation attributes. It helps prevent errors related to manual data extraction and parsing, which can introduce bugs or security vulnerabilities if not handled carefully.

To comply with this rule, define a model class representing the expected input and use action method parameters with attributes like [FromForm] or [FromHeader] to bind incoming data automatically. For example, use public IActionResult Register([FromForm] UserRegistrationModel model) instead of manually reading from Request.Form. This approach ensures cleaner, safer, and more maintainable code.

Non-Compliant Code Examples

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;

namespace MyApp.Controllers
{
    public class UserController : Controller
    {
        [HttpGet]
        public IActionResult Register()
        {
            return View();
        }

        // NON-COMPLIANT: Direct access to Request.Headers
        [HttpPost]
        public IActionResult Register_NonCompliant()
        {
            // Noncompliant: Direct access to Request.Headers
            var name = Request.Headers["X-User-Name"].ToString();
            var email = Request.Headers["X-User-Email"].ToString();
            var password = Request.Headers["X-User-Password"].ToString();
            var birthdateStr = Request.Headers["X-User-Birthdate"].ToString();
            
            // Manual parsing and error handling
            if (!DateTime.TryParse(birthdateStr, out var birthdate))
            {
                return BadRequest("Invalid birthdate");
            }

            // Manual validation
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(email))
            {
                return BadRequest("Name and email are required");
            }

            // Process registration...
            return Ok($"User {name} registered successfully");
        }

        // COMPLIANT: Using FromHeader attribute (Recommended)
        [HttpPost("register-compliant")]
        public IActionResult Register_Compliant(
            [FromHeader(Name = "X-User-Name")] string name,
            [FromHeader(Name = "X-User-Email")] string email,
            [FromHeader(Name = "X-User-Password")] string password,
            [FromHeader(Name = "X-User-Birthdate")] DateTime birthdate)
        {
            // Automatic binding and type conversion
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // Manual validation (or use Data Annotations)
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(email))
            {
                return BadRequest("Name and email are required");
            }

            // Process registration...
            return Ok($"User {name} registered successfully");
        }
    }
}
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
namespace MyApp.Controllers
{
    public class UserController : Controller
    {
        [HttpGet]
        public IActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Register_NonCompliant()
        {
            // Noncompliant: Direct access to Request.Form
            var name = Request.Form["name"];
            var email = Request.Form["email"];
            var password = Request.Form["password"];
            var birthdateStr = Request.Form["birthdate"];
            
            // Manual parsing and error handling
            if (!DateTime.TryParse(birthdateStr, out var birthdate))
            {
                return BadRequest("Invalid birthdate");
            }

            // Manual validation
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(email))
            {
                return BadRequest("Name and email are required");
            }

            // Process registration...
            return Ok($"User {name} registered successfully");
        }
    }
}

Compliant Code Examples

using Microsoft.AspNetCore.Mvc;
using System;
using System.ComponentModel.DataAnnotations;

namespace MyApp.Controllers
{
    // Model class for registration
    public class UserRegistrationModel
    {
        [Required(ErrorMessage = "Name is required")]
        [StringLength(100, ErrorMessage = "Name cannot exceed 100 characters")]
        public string Name { get; set; }

        [Required(ErrorMessage = "Email is required")]
        [EmailAddress(ErrorMessage = "Invalid email format")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Password is required")]
        [MinLength(6, ErrorMessage = "Password must be at least 6 characters")]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Required(ErrorMessage = "Birthdate is required")]
        [DataType(DataType.Date)]
        public DateTime Birthdate { get; set; }
    }

    public class UserController : Controller
    {
        [HttpGet]
        public IActionResult Register()
        {
            return View();
        }

        // COMPLIANT: Using Model Binding with [FromForm]
        [HttpPost]
        public IActionResult Register([FromForm] UserRegistrationModel model)
        {
            // Automatic validation based on Data Annotations
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // Process registration with validated model
            // All type conversions are handled automatically
            // birthdate is already a DateTime, not a string
            
            return Ok($"User {model.Name} registered successfully");
        }

        // Alternative: If you want to return validation errors to a view
        [HttpPost("register-view")]
        public IActionResult RegisterWithView([FromForm] UserRegistrationModel model)
        {
            if (!ModelState.IsValid)
            {
                // Return to view with validation errors
                return View("Register", model);
            }

            // Process registration...
            TempData["SuccessMessage"] = $"User {model.Name} registered successfully";
            return RedirectToAction("Success");
        }

        // Alternative: Using individual parameters (less common, but valid)
        [HttpPost("register-params")]
        public IActionResult RegisterWithParameters(
            [FromForm] string name,
            [FromForm] string email,
            [FromForm] string password,
            [FromForm] DateTime birthdate)
        {
            // Manual validation needed with this approach
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(email))
            {
                return BadRequest("Name and email are required");
            }

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // Process registration...
            return Ok($"User {name} registered successfully");
        }

        [HttpGet("success")]
        public IActionResult Success()
        {
            return View();
        }
    }
}
https://static.datadoghq.com/static/images/logos/github_avatar.svg https://static.datadoghq.com/static/images/logos/vscode_avatar.svg jetbrains

Integraciones sin problemas. Prueba Datadog Code Security