Asp.Net Web Api : Handling two get request with same signature - c#

Current situation
[HttpGet]
public HttpResponseMessage CheckProfileStatus(int id)
{
//check profile status from third party
return //profile status and HttpStatus;
}
[HttpGet]
public HttpResponseMessage ProcessTheProfile(int profileId)
{
//check profile status from third party again, if status is "Good", do something
return //someMessage and HttpStatus;
}
Url to call CheckProfileStatus method
myUrl/api/Profile/123
Url to call ProcessTheProfile method
myUrl/api/Profile/?profileId=123
I hope the comments in the code makes the situation clear.
I don't really like the fact that I have two HttpGet methods with same signature in one controller (even though it works).
I don't know if it is best practice.
Question:
Should I extract these two methods in two seperate controllers, is it completely fine to have two HttpGet methods with same signature in one controller or is there better way to handle this situation?

First, this is confusing to any client of the API.
You have 2 GET methods which are virtually identical. In fact most people prefer to add a route covering your first option which basically sets the profileId to the value after the forward slash.
Second, the expectation is that when you issue a GET against an entity with an ID, you get the representation of that entity. This is not what's happening here.
You need to decide which kind of API do you want. A generic one where stuff like this is fine :
myUrl/api/profile/process/123 or process/profile, or whatever else makes sense to the API.
If your API is supposed to be RESTful ( which basically means you will have one method per HTTP verb and nothing more ) then you need to add a new controller for ProcessProfile and then your url can look like this :
myUrl/api/ProcessProfile/123
None of these options is set in stone, they are just that, options.
The comments to the OP thread give some good options as well, which should be considered.

Related

ASP.NET Core: redirect from GET to POST

I want to call MarriageById as GET, like this:
var url = '/MarriageById?id=' + id;
But I also want to have a single ActionResult Marriage(Marriage marriage) that does some processing before showing the view. This second one must be POST because it will also receive the "send form" from asp.
I am trying this solution (see my own implementation below), but it is still redirected as a GET and ActionResult Marriage is not found:
[HttpGet]
public ActionResult MarriageById(int id)
{
var marriage = _marriageRepository.GetById(id);
return RedirectToAction(nameof(Marriage), marriage);
}
[HttpPost]
public ActionResult Marriage(Marriage marriage)
{
var people = _personRepository.GetAll();
ViewBag.men = Utils.GetPersonsSelectListByGender(people, isMale: true);
ViewBag.women = Utils.GetPersonsSelectListByGender(people, isMale: false);
return View(marriage);
}
Using RedirectToAction always implies a GET, so this won't work to reach the Marriage action method that only accepts POST.
However there is nothing wrong with calling the other method yourself, it is still a method like any other. So try this instead:
return Marriage(marriage);
And on a side note: if the Marriage method will always only be used to display data, and never to save, store or change data, then using POST is not the best choice. POST typically implies a call with side effects (save, store, change, or even delete), and in general it is best to stick to that convention.
I don't think you should mix GET with POST verbs. They are just semantically different.
If you have a similar functionality that you want to execute for those 2 methods, maybe instead of calling POST from GET you might want to extract the common parts ot some other 'private' method or even layer (depending on the use case).
Hope it makes sense

Understanding [HttpPost], [HttpGet] and Complex Actionmethod parameters in MVC

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.

Web API - REST help and clarification

