When to use JsonResult over ActionResult - c#

I've been unable to find a concrete answer regarding this question. I've viewed posts and subsequent posts from this question and elsewhere but all I've really come out of reading is that JsonResult has a hardcoded content type and there really isn't any performance gains.
If both results can return Json why would you need to use JsonResult over ActionResult.
public ActionResult()
{
return Json(foo)
}
public JsonResult()
{
return Json(bar)
}
Can anyone explain a scenario where ActionResult simply can't get the job done and JsonResult must be used. If not, why does JsonResult exist in the first place.

When to use JsonResult over ActionResult
I usually return concrete results (e.g. JsonResult, ViewResult) and there are my pros:
Controller's interface gives more information about it's behavior. It is easier to work with partial or shared views when you specify PartialViewResult and ViewResult as result type precisely.
It is easier to test since it is not needed to cast result to concrete types in your unit tests.
There are some links where people support this approach:
What's the difference between ActionResult and ViewResult for action method?
Must ASP.NET MVC Controller Methods Return ActionResult?
ViewResult vs ActionResult
There is a quote from Pro ASP.NET MVC 3 Framework:
Note Notice that that the return type for the action method in the
listing is ViewResult. The method would compile and work just as well
if we had specified the more general ActionResult type. In fact, some
MVC programmers will define the result of every action method as
ActionResult, even when they know it will always return a more
specific type. We have been particularly diligent in this practice in
the examples that follow to make it clear how you can use each result
type, but we tend to be more relaxed in real projects.
I would use ActionResult over concrete one only if an action should return different types of results. But it is not that common situation.
I'd like also to add that ActionResult is an abstract class so you cannot simply create an instance of this type and return it. JsonResult is concrete so you can create its instance and return from an action method. There are many other types that derived from ActionResult and basically all of them are used to override ExecuteResult method.
public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}
This method is invoked by ControllerActionInvoker and implements logic writing data to response object.
ControllerActionInvoker does not know about concrete results so that it can handle any result that is derived from ActionResult and implements ExecuteResult.
In both cases you return an instance of JsonResult type in your example and Json(model) it is simply a Factory Method that creates an instance of JsonResult.
There is another SO question Is it better to have a method's datatype be as specific as possible or more general? where best practices for method parameters and return values are discussed.
The general idea is providing abstract types as parameters so that your method can handle wider range of parameter; returning concrete enough types so that your clients do not need to cast or convert them.

You may have noticed that the names of all the common return types in an MVC controller end with "result", and more often than not, most actions return an ActionResult. If you look at the documentation, you can see that several, more specalized result types, inherit from the abstract class ActionResult. Because of this, you can now return an ActionResult in all of your actions, and even return different types. Example:
public ActionResult View(int id)
{
var result = _repository.Find(id);
if(result == null)
return HttpNotFound(); //HttpNotFoundResult, which inherits from HttpStatusCodeResult
return View(result); //ViewResult
}
All of this makes it easier to return different content, based on the request. So why would you use JsonResult over ActionResult? Perhaps so there are no misunderstandings, and you indeed only can return JSON, perhaps for readability, or some other personal preference.

It's just adhering simple Polymorphism principle.
By defining the method signature as returning an abstract ActionResult which is the base type for JsonResult, ViewResult, ContentResult (and others) you're given the ability to return any of the above types by letting the implementation of the action decide which ActionResult to return.
For example:
public ActionResult GetData(int id)
{
var data = .... // some data
if (Request.AcceptTypes.Contains("json"))
return Json(data);
else
return View(data);
}
It is actually a common practice in OOP to define the returned type of the method as abstract as possible. You can find it in .NET BCL as well, the IEnumerable<> usage in Linq for example:
public static IEnumerable<T> Where<T>
(
this IEnumerable<T> source,
Func<T, bool> predicate
);
The Where() method is declared as returning IEnumerable<T> so that you can call the method on any type that is implementing the IEnumerable<T> interface, be it an Array, List, HashSet or Dictionary.

