Is there a Best Practice for multiple Http Post - RPC style, custom MediaTypeFormatter or Other - asp.net-web-api

I'm not looking to start a holy war but looking for maybe a document on best
practices for creating APIs which contain multiple HTTP verbs.
I inherited a 4.7.2 Web API project and trying to straighten out some things and
hopefully sometime in the future get to move it to .NET Core.
In the mean time I have a resource that will be gaining new functionality.
To keep this simple, let's just say it is a "document".
Currently there is a [HttpPost] that is used to create the document metadata.
The ask is to extend it to provide "Clone", "Split", "Merge" all of which are
creation types but all have a dependency on an existing document.
I can go the RPC style
api/document/{action}/{id}
api/document/{id}/{action}
which flies in the face of HTTP REST implementations.
The second implementation is a little better but that "action" is not really a "resource".
The other option I have is to have a single HttpPost that looks like the code at the bottom
and pass a custom content-type. If I go this route, I must implement a MediaTypeFormatter
or I get a exception generated. I currently have this implemented and working, it's just
going to be a maintenance nightmare when/if I start adding/changing to use this methodology.
As I said, I'm on 4.7.2 so ConsumesAttribute is not available to me.
The question I have is.... Is there a best practice????
Thoughts?
[HttpPost]
public async Task<IHttpActionResult> Post([FromBody] string metadata)
{
var ct = Request.Headers["Content-Type"]
switch (ct)
{
// Call operation that will handle that Content Type which
// will deserialize document into a specific object type
}
}
Action Content Type
Create application/json
Clone application/vnd.mycompany.create-from-existing.v1+json
Split application/vnd.mycompany.split-from-existing.v1+json
Merge application/vnd.mycompany.merge-existing.v1+json
public class MyContentTypeToStringFormatter : MediaTypeFormatter { }

Related

Swashbuckle.AspNetCore [FromForm]IFormCollection

