问题设置
我试图使用System.Linq.Dynamic.Core包在我的应用程序中实现验证规则,但我遇到了奇怪的行为。我的想法是有能力从应用程序本身创建和管理这些验证规则。因此,我的数据库中有一个ValidationRule
对象定义为:
public class ValidationRule {
public string Description { get; set; }
public string ErrorMessage { get; set; }
public short Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
public string NewExpression { get; set; }
public string OldExpression { get; set; }
}
NewExpression
和OldExpression
属性包含我想传递给Any()
的动态版本的表达式。ValidationRule
对象的唯一重要部分是Name
、ErrorMessage
、NewExpression
和OldExpression
,因此我将它们投影到DTO中:
public class ValidationRuleDto {
public string ErrorMessage { get; set; }
public string Name { get; set; }
public string NewExpression { get; set; }
public string OldExpression { get; set; }
}
然后将此DTO传递给ValidationRuleHandler
,以计算正在使用DTO的表达式验证的对象的旧实例和新实例。ValidationRuleHandler
看起来如下所示:
public static class ValidationRuleHandler {
private static readonly ParsingConfig _parsingConfig = new() {
AreContextKeywordsEnabled = false
};
public static ICollection<string> Validate(
dynamic oldObject,
dynamic newObject,
IEnumerable<ValidationRuleDto> rules) => rules.Select(
_ => {
var oldResult = new[] {
oldObject
}.AsQueryable().Any(_parsingConfig, _.OldExpression);
var newResult = new[] {
newObject
}.AsQueryable().Any(_parsingConfig, _.NewExpression);
Debug.WriteLine($"Old => {oldObject.StageText} => {_.OldExpression} => {oldResult}");
Debug.WriteLine($"New => {newObject.StageText} => {_.NewExpression} => {newResult}");
return !(oldResult && newResult)
? null
: $"[{_.Name}] {_.ErrorMessage}";
}).Where(
_ => _ != null).ToHashSet();
}
对于传递给Validate()
的旧对象和新对象,我将对象投影到一个旧快照(来自数据库)和新快照(从数据库,但应用了更改)DTO。在Validate()
中,我将每个对象添加到单个项集合中,并将它们转换为IQueryable
,以便使用动态Any()
。我在这里的思考过程是,规则的表达式只需计算为真/假结果,因为如果表达式的条件过了,Any()
返回true/false,这似乎是最合适的方法。
问题
我遇到的问题是,在运行该应用程序时,我所期望的结果不会发生。作为参考,该应用程序是一个ASP.NET MVC 5 (5.2.9)应用程序,用于获取.NET Framework4.8。但是,当使用LINQPad (5.46.00)测试ValidationRuleHandler
时,结果是正确的。例如,当应用程序处理适用于用户的三条验证规则时,Debug
语句的输出如下:
下面是完全相同的验证规则和快照对象(完全相同的值)的LINQPad结果:
正如您所看到的,当从ValidationRuleHandler
调用LINQPad时,它正确地计算表达式,但是当从应用程序处理时,这是错误的。
我搞不懂它为什么会这样。仔细想想,我看不出有什么问题,LINQPad的表现也和预期的一样,但应用程序没有问题,我也不知道还能做什么。如果有人有任何建议,我会很感激的。我也愿意接受其他的建议,以实现同样的目标,如果有人必须处理类似的事情以前。
发布于 2022-09-08 00:07:37
因此,经过几个小时的尝试,不同的解决方案,看看它到底在哪里失败,没有什么工作,直到我改变表达式使用Equals()
。在此之后立即生效,我不知道为什么这个:(StageText.Equals("Closed"))
;工作,而这个:(StageText == "Closed")
;不工作。
当我在LINQPad上测试它而不是在应用程序中测试它的时候,我仍然很困惑为什么最初的方法是有效的。@Stef也证实了它的作用,所以我很困惑。也许这与从数据库中提取快照值有关,还是与从数据库中提取验证规则表达式有关?
无论如何,它适用于Equals()
,所以我开始使用它。
发布于 2022-09-06 17:41:05
在创建.NET完整Framework4.8控制台应用程序时,使用以下示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
namespace ConsoleApp48DynamicLinq
{
public class ValidationRule
{
public string Description { get; set; }
public string ErrorMessage { get; set; }
public short Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
public string NewExpression { get; set; }
public string OldExpression { get; set; }
}
public class ValidationRuleDto
{
public string ErrorMessage { get; set; }
public string Name { get; set; }
public string NewExpression { get; set; }
public string OldExpression { get; set; }
}
public class Test
{
public string StageText { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
var old = new Test
{
StageText = "Not Sold"
};
var @new = new Test
{
StageText = "Closed"
};
var validation = new ValidationRuleDto
{
OldExpression = "(StageText != \"Closed\")",
NewExpression = "(StageText == \"Closed\")"
};
var validations = new[] { validation };
ValidationRuleHandler.Validate(old, @new, validations);
}
public static class ValidationRuleHandler
{
private static readonly ParsingConfig ParsingConfig = new ParsingConfig
{
AreContextKeywordsEnabled = false
};
public static ICollection<string> Validate(
dynamic oldObject,
dynamic newObject,
IEnumerable<ValidationRuleDto> rules) => rules.Select(
_ =>
{
var oldResult = new[]
{
oldObject
}.AsQueryable().Any(ParsingConfig, _.OldExpression);
var newResult = new[]
{
newObject
}.AsQueryable().Any(ParsingConfig, _.NewExpression);
Console.WriteLine($"Old => {oldObject.StageText} => {_.OldExpression} => {oldResult}");
Console.WriteLine($"New => {newObject.StageText} => {_.NewExpression} => {newResult}");
return !(oldResult && newResult) ? null : $"[{_.Name}] {_.ErrorMessage}";
}).Where(_ => _ != null).ToHashSet();
}
}
}
它似乎运转良好:
https://stackoverflow.com/questions/73603628
复制相似问题