JsonFilter单元测试工作,但实际情况没有 - 内容类型出现错误 - 发生了什么?

时间:2010-02-17 15:41:05

标签: jquery asp.net-mvc mime-types

我使用了一些JsonFilter ActionResultAttribute,它使用newtonsoft.Json json转换器将请求中的json转换为真实对象。这看起来工作得很好一些基本参数,但不是更复杂的工作,所以我为它写了一个UT(是的,我应该TDD,但原型总是先来......)。

属性类方法:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
        if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
        {
            string inputContent;
            using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
            {
                inputContent = sr.ReadToEnd();
            }
            var result = JavaScriptConvert.DeserializeObject(inputContent, JsonDataType);
            filterContext.ActionParameters[Param] = result;
        }
}

现在进行单元测试(使用Rhino):

ActionExecutingContext aec = MockRepository.GenerateMock<ActionExecutingContext>();
HttpContextBase c = MockRepository.GenerateMock<HttpContextBase>();
HttpRequestBase r = MockRepository.GenerateMock<HttpRequestBase>();
aec.Stub(x => x.HttpContext).Return(c);
aec.Stub(x => x.ActionParameters).Return(new Dictionary<String, Object>());
c.Stub(x => x.Request).Return(r);
r.Stub(x => x.ContentType).Return("application/json");
r.Stub(x => x.InputStream).Return(new MemoryStream(new UTF8Encoding().GetBytes(lookupParams)));

JsonFilter f = new JsonFilter();
f.JsonDataType = typeof(LookupParameters);
f.Param = "TestParam";
f.OnActionExecuting(aec);

是的,它没有断言任何东西,但请放心,json按预期转换。现在为json字符串:

String lookupParams = "{\"FormID\":0,\"IDFieldID\":\"\",\"NameFieldID\":\"\",\"ReturnType\":\"html\",\"SearchText\":\"\",\"AdditionalParameters\":{\"CodeLevel\":1,\"Level1ID\":\"#AccountCodes_935ab17d-74f4-4f79-990f-07898bc98868 #Level1ID\",\"Level2ID\":\"#AccountCodes_935ab17d-74f4-4f79-990f-07898bc98868 #Level2ID\",\"Level3ID\":\"#AccountCodes_935ab17d-74f4-4f79-990f-07898bc98868 #Level3ID\"}}";

现在 - 我从网站本身和ContentType运行时已经介入此代码,ALWAYS似乎是“application / x-www-form-urlencoded”..即使是这种情况,对象(LookupParameters)在ActionResult中看到的代码本身仍然填充了正确的字段!那么在我的过滤器到达之前过滤它的东西是什么?它对我来说似乎是这样,因为对象正确地从json转换为真实对象,我的代码似乎永远不会被调用。这没关系,但其中一个属性(AdditionalParameters)是一个Dictionary并且始终为null。为了完整起见,这里是ActionResult代码:

[JsonFilter(Param = "lookupParams", JsonDataType = typeof(LookupParameters))]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Find(LookupParameters lookupParams)
{
    Dictionary<String, Object> addPrms = lookupParams.AdditionalParameters;
    ....

你也想要jQuery吗?这是:

    var json =
    {
        FormID: formId,
        IDFieldID: idField,
        NameFieldID: nameField,
        ReturnType: "html",
        SearchText: searchText,
        AdditionalParameters: adPrm // this is also a json format object
    };
    $.get(urlToAction,
        json,
        SomeFunctionIRun,
        "json");

3 个答案:

答案 0 :(得分:1)

你的过滤器中放置断点的位置是什么?你应该把它放在第一行:

if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))

然后必须对您的控制器操作进行修饰:

[ObjectFilter(Param="data", JsonDataType=typeof(JsonBag))] 

您的过滤器应该正在运行,但如果将contentType设置为“application / json”以外的任何内容,则过滤器中的代码将不会运行。它是在运行应用程序时停止在断点上,而不是在模拟/测试时停止吗?

答案 1 :(得分:1)

好的 - 所以我是d ** k但现在发现也许json序列化不是我想要的。让我快速展示一下这些改动:

jQuery - 而不是使用get / post,我们必须使用ajax来设置ContentType(我假设$ .post方法上的json数据类型对此进行了排序,但这是返回值! - DOH):

   $.ajax({
        url: url,
        type: "POST", // MUST BE POST
        dataType: 'json',
        data: JSON.stringify(json), // HUH?? if i dont stringify it, it's just a form format
        contentType: "application/json; charset=utf-8", // HAS TO BE application/json
        success: LoadEntityLookupDialog
    });

现在在服务器端,显然只是将我的行动设置为接受POST而我们就离开了。它显示的是post / get将尝试将请求中的数据转换为对象类型而不使用任何过滤器(甚至有用!),但是如果要在数据中发布json,则需要发送json字符串(实际上很有道理。)

这有更好的jquery方法吗?

答案 2 :(得分:1)

添加HttpContext.Request.InputStream.Position = 0;在你的使用声明之前...我花了大约30分钟来弄清楚为什么请求似乎是空白的。