-
Notifications
You must be signed in to change notification settings - Fork 0
Services
Module Services provides the ability to expose simple C# class as the endpoint on the internet. There are to main ideas in design of these classes. First, each class acts as single-action-controller, so every action needs one class. And second, such a class is simple tagged with interfaces to decorate it with functionality. Let start with examples...
At first, we need the execute method, so the Services module will know what to call on the class.
public class HelloHandler : IGet
{
public void Execute()
{
// Process request and provide response...
}
}
Implementing IGet
, we also notify module to execute this method when HTTP GET request arrives. For other HTTP methods, there are interfaces IPost
, IPut
and IDelete
(and others can be easily added).
So, we have the execute method, but we need to provide some output. This is realized using the IWithOutput<T>
interface.
public class HelloHandler : IGet, IWithOutput<string>
{
public string Output { get; private set; }
public void Execute()
{
Output = "Hello, World!";
}
}
The Output
property can be of any type, but if the type is other than string
or Stream
, than special serializer is needed (based on the request Accept header value. JSON and XML is suported be default).
To process request input, there is interface IForInput<T>
. This interface will process body of the HTTP request deserialize model of type T
. NOTE: We are considering using Sytem.Web.ModelBinding
, but for now, only HTTP request body is used.
public class HelloHandler : IGet, IWithOutput<string>, IForInput<string>
{
public string Input { get; set; }
public string Output { get; private set; }
public void Execute()
{
Output = String.Format("Hello, {0}!", Input);
}
}
This way we can have 'personalized' HelloHandler.
These interfaces are called 'behaviors'. Behaviors can be splitted into two groups. First one are those behaviors that provide data from HTTP request and are executed before execute method. These behaviors are prefixed with 'For'. The second group contains behaviors that process data in handler and copy it the HTTP response. These are prefixed with 'With'.
Each behavior is composed from contract (= interface that is implemented by the handler) and implementation (= class that implements IBehavior<T>
where T is the contract). There can also be behavior which contract is not defined by the interface, contract can be almost everything (attribute or even nothing).
In WebStack, everything that can be executed from HTTP request implements IRequestHandler
. Services design hides this away using composition. Service class handler is wrapped using of provided 'pipeline' implementations (name pipeline is used because behavior channel works like a pipeline).
Base pipeline processing is implemented in PipelineBase<T>
. This class implements processing of behaviors and the onlything that must be provided is the enumeration of behaviors that are relevant for the service handler class of type T
. The second abstract method, GetHandlerFactory
, is responsible for creating new instances of the service handler class.
Behaviors can be provides in multiple ways. The best way is using CodeDomPipelineFactory
which dynamically compiles tiny proxy for service handler class and provides best performance.
...
To bind the handler to some URL, use Routing module.
...
Some tutorials and design ideas description...