Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 118
Notice: A non well formed numeric value encountered in C:\ClientSites\bestaspnethostingreview.com\httpdocs\wp-content\plugins\crayon-syntax-highlighter\crayon_formatter.class.php on line 119
BestASPNETHostingReview.com | Best and recommended ASP.NET 5 hosting. In this post I’ll be showing how you can finally host ASP.NET in a Windows service. Yes, with ASP.NET 5, it is possible to host ASP.NET in a Windows service. It’s a quick one, so go read it now.
Project Dependencies
Open up project.json
and add in a dependencies
property with the following entries:
"Microsoft.AspNet.Hosting": "1.0.0-beta7"
– Bootstraps the web server"Microsoft.AspNet.Server.Kestrel": "1.0.0-beta7"
– Web server implementation"Microsoft.AspNet.StaticFiles": "1.0.0-beta7"
– Hosts static files"Microsoft.AspNet.Mvc": "6.0.0-beta7"
– Includes all the MVC packages
Your project.json
should now look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | { "version": "1.0.0-*", "description": "MyDnxService Console Application", "commands": { "run": "MyDnxService" }, "frameworks": { "dnx451": { "frameworkAssemblies": { "System.ServiceProcess": "4.0.0.0" } } }, "dependencies": { "Microsoft.AspNet.Hosting": "1.0.0-beta7", "Microsoft.AspNet.Server.Kestrel": "1.0.0-beta7", "Microsoft.AspNet.StaticFiles": "1.0.0-beta7", "Microsoft.AspNet.Mvc": "6.0.0-beta7" } } |
Run in Visual Studio or Command Line
It would really be a pain to develop and debug your application while running as a Windows service. That’s not to say you can’t, but if you are currently developing an application, you probably want to run it from Visual Studio or the command line. To do this, you need some sort of switch in the Main
method that will either call ServiceBase.Run
or just call directly into OnStart
and OnStop
. Let’s do this by writing our Main
method as follows:
1 2 3 4 5 6 7 8 9 10 11 12 | public void Main(string[] args) { if (args.Contains("--windows-service")) { Run(this); return; } OnStart(null); Console.ReadLine(); OnStop(); } |
Simply check for the presence of the --windows-service
argument, call ServiceBase.Run
and you are good to go. Now you can just run and debug your application from Visual Studio by hitting F5. When you want to install the application as a Windows service, don’t forget to pass --windows-service
at the end of the binPath=
argument.
sc.exe create <service-name> binPath= "\"<dnx-exe-path>\" \"<project-path>\" run --windows-service"
Are you looking for the best and cheap ASP.NET 5 hosting [su_button url=”http://asphostportal.com/ASPNET-5-Hosting” style=”stroked” background=”#eab912″]Click Here[/su_button]
Configure and Start the Server and ASP.NET
Let’s add some namespaces:
1 2 3 4 5 6 7 8 9 10 | using Microsoft.AspNet.Builder; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting.Internal; using Microsoft.Framework.Configuration; using Microsoft.Framework.Configuration.Memory; using Microsoft.Framework.DependencyInjection; using System; using System.Diagnostics; using System.Linq; using System.ServiceProcess; |
Before we start the server, we need to set up a few fields and a constructor on the Program
class. We need to store the hosting engine, its shutdown function and a service provider that we will use soon. The IServiceProvider
instance will be injected by the DNX runtime.
1 2 3 4 5 6 7 8 | private readonly IServiceProvider _serviceProvider; private IHostingEngine _hostingEngine; private IDisposable _shutdownServerDisposable; public Program(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } |
To get the server up and running, we will use the WebHostBuilder
class. Your Program.OnStart
method should look as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | protected override void OnStart(string[] args) { var configSource = new MemoryConfigurationSource(); configSource.Add("server.urls", "http://localhost:5000"); var config = new ConfigurationBuilder(configSource).Build(); var builder = new WebHostBuilder(_serviceProvider, config); builder.UseServer("Microsoft.AspNet.Server.Kestrel"); builder.UseServices(services => services.AddMvc()); builder.UseStartup(appBuilder => { appBuilder.UseDefaultFiles(); appBuilder.UseStaticFiles(); appBuilder.UseMvc(); }); _hostingEngine = builder.Build(); _shutdownServerDisposable = _hostingEngine.Start(); } |
There are several steps involved here:
- Create and populate the server configuration. (lines 3-6)
- Create the builder and tell it what server implementation to use. (lines 7-8)
- Configure services using the built-in dependecy injection support. (line 9)
- Configure the ASP.NET middleware pipeline. (lines 10-15)
- Build and start the server. (lines 17-18)
The previous code is oversimplified for the purposes of this article. We are hardcoding the server URL into an in memory config store, but you can set this up in other ways.
To gracefully shut down the server, implement Program.OnStop
as follows:
1 2 3 4 5 | protected override void OnStop() { if (_shutdownServerDisposable != null) _shutdownServerDisposable.Dispose(); } |
Getting Down to Business
Now that we have a server set up and running ASP.NET with static files and MVC, let’s add some content and a controller.
First, create an index.html
file and add “Hello world” as the content. Then create a controller file TimeController.cs
with the file contents as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | using Microsoft.AspNet.Mvc; using System; namespace MyDnxService { public class TimeController { [Route("time")] public DateTime GetTime() { return DateTime.Now; } } } |
That’s all there is to it. Now we can pull up http://localhost:5000
to see “Hello world” and http://localhost:5000/time
to see the current time.
The Runtime User and Going to Production
When you install a Windows service, you have to specify a user under which to run the process. If you don’t, “Local System” is the default. Why is this important? If we try to do the same thing in this case, the service will quickly fail to start because “Local System” won’t be able to resolve any of the package dependencies we just added.
As you add package references to the project.json
file, Visual Studio quietly runs dnu restore
in the background and downloads the packages to your user profile (c:\users\<username>\.dnx\packages
). When you run dnx.exe
, it will resolve any dependencies from your user profile. (You’ll see how to override this in a bit.)
Since “Local System” doesn’t have Visual Studio helping it out, we need to somehow get those packages installed someplace that it can see. Running dnu restore
as “Local System” will download the packages to c:\Windows\SysWOW64\config\systemprofile\.dnx\packages
(on the 64-bit OS) since there’s no user profile for that account. How can you run dnu restore
as “Local System”? This can be done by running psexec.exe -s cmd.exe
from Sysinternals (runs a cmd.exe
console as “Local System”) and then running dnu restore
from the directory of your project. You can imagine that having to do this each time you want to deploy is a gigantic inconvenience.
While you’re IN DEVELOPMENT, you should run the Windows service under your own account. This allows you to install the service once and not have to manually run dnu restore
under another account each time you modify your config (remember, Visual Studio is helping you out here). The service will be able to resolve the dependencies since it’s running under your account as well.
IN PRODUCTION, we can publish our project by running the following command (from the project’s root folder) and point the sc.exe create binPath=
to its output:
dnu publish --out ..\publish-output --runtime active --no-source
This command builds and packages your code and copies it and all of its dependencies into an output folder. It will also add a global.json
file in a sub-folder within the output directory that tells DNX to load the packages from the local folder and not the user’s profile. If that’s not enough, the command also packages the “active” DNX runtime. This means that the target machine doesn’t require DNX to be installed and doesn’t require you to run dnu restore
on the target machine either. With this method, once you copy the published folder to the production machine, you can run the service under the account of your choosing and point to the run.cmd
file within the root of the output folder.
sc.exe create <service-name> obj= <machine|domain>\<username> binPath= "\"<output-
folder-path>\run.cmd\" --windows-service"
Now you have what you need to run ASP.NET in a Windows service in both development and production environments.
Get the Source
The source code and installation scripts for this article can be found in the aspnet-windows-service Github repo.
Conclusion
We can finally run ASP.NET in our Windows services. This is a big win for us as we host an admin site for our scheduler out of a Windows service. We currently do this using a custom-built static file server and WCF for web services.
There was a lot of information covered in this article, and there is still a lot more that could be covered. If you liked this article or have any questions, please feel free to leave a comment below. Thanks, and I hope you have enjoyed this post.