I'm writing an API using WebAPI, and whilst I'm designing this from scratch, I'm trying to make it RESTful. In the past when doing web service work, I've always used RPC patterns (ASMX, SOAP, etc) - eg. using an arbitrary method name that matches what I want it to do. To me this seems much more intuitive and explicit than REST, but given WebApi seems to be more RESTful by nature (I know you can change the route so it's not), I've decided to try and make it RESTful.
I understand (I think!) the basics - eg. POST for create, PUT for update when specifying an ID, GET to get, DELETE to delete, etc, etc.
My confusion is how to deal with returning collections vs a single object. For example, say that I've got an API controller called UsersController. As far as I gather, I'd have the following URLs:
GET: /api/users (lists all users)
GET: /api/users/1 (lists details about user with ID 1)
POST: /api/users (creates a new user with details sent in the POST data)
PUT: /api/users/1 (updates the existing user with ID 1 with details sent in the POST data)
DELETE: /api/users/1 (deletes the existing user with ID 1)
For the first URL above, I need to also send various filter/search criteria. Does this criteria just get passed through as query string parameters? Or should I be using a completely different controller for this "search" functionality? Eg. UserSearchController? If so, should that be a POST in this case or still a GET? Actually as I write this, I'm wondering whether a separate controller makes sense anyway, as I'll probably want more detail returned in the GET for a single user than in the search results. Does it make it not RESTful if the same controller does return different data for a single object GET vs a GET returning a collection?
For the first URL above, I need to also send various filter/search criteria. Does this criteria just get passed through as query string parameters?
It definitely makes sense to use query string for specifying filter/search parameters.
should I be using a completely different controller for this "search" functionality? Eg. UserSearchController?
You should not do that. There are couple of reasons that i see here:
There will be almost identical functionality in GET: /api/users
You can easily implement GET: /api/users, GET: /api/users?filter=...&sort=... and GET: /api/users/1 in one method:
//If you are using EF it could look like
//filter and sort arguments could be added here as well
public HttpResponseMessage Get(int? id)
{
if(id.HasValue)
{
return Request.CreateResponse(
HttpStatusCode.OK,
Context.Users.SingleOrDefault<Users>(u => u.Id == id));
}
var users = Context.Users.Select(apply filter).OrderBy(apply sort).ToList();
return Request.CreateResponse(HttpStatusCode.OK, users);
}
You can take a look at OData - it may help you with the implementation.
Spreading this logic between different controllers compromises single responsibility principle - your users controller should handle all the logic related to users and only this logic
If so, should that be a POST in this case or still a GET?
If you want to make your API RESTful you should be using GET. BUT you should be aware, that returning an array of JSON objects through GET could be potentially vulnerable to JSON hijacking. One of the simplest solutions to this exploit is allowing to get JSON arrays through POST only (there are other solutions as well).
I'll probably want more detail returned in the GET for a single user than in the search results. Does it make it not RESTful if the same controller does return different data for a single object GET vs a GET returning a collection?
This is totally fine to return more details for a single object than for a collection. It doesn't affect RESTfulness of your API in any way.
COMMENT
You wrote:
PUT for update when specifying an ID
Actually it is not entirely correct:
PUT should be used for complete replacement of the entire entity
PATCH should be used to perform a partial update.
If you want to get passed through criteria as query string parameters to URI, you can do that using Attribute Routing into WebApi. I think attribute-routing-in-web-api helps to you.
Yes, I would pass filter parameters as query string options. The 'restfulness' of your application is not dependent on controller structure, so you can follow a structure that best suits your application

Creating WebApi controller with different verbs

I have WebApi controller that receives the request Get all entries:
public IEnumerable <client> GetAllClients ();
I need this same controller method:
public IEnumerable <clients> GetMaxPaymentClient ();
This method also available on request Get, how do I describe this method and how to call the client page?
It won't work having two methods with the same method signature and same HTTP verb at the start of their name in the same controller if you just use the default Web API routing. This operates by convention based on method names and there's no way for it to tell which method you intend to reach using a GET request to your controller.
Ways of differentiating the two methods could be:
Add a [route] attribute to one or both of your methods to differentiate them. More detail on this is at http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2. E.G. you could add [Route("clients/maxpayment")] to your second method.
Move one of the methods to a different controller. This is what I'd recommend if you're writing a REST style API. Max payment sounds like it should be a different resource from just general details for clients
Amend the method signature of the methods so that they're different, such as by adding an ID argument to one of them. Web API will be able to handle separate routes for methods like Get() and Get(string id). Presumably this isn't an option for you as I assume you have your desired method signatures already.

Attempting to generalize a authentication (Including parameter changing)

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)
{
}
}

Categories

Resources