请选择 进入手机版 | 继续访问电脑版
  • 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

asp.net mvc - C# MVC CMS - Customising Remote Validation

[复制链接]
菜鸟教程小白 发表于 2022-5-23 13:41:47 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

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.

Ensuring another record does not already contain the same value for a field

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.

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/en-us/library/gg508808(VS.98).aspx

Thanks for any help.



Best Answer-推荐答案


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; }

and the the method should be

public JsonResult IsViewNameAvailable(string viewName, int? id)

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.

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);
}

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);

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

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.

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝0

帖子79432

发布主题
推荐阅读 更多
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap