programing

ASP.NET MVC 아키텍처 : 구성, 상속 또는 복제에 의한 ViewModel?

randomtip 2021. 1. 16. 09:32
반응형

ASP.NET MVC 아키텍처 : 구성, 상속 또는 복제에 의한 ViewModel?


ASP.NET MVC 3 및 ​​Entity Framework 4.1 Code First를 사용하고 있습니다.

User엔티티 가 있다고 가정 해 봅시다 .

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }        
}

내에서 편집 할 때 필드 UserController를 추가하고PasswordConfirmationPasswordConfirmation == Password

1. 구성 별

첫 번째 시도는 다음과 같습니다.

public class EditUserModel
{
    [Required]
    public User User { get; set; }

    [Compare("User.Password", ErrorMessage = "Passwords don't match.")]
    public string PasswordConfirmation { get; set; }
}

이 경우 클라이언트 측 유효성 검사 작동하지만( : 편집 . 클라이언트 측 유효성 검사의 작업은 우연의 일치) 작동하지 않습니다서버 측 유효성 검사가 실패 다음과 같은 메시지가 : User.Password라는 이름의 속성을 찾을 수 없습니다

편집 : 이 경우 가장 좋은 해결책은 사용자 정의를 만드는 것입니다.CompareAttribute

구현 IValidatableObject

public class EditUserModel : IValidatableObject
{
    [Required]
    public User User { get; set; }
    public string PasswordConfirmation { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if(this.PasswordConfirmation != this.User.Password)
            return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) };

        return new ValidationResult[0];
    }
}

이 경우 서버 측 유효성 검사는 작동 하지만 클라이언트 측 유효성 검사는 더 이상 작동 하지 않습니다. 구현 IClientValidatable이 너무 복잡해 보이며이 경우 클라이언트 측 유효성 검사를 사용하지 않는 것이 좋습니다.

2. 상속

public class EditUserModel : User
{
    [Compare("Password", ErrorMessage = "Passwords don't match.")]
    public string PasswordConfirmation  { get; set; }
}

저장에 직접하려고 할 때 EditUserModelEF를 사용하여 작업, 나는에 대한 몇 가지 몇 가지 오류 메시지가 표시되지 않습니다 EditUserModel내가 사용 있도록 메타 데이터 AutoMapper를 변환하기 UserEditUserModel뒤로. 이 솔루션 은 작동 하지만 모델에서 뷰 모델로 또는 그 반대로 변환해야하기 때문에 더 복잡합니다.

3. 복제

(Malte Clasen 제안)

뷰 모델에는 모델의 모든 속성과 추가 속성이 있습니다. AutoMapper 를 사용하여 하나에서 다른 것으로 변환 할 수 있습니다.

public class EditUserModel {    
  public string Name { get; set; }    
  public string Email { get; set; }    
  public string Password { get; set; }   
  [Compare("Password", ErrorMessage = "Passwords don't match.")]     
  public string ConfirmPassword { get; set; }        
}

이것은 코드 중복 (DRY) 때문에 가장 좋아하는 솔루션입니다.

질문

이 경우 상속, 구성 및 복제의 장단점은 무엇입니까?

모델을 뷰 모델로 또는 그 반대로 변환하지 않고도 클라이언트 측과 서버 측 모두 유효성을 검사하는 간단한 방법이 있습니까?


이전에이 질문으로 고생 한 적이있는 저는 여러 경우에이 세 가지를 모두 해결했습니다. 일반적으로 내가 본 대부분의 의견은 MVC 프로젝트에서 중복을 선호하며 각 뷰에 대해 특별히 구성된 ViewModel을 사용합니다. 이러한 방식으로 사용하려는 규칙은 같은 것입니다 UserDetailsViewModelUserCreateViewModel. 말했듯이 그 시점에서 AutoMapper 또는 다른 자동 매핑 도구를 사용하여 도메인 개체에서 이러한 평면 ViewModel로 변환합니다.

나 역시 반복되는 코드를 좋아하지 않지만 유효성 검사 또는 기타 뷰 특정 속성으로 내 도메인 개체를 오염시키는 것도 좋아하지 않습니다. (모든 전문가의 의견에 관계없이) 거의 아무도 다투지 않아도되는 또 다른 장점은 ViewModel을 반드시 조작하지 않고도 어떤 방식 으로든 도메인 객체를 조작 할 수 있다는 것입니다. 나는 그것이 나에게 많은 비중을 차지하기 때문에가 아니라 일반적으로 인용되기 때문에 언급합니다.

