[英]C# MVC CMS - Customising Remote Validation
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). 在下面的链接中,我问了一个有关如何确保字段不包含相同值的问题(例如,当字段上存在唯一约束时,正确约束C#时会导致抛出异常)。 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.
简而言之-系统需要检查ViewName和ViewPath(路由)是否都是唯一的,因此需要搜索数据库。
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: 我遇到问题的部分是[Remote]验证属性,该属性定义如下:
[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. 我的问题是:1.如何使它按预期工作。 2. I can see that both methods are pretty much identical, which violates the DRY principle.
2.我可以看到这两种方法几乎相同,这违反了DRY原理。 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 https://msdn.microsoft.com/zh-CN/library/gg508808(VS.98).aspx
Thanks for any help. 谢谢你的帮助。
You need to add a parameter to pass the ID property of the model as AdditionalFields
. 您需要添加一个参数以将模型的ID属性作为
AdditionalFields
传递。 Assuming its int Id
, then 假设其
int Id
,则
[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. 请注意,在“
Edit
视图中,您为Id
属性包括了一个隐藏的输入,因此其值将由jquery.validate远程函数发布回去。
You can then check if the id
parameter is null
(ie it's new) or has a value (it's existing) and adjust the queries to suit. 然后,您可以检查
id
参数是否为null
(即它是新的)或具有一个值(它是现有的),并调整查询以适合。
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);
当前正在发生的事情是,
Remote
仅发布ViewName
属性的值,并且由于您的参数是模型,因此将使用默认的id
值( 0
)对其进行初始化,并且您的查询将转换为Any(v => v.ViewName == viewName && v.Id != 0);
I also recommend using a view model rather that your partial class
我还建议使用视图模型,而不是
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. 附注:从生成的代码
suggestedViewName
,你的期望很高的ViewName
以相同的值,这意味着在你里面你可能使众多数据库调用for
循环。 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. 您可以考虑使用linq
.StartsWith()
查询来获取所有以ViewName
值开头的记录,然后检查循环中设置的内存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.