JsonResult类是一种非常有用的方法,可以通过AJAX将Json作为动作返回给客户端.
public JsonResult JoinMailingList(string txtEmail) { // ... return new JsonResult() { Data = new { foo = "123", success = true } }; }
然而(至少根据我的第一印象)这真的不是一个很好的分离关注点.
单元测试方法更难写,因为它们没有很好的强类型数据来测试,必须知道如何解释Json.
未来的其他一些View更难以通过HTTP(或任何涉及序列化的远程协议)被"插入",因为在这种情况下,它不需要序列化和反序列化响应.
如果您有两个不同的地方需要该行动的结果怎么办?一个人想要Json,另一个人想要XML或者完全或部分渲染的视图.
我想知道为什么对象和Json之间的转换没有通过属性以声明方式实现.在下面的代码中,您基本上告诉MVC this method is convertible to Json
,然后如果从AJAX客户端调用它,则检查new JsonResult()
内部执行转换的属性.
单元测试可以只采取动作结果(ObjectActionResult
)并拉出强类型Foo
.
[JsonConvertible] public ActionResult JoinMailingList(string txtEmail) { // ... return new ObjectActionResult() { Data = new Foo(123, true) }; }
我只是好奇人们的想法和任何可供选择的模式.
这些也只是我最初的观察 - 可能还有更多理由说明为什么这不是一个理想的设计(可能还有很多理由为什么它是一个完全可以接受和实用的设计!)我今晚只是感觉理论和魔鬼 - 拥护者.
*免责声明:我甚至没有开始考虑如何实施属性或者它可能具有哪些副作用或重复性等.
我觉得你无所事事.那么如果控制器在其公共接口中知道JSON呢?
曾经有人告诉我:"让你的代码变得通用,不要让你的应用程序通用."
你在这里写一个应用程序控制器.应用程序控制器是可以的 - 它的职责是在模型和视图之间进行缓解并调用模型中的更改 - 以了解某个视图(JSON,HTML,PList,XML,YAML).
在我自己的项目中,我通常有类似的东西:
interface IFormatter { ActionResult Format(object o); } class HtmlFormatter : IFormatter { // ... } class JsonFormatter : IFormatter { // ... } class PlistFormatter : IFormatter { // ... } class XmlFormatter : IFormatter { // ... }
基本上是"格式化程序",它接受对象并为它们提供不同的表示.HtmlFormatter
如果对象实现,s甚至足够智能输出表IEnumerable
.
现在,返回数据的控制器(或者可以使用HtmlFormatter
s 生成网站部分的控制器)采用"格式"参数:
public ActionResult JoinMailingList(string txtEmail, string format) { // ... return Formatter.For(format).Format( new { foo = "123", success = true } ); }
您可以为单元测试添加"对象"格式化程序:
class ObjectFormatter : IFormatter { ActionResult Format(object o) { return new ObjectActionResult() { Data = o }; } }
使用此方法,您的任何查询/操作/过程/ ajax调用,无论您想要调用它们,都可以以各种格式输出.
我一般不要担心它.Asp.Net MVC足以解决问题,将泄漏降至最低.你是对的; 测试时有一点障碍.
这是我使用的测试助手,它运行良好:
protected static DictionaryGetJsonProps(JsonResult result) { var properties = new Dictionary (); if (result != null && result.Data != null) { object o = result.Data; foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(o)) properties.Add(prop.Name, prop.GetValue(o) as string); } return properties; }
您可以使用Request.IsAjaxRequest()扩展方法返回不同的ActionResult类型:
if (this.Request != null && this.Request.IsAjaxRequest()) return Json(new { Message = "Success" }); else return RedirectToAction("Some Action");
注意:您需要Request!= null才能破坏您的测试.