마지막으로, 진정으로 평평한 ViewModel을 사용하면 더 깔끔한 마크 업이 가능합니다. 컴포지션을 사용할 때 .NET과 같은 이름으로 HTML 요소를 만드는 데 종종 오류가 발생했습니다 User.Address.Street. 플랫 ViewModel은 적어도 저의 가능성을 줄여줍니다 (항상 HtmlHelper 루틴을 사용하여 요소를 만들 수 있지만 항상 가능한 것은 아닙니다).

내 최근 프로젝트는 어쨌든 요즘 별도의 ViewModel이 거의 필요했습니다. 그것들은 모두 NHibernate 기반이며 NHibernate 객체에서 프록시를 사용하면 뷰에 직접 사용할 수 없습니다.

업데이트 -다음은 내가 과거에 언급 한 좋은 기사입니다. http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx


도메인 및 뷰 모델에 대한 독립 클래스를 고려할 수도 있습니다.이 경우 예를 들면 다음과 같습니다.

public class EditUserModel {    
  public string Name { get; set; }    
  public string Email { get; set; }    
  public string Password { get; set; }        
  public string ConfirmPassword { get; set; }        
}

ID가 URL에 저장된 경우. User와 EditorUserModel 인스턴스 간의 수동 복사를 피하려면 AutoMapper 가 도움이 될 수 있습니다. 이렇게하면 도메인 모델의 암호 해시에서 뷰 모델의 암호 문자열을 쉽게 분리 할 수 ​​있습니다.


I have trying to work this out and I found a solution that does not involve duplicating code. It's kind of workaround but, in my opinion, it's better than the other proposed solutions.

You have the User Model with all the validation:

public class UserModel
{
    [Required]
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }        
}

You compose the previous model with a new model

public class EditUserModel
{
    public UserModel User { get; set; }

    [Required]
    public string PasswordConfirmation { get; set; }
}

The trick is in the action, you could receive more than one model:

[HtttPost]
public ActionResult UpdateInformation(UserModel user, EditUserModel editUserModel) {
    if (ModelState.IsValid) {
         // copy the inner model to the outer model, workaround here:
         editUserModel.User = user
         // do whatever you want with editUserModel, it has all the needed information
    }
}

In this way the validation works as expected.

Hope this helps.


I don't use Entity Models too much, I prefer LINQ - SQL models so this may be incorrect:

Why not use a meta-data class which is applied to the Entity? With LINQ - SQL the metadata assigned is taken into consideration for both client-side as well as server-side validation.

From what I understand application of a [MetaDataType] attribute is similar to inheritance only it works without implementing a new class (model) for alterations to the basic entity.

Also, another option you might want to try is creating a custom attribute - I did this once for a similar purpose. Essentially a flag which indicated the persistence of a member.

So i would have an entity defined as follows:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }     

    [DoNotPersist]   
    public string ConfirmPassword {get; set;}

}

Also, I don't know what you are doing to store data but I had hooked an override into the OnInserting , OnEditing, OnDeleting functions for my DataContext which basically removed any members having my custom attribute.

I like this method simple because we use a lot of temporary, rather algorithmic data for each model (building good UI's for Business Intelligence) which is not saved in the database but is used everywhere inside model functions, controllers, etc - so we use dependency injection in all model repositories and controllers and so we have all these extra data points for each table to play with.

Hope that helps!

PS:- Composition vs Inheritance - it really depends on the target user of the application. If it is for an intranet app where security is less of an issue and the user / browser environment is controlled then just use client side validation, ie: composition.


I would favour composition over inheritance.

In case of your user password it looks like you're actually storing the password in Users table in clear text, which is VERY, VERY BAD.

You should store only a salted hash, and your EditUserModel should have two string properties for password and password confirmation, which are NOT the fields in your table.

ReferenceURL : https://stackoverflow.com/questions/6954102/asp-net-mvc-architecture-viewmodel-by-composition-inheritance-or-duplication

반응형