I have the following action in my .NET Core 2 controller. It is an API that should store all data posted as application/x-www-form-urlencoded
[HttpPost("data/add/{formid}"]
public void Add(int formid, [FromForm]IFormCollection formData) {
//do something
}
So the Swagger UI allows to try the action using UI:
Swagger UI
But the Swagger UI produces POST with body: formData=field1%3Dvalue1%26field2%3Dvalue2
I expect it to be: field1=value1&field2=value2
So the question is, is it a limitation of OpenAPI, or a bug of the SwaggerUI? Or maybe there is a way to get what I expect?
IFormCollection is a dynamic dictionary, so Swagger doesn't know how to handle it, since it effectively has no rules. That in an of itself should be enough to signal to you that this isn't something you should be using in a REST-based API. The whole point is to make the API self-documenting, which means it should accept the actual stuff it needs as strongly-typed params, not a generic data dump.
In other words, instead, do something like:
public void Add(int formid, [FromForm]DataClass data)
Where DataClass is an actual class with properties that match the names of the fields you're posting. Using a strongly-typed param does not preclude posting as application/x-www-form-urlencoded. There's really no good reason to ever use IFormCollection.

asp.net webapi controller, return typed entity or HttpResponseMessage

i would like to know what is the benefit of using HttpResponseMessage as the return type in my ApiController ? compare to returning the typed entity or collection directly.
we were trying to decided on a practice to keep things consistent for the project we are working on.
Returning HttpResponseMessage is useful when you are trying to use your controller layer as the translation between the HTTP protocol and your internal .Net services. It allows direct control over the HTTP payload and headers. It makes it easy to return 202, 204, 304, 303 responses. It makes it easy to set caching headers. You have explicit control over the media type of the response.
By returning an object you effectively adding a "do nothing" layer to your architecture. Consider....
public Foo Get(int id) {
return _fooRepository.GetFoo(id)
}
What is the purpose of this method? What value does it add? At least in MVC land, the controller had the role of matching the model and the view.
When you return objects from an APIController you have to impact the HTTPResponseMessage indirectly using a set of abstractions that are specific to Web API/MVC and have no corresponding concept in the HTTP world. Formatters, ActionFilters, ModelBinders, HttpResponseException are all infrastructure designed to allow the framework to process your HTTP request and response messages behind the scenes.
Returning HttpResponseMessage directly requires that your controller method does the work necessary to return the desired HTTP message.
I don't believe that it adds any complexity to your application, it just makes what is happening visible.
It comes down to whether you want to use Web API as an "object remoting over HTTP" framework (in which case I would also take a look at ServiceStack) or whether you want to take advantage of HTTP as an application protocol.

Code Design. How to access your api-key in your business logic?

It's a code design question :)
I have a DelegatingHandler which takes the http request header and validates the API-key. Pretty common task I guess. In my controller I call my business logic and pass along all business-relevant information. However now I'm challenged with the task to change behavior inside my business logic (separate assemblies) depending on certain api-keys.
Various possible solutions come to my mind...
Change business logic method signatures to ask for an api-key, too.
public void SomeUseCase(Entity1 e1, Entity2 e2, string apiKey);
Use HttpContext.Current to access the current request context. However I read somewhere that using HttpContext restrict my hosting options to IIS. Is there any better suited option for that?
var request = HttpContext.Current.Request; // next extract header information
Use Sessions (don't really want to go that road...)
What's your opinion on that topic?
I'd go for #1 although I don't like the idea of mixing in enivonmental stuff in business logic methods. But depending on your point of view you might argue the api-key is in fact logic-relevant.
Update #1:
I'm using a delegatingHandler to validate the apiKey and once it is validated I add it to the Request's Properties Collection.
The part in question is how the "api-key" or RegisteredIdentifier is passed along to the business logic layer. Right now I am passing the object (e.g. IRegisteredIdentifier) as a parameter to the business logic classes' constructors. I understand there is no more elegant way to solve this(?). I thought about changing the method signatures but I'm not sure whether it's interface pollution or not. Some methods need to work with the api-key, most don't. Experience tells me that the number will more likely grow than drop :) So keeping a reference to it in my bl classes seems to be a good choice.
Thank you for your answers - I think all of them are part of my solution. I'm new to StackOverflow.. but as far as I can see - I cannot rate answers yet. Rest assured I'm still thankful :)
I would suggest two different options.
Promote the value into a custom HTTP header (e.g. something like mycompany-api-key: XXXX ). This makes your delegating handler work more like a standard HTTP intermediary. This would be handy if you ever hand off your request to some secondary internal server.
Put the api-key into the request.Properties dictionary. The idea of the the Properties dictionary is to provide a place to put custom meta information about the request.
HTTP works hard to make sure authentication/authorization is a orthogonal concern to the actual request, which is why I would try and keep it out of the action signature.
I would go for option 1.
But you could introduce the entity RegisteredIdentifier (Enterprise Patterns and MDA by Jim Arlow and Ila Neustadt) in your business logic.
The api-key can be converted to a RegisteredIdentifier.
RegisteredIdentifier id = new RegisteredIdentitief(api-key);
public void SomeUseCase(Entity1 e1, Entity2 e2, RegisteredIdentifier id);
The business logic layer has a dependency on the API key. So I would suggest:
interface IApiKeyProvider
{
string ApiGet { get; }
}
..then have your BLL require that an object implementing that interface is supplied to it (in constructor, setup, or even each method that requires it).
Since in the future it might not be one API key. The key point is that this identifies the BLL is dependent on something, and defining a contract for the something.
Real-world example:
Then, in your DI container (Ninject etc), bind your own ConfigFileApiKeyProvider (or whatever) implementation to that interface, in the "place" (layer) that DOES have the API key. So the app that calls the BLL specifies/configures how the API key is specified.
Edit: I misunderstood the part about this being a "how-to-do-it-over-HTTP" question and not a code architecture/code design question. So:
HTTP header is the way to go in terms of transport

