이 페이지는 아직 한국어로 제공되지 않습니다. 번역 작업 중입니다. 현재 번역 프로젝트에 대한 질문이나 피드백이 있으신 경우 언제든지 연락주시기 바랍니다.
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
usingMicrosoft.AspNetCore.Mvc;usingSystem;usingSystem.Collections.Generic;namespaceMyApp.Controllers{publicclassUserController:Controller{ [HttpGet]publicIActionResultRegister(){returnView();}// NON-COMPLIANT: Direct access to Request.Headers [HttpPost]publicIActionResultRegister_NonCompliant(){// Noncompliant: Direct access to Request.Headersvarname=Request.Headers["X-User-Name"].ToString();varemail=Request.Headers["X-User-Email"].ToString();varpassword=Request.Headers["X-User-Password"].ToString();varbirthdateStr=Request.Headers["X-User-Birthdate"].ToString();// Manual parsing and error handlingif(!DateTime.TryParse(birthdateStr,outvarbirthdate)){returnBadRequest("Invalid birthdate");}// Manual validationif(string.IsNullOrEmpty(name)||string.IsNullOrEmpty(email)){returnBadRequest("Name and email are required");}// Process registration...returnOk($"User {name} registered successfully");}// COMPLIANT: Using FromHeader attribute (Recommended) [HttpPost("register-compliant")]publicIActionResultRegister_Compliant( [FromHeader(Name = "X-User-Name")]stringname, [FromHeader(Name = "X-User-Email")]stringemail, [FromHeader(Name = "X-User-Password")]stringpassword, [FromHeader(Name = "X-User-Birthdate")]DateTimebirthdate){// Automatic binding and type conversionif(!ModelState.IsValid){returnBadRequest(ModelState);}// Manual validation (or use Data Annotations)if(string.IsNullOrEmpty(name)||string.IsNullOrEmpty(email)){returnBadRequest("Name and email are required");}// Process registration...returnOk($"User {name} registered successfully");}}}
usingMicrosoft.AspNetCore.Mvc;usingSystem;usingSystem.Collections.Generic;namespaceMyApp.Controllers{publicclassUserController:Controller{ [HttpGet]publicIActionResultRegister(){returnView();} [HttpPost]publicIActionResultRegister_NonCompliant(){// Noncompliant: Direct access to Request.Formvarname=Request.Form["name"];varemail=Request.Form["email"];varpassword=Request.Form["password"];varbirthdateStr=Request.Form["birthdate"];// Manual parsing and error handlingif(!DateTime.TryParse(birthdateStr,outvarbirthdate)){returnBadRequest("Invalid birthdate");}// Manual validationif(string.IsNullOrEmpty(name)||string.IsNullOrEmpty(email)){returnBadRequest("Name and email are required");}// Process registration...returnOk($"User {name} registered successfully");}}}
Compliant Code Examples
usingMicrosoft.AspNetCore.Mvc;usingSystem;usingSystem.ComponentModel.DataAnnotations;namespaceMyApp.Controllers{// Model class for registrationpublicclassUserRegistrationModel{ [Required(ErrorMessage = "Name is required")] [StringLength(100, ErrorMessage = "Name cannot exceed 100 characters")]publicstringName{get;set;} [Required(ErrorMessage = "Email is required")] [EmailAddress(ErrorMessage = "Invalid email format")]publicstringEmail{get;set;} [Required(ErrorMessage = "Password is required")] [MinLength(6, ErrorMessage = "Password must be at least 6 characters")] [DataType(DataType.Password)]publicstringPassword{get;set;} [Required(ErrorMessage = "Birthdate is required")] [DataType(DataType.Date)]publicDateTimeBirthdate{get;set;}}publicclassUserController:Controller{ [HttpGet]publicIActionResultRegister(){returnView();}// COMPLIANT: Using Model Binding with [FromForm] [HttpPost]publicIActionResultRegister([FromForm]UserRegistrationModelmodel){// Automatic validation based on Data Annotationsif(!ModelState.IsValid){returnBadRequest(ModelState);}// Process registration with validated model// All type conversions are handled automatically// birthdate is already a DateTime, not a stringreturnOk($"User {model.Name} registered successfully");}// Alternative: If you want to return validation errors to a view [HttpPost("register-view")]publicIActionResultRegisterWithView([FromForm]UserRegistrationModelmodel){if(!ModelState.IsValid){// Return to view with validation errorsreturnView("Register",model);}// Process registration...TempData["SuccessMessage"]=$"User {model.Name} registered successfully";returnRedirectToAction("Success");}// Alternative: Using individual parameters (less common, but valid) [HttpPost("register-params")]publicIActionResultRegisterWithParameters( [FromForm]stringname, [FromForm]stringemail, [FromForm]stringpassword, [FromForm]DateTimebirthdate){// Manual validation needed with this approachif(string.IsNullOrEmpty(name)||string.IsNullOrEmpty(email)){returnBadRequest("Name and email are required");}if(!ModelState.IsValid){returnBadRequest(ModelState);}// Process registration...returnOk($"User {name} registered successfully");} [HttpGet("success")]publicIActionResultSuccess(){returnView();}}}
원활한 통합. Datadog Code Security를 경험해 보세요
Datadog Code Security
이 규칙을 사용해 Datadog Code Security로 코드를 분석하세요
규칙 사용 방법
1
2
rulesets:- csharp-best-practices # Rules to enforce C# best practices.
리포지토리 루트에 위의 내용을 포함하는 static-analysis.datadog.yml을 만듭니다
무료 IDE 플러그인을 사용하거나 CI 파이프라인에 Code Security 검사를 추가합니다