【问题标题】:ASP.NET MVC 3 - Model ValidationASP.NET MVC 3 - 模型验证
【发布时间】:2011-11-16 20:00:56
【问题描述】:

我刚刚学习 MVC,我有一些关于设计/事情应该如何工作的问题。

我正在使用 MVC 3 和 Razor,以及实体框架类(例如 Location),我将创建一个带有验证注释的伙伴类。在我的视图中,我有一个局部视图,它呈现一个 DevExpress TreeView(使用位置列表)和一个用于在树中创建/编辑位置的表单。我有一个 LocationController、一个 LocationManagementView、一个 LocationManagementPartialView(包含树视图的代码)和一个 LocationModel。 LocationModel 将保存 buddy 类并获取获取子节点的方法(仅在展开节点后获取子节点)。我有一个将使用 StructureMap 注入的服务包装器(用于我的服务客户端)。

我应该将服务包装器注入 Controller 的构造函数还是 Model 的构造函数?

另外,我的模型具有使用服务包装器从数据库中获取数据的 get 方法(这些方法是否属于模型中的此处?):例如,树视图的 GetChildren。

另外,将 Location buddy 类存储在 Model 中是否正确?

我想确保我很好地设计了这个应用程序,因为它是一个更大的项目的一部分。任何设计指针都非常感谢。我一直在阅读 ScottGu 的关于 MVC 内容的博客。

参考:http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx

【问题讨论】:

  • 您需要花一些时间阅读您的问题。用段落更好地格式化它。并且只列出那些相关的类。

标签: asp.net-mvc-3 validation model


【解决方案1】:

以下是针对您的“框架”的一些建议。

实体框架

对于从 EF 返回的每个模型,提取 EF 模型的接口并将该接口用作数据源,而不是实现的 EF 类。这样做的原因是,如果您决定为任何一个或多个模型(或整个实体框架)使用另一个数据源,您可以简单地确保您的新数据层返回相同的接口,而无需更改整个 Web代码。缺点是确保您的界面在您进行模型更改时是最新的。

这还允许您的视图模型实现 EF 模型的接口(带有您选择的附加逻辑)。如果您对数据层的所有插入/更新调用都接受返回的相同接口模型,这将是有利的。这允许您创建具有不同要求的多个模型,这些模型都适合数据层插入/更新所需的内容。缺点是在您的数据层中,您必须[创建一个新的 EF 模型]/[获取要更新的模型]并将接口中的字段映射到模型。

查看模型

我强烈建议每个视图模型不是需要显示的实际模型,而是包含模型的类。例子:

public class Car  //Not what I recommend passing to a view
{
    public string Make { get; set; }
    public string Model { get; set; }
}

//Pass this to the view, i'll explain why...
public class CarViewModel : IPartialViewCar      {
    public Car Car { get; set; }
    public ColorCollection { get; set; }
}

通过传递示例“CarViewModel”,您可以将部分视图与视图分离。方法如下(使用上述模型):

public interface IPartialViewCar  
{
    public Car { get; }
}

[BuildCar.cshtml]
@Model MyNameSpace.Models.Car

@Html.EditorFor(model)

[PartialViewCar.cshtml]
@Model MyNameSpace.Models.IPartialViewCar  

@Html.EditorFor(model)  //something like that..

现在,无论何时您想使用PartialViewCar,您只需要创建一个实现IPartialViewCar 接口的模型,基本上将部分视图与视图分离。

验证

我建议创建包含所有验证逻辑的接口(如果你真的需要,可以创建类,但实际上并不需要)。

假设我们希望匿名用户输入品牌和型号,但注册用户只需输入品牌。如何轻松完成,方法如下:(在前面的代码上扩展更多)

public interface IAnonymouseCarValidation
{
    [required]
    public string Make { get; set; }
    [required]
    public string Model { get; set; }
}

public interface IRegisteredCarValidation
{
    [required]
    public string Make { get; set; }
}

public interface ICar
{
    public string Make { get; set;}
    public string Model { get; set; }
}

[updating the Car model to abstract and use an interface now]
public abstract class Car : ICar
{
    //maybe some constructor logic for all car stuff

    public string Make { get; set;}
    public string Model { get; set; }

    //maybe some methods for all car stuff
}

//MetadataType tells MVC to use the dataannotations on the
//typeof class/interface for validation!
[MetadataType(typeof(AnonymouseCarValidation))]
public class AnonymousCar : Car
{
}


[MetadataType(typeof(AnonymouseCarValidation))]
public class RegisteredCar : Car
{
}

[Now update the ViewModel]
public class CarViewModel : IPartialViewCar     
{
    public ICar Car { get; set; }  //this is now ICar 
    public ColorCollection { get; set; }
}

现在您可以创建 AnonymouseCarRegisteredCar,将其传递给 CarViewModel,并让 MVC 负责验证。当您需要更新验证时,您更新单个接口。这样做的缺点是感觉相当复杂。

注入和数据请求

我的偏好是尽量保持控制器操作尽可能简单,而不是在其中包含用于检索数据的代码。我选择不这样做的原因是我不喜欢重复代码。例如:

public class AccountControllers
{
    DataServer _Service;

    public AccountControllers(DataServer Service)
    {
        this._Service = Service;
    }

    public ActionResult ShowProfiles()
    {
        ProfileViewModel model = new ProfileViewModel();
        model.Profiles = this._Service.Profiles();
        return View(model);
    }

    public ActionResult UpdateProfile(ProfileViewModel updatedModel)
    {
        service.UpdateProfile(updatedModel);

        ProfileViewModel model = new ProfileViewModel();
        model.Profiles = this._Service.Profiles();
        return View(model);
    }
}

相反,我会做类似的事情:(不完全)

    public ActionResult ShowProfile(Guid ID)
    {
        ProfileViewModel model = new ProfileViewModel(this._service);
        return View(model);
    }

    public ActionResult UpdateProfile(ProfileViewModel updatedModel)
    {
        // pass in the service, or use a property or have SetService method
        updatedModel.Update(this._service)

        ProfileViewModel model = new ProfileViewModel(this._service);
        return View(model);
    }

public class ProfileViewModel()
{
    DataServer _Service;
    Profile _Profile
    public ProfileViewModel()
    {
    }

    public ProfileViewModel(DataServer Service)
    {
        this._Service = Service;
    }


    public Profile Profiles()
    {
        get
        {
            if (this._service == null)
            {
                throw new InvalidOperationException("Service was not set.");
            }
            return = Service.Profiles(ID);
    }

这意味着配置文件在被请求时被枚举,我不必自己填充它。如果我使用代码来发挥自己的优势,而不是要求我或其他程序员手动填充模型,那么错误往往会更少。

【讨论】:

    猜你喜欢
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多