ActionMethodSelectorAttribute equivalent in ASP.NET Web API?

Is there a Web API equivalent to the MVC ActionMethodSelectorAttribute?
My specific purpose is this: I have, for example, a ResourceController and when I POST to the controller, I'd like to be able to receive a single resource (Resource) or a list (IEnumerable<Resource>).
I was hoping creating two methods with different parameters would cause the deserialization process to do some evaluation but this doesn't seem to be the case (and frankly, I don't think it's efficiently realistic with the combination of content negotiation and the fact that many data formats, like JSON, make it difficult to infer the data type). So I originally had:
public HttpResponseMessage Post(Resource resource) {...}
public HttpResponseMessage Post(IEnumerable<Resource> resources) {...}
...but this gets the "multiple actions" error. So I investigated how to annotate my methods and came across ActionMethodSelectorAttribute but also discovered this is only for MVC routing and not Web API.
So... without requiring a different path for POSTing multiple resources vs. one (which isn't the end of the world), what would I do to differentiate?
My thoughts along the ActionMethodSelectorAttribute were to require a query parameter specifying multiple, which I suppose is no different than a different path. So, I think I just eliminated my current need to do this, but I would still like to know if there is an equivalent ActionMethodSelectorAttribute for Web API :)
I haven't seen a replacement for that method (there is an IActionMethodSelector interface but it is internal to the DLL). One option (although it seems like it might be overdoing it) is to overload the IHttpActionSelector implementation that is used.
But changing gears slightly, why not always expect an IEnumerable<Resource>? My first guess is that the collection method (that takes IEnumerable<Resource>) would simply loop and call the single value (just Resource) function?

Command Pattern in .NET MVC 3 (removing junk from the controller)

I am trying to implement this Command Pattern on my .NET MVC 3 application, specifically for saving edits to a Thing. I am undecided on how to proceed. Before I get to the actual question, here is the simplified code:
public class ThingController
{
private readonly ICommandHandler<EditThingCommand> handler;
public ThingController(ICommandHandler<EditThingCommand> handler)
{
this.handler = handler;
}
public ActionMethod EditThing(int id)
{
...build EditThingViewModel and return with View...
}
[HttpPost]
public ActionMethod EditThing(int id, EditThingViewModel vm)
{
var command = new EditThingCommand
{
...not sure yet...
};
this.handler.Handle(command);
...redirect somewhere...
}
}
My EditThingViewModel is wholly disconnected from my domain, which consists of POCO classes. It seems like my EditThingCommand should look like this:
public class EditThingCommand
{
Thing ModifiedThing;
}
However, building ModifiedThing would then still be happening in my controller. That's the majority of the work in this case. By the time ModifiedThing is built (and the "old" timestamp applied to it for optimistic concurrency checking), all that's left is for command to call Update on my data context.
Clearly there is value in being able to easily decorate it with other commands, but I'd also like to be able to move the construction of ModifiedThing outside of my controller. (Perhaps this question is really just about that.) EditThingCommand is in my domain and doesn't have a reference to EditThingViewModel, so it can't go there. Does it make sense to have another command in my presentation layer for mapping my viewmodel to my poco entity?
I created an EditThingPostCommand outside of my domain, which takes the EditThingViewModel as a parameter. The EditThingPostCommandHandler is responsible for creating the EditThingCommand and calling its handler.
It works, but I'm not going to assume that's the best answer to my question. Arguably most of what the EditThingPostCommandHandler is doing could be done in a custom AutoMapper configuration, which would still serve the purpose of cleaning up the controller action method.
After several months of using this pattern on other projects, it is apparent to me that the commands on this particular project were simply too general and therefore too complex, requiring too much setup. It would have been better to create, for example, an EditThingTitleCommand and a MoveThingPiecesCommand and so on, and call them from their own ActionMethods.
In other words, when using the command pattern, don't just use the commands as replacements for typical CRUD operations. With more specificity comes more benefit.

Resources