如何编写优雅的验证方法
本文关键字:验证 方法 何编写 | 更新日期: 2023-09-27 18:26:53
我有Notifications
,它可以被Employee
标记为已读
其工作原理如下:
- 用户/员工打开通知(网页)
- 用户点击"标记为已读"
- 用户必须插入他的EmployeeNumber并单击"确认"
- 如果出现错误,用户将获得反馈
在我的示例中,我必须验证输入EmployeeNumber的Employee
是否存在于我的数据库中,如果存在,则加载该条目。
我需要在多个地方进行验证,所以我想我可以将其提取到D.R.Y.的方法中
员工服务:
public class EmployeeService : BaseService
{
public static Employee VerifyEmployeeNumber(ISession session, string employeeNumber)
{
if (employeeNumber.IsNullOrWhitespace())
throw new ArgumentNullException();
Employee employee = session.Query<Employee>().FirstOrDefault(x => x.Number == employeeNumber);
if (employee == null)
throw new ArgumentException();
return employee;
}
}
通知服务
public class NotificationService : BaseService
{
public string SetNotificationAsRead(long notificationId, string employeeNumber)
{
Employee employee;
try
{
employee = EmployeeService.VerifyEmployeeNumber(Session, employeeNumber);
}
catch (ArgumentNullException)
{
return "No Employeenumber was entered";
}
catch (ArgumentException)
{
return "No Employee exists with this number";
}
//Update my notification as read
return null;
}
}
通知控制器:
public JsonResult MarkAsRead(long notificationId, string employeeNumber)
{
string errormessage = NotificationService.SetNotificationAsRead(notificationId, employeeNumber);
if (errormessage.IsNotNullOrWhitespace())
return Error(errormessage);
return Success();
}
JSON在前端进行解析。
问题:
我还需要在其他服务(如BarcodeService
)中验证我的EmployeeNumber。我还必须显示相同的错误
因此,我必须再次编写try-catch
并对错误消息进行硬编码。
这看起来既笨拙又可怕。
我如何才能以更好的方式实现这一点
我似乎需要一种方法,可以返回错误或员工,这在c#中是不可能的
提前谢谢。
广告信息:
- 不需要通用验证
- @我Stanley-我可以将消息放入Employeeclass中,但如果我只在一个地方需要它们,我认为将它们硬编码到验证方法中也不算太糟
- 我认为最大的问题是如何将错误消息从Businesslogic(Services)发送到用户(Controllers->JSON->Webpage)
可能的改进1:
我只考虑验证该员工是否与我的VerifyEmployeeNumber
一起存在,并且如果没有返回错误,则从DB加载该员工。这有2个DB访问的缺点。
这里的问题是优雅在很大程度上是一种主观特征。我可以提出一些可能有助于更好地封装代码并防止重复行的建议,但我的建议可能会让下一个人感到厌恶。
你似乎在问两个不同的问题,或者至少是一个可以分为两部分的问题:
- 如何处理错误消息,这样就不会每次都对其进行硬编码
- 如何处理您的验证方法,这样您就不会每次都重复您的try/catch块
为了它忽略了对整体设计方法的任何怀疑。。。
错误消息位至少很容易清理——使错误字符串成为错误类的一部分或类本身的一部分。例如,你可以做:
public class Employee : BaseClass
{
...
//Error Messages for Employee checks
public static string ErrorNotFound = "No Employee exists with this number";
public static string ErrorInvalid = "Invalid Employee Number";
...
}
然后,您可以通过执行Employee.ErrorNotFound
来调用该字符串,而不是每次都写出它。
或者,您可以创建一个类/结构,保存所有名为ErrorMsg或其他的错误消息,并调用ErrorMsg.EmployeeNotFound
。这本身比硬编码的字符串更整洁,但在第二节中,进一步的优势将变得清晰。
现在,尝试/捕捉的东西。如果你打算坚持使用异常(请参阅下面的注释),那么根据你想要的通用性,只需重复你对EmployeeService所做的操作,并创建一个封装try/catch的方法。没有理由不将其作为EmployeeService中的一个功能,因为这就是该服务始终提供的功能,对吧?该员工是否存在或输入是否有效。
如果你想让它变得有趣,并且有一个函数可以处理所有验证,无论是员工还是其他形式的验证,你可以试着玩Delegate,创建一个函数,它将调用正确的验证函数,然后输出相关的错误消息。我不会详细介绍,因为有数百种方法可以正确地做到这一点,我不知道你的系统有多复杂。如果你唯一需要验证的是EmployeeNumber,那么可能没有理由创建一个通用的验证处理程序函数。
有几件事需要注意:
1) 你对例外的使用充其量是有争议的。您将看到的大多数指导原则(例如MSDN)强烈建议使用异常来捕获意外行为,而不是作为流控制的标准形式。在这些函数中,您可以有效地将它们用作返回值——在正常使用过程中,这些异常很可能会重复出现。返回NULL
或一些"未找到员工"对象要好得多,然后可以通过标准流控制进行处理。
这样做的好处是:a)你不必有那么多try/catch语句,b)它标准化了你必须检查的内容,看看你是否找到了员工——如果它不是NULL,那就太好了,你找到了一个。我不需要去查看抛出了什么样的异常。
2) 是否有必要区分"没有员工使用此号码"answers"没有输入员工号码"?两者都是一回事。如果您只使用一条包含"找不到此号码的员工"或类似内容的错误消息。如果设置为具有不同的错误消息,请通过引用将字符串传递到函数中,并在出现错误时填充该字符串,然后在函数返回NULL时打印错误消息的字符串内容。
很可能每个回答这个问题的人都会根据他们的深度和关注的部分来选择不同的东西(我可能错过了一些设计方面,这很可能会使我提出的任何建议都无效!)。这取决于你考虑你想采纳哪条建议。
我不知道你将如何选择"正确"的答案。。。
我认为您的Employee VerifyEmployeeNumber(ISession session, string employeeNumber)
方法设计有问题。通过验证一个实体并返回它,可以混合使用命令和查询。这就是为什么分离会出现问题。
我宁愿查询员工,然后用另一种方法验证他。请注意,您正在尝试SetNotificationAsRead
,但另外还需要查询员工并验证值。这是糟糕设计的证据。
最好只是:
public JsonResult MarkAsRead(long notificationId, string employeeNumber)
{
var employee = _session.Query<Employee>().FirstOrDefault(x => x.Number == employeeNumber);
var error = EmployeeService.VerifyEmployee(_session, employee);
if (errormessage.IsNotNullOrWhitespace())
return Error(errormessage);
NotificationService.SetNotificationAsRead(notificationId, employee);
return Success();
}
这只是一个概念,但你应该有一个想法。