C#MVC CMS-自定义远程验证 [英] C# MVC CMS - Customising Remote Validation

查看:78
本文介绍了C#MVC CMS-自定义远程验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的链接中,我问了一个有关如何确保字段不包含相同值的问题(例如,当字段上存在唯一约束时,正确约束C#时会抛出异常).用我收到的答案,它解决了这个问题,但又提出了另一个问题.

At the link below I asked a question about how to ensure a field does not already contain the same value (for example when there is a unique constraint on a field which correctly causes C# to throw an exception when voilated). With the answer I received, it solved that problem but presented another.

确保另一条记录不会已经包含与字段相同的值

我现在遇到的主要问题是创建新视图时.验证按预期进行.简而言之-系统需要检查ViewName和ViewPath(路由)是否都是唯一的,因此需要搜索数据库.

The main issue I now have is that when I create a new View. The validation works as expected. In brief - The system needs to check that the ViewName and ViewPath (route) are both unique so a search of the DB is required.

但是,当我编辑视图时,验证又开始了(实际上不应该因为显然是因为您正在编辑视图而已存在).

However, when I edit the view, the validation kicks in again (and it actually should not because obviously the view exists already because you are editing it).

我现在的问题是如何自定义远程验证,以使其在编辑和创建时都可以不同地工作.虽然我们不能编辑视图名称以匹配现有视图,但也不应仅仅因为它与当前视图相同而停止保存当前视图.

My issue now is how do I customise the remote validation to work differently for edit vs create. While we should not be able to edit the name of a view to match an existing view, we should also not be stopped from saving the current view simply because it is the same as the current view.

下面是我的模型(不是(希望)由工具生成的部分:-):

Below is my Model (the part that is not (hopefully) generated by a tool :-):

[MetadataType(typeof(IViewMetaData))]
public partial class View : IViewMetaData { }

public interface IViewMetaData
{
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")]
    [StringLength(50, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")]
    [Display(ResourceType = typeof(DALResources), Name = "ViewName")]
    [Remote("IsViewNameAvailable", "Validation")]
    string ViewName { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")]
    [StringLength(400, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")]
    [Display(ResourceType = typeof(DALResources), Name = "ViewPath")]
    [Remote("IsViewPathAvailable", "Validation")]
    string ViewPath { get; set; }

    [Display(ResourceType = typeof(DALResources), Name = "ViewContent")]
    string ViewContent { get; set; }
}

我遇到问题的部分是[远程]验证属性,该属性定义如下:

The part I am having a problem with is the [Remote] validation attribute which is defined below:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public class ValidationController : Controller
{
    private FRCMSV1Entities db = new FRCMSV1Entities();

    public JsonResult IsViewNameAvailable(View view)
    {
        bool isViewNameInvalid = db.View.Any(v => v.ViewName == view.ViewName && v.Id != view.Id);

        if (!isViewNameInvalid)
            return Json(true, JsonRequestBehavior.AllowGet);

        string suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewName);

        for (int i = 1; i < 100; i++)
        {
            string altViewName = view.ViewName + i.ToString();
            bool doesAltViewNameExist = db.View.Any(v => v.ViewName == altViewName);
            if (!doesAltViewNameExist)
            {
                suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewName, altViewName);
                break;
            }
        }
        return Json(suggestedViewName, JsonRequestBehavior.AllowGet);
    }

    public JsonResult IsViewPathAvailable(View view)
    {
        bool doesViewPathExist = db.View.Any(v => v.ViewPath == view.ViewPath && v.Id != view.Id);

        if (!doesViewPathExist)
            return Json(true, JsonRequestBehavior.AllowGet);

        string suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewPath);

        for (int i = 1; i < 100; i++)
        {
            string altViewPath = view.ViewPath + i.ToString();
            bool doesAltViewPathExist = db.View.Any(v => v.ViewPath == altViewPath);
            if (!doesAltViewPathExist)
            {
                suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewPath, altViewPath);
                break;
            }
        }
        return Json(suggestedViewPath, JsonRequestBehavior.AllowGet);
    }
}

问题是,验证需要在创建和编辑上都相同.它只需要对编辑进行额外的检查以确保我们仍在引用相同的记录,如果是这样,则因为没有错,所以无需显示验证消息.

The problem is, the validation needs to work the same on both create and edit. It just needs to do an additional check on edit to ensure we are still referring to the same record and if so, then there is no need to show the validation message because there is nothing wrong.

我的问题是: 1.如何使它按预期工作. 2.我可以看到这两种方法几乎相同,这违反了DRY原理.我如何才能使它更通用并简化它.但是,第一个问题确实是我想回答的问题,因为重构没有用的东西没有意义.

My question is: 1. How do I get this to work as expected. 2. I can see that both methods are pretty much identical, which violates the DRY principle. How can I make this more generic and simplify it. However the first question is really the one I would like answered because there is no point in refactoring something that doesn't work.

有关更多信息,以上代码也是以下链接中代码的

For more information, the above code is also an edit of the code at the following link:

https://msdn.microsoft.com/zh-cn/library/gg508808(VS.98).aspx

感谢您的帮助.

推荐答案

您需要添加参数以将模型的ID属性作为AdditionalFields传递.假设其int Id,然后

You need to add a parameter to pass the ID property of the model as AdditionalFields. Assuming its int Id, then

[Remote("IsViewPathAvailable", "Validation", AdditionalFields = "Id")]
public string ViewName { get; set; }

,方法应该是

public JsonResult IsViewNameAvailable(string viewName, int? id)

请注意,在Edit视图中,您为Id属性包括了一个隐藏的输入,因此其值将由jquery.validate远程功能回传.

Note that in the Edit view, you include a hidden input for the Id property, so its value will be posted back by the jquery.validate remote function.

然后您可以检查id参数是否为null(即它是新的)或具有值(已存在)并调整查询以适合.

You can then check if the id parameter is null (i.e. it's new) or has a value (it's existing) and adjust the queries to suit.

bool isViewNameInvalid;
if (id.HasValue)
{
    isViewNameInvalid = db.View.Any(v => v.ViewName == viewName && v.Id != id);
}
else
{
    isViewNameInvalid = db.View.Any(v => v.ViewName == ViewName);
}

当前发生的情况是Remote仅发布了ViewName属性的值,并且由于您的参数是模型,因此将使用默认的id值(0)进行初始化,而您的查询被翻译为Any(v => v.ViewName == viewName && v.Id != 0);

What is currently happening is that the Remote is only posting the value of the ViewName property, and because your parameter is the model, it is initialized with the default id value (0) and your query is translated to Any(v => v.ViewName == viewName && v.Id != 0);

我还建议您使用视图模型,而不是您的partial class

I also recommend using a view model rather that your partial class

侧面说明:从生成suggestedViewName的代码中,您期望许多具有相同值的ViewName,这意味着您可能在for循环内进行了许多数据库调用.您可以考虑使用linq .StartsWith()查询来获取所有以ViewName值开头的记录,然后检查循环中设置的内存.

Side note: from the code that generates suggestedViewName, your expecting a lot of ViewName with the same value, meaning your possibly making numerous database calls inside you for loop. You could consider using linq .StartsWith() query to get all the records that start with your ViewName value, and then check the in-memory set in your loop.

这篇关于C#MVC CMS-自定义远程验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