Should my MVC controller really know about JSON?

后端 未结 7 1949
有刺的猬
有刺的猬 2021-01-30 14:51

The JsonResult class is a very useful way to return Json as an action to the client via AJAX.

public JsonResult JoinMailingList(string txtEmail)
{
        // ...         


        
7条回答
  •  有刺的猬
    2021-01-30 15:09

    I'm not too worried about returning JSon as I was before. The nature of AJAX seems to be such that the message you want to process in Javascript only applies for that AJAX situation. The AJAX need for performance just has to influence the code somehow. You probably wouldn't want to return the same data to a different client.

    Couple things regarding testing of JSonResult that I've noticed (and I still have yet to write any tests for my app) :

    1) when you return a JSonResult from your action method that is 'received' by your test method you still have access to the original Data object. This wasn't apparent to me at first (despite being somewhat obvious). Rob's answer above (or maybe below!) uses this fact to take the Data parameter and create a dictionary from it. If Data is of a known type then of course you can cast it to that type.

    Personally I've been only returning very very simple messages through AJAX, without any structure. I came up with an extension method which might be useful for testing if you just have a simple message constructed from an anonymous type. If you have more than one 'level' to your object - you're probably better off creating an actual class to represent the JSon object anyway, in which case you just cast jsonResult.Data to that type.

    Sample usage first :

    Action method:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult ContactUsForm(FormCollection formData){
    
         // process formData ...
    
         var result = new JsonResult()
         {
              Data = new { success = true, message = "Thank you " + firstName }
         };
    
         return result;
    }
    

    Unit test:

    var result = controller.ContactUsForm(formsData);
    if (result is JSonResult) {
    
         var json = result as JsonResult;
         bool success = json.GetProperty("success");
         string message = json.GetProperty("message");
    
         // validate message and success are as expected
    }
    

    You can then run assertions or whatever you want in your test. In addition the extension method will throw exceptions if the type is not as expected.

    Extension method:

    public static TSource GetProperty(this JsonResult json, string propertyName) 
    {
        if (propertyName == null) 
        {
            throw new ArgumentNullException("propertyName");
        }
    
        if (json.Data == null)
        {
            throw new ArgumentNullException("JsonResult.Data"); // what exception should this be?
        }
    
        // reflection time!
        var propertyInfo = json.Data.GetType().GetProperty(propertyName);
    
        if (propertyInfo == null) {
            throw new ArgumentException("The property '" + propertyName + "' does not exist on class '" + json.Data.GetType() + "'");
        }
    
        if (propertyInfo.PropertyType != typeof(TSource))
        {
            throw new ArgumentException("The property '" + propertyName + "' was found on class '" + json.Data.GetType() + "' but was not of expected type '" + typeof(TSource).ToString());
        }
    
        var reflectedValue = (TSource) propertyInfo.GetValue(json.Data, null);
        return reflectedValue;
    }
    

提交回复
热议问题