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.
Related
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.
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.
We're using a third-party authentication mechanism (CAS, via the .NET CAS Client). As part of this, we need to extract some data about the logged in user.
We have achieved this by accessing the HttpApplication.User instance from Global.asax (a DotNetCasClient.Security.CasPrincipal in our scenario). However, we need it to work from a controller.
The problem is that from a controller we have access to Controller.User, the instance of which is a plain old System.Web.Security.RolePrincipal, which is not what we need.
So:
Why are these instances not the same?
Is it possible to get the HttpApplication.User from within a controller?
I know there has got to be a better way to do this -- but in the meantime, I would suggest using HttpContext.Current.Items["YourKey"] and then accessing the Context.Item in your controller.
See HttpContext.Items in MSDN for more information.
Have you tried to inherit from Controller and override OnAuthorization?
protected override void OnAuthorization(AuthorizationContext filterContext)
{
filterContext.HttpContext.ApplicationInstance.User // CasPrincipal ???
......
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();
The Problem
I have a class which calculates the path a user took using CoreLocation and and array of arrays containing the coordinates of each point (taken when the users location changes). This class method is being called by my View Controller, but I want to set it's delegate to another class which will store the result in Core Data or upload it to a database. I can return the array to the View Controller by using:
PathFinder.delegate = self
Then make my View Controller implement my delegate protocol, but this isn't what I want.
What I've Considered
I've thought about making the class which uploads the data to the database/stores it in Core Data a singleton class so that I can easily access it from my View Controller. E.g.
PathFinder.delegate = <MY SINGLETON CLASS>
Conclusion
What would be the best way to do this? Would it be bad practice to put the code to upload the array to my server in the PathFinder class? Any help would be appreciated.
I have something like this - a singleton class that manages a Core Data repository for images (some in the repository, some on the file system but a URL in the entity).
Why not have a singleton class that all objects that need the services import? That way, you tell some object to do something, when that works is done they tell the repository to save it. You can use a delegate protocol to know if it succeeded or not, but just decouple the saving of it from driving the process and knowing the outcome.