Actually there is no reasons to use JsonResult as return type of Action methods.
In this case it is better to use abstract class ActionResult to follow polymorphic principles.
By calling return Json(value) you are actually calling helper method of Controller class which looks like:
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
};
}
As we can see - Json helper method it instantiate JsonResult anyway.

Related

c# HTTP Post IHttpActionResult

I have two httppost method one is taking an a concrete class with is working fine. The other one is taking in an interface. When I use postman I get null for the interface method.Should I be able to send a model class to an interface do I need to use custom model binder and if I do where do I need to add it?
public IHttpActionResult InsertData([FromBody] DataLog _datalog)
public IHttpActionResult Insert([ModelBinder(typeof(IDataLog))] IDataLog _log)
I think this would answer your question as well.
Interfaces
Reason why you cannot use interface as an object is because there are no public accessors for them. They also cannot have fields. It is just signature of the properties, and methods.
Interfaces
cannot have implementation
cannot have modifiers public
cannot have virtual
Classes
Each class you define have public properties that have getters and setters. Setters are what sets the values of these public properties. You can use the interfaces and extend them to classes and use these classes as objects to receive the data
Good read about defining and implementing interfaces
Custom Model Binding in ASP with examples
I donĀ“t know if i understand your question. Anyway regarding the code i must say:
Do not use '_' to named your variables, classes, parameters...it is not CLS compliant.
https://learn.microsoft.com/en-us/dotnet/api/system.clscompliantattribute?view=netframework-4.8
Maybe you can use the letter 'D' following the SOLID principle. D as Dependency Inversion using the IOC to Dependency Injection.
https://en.wikipedia.org/wiki/SOLIDhttps://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
In case that you have only one return type within your method, instead of using generic ActionResults types you can do something like, just to understand the logic:
Instead of:
public ActionResult Index()
{
return View();
}
Do this:
public ViewResult Index()
{
return View();
}
Difference Between ViewResult() and ActionResult()
Do Async await (TAP ) pattern.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
Instead of:
public IHttpActionResult InsertData([FromBody] DataLog _datalog)
Make the code to compile faster like this, adding the HttpPost attribute, even knowing this is a POST action:
Do this:
[HttpPost]
public IHttpActionResult InsertData([FromBody] DataLog _datalog)
Hope those good practices helps you somehow! :)

Why does MVC ignore controller methods in inherited controllers?

