views:

153

answers:

2

Is it possible for a controller method to return a view if called restfully and if called, via JavaScript, would return a JsonResult. My motivation is that I want to have the freedom to implement my view however I want to do this WITHOUT having to create two controller methods (one for each separate scenario...see elaboration below).

If let's say I type in www.example.com/person/get?id=232 in the browser, I would want the Get(int id) method to do something like the following:

    
        public ActionResult Get(int id)
        {
             Person somePerson = _repository.GetPerson(id);
             ViewData.Add("Person", somePerson);
             return View("Get");
        }
    

But if let's say this same controller method is called via jQuery:

    
        //controller method called asynchronously via jQuery
        function GetPerson(id){
            $.getJSON(
                "www.example.com/person/get", //url
                { id: 232 }, //parameters
                function(data)
                { 
                    alert(data.FirstName); 
                }   //function to call OnComplete
            );
        }
    

I would want it to act like the following:

    
        public JsonResult Get(int id)
        {
            Person somePerson = _repository.GetPerson(id);
            return Json(somePerson);
        }
    
+4  A: 

I figured it out. In the particular scenario above, I can do:

    
        if(Request.IsAjaxRequest())
        {
            return Json(someObject);
        }
        else
        {
            ViewData.Add("SomeObject", someObject);
            return View("Get");
        }
    

I can now start working on a more "elegant" solution to this problem....>_<

Amir
It is better to use the IsAjax attribute in my answer so that you can use the same functionality in another Action Methods
Marwan Aouida
I plan to encapsulate the boolean test in a strategy pattern that takes in my ViewData object as a parameter. In the strategy class's implementation, I'll check Request.IsAjaxRequest() and return either a View or Json. I'll get the resusability of the class and it saves me from writing an additional method for the Json approach. The logic to retrieve from teh repository is shared between the two methods, and I don't want to duplicate that (of course). I'll play around with it and let you know.
Amir
+3  A: 

You can do this using the ActionMethodSelector Attribute.
First Create your attribute like this:

 public class IsAjaxRequest :ActionMethodSelectorAttribute
    {
       public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
       {
           return controllerContext.HttpContext.Request.IsAjaxRequest();
       }

    }

Then use it:

 public ActionResult Get( int id )
 {
          Person somePerson = _repository.GetPerson(id);
          ViewData.Add("Person", somePerson);
          return View("Get");
 }


 [IsAjaxRequest]
 [ActionName("Get")]
 public ActionResult Get_Ajax( int id )
 {
         Person somePerson = _repository.GetPerson(id);
         return Json(somePerson);

 }
Marwan Aouida
That's good to Marwan, thanks. I will probably do something along the lines of: return _viewStrategy.Resolve(Request, someObject);
Amir