Quino has long included support for connecting to an application server instead of connecting directly to databases or other sources. The application server uses the same model as the client and provides modeled services (application-specific) as well as CRUD for non-modeled data interactions.
We wrote the first version of the server in 2008. Since then, it's acquired better authentication and authorization capabilities as well as routing and state-handling. We've always based it on the .NET
As late as Quino 2.0-beta2 (which we had deployed in production environments already), the server hierarchy looked like screenshot below, pulled from issue QNO-4927:
This screenshot was captured after a few unneeded interfaces had already been removed. As you can see by the class names, we'd struggled heroically to deal with the complexity that arises when you use inheritance rather than composition.
The state-handling was welded onto an authentication-enabled server, and the base machinery for supporting authentication was spread across three hierarchy layers. The hierarchy only hints at composition in its naming: the "Stateful" part of the class name
CoreStatefulHttpServerBase<TState> had already been moved to a state provider and a state creator in previous versions. That support is unchanged in the 2.0 version.
We mentioned above that implementation was "spread across three hierarchy layers". There's nothing wrong with that, in principle. In fact, it's a good idea to encapsulate higher-level patterns in a layer that doesn't introduce too many dependencies and to introduce dependencies in other layers. This allows applications not only to be able to use a common implementation without pulling in unwanted dependencies, but also to profit from the common tests that ensure the components works as advertised.
In Quino, the following three layers are present in many components:
Encodo.Connectionsand so on)
Quino.Applicationand so on).
The diagram below shows the new hotness in Quino 2.2
The hierarchy is now extremely flat. There is an
IServer interface and a
Server implementation, both generic in
TListener, of type
IServerListener. The server manages a single instance of an
The listener, in turn, has an
IHttpServerRequestHandler, the main implementation of which uses an
As mentioned above, the
IServerStateProvider is included in this diagram, but is unchanged from Quino 2.0-beta3, except that it is now used by the request handler rather than directly by the server.
You can see how the abstract layer is enhanced by an HTTP-specific layer (the
Encodo.Server.Http namespace) and the metadata-specific layer is nice encapsulated in three classes in the
This type hierarchy has decoupled the main elements of the workflow of handling requests for a server:
It is important to note that this behavior is unchanged from the previous version -- it's just that now each step is encapsulated in its own component. The components are small and easily replaced, with clear and concise interfaces.
Note also that the current implementation of the request handler is for HTTP servers only. Should the need arise, however, it would be relatively easy to abstract away the
HttpListener dependency and generalize most of the logic in the request handler for any kind of server, regardless of protocol and networking implementation. Only the request handler is affected by the HTTP dependency, though: authentication, state-provision and listener-management can all be re-used as-is.
Also of note is that the only full-fledged implementation is for metadata-based applications. At the bottom of the diagram, you can see the metadata-specific implementations for the route registry, state provider and authenticator. This is reflected in the standard registration in the IOC.
These are the service registrations from
return handler .RegisterSingle<IServerSettings, ServerSettings>() .RegisterSingle<IServerListenerFactory<HttpServerListener>, HttpServerListenerFactory>() .Register<IServer, Server<HttpServerListener>>();
And these are the service registrations from
handler .RegisterSingle<IServerRouteRegistry<IMetaServerState>, StandardMetaServerRouteRegistry>() .RegisterSingle<IServerStateProvider<IMetaServerState>, MetaPersistentServerStateProvider>() .RegisterSingle<IServerStateCreator<IMetaServerState>, MetaServerStateCreator>() .RegisterSingle<IHttpServerAuthenticator<IMetaServerState>, MetaHttpServerAuthenticator>() .RegisterSingle<IHttpServerRequestHandler, HttpServerRequestHandler<IMetaServerState>>()
As you can see, the registration is extremely fine-grained and allows very precise customization as well as easy mocking and testing.
Any Men in Black fans out there? Tommy Lee Jones was "old and busted" while Will Smith was "the new hotness"? No? Just me? All righty then...↩
This diagram brought to you by the diagramming and architecture tools in ReSharper 9.2. Just select the files or assemblies you want to diagram in the Solution Explorer and choose the option to show them in a diagram. You can right-click any type or assembly to show dependent or referenced modules or types. For type diagrams , you can easily control which relationships are to be shown (e.g. I hide aggregations to avoid clutter) and how the elements are to be grouped (e.g. I grouped by namespace to include the boxes in my diagram).↩
Sign up for our Newsletter