Introduction
This project allows you to create and maintain a low-usage server without the overhead of Apache or IIS.
Background
I was tasked to provide a communications server which would send notifications to clients about events on the server. Part of that task was to allow the communications server to be configured through a website. There was a restriction to this service where we were not allowed to install anything else but our software which meant that we could not use IIS as the host. I finished writing the server as self-hosted NT service and I wrote a proof of concept website in the same host that could serve up an HTML page and an image on that page. The project stalled and the proof of concept was dead.
This is my effort to take that proof of concept and show that WCF can be used to implement a low usage, administrative website.
Requirements
This project was built with Visual Studio 2013 and .NET 4.5, however, I have also included solutions for VS2010 and VS2012 and they both use .NET 4.0. From what I understand, VS2008 does not support .NET 4.0, so I have not created a solution for that and I am not planning to create one.
You must run DBWebHost.exe as an administrator. The explanation is below. You will also need to open up the appropriate ports on your firewall to allow other clients to access your website.
The Components
There are five components to this project:
- DBWebHost.exe
- HttpAccess.dll
- DBServerLibrary.dll
- DBWebsite.dll
- DBTestsite.dll
DBWebHost
is the main program. It is responsible for creating a WebServiceHost
, opening it, closing it and cleaning up. I am using WebServiceHost
instead of ServiceHost
because it is simpler to set up programmatically and does not require behaviors to be explicitly configured.
To enable HTTP access to your service, you will have to open the port you want to use on your firewall and you will need to configure HTTP.SYS to allow access. Most sites show you how to configure HTTP.SYS through the command shell like so:
netsh http add urlacl http:
HttpAccess.dll, however, uses HttpSetServiceConfiguration
which is part of the HttpApi
library. To use this method with the DACL specified, you need to run this as an administrator. I really don't recommend this approach. A better way would be to set this during installation which I have done in the past. I have not done it for this project because I wanted to show how HttpSetServiceConfiguration
works. If you were to call HttpAccess.dll from an installer or separate process, DBWebHost.exe could run without admin privileges.
DBServerLibrary.dll is the router. The IDBWebService
interface defines the routing structure and the parameters accepted by the service. DBWebService
implements the interface. I have rewritten this considerably since the last release. The interface now only supports Get
and Post
methods. There are stubs for Put
and Delete
which are not active, though I may be implementing these later.
DBWebService
will take the incoming request and parse it into the host name, the website name, the controller name and the action name. Anything after the action name is treated as part of the query string. It will then take this information along with any streams that are passed and create a Request object and that request object may be passed to the Action
method.
There are two ways of defining your Controller
class and Action
method.
The first is the way previous versions defined them: URIs for pages are constructed with /dbwebservice/{website}/{controller}/{action} where {website}
is the name of the website module you are hosting, {controller}
is the prefix name of the Controller
class and {action}
is the name of the method to call on the Controller
. These values are case insensitive. DBWebService
will take these values, set them to lower case, and then set the first letter to upper case. For instance, the in path /dbwebservice/HOME/index, DBWebService
will convert "HOME
" to "Home
" and append "Controller
" so that the name of the expected Controller
is "HomeController
". It will take "index
" and convert it to "Index
" so that it can look for the "Index
" method on the "HomeController
" object.
The second way is determined by attributes on the Controller
class and Action
method. I have included a PathResolutionAttribute
class which can be used to decorate the Controller
classes and Action
methods. A helper class in DBServerLibrary.dll called ParsedUri
will take the {controller} and {action}
values and look for matches in the website assembly. If it fails to find those values in the assembly, it will fall back to the old method of finding the Controller
class and Action
method.
Now, I should mention that the UriTemplate
properties on the WebGet
and WebInvoke
attributes have been changed from /{controller}/{action} to /{*path}. This allows the request string
to be virtually anything so it is up to the server to parse the request rather than relying on the underlying dispatch system.
I have included the interfaces IErrorController
and IResourceController
which are special case Controllers and are used to display errors and return resource files such as images, JavaScript, CSS files, etc. DBWebService
used to handle resources directly, but since it can now handle multiple websites, resource and error requests should now be handled by the site itself. DBWebService
looks for these interfaces when it cannot resolve request string and tries to resolve it first with the IResourceController and then with the IErrorController
. If the request string
cannot be resolved through either interface, a default ErrorController
object will be created and returned.
An added benefit to all of this is that the HTML links you use on your websites can now be relative links. This was not supported in earlier versions.
DBWebsite.dll and DBTestsite.dll are the implementations of websites which render the HTML and provide the assets (images scripts, etc.) for the websites and they are used to demonstrate how Controllers
and Actions
work. They demonstrate how CSS is applied, that they support JavaScript and JavaScript libraries such as jQuery, Ajax GETs and Json posts, as well as support for CGI processing through PHP. As of this release, you are no longer bound to only one website for your host.
Configuration
There are three values that can be configured in the App.config (actually it is DBWebHost.exe.config):
port
is the value of the port
that will be opened for request. The default is 80
. It is used by DBWebHost
. secureport
is the value of the port
that will be opened for SSL requests. It is used by DBWebHost
. cert
is the name (subject) of the certificate you are using for SSL requests. It is used by DBWebHost
.
There is a section called ProcessorSection
which contains the information about the different CGI processors you can use. You are no longer restricted to one type of processor. This replaces cgiExec
, cgiType
, and cgiParams
.
There is another section called SitesSection
which contains the name of the website modules you want to include and their paths. If you have a problem with loading a website assembly, this is the first place to look. This replaces the module configuration value.
Points of Interest
Be careful with editing PHP files in Visual Studio. PHP does not like Byte Order Marks (BOM) in the files. See PhpProcessor.cs for details on how to save files used by the PHP processor.
To test SSL, you will need to either have purchased a certificate or create one from your own personal certificate authority. I recommend reading How To Be Your Own Certificate Authority and Create Your Own Certificate to Sign Code Files by Mike Meinz. The server is expecting the certificate to be located in the "My" store in the LocalMachine
store location. I will be making this configurable in future releases.
If you are having any trouble loading the website assemblies, the first place to check is the DBWebHost
App.Config file and make sure that the path values in the SitesSection
area are correct.
Check the release notes for fixes and additions.
There is a TODO.txt file which outlines future improvements. If you have a request for a feature which is not in the TODO list, let me know.
The binaries included are built using VS2013.
History
- Release 1.0: 5/5/2014
- Release 1.0.2: 5/18/2014
- Added support for Visual Studio 2010 and 2012
- Added support for Perl processing
- Restructured Session collection so sessions can be cleaned up on a worker thread
- Changed JQuery method to an overloaded JavaScript method so any library can be used
- Fixed various bugs
- Release 1.0.3: 6/17/2014
- Added support for SSL
- Added support for custom error pages
- Added support for multiple processor engines
- Added support for multi-part form data (used for uploading files)
- Added support for redirection to a default page on a bad URI
- Release 1.1.1: 7/6/2014
- Added support for multiple websites
- Simplified service interface
- Deferred resource requests to websites
- Allow for relative paths of links and resources in HTML
- Allow definition of Controller and Action names by attributes