2013-01-11 1 views
14

큰 모델이 있습니다. (모델 클래스에는 필드/속성이 많이 포함되어 있고 각 속성에는 적어도 하나의 유효성 검사 속성 (예 : Required, MaxLength, MinLength 등)이 있습니다. 모델에 데이터를 채우기위한 입력이 많은 하나의보기를 만드는 대신 사용자가 모델 필드의 일부를 채우고 다음 단계 (어떤 종류의 "마법사")로 이동하는 여러보기를 만들고 싶습니다. 단계 사이를 리디렉션하는 동안 모델 객체 전체 채우기가 Session에 저장되지 않았습니다. 뭔가 아래 같은 :ASP .NET MVC에서 모델의 일부분 만 유효성을 검사하는 방법?

모델 :

public class ModelClass 
{ 
    [MaxLength(100)] ... 
    public string Prop1{get;set;} 
    [MaxLength(100)] ... 
    public string Prop2{get;set;} 
    ... 
    [Required][MaxLength(100)] ... 
    public string Prop20{get;set;} 
} 

컨트롤러 : 등 Prop3Prop4

에 대한

[HttpPost] 
public ActionResult Step1(ModelClass postedModel) 
{  
    // user posts only for example Prop1 and Prop2 
    // so while submit I have completly emty model object 
    // but with filled Prop1 and Prop2 
    // I pass those two values to Session["model"] 
    var originalModel = Session["model"] as ModelClass ?? new ModelClass(); 
    originalModel.Prop1 = postedModel.Prop1; 
    originalModel.Prop2 = postedModel.Prop2; 
    Session["model"] = originalModel; 

    // and return next step view 
    return View("Step2"); 
} 

[HttpPost] 
public ActionResult Step2(ModelClass postedModel) 
{ 
    // Analogically the same 
    // I have posted only Prop3 and Prop4 

    var originalModel = Session["model"] as ModelClass; 
    if (originalModel!=null) 
    { 
     originalModel.Prop3 = postedModel.Prop3; 
     originalModel.Prop4 = postedModel.Prop4; 
     Session["model"] = originalModel; 

     // return next step view 
     return View("Step3"); 
    } 
    return View("SomeErrorViewIfSessionBrokesSomeHow") 
} 

Step1보기 만 Prop1Prop2에 대한 입력을 가지고, 2 단계보기에 포함 된 입력 여기에 그 중 하나가 있습니다

사용자가 1 단계와 같이 켜져 있고 Prop1을 100 자 이상의 값으로 채우는 경우 클라이언트 측 유효성 검사가 올바르게 작동합니다. 그러나 물론 컨트롤러의 서버 측에서이 값을 확인해야합니다. 전체 모델이 있다면 다음과 같이하십시오.

if(!ModelState.IsValid) return View("the same view with the same model object"); 

그래서 사용자가 양식을 다시 작성하고 수정해야합니다. BUT 1 단계에서 사용자는 20 개의 속성 2 개만 채우고 유효성을 검사해야합니다. 모델 상태가 유효하지 않으므로 ModelState.IsValid을 사용할 수 없습니다. Prop20[Required] 속성으로 표시되어있는 경우 사용자가 Prop1Prop2을 제출하면 Prop20은 null이며 그 이유는 ModelState이 유효하지 않습니다. 물론 사용자가 step2로 이동하여 모든 단계를 완료하고 마지막 단계에서만 모델 상태를 확인하도록 허용 할 수 있지만 단계 1을 잘못 기입하면 사용자가 2 단계로 이동하는 것을 허용하지 않으려합니다. 그리고 컨트롤러에서이 검증을 원합니다. 질문은 다음과 같습니다. 모델의 일부분 만 유효성을 검사하려면 어떻게해야합니까? 모델 속성 중 일부만 유효성 검사 속성과 일치하는지 어떻게 확인할 수 있습니까?

+8

별도의보기가 될 수있는 각 단계마다 다른보기 모델을 만들 수 있습니다. ProductStepViewModel 및 ProductStep1View와 유사하지만 그보다 나은 이름을 지정합니다. –

+0

@NickBray, ModelClass는 원래 모델에서 매핑 된 뷰 모델 클래스이므로 다른 특정 단계 클래스의 컴포지션으로 ModelClass를 만드는 경우 해당 모델 클래스를 매핑하기 위해 매퍼에 대해 약 40 개의 매핑 규칙을 추가해야합니다. 그러면 무리가됩니다 코드 나는 이미 그것에 대해 생각했지만 충고에 감사드립니다. – Dmytro

+0

@DmytroTsiniavsky 매핑 규칙을 명시 적으로 설정하지 않아도되는 대신 [Value Injecter] (http://valueinjecter.codeplex.com/)와 같은 것을 사용할 수 있습니다. – Mun

답변

14

한 가지 가능한 솔루션 :

  1. 사용 ModelState.IsValidField (문자열 키);

    if (ModelState.IsValidField("Name") && ModelState.IsValidField("Address")) 
    { ... } 
    

그런 다음 마지막에 모든 것이 이루어집니다 사용 :

List<string> PropertyNames = new List<string>() 
{ 
    "Prop1", 
    "Prop2" 
}; 

if (PropertyNames.Any(p => !ModelState.IsValidField(p))) 
{ 
    // Error 
} 
else 
{ 
    // Everything is okay 
} 

또는 :

if(ModelState.IsValid) { .. } 
+0

끝내지 않는 문자열을 입력하면 항상 반환되므로 올바르게 입력해야합니다. –

9

나는 가장 우아한 방법은 그런 식으로 그것을 할 생각 :

List<string> PropertyNames = new List<string>() 
{ 
    "Prop1", 
    "Prop2" 
}; 

if (PropertyNames.All(p => ModelState.IsValidField(p))) 
{ 
    // Everything is okay 
} 
else 
{ 
    // Error 
} 
2

그냥 기존 답변에 추가하십시오. 우리는 모델 자체 부분을 지식없이 속성 이름을 얻을 수 있습니다 이제

public class ValidationStageAttribute : Attribute 
{ 
    public StageNumber { get; private set; } 
    public ValidationStageAttribute(int stageNumber) 
    { 
     StageNumber = stageNumber 
    } 
} 

: 대신 속성 이름을 하드 코딩하는 것보다 내가 속성을 사용하여 유효성 검사의 나머지 부분과 함께 추가 할 수는의 라인을 따라 속성 유효성 검사를 메소드로 가져올 수 있습니다 (많이 사용하는 경우 기본 제어기가 좋은 위치가됩니다).

protected bool ValidateStage(object model, int stageToValidate) 
{ 
    var propertiesForStage = postedModel.GetType() 
     .GetProperties() 
     .Where(prop => prop.GetCustomAttributes(false).OfType<ValidationStageAttribute>().Where(attr => attr.StageNumber == stageToValidate)); 
     .Select(prop => prop.Name); 

    return propertiesForStage.All(p => ModelStage.IsValidField(p)); 
} 

이제 당신이 당신의 사후 조치를해야 할 것 모두가 MVC 코어에서 ValidateStage(postedModel, 1)

2

를 호출하는 것, 이것에 해당 될 것입니다 : 그러나

if (ModelState.GetFieldValidationState("Name") == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Valid) 
{ 
    // do something 
} 

을 나는 것 이 경우에는 이라는 별개의 뷰 모델을 만드는 것이 좋습니다.

부분보기 모델을 더 큰보기 모델에서 상속 할 수 있으므로 코드 (DRY principal)에서 반복하지 않아도됩니다.

속성 이름을 하드 코딩하지 않는 것이 좋습니다.

관련 문제