如何在多个Controller类之间重用Action Method验证

时间:2016-04-14 15:32:17

标签: c# asp.net asp.net-mvc asp.net-mvc-5

我正在使用实体框架-6在asp.net mvc-5 Web应用程序上工作。我已经使用实体框架映射了我的数据库表,生成包含DBContext类的.edmx文件。目前我有两个控制器类,一个用于管理服务器,另一个用于管理vms。添加/编辑服务器或虚拟机时,我想检查他们的ip和& mac地址已经存在。目前我正在对动作方法本身进行如下检查: -

public class Server : Controller{
    [HttpPost]
     [ValidateAntiForgeryToken]
     public ActionResult Create(ServerJoin sj)
            {
                bool ITipunique = repository.ISITIPUnique(vmj.NetworkInfo2.FirstOrDefault().IPADDRESS);
                bool ITmacunique = repository.ISITMACUnique(vmj.NetworkInfo2.FirstOrDefault().MACADDRESS);
                bool Tipunique = repository.ISTIPUnique(vmj.NetworkInfo2.FirstOrDefault().IPADDRESS);
                bool Tmacunique = repository.ISTMACUnique(vmj.NetworkInfo2.FirstOrDefault().MACADDRESS);

                try
                {

                    if ((sj.IsIPUnique == true) && (!ITipunique || !Tipunique))
                    {

                        ModelState.AddModelError("NetworkInfo2[0].IPAddress", "Error occurred. The Same IP is already assigned.");

                    }
                    if ((sj.IsMACUnique == true) && (!ITmacunique || !Tmacunique))
                    {

                        ModelState.AddModelError("NetworkInfo2[0].MACAddress", "Error occurred. The Same MAC Address is already assigned.");

                    }

&安培;

public class VM : Controlelr {    
    [HttpPost]
    [ValidateAntiForgeryToken]

            public ActionResult Create(VMJoin vmj)
            {

                bool ITipunique = repository.ISITIPUnique(vmj.NetworkInfo2.FirstOrDefault().IPADDRESS);
                bool ITmacunique = repository.ISITMACUnique(vmj.NetworkInfo2.FirstOrDefault().MACADDRESS);
                bool Tipunique = repository.ISTIPUnique(vmj.NetworkInfo2.FirstOrDefault().IPADDRESS);
                bool Tmacunique = repository.ISTMACUnique(vmj.NetworkInfo2.FirstOrDefault().MACADDRESS);
                try
                {
                    if ((vmj.IsIPUnique == true) && (!ITipunique || !Tipunique))
                    {

                        ModelState.AddModelError("NetworkInfo2[0].IPAddress", "Error occurred. The Same IP is already assigned.");

                    }
                    if ((vmj.IsMACUnique == true) && (!ITmacunique || !Tmacunique))
                    {

                        ModelState.AddModelError("NetworkInfo2[0].MACAddress", "Error occurred. The Same MAC Address is already assigned.");

                    }
                    if (!repository.IshypervisorServers(vmj.VirtualMachine.ServerID))
                    {
                        ModelState.AddModelError("VirtualMachine.ServerID", "Error occurred. Please select a valid hypervisor server. ");
                    }

这种方法运行良好,但我面临的一个问题是我必须在所有相关的操作方法上重复这些验证(添加和编辑)和其他控制器类(服务器,虚拟机,存储设备等) ...)那么有没有办法以更好的方式管理共享验证,这有助于重用和可维护性?

修改

ServerJoin如下: -

public class ServerJoin : IValidatableObject
    {
        public Server Server { get; set; }
        public Resource Resource { get; set; }
        public Technology Technology { get; set; }
        public SDOrganization Site { get; set; }
        public SDOrganization Customer { get; set; }
        public NetworkInfo NetworkInfo { get; set; }
        public ICollection<NetworkInfo> NetworkInfo2 { get; set; }
        [Display(Name="Unique")]
        public bool IsMACUnique { get; set; }
        [Display(Name = "Unique")]
        public bool IsIPUnique { get; set; }
        public Nullable<double> SPEED { get; set; }
        public Nullable<Int64> PROCESSORCOUNT { get; set; }
        [Display(Name = "IP Unique")]
        public bool IsTIPUnique { get; set; }
        [Display(Name = "MAC Unique")]
        public bool IsTMACUnique { get; set; }
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Server != null)
            {


                if (Server.RackUnitID != null && Server.RackID == null)
                {
                    yield return new ValidationResult("Please select a Rack, or remove the current Rack Unit", new[] { "Server.RackUnitID" });
                }
                if (Server.RackUnitIDTo != null && Server.RackUnitID == null)
                {
                    yield return new ValidationResult("Please select a Rack From Value", new[] { "Server.RackUnitID" });
                }
                if (Server.RackUnitIDTo != null && Server.RackUnitID != null && Server.RackUnitID > Server.RackUnitIDTo)
                {
                    yield return new ValidationResult("Rack Unit From must be less than or equal Rack Unit To", new[] { "Server.RackUnitID" });
                }


            }

&安培;

 public class VMJoin
    {
         public VirtualMachine VirtualMachine { get; set; }
         public Resource Resource { get; set; }
         public Technology Technology { get; set; }
         public SDOrganization Site { get; set; }
         public SDOrganization Customer { get; set; }
         public NetworkInfo NetworkInfo { get; set; }
         public ICollection<NetworkInfo> NetworkInfo2 { get; set; }
         public ICollection<TechnologyIP> TechnologyIP { get; set; }
         [Display(Name = "Unique")]
         public bool IsMACUnique { get; set; }
         [Display(Name = "Unique")]
         public bool IsIPUnique { get; set; }
         public Nullable<double> SPEED { get; set; }
         public TechnologyIP TechnologyIP2 { get; set; }
         [Display(Name = "IP Unique")]
         public bool IsTIPUnique  { get; set; }
         [Display(Name = "MAC Unique")]
         public bool IsTMACUnique { get; set; }

    }
}

4 个答案:

答案 0 :(得分:5)

首先为您的模型创建一个具有公共属性的基类,这也将减少具体类中的代码。

public class BaseModel
{
    public bool IsIPUnique { get; set; }
    public bool IsMACUnique { get; set; }
    .... // other common properties
}
public class ServerJoin : BaseModel
{
    .... //  properties specific to ServerJoin 
}
public class VMJoin : BaseModel
{
    .... //  properties specific to VMJoin
}

并为公共验证代码

创建一个基本控制器
public class BaseController : Controller
{
    public void Validate(BaseModel model)
    {
        bool ITipunique = repository.ISITIPUnique(vmj.NetworkInfo2.FirstOrDefault().IPADDRESS);
        ....
        if ((model.IsIPUnique == true) && (!ITipunique || !Tipunique))
        {
            ModelState.AddModelError("NetworkInfo2[0].IPAddress", "Error occurred. The Same IP is already assigned.");
        }
        if ((model.IsMACUnique == true) && (!ITmacunique || !Tmacunique))
        {
            ModelState.AddModelError("NetworkInfo2[0].MACAddress", "Error occurred. The Same MAC Address is already assigned.");
        }
        .... // other common validation  
    }
}

然后在特定的控制器上

public class ServerController : BaseController
{
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(ServerJoin sj)
    {
        Validate(sj); // adds the ModelStateErrors
        if (!ModelState.IsValid)
        {
            return View(sj);
        }
        ....
    }
}

public class VMController : BaseController
{
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(VMJoin vmj)
    {
        Validate(vmj); // adds the ModelStateErrors
        if (!ModelState.IsValid)
        {
            return View(vmj);
        }
        ....
    }
}

答案 1 :(得分:3)

如果php://memoryVMJoin具有相同的界面,您可以使用ServerJoin作为第二个参数创建扩展方法。

<强>更新 这是扩展方法的例子

ModelState

答案 2 :(得分:2)

在我看来,最干净的方法是使用自定义验证数据注释属性。

您只需创建自定义属性

public class IPUniqueValidator : ValidationAttribute
{
    public string ShouldCheck { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            var IP = value.ToString();
            var isValid = false;

            // Using reflection to get the other property value 
            var shouldCheckPropert = validationContext.ObjectInstance.GetType().GetProperty(this.ShouldCheck);
            var shouldCheckPropertValue = (bool)shouldCheckPropert.GetValue(validationContext.ObjectInstance, null);
            if (shouldCheckPropertValue)
            {
                // do validation code...
            }

            if (isValid)
            {
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult("Error occurred. The Same IP is already assigned.");
            }
        }
        else
        {
            return new ValidationResult("" + validationContext.DisplayName + " is required");
        }
    }
}

使用新属性标记模型:

public class VMJoin
{
    [IPUniqueValidator(ShouldCheck = "ShouldCheck")]
    public string IpAddress { get; set; }

    public bool ShouldCheck { get; set; }
}

public class ServerJoin
{
    [IPUniqueValidator(ShouldCheck = "ShouldCheck")]
    public string IpAddress { get; set; }

    public bool ShouldCheck { get; set; }
}

它只留下您添加检查验证状态。该框架将为您完成所有工作。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ServerJoin sj)
{
    if (ModelState.IsValid)
    {
        // do staff 
    }
}

答案 3 :(得分:0)

我会使用自定义ActionFilter。在此处查看如何从操作过滤器访问ModelState

How do I access the ModelState from an ActionFilter?

您还可以在自定义操作筛选器中设置依赖项注入,以接收所需的存储库,从而进一步提高可测试性/可维护性。