As far as I understand the ApiController is for performing CRUD on resources.. But I have a case where I am just calling some Helper method (Restoring a DB on a SQL server) and so I am not sure if ApiController makes sense ?
Should I only use ApiController when I am performing CRUD on something ? Or should I use ApiController for anything that does not return a view ? Is 'post' the correct HTTP verb to use ? Am I going about this all wrong ?
Id like to get it clear in my head when to use one over the other.
[HttpPost]
public JsonResult RestoreBaselineDB()
{
//Get values from web.config
string sqlServer = ConfigurationManager.AppSettings["DBTools_sqlServer"];
string backupFilePath = ConfigurationManager.AppSettings["DBTools_backupFilePath"];
string destinationDatabaseName = ConfigurationManager.AppSettings["DBTools_destinationDatabaseName"];
DatabaseHelper.RestoreDatabase(sqlServer,
backupFilePath,
destinationDatabaseName,
"c:\\temp",
"ProcessManager",
"ProcessManager_log");
return Json(new
{
Status = "OK",
}, JsonRequestBehavior.AllowGet);
}
Controller is the base class for MVC, and ApiController for web api, which can be intermixed but should have clear, distinct purposes. I would use ApiController if you intend to create a restful web service, and Controller for your web application's user interface. I wouldn't necessarily intermix the two, based on the function you are creating.
For instance, if you are creating a REST service for an API your are exposing to the world or your application, keep everything contained in a web api set of APIControllers. But consider using a Controller for returning JSON to a view in a utility scenario.
This is, of course, subjective and likely to have differing opinions.
As #Brian Mains recommends, in your situation, you should use an ApiController because, as you say, it does not return a view. Controller should be used for your UI.
The answer to your question about is ApiController just for CRUD takes you dangerously close to the REST flame wars.
A pure REST approach to this would be to think of your restore database operation as creating a DatabaseRestoreRequest resource (and therefore should be a POST).
POST <Host>/Api/DatabaseRestoreRequest
Since the restore is probably a lengthy operation (especially for large databases), the body of the POST response would represent a resource with a unique identifier and a status that could be one of
InProgress
Failed
Complete
Having done a POST to initiate the restore (status would be InProgress), you would then make a GET request, providing the unique identifier. The GET response would give the updated status. You could call GET repeatedly until the response had a status of Complete.
GET <Host>/Api/DatabaseRestoreRequest/<requestID>
You may also have a DELETE operation, which could cancel the restore operation.
DELETE <Host>/Api/DatabaseRestoreRequest/<requestID>
If this seems over complicated and unnatural to you, you could just use a pattern like that used by the Windows Azure management API (and others). This uses a URI scheme that indicates a resource in the main URI and then the operation as a query string parameter
For example, to re-image a virtual machine you would do a POST to
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deploymentslots/<deployment-slot>/roleinstances/<role-instance-name>?comp=reimage
In your case it could be something like
POST <Host>/Api/Database?comp=restore
POST is traditionally used for this kind of operation because they are often non-idempotent. Idempotent means that if you repeat it several times it has the same effect as if you do it just once). PUT is supposed to be idempotent. POST does not have to be. This comes from the W3C:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
REST purists might decide to flame and downvote me for suggesting the second option. But hey...
Related
If I have 2 controller actions:
[HttpGet]
public ActionResult Login()
{
//...
return View();
}
and
[HttpPost]
public ActionResult Login(FormCollection values)
{
//...
return RedirectToAction("Index","Home");
}
It seems that the Post decoration is required for this to work (which makes sense), but the HttpGet decoration is entirely optional. It works fine with or without. It seems that MVC defaults controller actions to HttpGet unless otherwise specified.
I'll have to decided if I want a future reader of my code to have to figure that out on my own or not, or whether I want to have to remember to add HttpGet everywhere for consistency. But my question is not about whether it is a good practice to include the explicit decoration even though it is defaulted that way already.
My question is: is it ALWAYS the case that I don't need to decorate controller methods with HttpGet? Is there some way that this can bite me if I do or do not explicitly specify? I've searched on this a but and all I can find is posts describing why you might want to use both annotations rather than the reason for/against including the HttpGet specifically.
You don't have to specify this explicitly, no. However, please note:
Not specifying the verb on an action will mean that the method accepts both GET and POST. If there are two actions, however, the one labelled POST will be used for POST and the other will default for GETs.
Applying HttpGet will mean an action accepts only GET requests.
Labelling actions as GET can make it more obvious to other developers what your intention is.
Is there some way that this can bite me if I do or do not explicitly specify?
Not very likely. I could imagine a situation where something might be showing some strange behaviour or not working as expected because of it, but it'd be rare.
Is there some way that this can bite me if I do or do not explicitly specify?
Here I want to develop an answer of Rowan Freeman about the consequences of not using [HttpGet] explicitly for every GET method.
As it was already mentioned, a method without [HttpGet] annotation will accept both GET and POST request (unless there is another method with same name that is annotated with [HttpPost]). If a method is explicitly annotated with [HttpGet], 405 Method Not Allowed will be returned.
One consequence that I could imagine is that if an attacker wanted to send big amount of data through GET request, it would have a limit. Without [HttpGet] annotation, this limit is not a problem, because an attacker can switch to POST and do the same without any limit.
Another similar case is that:
HTTPGet can carry only string data whereas HTTPPost can carry both string and binary data.
Yet another thing is that POST requests will probably not entirely be logged on a server, therefore an attacker can somehow hide it's activity from an administrator as attackers payloads won't be visible (body won't be present in logs).
A comparison between POST and GET (which I cited from) can be found here:
ASP.NET MVC 5 – HTTPGET And HTTPPOST Method With Example
Of course, all of these cases are pretty rare, but this is what exploiting is about - finding rare things that can turn out to be a vulnerability.
To conclude, it is a good habit to always write [HttpGet] annotation in controller methods. It is just a one line that can improve security of your web application.
I'm building my first API and I'm wondering what the best approach here is. I have an object with a boolean fiels "isArchived". When the user clicks "Archive" on the object, I'd like to flip this boolean. My question: Can I just call something like:
PUT /api/objects/archive/1
which would hit a controller with logic like this:
[ActionName("archive")]
public HttpResponseMessage ArchiveObject(int id)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
_service.ArchiveObject(id);
return Request.CreateResponse(HttpStatusCode.OK);
}
or is it better to PATCH via something like this:
PATCH /api/objects/1
and then send some data in the body like
{isArchived: true}
It seems like the latter is more expensive since we're sending data instead of just an id. What's best, and why?
What is RESTful is the basically the question here.
If you want really deep fun explanation I strongly suggest that you check this epic and famous REST "article": How I Explained REST to My Wife
So back you your concrete question. In the spirit of the REST you should create a proper "resource". In your case that means the "archive object" resource. And you just apply the HTTP verbs against it. This is in essence a RESTful service.
If you try like you are trying to give an action a name, you are probably on the wrong path.
So what to do? Create "archive object" WebAPI controller and then, I presume, depends weather the function is idempotent user the proper HTTP verb. POST for create, PUT for update scenario (idempotent function). Do not forget to return in POST (create) scenario the new resource URI. But as far as I can see form your code you are up to the PUT scenario. Since you are able (I presume) to archive object many times.
How to sent additional data (in your case {isArchived: true}) to the API? Simpy, just put those kind of data into the body of the request. That's why we have the body message in HTTP requests.
So, your PUT URI should look like:
PUT /api/objects/achive/1
So that mean that you have object controller as well as "archive controller". Great is't it? And if you do the proper REST the API is really beautiful and easy to understand and use. This is all about of RESTful services.
Based on another question:
Creating a Child object in MVC4 - Parent's information not being passed to Create() controller
Does MVC provide a mechanism to send data from the HttpGet Create() to the HttpPost Create() without going through the client? If I need to send some data to the Post method that is meaningless to the client, how can I avoid cluttering the Views and over-exposing model properties to potential attackers?
Your GET and POST actions are just methods on a class. It really doesn't sound like there's any reason to use POST here, if your only concern is to execute a block of code under certain conditions.
Change your POST (drop the attribute) and make it a private method so it is inaccessible to the client. In your GET, do whatever checks you need to do, then invoke the method.
If you do need to expose the POST, refactor the code in question out to a seperate private method that you can call from either GET or POST. A better implementation would be a separate class with the method located there for reuse/testing/SoC.
Just a caution if you are working with a DB here...while there are some legitimate reasons to write to the DB during a GET, note that this is not the indempotent nature of the GET in most circumstances (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html).
Cheers.
Yes - as I mentioned in the other answer you can use TempData - however you don't need this. You are using nothing but an id and a name from your entity, just pass only those in the view model. You don't need the full entity.
On the server side ensure your user has access to those records. For example if I was editing a Customer record, I'd ensure the current user has access via something like:
var currentUsersCompanyId = GetCurrentUserCompanyId();
ctx.Customers.Single(o=>o.CustomerId = customerId and currentUsersCompanyId == customerId)
There are a variety of ways to do this based on how you control permissions - and third party platforms for .net such as Apprenda that help do this more automatically behind the scenes.
I am trying to develop a RESTful Web service as an ASP.NET MVC 3 Web Application.
(I know, I should use the right tool for the job, which in this case means I should use WCF. But WCF has too many abstraction layers and is thus too big to fit inside my head. It would be cool for a research project, but I am trying to do my job. Besides I previously tried it, and now I am of the opinion that, despite its big promises, WCF sucks big time.)
Anyway, what I want to do is simple: I want my Web service to return its results as either XML or JSON, depending on the type specified in the HTTP request (by, default, JSON). How do I do that?
A Json action result already exists. MvcContrib has an XML action result you can return, or you could just use Content (xmlContent, "text/xml") as your action result.
You can query the accept header to determine which action result you would like to return. As long as your action method returns type ActionResult, it doesn't matter which type it returns.
That said, once you prove the overall concept, there are better ways to structure what you're trying to do.
A quick solution is to create an optional parameter on your Controller method, and return the view as the appropriate format.
public ActionResult GetFormattedResults(string format)
{
var data = GetResults();
ActionResult result = new JsonResult(data);
switch(format.ToLower())
{
case "xml":
result = new XmlResult(data); // this class doesn't exist in MVC3 you will need to roll your own
case "html":
result = new View(data);
}
return result;
}
You could also wrap the formatting functionality into an ActionFilter so you can reuse the functionality across controller methods.
I'd like to simply check from a Controller whether another URL is authorized.
So for example, I'd like to call into a Controller like so:
[HttpPost]
public ActionResult IsUrlAuthorized(string url)
{
bool isAuthorized = // What do I put here?
return Json(isAuthorized);
}
So I'd like to know what I could call to check on whether the current user is authorized for the passed-in URL or not. I'm guessing the answer has something to do with Routes, which sit a little bit outside MVC?
This is a somewhat similar question but not quite the same thing:
ASP.NET MVC. Check if user is authorized from JavaScript
Since the user may or may not be authorized in general, but may not have the right permissions or role assignments to see a specific URL.
Ideas?
Update: I use standard MVC authorization attributes to lock down my app, so I'll just give an example of what that looks like here. In MVC Routes map to Controllers. A single method on a Controller can be restricted to one or more Roles:
public class HomeController : Controller
{
[Authorize(Roles = "User, Moderator")]
public ActionResult ListRecentPosts()
{
. . .
}
}
Or, an entire Controller can be restricted to one or more roles:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
. . .
The actual URL that any of these controller methods responds to is based on a default mapping in a standard MVC app:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But, you can be nice to your users and make URLs guessable by adding a lot more Routes - as a result, a Controller method can have many names that point to it. You can't just assume and infer the controller name from the URL (even if it maps out that way for half the URLs in the site).
So presumably I either need a way to ask the Routing engine directly whether a URL is authorized for the current user, or a 2-step of asking the Routing engine for which Controller and Method, then ask if those are authorized - hopefully not by using Reflection and matching Roles directly as that again would appear to assume too much.
Update 2: The way this came up is I have an Account strip at the top of my app. Its state can change by selecting one of several accounts you're authorized as. Depending on where you are in the app, the account you chose might have authorization to view this page - and you might be in the middle of filling out a form you don't want to lose. So the naive approach - just refresh when they pick another account - is harmful, and a waste of the user's time even if there is no form and they're just reading a page that's all text.
While that convenience to the user is nice, the user is going to fairly assume that pages they can't see as a user who shouldn't have permission really are denied (and, it would be harmful to leave them on a page that's forbidden - actions taken from it will fail). So I need to know whether to redirect away based on their new permissions.
One of the things I love about .Net is the way many of its best libraries decompose so well, so you can easily recompose things that are part of its normal functionality, or a new twist. Both the Routing module and MVC appear to be very well constructed, so I have to suspect this can be done.
The cheap hack is to ensure that my authorization module returns a consistent redirect status code when a user isn't authorized, and when the user changes their account in the account strip, fire 2 AJAX calls: One to change account, and then a second to the current page over AJAX just to check the HTTP Status Code. 200 OK means leave the page as is, Redirect means follow the redirect. Obviously this is a little ugly, involves an extra HTTP call, creates a false hit in the logs, and makes an assumption about how authorization is handled across the app.
There could be a secondary concern - the page might be authorized, but just change how it works or looks. This particular app has no change in look based on account (besides the account strip itself), and I can handle functionality changes by just providing a custom event that forms listen to - they can reload any relevant data from the server in response to it.
Using UrlAuthorization.CheckUrlAccessForPrincipal only works if you're only using URL authorization. But for MVC using Routing, we highly recommend that you don't use URL authorization to secure an app.
Instead, we recommend using Authorization attributes on the controller class. The reason is there could be multiple URLs that call the same controller action. It's always better to secure the resource at the the resource and not just at the entry ways.
In this particular case, you'd have to get an instance of the controller given the URL. THat's a little tricky as you'll basically have to run the MVC pipeline from the point where you have the URL to the point where you have the controller. It's possible, but seems heavyweight.
I wonder if there isn't a better and simpler way to accomplish your goals. What is it you're really trying to do?
UPDATE: Based on your scenario, it sounds like this is an initial check just for UI purposes. Perhaps all you need to do is make an asynchronous Ajax request to the URL and check the HTTP Status code. If it's a 401 status code, you know the user is not authorized. That seems like the safest bet.
How about UrlAuthorizationModule.CheckUrlAccessForPrincipal method.
UrlAuthorizationModule.CheckUrlAccessForPrincipal Method (System.Web.Security)