... which may not really be the question at all, but that's what it looks like to me right now.
I have a controller structure that has several layers of inheritance. The base controller is the one that implements Controller and has a method called Create(Guid var1, DateTime? var2) and is called like /MyDomain/Create/00000-0000-0000-000000.
I'm currently trying to implement a method in a controller lower down in the inheritance tree with the signature Create() which takes a QueryString parameter. (/MyDomain/Create?otherVar=somevalue) However, ASP.NET decides this is not valid as an "endpoint" and throws an error message saying The parameters dictionary contains a null entry for parameter 'var1' of non-nullable type 'System.Guid' for method 'System.Web.Mvc.ActionResult Create(System.Guid, System.Nullable`1[System.DateTime])'
I don't really know what is going on here. If I try to call another method on the same controller (with a name that is unique and not used higher up in the inheritance stack e.g. /MyDomain/DifferentMethod) it works without a problem.
My google-fu is coming up short on this problem.
So you have something like:
public abstract class BaseController{
[HttpGet]
public IActionResult Create(Guid var1, DateTime var2){..
}
and
public class SomeClassController : BaseController{
[HttpGet]
public IActionResult Create(){..
}
The problem is that you cannot have 2 routes with the same name and different signature.
This is because the routing don't know exactly where you want to go: with the url '/blalbalba/Create/' witch one you want?
The base class or the inherited once?
It's not so obvious.
Ps take a look on this answer:
ASP.NET MVC ambiguous action methods

IActionResult misunderstanding

I just downloaded music store (microsoft sample projct) source code that based on ASP.NET 5. I don't understand there why developers from Microsoft use IActionResult interface as a return type in controllers.
What is a reason of IActionResult interface usage? Why don't just use ActionResult type.
See this post about IActionResult vs. ActionResult: http://forums.asp.net/post/5980446.aspx
IActionResult allows a wider range of return types, including any custom code that implements the IActionResult interface. ActionResult is limited only to those classes which extend the ActionResult abstract class (which you could also do with custom code, but using an interface allows for something like multiple inheritance, while extending a class does not).
Using interfaces as parameters will allow you to use dependency injection to obtain its dependencies and those dependencies can be replaced with mock implementations when testing which implement those interfaces.
IActionResult has more return types than ActionResult. For ex: If you want to return HttpNotFound you have to use IActionResult return type.

MVC 3 Call Controller method directly but also invoke the ActionFilterAttribute?

How would you go about invoking the ActionFilterAttribute when you are calling a controllers method directly? Imagine the following:
public class ApiController : Controller {
public ActionResult CallSomething() {
return IsCalled();
}
[MyAction]
public ActionResult IsCalled() {
return View();
}
}
So the request comes into /Api/CallSomething, the CallSomething() method internally calls another method (in this case IsCalled()) but when that method is called the ActionFilterAttribute is invoked and runs.
At the moment the ActionFilterAttribute will only be invoked if it's part of the original request, which makes sense because then it's part of the whole MVC lifecycle and all I'm doing is just calling a method directly, I'd need to do a RedirectToAction if I wanted it to get fired by MVC. RedirectToAction alters the URL so this isn't suitable for my purposes.
I've poked about the System.Web.Mvc code but I can't see how or when its being invoked. I figure that if it can do it then so can I potentially using reflection. In this event the Views aren't relevant as I am override the ExecuteResult() to write my own content into the http response.
Anyway I've resigned myself to this maybe not being possible but I'd just thought it would be worth a try.
There is no practically correct way to achieve that. So don't attempt to do it. Controller actions shouldn't be calling themselves as in your example. Use a redirect in this case. Or have the client send the request directly to the second action if you don't want the redirect.
Oh and if you have some common functionality between those controller actions that you want to reuse, simply externalize this functionality into some other layer. There are many ways to provide common functionality in ASP.NET MVC 3 depending on the exact scenario.
The simplest way to do what you're talking about is just to factor out the functionality that you want to execute as a filter and ad-hoc. It doesn't make sense to force a filter to execute where it shouldn't be executing. But it might make sense to want to call some part of the filter ad-hoc. The simplest way to do this is with a plain old static method:
public class ApiController : Controller {
public ActionResult CallSomething() {
MyActionFilter.CommonStaticMethodThatIsAlsoUsedInTheNormalFilter();
return IsCalled();
}
[MyActionFilter]
public ActionResult IsCalled() {
return View();
}
}
You should be more specific about what you're trying to achieve, there might be other features of the framework that are a better fit.

Can I retrieve a ViewModel from an ActionResult?

Trying to avoid repetition here. I have an action in a base class controller which I am not allowed to modify. I'd like my action to do some checks, call the base class action, and modify the result in some way before rendering. But part of what I need to do involves modifying some properties of the ViewModel, and the base class returns an ActionResult. I see no way to get the ViewModel from the ActionResult, and so I may have to write a custom method, most of which would just mimic what the base class is doing. I'd strongly prefer not to do this. Any suggestions?
That's because ActionResult is a fairly high-level base class. Try casting it to the appropriate subtype, such as ViewResult.
Quick sample code:
public ActionResult WrapperAction()
{
// do your initial stuff
// call your base controller action and cast the result
// it would be safer to test for various result types and handle accordingly
ViewResult result = (ViewResult)base.SomeAction();
object model = result.ViewData.Model;
// do something with the model
return result;
}

Categories