Is it possible to omit writing [FromBody]?
[HttpPost]
public string SomeMethod([FromBody]SomeModel model)
{
return "OK";
}
Should I apply some global attribute? How to achieve this?
The model binding attributes in MVC 5 specify a "BindingSource" for each parameter on an action and can specify for each property on a controller, too. You can see specifically the code where it picks it up for the FromBody attribute in the BodyModelBinder
Let me say first that you should beware that as of beta6 (and I think some point in beta5), having multiple parameters/properties with BindingSource.Body is not allowed, and you will not be able to use your actions if you have multiple parameters left as the default. This might actually be desirable if you want to annotate more; my guess is that you do not.
You can see in the DefaultApiDescriptionProvider where the default source is set; unfortunately, there is no hook at this point to tie into, and the method itself is private and not virtual; you'll need to re-implement the entire class.
Once you have, though, it's rather easy to register it in your ConfigureServices to use it instead:
services.TryAdd(ServiceDescriptor.Transient<IApiDescriptionProvider, YourApiDescriptionProvider>());
You can see the default being registered in the source, too.
probably more than one way to achieve this.. here is one way: a custom ActionValueBinder..
Write a custom class to extend from DefaultActionValueBinder.
public class FromBodyParameterBindingActionValueBinder : DefaultActionValueBinder
Override the GetParameterBinding method.
protected override HttpParameterBinding
GetParameterBinding(HttpParameterDescriptor parameter)
{
return parameter.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Post)
|| parameter.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Put) ?
parameter.BindWithAttribute(new FromBodyAttribute()) :
base.GetParameterBinding(parameter);
}
basically what we're saying is that if the Web API system gets a POST or PUT call, make FromBody as the default parameter binding methodology.
Once we have our custom binder, register it globally.
GlobalConfiguration.Services.Replace(typeof(IActionValueBinder), new FromBodyParameterBindingActionValueBinder());
what this does is that for every POST/PUT request, Web API will try to create the model from the request Body. you don't need to provide the [FromBody] attribute explicitly.
having said that, you need to understand the implications of what you're requesting..
Web API has some default rules on model binding. (can be changed)
primitive action parameters are first, looked into the query string
then request body.
complex action parameters are first, looked into the request body.
then query string.
also, web api can only read the first [FromBody] action parameter.. subsequent parameters cannot be read from the body.
the reason i am enumerating the above rules, is so that you're aware of the behavior when you expect some model to be created, but web api does not seem to create it from the body.
for me, explicitly providing [FromBody] is a lot more readable and predictable.. but if you're in full control of your APIs in terms of Http Verbs and expect all requests to be via the Body, it is a perfectly valid thing to do.
Related
I have a controller marked with [Route("api/entities")]. There is a method for getting all entities:
[Audit(ActionType.EntityList)] // custom annotation for audit
[Authorize]
[HttpGet]
public IActionResult GetEntities()
{
// ...
}
As you can see, by using annotations I save the request to some audit and authorize the request only to allowed users.
Now, I want to enhance this endpoint so it can return the top N entities. Example request: /api/entities?top=5. I have found that I should use an optional parameter for the method and use if to detect the case.
However, I need to save such call in audit as differnt type (e.g. [Audit(ActionType.EntityTop)]) and I do not need an authorization there (everyone can fetch the top entities).
How can I map the /api/entities request to one method and /api/entities?top=N to another? In Spring from Java I would use a params field of #RequestMapping.
I do not want to change the URL of this endpoint, because the top parameter modifies only the list that is being returned so one should use GET parameters for that. By having the same URL I also do not change the semantic meaning of the response (it is still list of the same entities). It is important when using RESTful frontend framework like Restangular.
Are you sure you need same action? It looks like you want to solve different tasks here, so I'd suggest you to create another action
[Audit(ActionType.EntityTop)]
[HttpGet("top/{top:int}")] //you can specify route via Annotations
public IActionResult GetEntities(int top)
{
// ...
}
Request with top entities will match /api/entities/top/5
I have an Api controller with the following method:
[Route("{app}")]
public IHttpActionResult Put(string app, Property setting){ //do stuff }
I want to over load it with:
[Route("{app}")]
public IHttpActionResult Put(string app, Property[] settings){
foreach (Property property in settings)
{
Put(app, property);
}
return Ok("Settings Updated");
}
This overload causes a routing conflict. I don't want to change the route. How can I achieve what I want?
You're using attribute routing here with two put requests. Firstly I'd suggest to use a [FromBody] atrribute before the Property[] settings parameter here.
Based on the way you used Route Attributes here points to the same action where you have multiple assigned already. So I can suggest two things here.
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection.
Just use the second action that you mentioned that takes Property[] settings and just check whether the array is empty or not and you really don't have to worry about one setting change or more as essentially it's the same underneath. :)
And as you're using Asp.net Web Api 2 this could contain important information.
I am very very new to MVC the design-pattern and also the Framework. I am also not extremely well- versed in fundamentals of ASP.NET Forms. However, I do understand the basics of web development and HTTP Post and GET as well.
Now, I have been going through some MVC tutorials and I though I was getting a good hold of how MVC the pattern works and also how "Routing Engine" works. Then suddenly I came across a code which looks like folloing:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return Content("Thanks", "text/html");
}
}
I have few questions looking at it:
My understanding of routing engine was that the control is passed to a particular ActionMethod based on URL and normally URL are basically Controller/ActionMethod/Id kind where paramter to action menthod are rather Primitive types. In this example above what kind of URL would it take to call "
public ActionResult Index(MyViewModel model)?"
Since NyViewModel is a complex type, you can not pass it as part of URL. How can you call it?
Why is this second method adorned with [HttpPost] when the first method does not require any attributes? Are there any guidelines on when to use [Http] attributes and when not?
I think I am missing a big pice in the puzzle and both the questions are interrelated. However, need some help in making sense with the relationship
The [HttpPost] attribute tells the routing engine to send any POST requests to that action method to the one method over the other. This is a type of overloading.
Why is this second method adorned with [HttpPost] when the first method does not require any attributes?
The default for a method is [HttpGet]. Because of that, no attribute is needed.
Are there any guidelines on when to use [Http] attributes and when not?
Ideally, attributes should be on every method, in order to avoid confusion. As you get more familiar with how things are working, you will often take shortcuts (as with everything else), and omit them when you know that they are not necessary.
Since MyViewModel is a complex type, you can not pass it as part of URL. How can you call it?
The data will be turned into the model from the data in the body of the request. This can come either as a JSON object, or as Form data. (There are tricks to get the object initialized from the URL, but they can be a little complicated and advanced.)
Generally, complex objects are passed in the HTTP body with verbs that support it such as POST and PUT. The body content must pass Model Binding validation. That basically means that if it's a POST request with Content-Type: application/json, it must deserialize from JSON into MyViewModel. If the content is XML, it must deserialize as XML.
General convention is to have all the primitive types that can be found in the URL path, query, and headers first, then one complex type from the POST (or PUT) body after that. I believe it's possible to put complex types elsewhere, but then you're getting into type converters and custom attributes which you should probably hold off on if you're a beginner.
Why is this second method adorned with [HttpPost] when the first method does not require any attributes? Are there any guidelines on when to use [Http] attributes and when not?
"[HttpPost]" is telling the routing engine that this method overload is only available via HTTP POST. Attempting to PUT /home/index with a body will fail with 404 Not Found, in this case. The parameter-free version of Index() doesn't require it because it can work with any HTTP verb, including GET, POST, and PUT.
Best Practice - Request handling
It is best practice to only use public methods in your controller which are going to be serviced either with a view or with json. For all public methods in your controller, it is best practice to either mark them with an [HttpGet] or an [HttpPost], or one of the other types which I wont cover as they are more edge case scenario.
These Http attributes restrict the method to only servicing those specific types of requests. While the default is [HttpGet], I have found that not marking [HttpGet] in all scenarios can at times lead to unexpected behavior when there are naming conflicts.
Best Practice - PRG
Post-Redirect-Get is a design pattern which essentially stipulates that any time you are going to be sending a response which came from a POST request, you should redirect to a get in order to send the response. This protects from a number of scenarios, including not posting again if the back button is used.
The redirect usually comes in the form of the [HttpPost] ActionResult using return RedirectToAction("MyHttpGetAction");.
Posting complex models
There are multiple ways which you can send a complex model. The main difference is that if you are using a GET request it is in the url, and if you are using a POST request it is in the request headers. If you use ajax then the difference becomes blurred as you will almost always send it in the body.
Consider a method with this routing attribute:
[Route("api/Deliveries/{ID:int}/{CountToFetch:int}")]
The method with these routing attributes is called by the client passing a URI like this:
http://localhost:28642/api/deliveries/42/100
So this way, the path info ("api/Deliveries") and the args ({ID:int}/{CountToFetch:int}) appear to be homogeneous and/or homologous.
The method on the Controller that is called gets these args assigned to it, as this makes clear:
public IEnumerable<Delivery> GetBatchOfDeliveriesByStartingID(int ID, int CountToFetch)
{
return _deliveryRepository.GetRange(ID, CountToFetch);
}
This works fine.
BUT there is another, perhaps more "accepted" way of forming routing attributes, where args are excluded:
[Route("api/Deliveries")]
...wherewith GetBatchOfDeliveriesByStartingID() is now called this way:
http://localhost:28642/api/deliveries?ID=42&CountToFetch=100
This is fine (maybe); what gives me pause is, now that the routing attribute has been simplified so, how does the routing engine know the difference between GetBatchOfDeliveriesByStartingID(), and GetDeliveryById(), for instance, which currently has this routing attribute:
[Route("api/Deliveries/{ID:int}")]
...but under the new regime would have:
[Route("api/Deliveries")]
...and be called like so:
http://localhost:28642/api/deliveries?ID=42
IOW, the two methods have the exact same routing attribute applied to them.
Is the Web API routing mechanism smart enough to still invoke the appropriate method based on the args passed in the URI and/or based on the return type of the two methods being different (e.g., the former returns an IEnumerable of Delivery, whereas the latter returns a single Delivery)?
Yes, the Web API routing engine is, if not as smart as Einstein, at least as smart as your average Congressman
This code:
[Route("api/Deliveries")]
public Delivery GetDeliveryById(int ID)
{
return _deliveryRepository.GetById(ID);
}
[Route("api/Deliveries")]
public IEnumerable<Delivery> GetBatchOfDeliveriesByStartingID(int ID, int CountToFetch)
{
return _deliveryRepository.GetRange(ID, CountToFetch);
}
...works fine.
If I pass this:
http://localhost:28642/api/deliveries?ID=7
...GetDeliveryById() is called.
...and if I pass this:
http://localhost:28642/api/deliveries?ID=7&CountToFetch=42
...GetBatchOfDeliveriesByStartingID() is called.
In our MVC project we are attempting to make everything as generic as possible.
Because of this we want to have one authentication class/method which covers all our methods.
As a example: The following code is a MVC class which can be called to from a client
public class Test
{
public void Test()
{
}
public int Test2(int i)
{
return i
}
public void Test3(string i)
{
}
}
A customer of our webservice can use a service reference to get access to Test(), Test2() and Test3().
Now i'm searching for a class, model, interface or anything else which I can use to alter the access to the method (Currently using [PrincipalPermission] attribute) as well as alter the parameter value.
Example:
Customer A calls Test2(150)
The class/method checks whether Customer A has access to Test2. The class/method validates the user but notices that the user does not have access to 150. He only has access to 100.So the class/method sets the parameter to 100 and lets it follow through on it's journey.
Customber B class Test()
The class/method checks whether Customer B has access to Test. After validation it shows that the user does not have access so it throws a SecurityException.
My question:
In what class, interface, attribute or whatever can I best do this?
(ps. As example i've only used authentication and parameter handling, but we plan to do a lot more in this stage.)
Edit
I notice most, if not all, assume I'm using actionResults. So i'd like to state that this is used in a webservice where we provide our customers with information from our database. In no way will we come in contact with a ActionResult during the requests to our webservice. (Atleast, not our customers)
Authentication can also be done through an aspect. The aspect oriented paradigm is designed to honor those so-called cross-cutting concerns. Cross-cutting concerns implemented in the "old-fashioned" oo-way make your business logic harder to read (like in Nick's example above) or even worse to understand, because they don't bring any "direct" benefit to your code:
public ActionResult YourAction(int id) {
if (!CustomerCanAccess(id)) {
return new HttpUnauthorizedResult();
}
/* the rest of your code */
}
The only thing you want here is /* the rest of your code */ and nothing more.
Stuff like logging, exception handling, caching and authorization for example could be implemented as an aspect and thus be maintained at one single point.
PostSharp is an example for an aspect-oriented C# framework. With PostSharp you could create a custom aspect and then annotate your method (like you did with the PrincipalPermissionAttribute). PostSharp will then weave your aspect code into your code during compilation. With the use of PostSharp aspects it would be possible to hook into the method invocation authenticating the calling user, changing method parameters or throw custom exceptions (See this blog post for a brief explanation how this is implemented).
There isn't a built-in attribute that handles this scenario.
I find it's usually best to just do something like this:
public ActionResult YourAction(int id) {
if (!CustomerCanAccess(id)) {
return new HttpUnauthorizedResult();
}
/* the rest of your code */
}
This is as simple as it gets and easy to extend. I think you'll find that in many cases this is all you need. It also keeps your security assertions testable. You can write a unit test that simply calls the method (without any MVC plumbing), and checks whether the caller was authorized or not.
Note that if you are using ASP.Net Forms Authentication, you may also need to add:
Response.SuppressFormsAuthenticationRedirect = true;
if you don't want your users to be redirected to the login page when they attempt to access a resource for which they are not authorized.
Here's how I've made my life simpler.
Never use simple values for action arguments. Always create a class that represents the action arguments. Even if there's only one value. I've found that I usually end up being able to re-use this class.
Make sure that all of teh properties of this class are nullable (this keeps you from running into default values (0 for integers) being automatically filles out) and thatallowable ranges are defined (this makes sure you don't worry about negative numbers)
Once you have a class that represents your arguments, throwing a validator onto a property ends up being trivial.
The thing is that you're not passing a meaningless int. It has a purpose, it could be a product number, an account number, etc. Create a class that has that as a property (e.g An AccountIdentifier class with a single field called 'id). Then all you have to do is create a [CurrentUsedCanAccessAccountId] attribute and place it on that property.
All your controller has to do is check whether or not ModelState.IsValid and you're done.
There are more elegant solutions out there, such as adding an action filter to the methods that would automatically re-direct based on whether or not the user has access to a specific value for the parameter, but this will work rather well
First, just to say it, that your own methods are probably the most appropriate place to handle input values (adjust/discard) - and with the addition of Authorize and custom filter actions you can get most done, and the 'MVC way'. You could also go the 'OO way' and have your ITest interface, dispatcher etc. (you get more compiler support - but it's more coupled). However, let's just presume that you need something more complex...
I'm also assuming that your Test is a controller - and even if it isn't it can be made part of the 'pipeline' (or by mimicking what MVC does), And with MVC in mind...
One obvious solution would be to apply filters, or action filters via
ActionFilterAttribute
Class
(like Authorize etc.) - by creating your own custom attribute and
overriding OnActionExecuting etc.
And while that is fine, it's not going to help much with parameters manipulation as you'd have to specify the code 'out of place' - or somehow inject delegates, lambda expressions for each attribute.
It is basically an interceptor of some sort that you need - which allows you to attach your own processing. I've done something similar - but this guy did a great job explaining and implementing a solution - so instead of me repeating most of that I'd suggest just to read through that.
ASP.NET MVC controller action with Interceptor pattern (by Amar, I think)
What that does is to use existing MVC mechanisms for filters - but it exposes it via a different 'interface' - and I think it's much easier dealing with inputs. Basically, what you'd do is something like...
[ActionInterceptor(InterceptionOrder.Before, typeof(TestController), "Test1")]
public void OnTest1(InterceptorParasDictionary<string, object> paras, object result)
The parameters and changes are propagated, you have a context of a sort so you can terminate further execution - or let both methods do their work etc.
What's also interesting - is the whole pattern - which is IOC of a
sort - you define the intercepting code in another class/controller
all together - so instead of 'decorating' your own Test methods -
attributes and most of the work are placed outside.
And to change your parameters you'd do something like...
// I'd create/wrap my own User and make this w/ more support interfaces etc.
if (paras.Count > 0 && Context.User...)
{
(paras["id"] as int) = 100;
}
And I'm guessing you could further change the implementation for your own case at hand.
That's just a rough design - I don't know if the code there is ready for production (it's for MVC3 but things are similar if not the same), but it's simplistic enough (when explained) and should work fine with some minor adjustments on your side.
I'm not sure if I understood your question, but it looks like a model binder can help.
Your model binder can have an interface injected that is responsible for determining if a user has permissions or not to a method, and in case it is needed it can change the value provided as a parameter.
ValueProviders, that implement the interface IValueProvider, may also be helpful in your case.
I believe the reason you haven't gotten ay good enough answer is because there are a few ambiguities in your question.
First, you say you have an MVC class that is called from a client and yet you say there are no ActionResults. So you would do well to clarify if you are using asp.net mvc framework, web api, wcf service or soap (asmx) web service.
If my assumption is right and you are using asp.net mvc framework, how are you defining web services without using action results and how does your client 'call' this service.
I am not saying it is impossible or that what you may have done is wrong, but a bit more clarity (and code) would help.
My advice if you are using asp.net mvc3 would be to design it so that you use controllers and actions to create your web service. all you would need to do would be to return Json, xml or whatever else your client expects in an action result.
If you did this, then I would suggest you implement your business logic in a class much like the one you have posted in your question. This class should have no knowledge of you authentication or access level requirements and should concentrate solely on implementing the required business logic and producing correct results.
You could then write a custom action filter for your action methods which could inspect the action parameter and determine if the caller is authenticated and authorized to actually access the method. Please see here for how to write a custom action filter.
If you think this sounds like what you want and my assumptions are correct, let me know and I will be happy to post some code to capture what I have described above.
If I have gone off on a tangent, please clarify the questions and we might be one step closer to suggesting a solution.
p.s. An AOP 'way of thinking' is what you need. PostSharp as an AOP tool is great, but I doubt there is anything postsharp will do for you here that you cannot achieve with a slightly different architecture and proper use of the features of asp.net mvc.
first create an attribute by inheriting from ActionFilterAttribute (system.web.mvc)
then override OnActionExecuting method and check if user has permission or not
this the example
public class CheckLoginAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!Membership.IslogedIn)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{ "area",""},
{ "action", "login" },
{ "controller", "user" },
{ "redirecturl",filterContext.RequestContext.HttpContext.Request.RawUrl}
});
}
}
}
and then, use this attribute for every method you need to check user permission
public class Test
{
[ChecklLogin]
public void Test()
{
}
[ChecklLogin]
public int Test2(int i)
{
return i
}
[ChecklLogin]
public void Test3(string i)
{
}
}