JsonResult from MVC Controller - asp.net-mvc-4

We're having some discussion in our team that all the methods which are returning JsonResult should be moved to WebApi 'controllers' so that there is a clean segregation.
I'm not too sure about that. Is it wrong for a MVC controller to return ActionResults as well as JsonResults?

In our projects, we indeed move the actions for ajax request to a partial controller called "ScriptController" or "WebApiControler".
I think it is good to maintain, codes also seem to clear.

Related

ASP.NET Core Web API split controller based on aggregates

In my API project I have currently 1 controller with the following syntax:
Abstract base controller
[Produces("application/json")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status406NotAcceptable)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public abstract class BaseApiController : ControllerBase
{
// ....
}
TestApiController
public class TestApiController : BaseApiController
{
// Parent action methods
[HttpGet]
[HttpPost]
...
// Child action methods
[HttpGet("{test:guid}/child")]
[HttpGet("{test:guid}/child/{id:guid}")]
...
}
This gives us the following urls:
http://localhost/api/v1.0/test
http://localhost/api/v1.0/test/1
http://localhost/api/v1.0/test/1/child
http://localhost/api/v1.0/test/1/child/1
Question
How can I split the controller into multiple files without braking the urls but to have a cleaner overview.
So a controller for all the test actions and another controller for all the child actions.
I'm not talking from an abundance of experience with controllers here (I have done some), but I think you'll find that the controller is the controller - in that there's no easy way to have a controller-route that isn't 1:1.
But, if you want to make controllers more manageable you could just keep them as lean as possible and put the bulk of code into classes that the controller calls.
Alternatively, rather than trying to split/decompose the controller and not the route, rework the overall API design/structure so that you have more controllers and routes. The Interface Segregation Principle comes to mind here (yes it's born out of OO but the principle is still applicable).
At the end of the day, you have calls coming into to API's defined by their routes, and off to the controllers - it doesn't really matter how that all looks (is structured) as long as the API is sufficiently sensible, intuitive and fit for purpose.
After some more searching on the internet I came across the following interesting Nuget package:
Nuget: Ardalis.ApiEndpoints.
Source code and examples about this can be found here:
Github: Ardalis.ApiEndpoints.
This allows us to separate controller into folders and for each action a separated class to give use exactly what we want.

Controller and JsonResult asp.net core

Why do i need to inherit from Controller to return JsonResult?
What is the mechanism that makes the JsonResult type available?
I've tried thinking on it and I figure maybe Controller declares it as a type, but I don't know.
You will need to inherit from Controller in order to use the Controller.Json utility method. You will however not need to inherit from Controller just to create a JsonResult. You can always just new-up one. As long as you are within a controller (not necessarily one that inherits Controller), this will still work:
return new JsonResult(object);
As for why you will need to inherit from Controller and not just ControllerBase; many of the result utility methods actually live in Controller. The reason for this is that those are targeted to view-centric controllers while ControllerBase is typically used for API controllers.
Now one would think that returning JSON results would be especially useful for API controllers but that is actually not the case: For API controllers, you should rather return an ObjectResult and have the conventions take care of serializing that into the format that was requested by the client. That way, an API controller can easily support formats like JSON and XML at the same time.

When to use AuthorizeFilter in ASP.NET Core

I've started looking into ASP.NET core, in particular Authorization. The model's changed quite a bit and I must say I'm finding it a little confusing compared to the last implementation.
I've seen various posts lamenting that it's now not possible to pass parameters to the Authorization attribute constructor and that instead we now have Policy/Requirement/Handler.
So what exactly is the user case for AuthorizeFilter? How does it differ from AuthorizeAttribute? When should I implement Requirement/Handler and when (or should I ever) implement an AuthorizeFilter (which looks like it might work closer to the old model)?
I couldn't find any resources online that detailed this particular aspect so any enlightenment is greatly appreciated.
The Documentation above the class of AuthorizeFilter says:
MVC recognizes the <see cref="T:Microsoft.AspNetCore.Authorization.AuthorizeAttribute" />
and adds an instance of this filter to the associated action or controller.
So when a controller is created an instance of the AuthorizeFilter is added to the controllers filters when a AuthorizeAttribute is present.
Basically they split the decoration: AuthorizeAttribute from the implementation: AuthorizeFilter.
So if you want clean code you can use AuthorizeAttribute to decorate your controller class.
if you want more understandable/logical code you can add te AuthorizeFilter to the filters in the Controller Constructor method.

Can asp.net mvc controller methods be considered restful?

If I perform all my operations (add item to cart, check out etc) by calls to controller methods that return JSON to my knockout.js presentation layer, can my application be considered restful?
Not really. There is nothing available to respond to HTTP verbs other than GET and POST. If you want you can use an ApiController class This is designed as a restful controller.

How does ASP.Net MVC resolve controllers?

I'm trying to build an asp.net mvc 4 application.
I want the application to encompass both a HTML site and a restful api, e.g.
www.mysite.com/MyDetails/
www.mysiste.com/api/users/{userid}/Details/
In the above example I would use 2 controller classes.
MyDetailsController which inherits from System.Web.Mvc.Controller
DetailsController which inherits from System.Web.Http.ApiController
I've also added a simple 'Users Route' to the WebApiConfig:
routeTemplate: "api/users/{userid}/{controller}/{id}
In my early testing it appears as though the following scenarios are invalid:
www.mysite.com/api/users/12345/MyDetails/
www.mysite.com/Details/
Both of those return a 404.
This is definitely a good thing but what I'm trying to find out is why doesn't it work?
Can I rely on it not working or is it just coincidence in my simple test?
I've read about people struggling to develop a single MVC app/project that encompasses both HTML and REST apis but the most common complaint seems to be you can't duplicate controller names and it still seems like you can't simply use a namespace to differentiate them.
In this example I've deliberately designed the class names to avoid any conflict so what other gotchas are waiting to trip me up?
Thanks,
Chris A
Check your routes file, should be Global.asax under RegisterRoutes. The MapRoute call should tell you everything you need to know for MVC routing. Keep in mind, the order of the routes is important: top routes take priority over the bottom. Web API uses the WebApiConfig class and MapHttpRoute call to configure routes.
Please ensure you have put a (MVC) route on top of the action you wish to hit of your controller, default action being index.
[System.Web.Mvc.Route("Help")]
public ActionResult Index()
{
ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
return View(Configuration.Services.GetApiExplorer().ApiDescriptions);
}
Code above will hit this action method (provided your controller is registered and derived either from apiController or Controller) in the following way:
http://localhost:54541/help inside your IISExpress.
To register please do the following:
In "global.asax.cs", you’ll need to add:
AreaRegistration.RegisterAllAreas();