我一直在阅读DDD,我很困惑在使用像NHibernate这样的ORM时它会如何适应.
现在我有一个.NET MVC应用程序与相当"胖"的控制器,我正在试图弄清楚如何最好地解决这个问题.将此业务逻辑移动到模型层中是最好的方法,但我不确定如何做到这一点.
我的应用程序已设置好,以便NHibernate的会话由HttpModule管理(获取会话/事务),这是由返回实体对象的存储库使用的(Think S#arp arch ...结果是真的重复了一个很多他们的功能).这些存储库由DataServices使用,它现在只是存储库的包装(它们之间的一对一映射,例如UserDataService采用UserRepository,或实际上是存储库).这些DataServices现在只确保在保存/更新时检查装饰实体类的数据注释.
通过这种方式,我的实体实际上只是数据对象,但不包含任何真实的逻辑.虽然我可以在实体类中放置一些东西(例如"批准"方法),当该操作需要执行诸如发送电子邮件或触摸其他非相关对象之类的操作时,或者,例如,检查是否有任何用户在批准之前拥有相同的电子邮件等,那么实体将需要访问其他存储库等.用IoC注入这些用户不适用于NHibernate,所以你必须使用工厂模式我假设得到这些.我不知道你怎么会在测试中嘲笑那些.
因此,我认为,下一个最合乎逻辑的方法是,每个控制器基本上都有一个服务,并将当前控制器中正在完成的所有工作提取到每个服务的方法中.我认为这可以打破DDD的想法,因为逻辑现在不再包含在实际的模型对象中.
另一种观察方式我认为这些服务中的每一个都与它所使用的数据对象形成一个单一的模型(数据存储区域的分离和对其进行操作的逻辑),但我只是想看看其他什么正在使用像NHIB这样的ORM来解决DDD的"胖控制器"问题,它通过返回填充的数据对象和存储库模型来工作.
更新 我想我的问题是我如何看待这个:NHibernate似乎把业务对象(实体)放在堆栈的底部,然后存储库继续操作.服务器使用存储库,这些服务可以使用多个存储库和其他服务(电子邮件,文件访问)来执行操作.即:应用程序>服务>存储库> Business Objects
我正在阅读的纯DDD方法似乎反映了Active Record偏差,其中CRUD函数存在于业务对象中(我直接调用User.Delete而不是来自服务的Repository.Delete),以及实际的业务对象句柄在这种情况下需要完成的事情的逻辑(如通过电子邮件发送用户,删除属于用户的文件等).即应用程序>(服务)> Business Objects>存储库
使用NHibernate,看起来我会更好地使用NHibernate函数的第一种方法,并且我正在寻找对我的逻辑的确认.或者如果我感到困惑,可以对这种分层方法如何工作进行一些澄清.我的理解是,如果我有一个"批准"方法来更新用户模型,保留它,并且让我们说,给少数人发电子邮件,这个方法应该放在用户实体对象上,但允许适当的IoC,所以我可以注入messagingService,我需要在我的服务层而不是User对象上执行此操作.
从"多UI"的角度来看,这是有道理的,因为执行操作的逻辑是从我的UI层(MVC)中取出的,并放入这些服务中...但我实际上只是将逻辑分解为另一个类而不是直接在控制器中执行它,如果我不会涉及任何其他UI,那么我刚刚交换了一个"胖控制器"用于"胖服务",因为该服务实际上将封装每个控制器动作的方法来完成它的工作.
我注意到ASP.NET MVC的TextAreaFor HTML帮助程序中最烦人(可能)的错误.出于某种原因,HTML帮助程序会在textarea中的任何内容之前添加NewLine.显然,这是为了解决个人内容的可能问题,从有意的新线开始,浏览器按照规范忽略它.
然而,通过添加它,我得到了更多烦人的错误,现在我的所有textareas在表单加载任何内容之前自动有一个额外的行(即在我的字段中的任何内容之前显示:).在吐出之前,似乎某些东西正在编码"换行符".
任何人有一个解决方法吗?我希望打算输出它的预期行为
<textarea>
Stuff</textarea>
Run Code Online (Sandbox Code Playgroud)
不是
<textarea> Stuff</textarea>
Run Code Online (Sandbox Code Playgroud)
我越来越...
编辑 进一步检查,这似乎是由于我使用AntiXssLibrary进行编码而不是默认的HtmlEncoder.我使用的是4.0版,我的编码器类方法如下所示:
protected override void HtmlEncode(string value, TextWriter output)
{
output.Write(Microsoft.Security.Application.Encoder.HtmlEncode(value));
}
Run Code Online (Sandbox Code Playgroud)
所以我的想法是,因为从TextAreaHelper调用的TagBuilder类,HTML编码标签的内容,它是默认HTML编码器的行为,但AntiXssLibrary更彻底,因此你看到这种行为?
我有一个"更改密码"页面,需要在发送之前通过Javascript散列在页面上输入的任何密码.为了使它复杂化,页面通过jQuery load()调用加载,并由jQuery.Form ajaxForm()调用提交.如果一切都在MVC2中工作,但MVC3给我带来了麻烦.
也就是说,我有一个带有"更改密码"链接的页面,当点击它时,将更改密码页面加载到jQuery模式弹出窗口中,然后更改密码页面上的表单通过jQuery.Form库提交(基本上只是包装一个$ .ajax调用),并将其结果返回到模态相同的模态弹出窗口.
基本上,我有一个具有两个属性的模型,OldPassword和NewPassword.我有两个由视图生成的隐藏字段.它们保存了另外两个字段的散列值,PrehashOldPassword和PrehashNewPassword,并通过keyup事件得到更新(我知道,这意味着它在每个keyup上都做了一个完整的SHA256哈希......效率低下,但得到了测试的工作).这里的关键是需要在这些Prehash字段上执行正则表达式验证和必需的字段验证,这些字段仅存在于客户端(显然我不希望以任何方式将这些字段传输到服务器).
所以我手动创建这两个并将data-val-*属性添加到元素中,即它们不是由MVC助手等生成的.我猜这是我遗漏的东西.当表单提交所有字段为空时,应弹出所有错误,但表单仍然向前并提交.
==
所以我尝试过的事情:
是的,不显眼的库parse()方法已被调用来解析加载的AJAX表单内容,它似乎正确地获取所有数据验证内容,因为我看到错误显示为字段blur(),当我点击时提交(在ajax请求完成之前并替换弹出窗口的内容).
可能需要注意:在AJAX成功将更改密码页面加载到弹出窗口后,调用不显眼的库的解析方法... AJAX表单提交绑定放在document.ready的加载内容上,ergo,AJAX表单提交绑定可能是在解析方法可能绑定到提交事件的验证调用之前绑定并因此触发之前...
然而,(1)我在其他地方做同样的事情没有问题,唯一的区别是我手动将这些data-val-*属性放在我手动创建的元素上!并且(2),如果我在OldPassword或NewPassword字段上引起某种错误,即通过不向它们加载值而导致必需的字段验证错误,它们会显示错误,并成功停止通过jQuery.Form提交表单方法.
所以我觉得这里有些错误:
<input id="PrehashNewPassword" type="password" name="PrehashNewPassword" data-val-required="The password field is required." data-val-regex-pattern="<%= RegexHelper.PasswordRegularExpression %>" data-val-regex="<%= RegexHelper.PasswordRegularExpressionError %>" data-val="true" />
Run Code Online (Sandbox Code Playgroud)
我知道jquery.validate正在使规则正确,因为我看到了错误.当这些手动生成的元素出现错误时,它不会停止提交表单,除非我做这样的事情,并在表单的AJAX提交上添加预提交回调:
$("#ChangePasswordForm").ajaxForm({
beforeSubmit: function () { if (!$('#ChangePasswordForm').valid()) { return false; } },
target: '#overlay'
});
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但它有点难看,我相信它会导致验证被调用两次......不是很大,但不太理想.那么我是否需要在不引人注目的库中进行其他调用来绑定这些调用?