public void SimpleSpeedTest( int requestCount ) { ServicePointManager.UseNagleAlgorithm = false; ServicePointManager.DefaultConnectionLimit = int.MaxValue; var nanoConfiguration = new NanoConfiguration(); nanoConfiguration.AddDirectory( "/", "www" ); using( HttpListenerNanoServer.Start( nanoConfiguration, "http://localhost:4545" ) ) { var stopwatch = Stopwatch.StartNew(); Parallel.For( 0, requestCount, i => { using( var client = new WebClient() ) { byte[] responsebytes = client.DownloadData( "http://localhost:4545/" ); string responsebody = Encoding.UTF8.GetString( responsebytes ); if( requestCount == 1 ) Trace.WriteLine( responsebody ); } } ); var elapsedTime = stopwatch.Elapsed; Trace.WriteLine( string.Format( "{0} requests completed in {1}", requestCount, elapsedTime.GetFormattedTime() ) ); var averageRequestTimeInMilliseconds = elapsedTime.TotalMilliseconds / requestCount; var averageRequestTimeSpan = TimeSpan.FromTicks( (long)( TimeSpan.TicksPerMillisecond * averageRequestTimeInMilliseconds ) ); Trace.WriteLine( string.Format( "Average request time: {0}", averageRequestTimeSpan.GetFormattedTime() ) ); } }
private static void Main( string[] args ) { const string url = "http://localhost:4545"; var exitEvent = new ManualResetEvent( false ); Console.CancelKeyPress += ( sender, eventArgs ) => { eventArgs.Cancel = true; exitEvent.Set(); }; var config = new NanoConfiguration(); config.AddDirectory( "/", "www", null, true ); config.AddMethods<Customer>( "/api/customer/" ); config.AddFunc( "/hi", context => "Hello World!" ); config.AddBackgroundTask( "Test", 30000, () => { string result = "Hi, the time is now: " + DateTime.Now; Console.WriteLine( result ); return result; } ); using ( HttpListenerNanoServer.Start( config, url ) ) { if ( Debugger.IsAttached ) Process.Start( url + "/ApiExplorer/" ); Console.WriteLine( "Nano Server is running on: " + url ); Console.WriteLine( "Press Ctrl+C to exit." ); exitEvent.WaitOne(); } }
public void SimpleSpeedTest(int requestCount) { ServicePointManager.UseNagleAlgorithm = false; ServicePointManager.DefaultConnectionLimit = int.MaxValue; var nanoConfiguration = new NanoConfiguration(); nanoConfiguration.AddDirectory("/", "www"); using (HttpListenerNanoServer.Start(nanoConfiguration, "http://localhost:4545")) { var stopwatch = Stopwatch.StartNew(); Parallel.For(0, requestCount, i => { using (var client = new WebClient()) { byte[] responsebytes = client.DownloadData("http://localhost:4545/"); string responsebody = Encoding.UTF8.GetString(responsebytes); if (requestCount == 1) { Trace.WriteLine(responsebody); } } }); var elapsedTime = stopwatch.Elapsed; Trace.WriteLine(string.Format("{0} requests completed in {1}", requestCount, elapsedTime.GetFormattedTime())); var averageRequestTimeInMilliseconds = elapsedTime.TotalMilliseconds / requestCount; var averageRequestTimeSpan = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * averageRequestTimeInMilliseconds)); Trace.WriteLine(string.Format("Average request time: {0}", averageRequestTimeSpan.GetFormattedTime())); } }
public void Start(string urls) { var validatedUrls = ValidateUrls(urls); var config = new NanoConfiguration(); // When the Debugger is attached, map two folders up so that you can live edit files in Visual Studio without having to restart // your application to get the files copied to your bin directory. config.AddDirectory("/", Debugger.IsAttached ? "../../www" : "www", returnHttp404WhenFileWasNotFound: true); config.AddMethods <Customer>("/api/customer/"); config.AddFunc("/hi", context => "Hello World!"); config.GlobalEventHandler.UnhandledExceptionHandlers.Add((exception, context) => { try { if (!EventLog.SourceExists(_applicationName)) { EventLog.CreateEventSource(_applicationName, "Application"); } var msg = new StringBuilder() .AppendLine("Nano Error:") .AppendLine("-----------").AppendLine() .AppendLine("URL: " + context.Request.Url).AppendLine() .AppendLine("Message: " + exception.Message).AppendLine() .AppendLine("StackTrace:") .AppendLine(exception.StackTrace) .ToString(); EventLog.WriteEntry(_applicationName, msg, EventLogEntryType.Error); } catch (Exception) { // Gulp: Never throw an exception in the unhandled exception handler } }); _server = HttpListenerNanoServer.Start(config, validatedUrls); _server.HttpListenerConfiguration.ApplicationPath = "YourOptionalVirtualAppPathName"; if (Debugger.IsAttached) { Process.Start(_server.HttpListenerConfiguration.GetFirstUrlBeingListenedOn().TrimEnd('/') + "/ApiExplorer"); } Console.WriteLine("Nano Server is running on: " + _server.HttpListenerConfiguration.GetFirstUrlBeingListenedOn()); }
public static void Start( HttpApplication httpApplication ) { var config = new NanoConfiguration(); config.GlobalEventHandler.PreInvokeHandlers.Add( context => { } ); config.GlobalEventHandler.UnhandledExceptionHandlers.Add((exception, context) => { }); var eventHandler = new EventHandler(); eventHandler.PreInvokeHandlers.Add( context => { } ); eventHandler.PostInvokeHandlers.Add( context => { } ); eventHandler.UnhandledExceptionHandlers.Add( ( exception, context ) => { } ); config.AddMethods<Customer>(); // methods will be added under '/api/customer/' config.AddMethods<Customer2>(); config.AddFile( "/home", @"\www\home\index.html" ); config.AddFunc( "/hi", x => "Hello World! " + x.Request.Url ); config.AddFunc( "/howdy", x => { var model = x.Bind<Person>( "person" ); // Looks for a complex request parameter named 'person' to bind to a 'Person' class return model; } ); config.EnableCors(); config.AddFunc( "/probe", context => true ); config.AddFunc( "/monitoring/probe", context => true ); config.AddDirectory( "/", @"\www\" ); SystemWebNanoServer.Start( httpApplication, config ); }
public WebServer(IAppSettings appSettings) { var port = GetUnusedPort(); baseUrl = $"http://localhost:{port}"; nano = new NanoConfiguration { ApplicationName = "Turbine", EnableVerboseErrors = appSettings.Verbose, }; // logging if (appSettings.Verbose) { nano.GlobalEventHandler.PostInvokeHandlers.Add(context => { var address = context.Request.Url.ToString().Replace(baseUrl, "/").Replace("//", "/"); var statusName = Enum.GetName(typeof(Constants.HttpStatusCode), context.Response.HttpStatusCode); Colorizer.WriteLine($"WebServer: [DarkYellow!{address} => {context.Response.HttpStatusCode} {statusName}]"); }); } nano.GlobalEventHandler.UnhandledExceptionHandlers.Add((exception, context) => { var address = context.Request.Url.ToString().Replace(baseUrl, "/").Replace("//", "/"); Colorizer.WriteLine($"WebServer: [DarkRed!{address} => Exception: {exception.Message}]"); }); // pulse var startTime = DateTime.Now; if (appSettings.Verbose) { nano.AddBackgroundTask("Uptime", (int)TimeSpan.FromMinutes(1).TotalMilliseconds, () => { var uptime = DateTime.Now - startTime; Colorizer.WriteLine($"WebServer: [DarkYellow!Uptime {uptime}]"); return(uptime); }); } // hosting nano.AddDirectory("/", appSettings.Output, returnHttp404WhenFileWasNotFound: true); nano.DisableCorrelationId(); nano.EnableCors(); }
public static void Start(HttpApplication httpApplication) { var config = new NanoConfiguration(); config.GlobalEventHandler.PreInvokeHandlers.Add(context => { }); var eventHandler = new EventHandler(); eventHandler.PreInvokeHandlers.Add(context => { }); eventHandler.PostInvokeHandlers.Add(context => { }); eventHandler.UnhandledExceptionHandlers.Add((exception, context) => { }); config.AddMethods <Customer>(); // methods will be added under '/api/customer/' config.AddFile("/home", @"\www\home\index.html"); config.AddFunc("/hi", x => "Hello World! " + x.Request.Url); config.AddFunc("/howdy", x => { var model = x.Bind <Person>("person"); return(model); }); config.EnableCors(); config.AddFunc("/probe", context => true); config.AddFunc("/monitoring/probe", context => true); config.AddDirectory("/", @"\www\"); SystemWebNanoServer.Start(httpApplication, config); }
public void Start( string urls ) { var validatedUrls = ValidateUrls( urls ); var config = new NanoConfiguration(); config.AddDirectory( "/", "www", null, true ); config.AddMethods<Customer>( "/api/customer/" ); config.AddFunc( "/hi", context => "Hello World!" ); config.GlobalEventHandler.UnhandledExceptionHandlers.Add( ( exception, context ) => { try { if ( !EventLog.SourceExists( _applicationName ) ) EventLog.CreateEventSource( _applicationName, "Application" ); var msg = new StringBuilder() .AppendLine( "Nano Error:" ) .AppendLine( "-----------" ).AppendLine() .AppendLine( "URL: " + context.Request.Url ).AppendLine() .AppendLine( "Message: " + exception.Message ).AppendLine() .AppendLine( "StackTrace:" ) .AppendLine( exception.StackTrace ) .ToString(); EventLog.WriteEntry( _applicationName, msg, EventLogEntryType.Error ); } catch ( Exception ) { // Gulp: Never throw an exception in the unhandled exception handler } } ); _server = HttpListenerNanoServer.Start( config, validatedUrls ); _server.HttpListenerConfiguration.ApplicationPath = "YourOptionalVirtualAppPathName"; if( Debugger.IsAttached ) Process.Start( _server.HttpListenerConfiguration.GetFirstUrlBeingListenedOn().TrimEnd( '/' ) + "/ApiExplorer" ); Console.WriteLine( "Nano Server is running on: " + _server.HttpListenerConfiguration.GetFirstUrlBeingListenedOn() ); }
private static void Main(string[] args) { const string url = "http://localhost:4545"; var exitEvent = new ManualResetEvent(false); Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; exitEvent.Set(); }; var config = new NanoConfiguration(); // When the Debugger is attached, map two folders up so that you can live edit files in Visual Studio without having to restart // your application to get the files copied to your bin directory. config.AddDirectory("/", Debugger.IsAttached ? "../../www" : "www", returnHttp404WhenFileWasNotFound: true); config.AddMethods <Customer>("/api/customer/"); config.AddFunc("/hi", context => "Hello World!"); config.AddBackgroundTask("Test", 30000, () => { string result = "Hi, the time is now: " + DateTime.Now; Console.WriteLine(result); return(result); }); using (HttpListenerNanoServer.Start(config, url)) { if (Debugger.IsAttached) { Process.Start(url + "/ApiExplorer/"); } Console.WriteLine("Nano Server is running on: " + url); Console.WriteLine("Press Ctrl+C to exit."); Console.WriteLine(config.ToString()); exitEvent.WaitOne(); } }
private static void Main( string[] args ) { const string url = "http://localhost:4545"; var exitEvent = new ManualResetEvent( false ); Console.CancelKeyPress += ( sender, eventArgs ) => { eventArgs.Cancel = true; exitEvent.Set(); }; var config = new NanoConfiguration(); // When the Debugger is attached, map two folders up so that you can live edit files in Visual Studio without having to restart // your application to get the files copied to your bin directory. config.AddDirectory( "/", Debugger.IsAttached ? "../../www" : "www", returnHttp404WhenFileWasNotFound: true ); config.AddMethods<Customer>(); config.AddMethods<Customer2>(); config.AddFunc( "/hi", context => "Hello World!" ); config.AddBackgroundTask( "Test", 30000, () => { string result = "Hi, the time is now: " + DateTime.Now; Console.WriteLine( result ); return result; } ); using ( HttpListenerNanoServer.Start( config, url ) ) { if ( Debugger.IsAttached ) Process.Start( url + "/ApiExplorer/" ); Console.WriteLine( "Nano Server is running on: " + url ); Console.WriteLine( "Press Ctrl+C to exit." ); Console.WriteLine( config.ToString() ); exitEvent.WaitOne(); } }
/// <summary> /// Gets the <see cref="NanoConfiguration"/> used by all of the demo projects. /// </summary> /// <returns><see cref="NanoConfiguration"/> instance.</returns> public static NanoConfiguration GetNanoConfiguration() { DateTime startupDateTime = DateTime.Now; int requestCounter = 0; int errorCounter = 0; // Every Nano app begins with the creation of an instance of a NanoConfiguration. // This is *the* entry point into Nano and how all of Nano is configured. var config = new NanoConfiguration(); config.GlobalEventHandler.UnhandledExceptionHandlers.Add((exception, context) => { // Log your exception here, etc. Interlocked.Increment(ref errorCounter); }); config.GlobalEventHandler.PreInvokeHandlers.Add(context => { // Do stuff before an API method is called or file is accessed. // Examples: Logging requests, authentication, authorization, adding headers, starting timers, etc. Interlocked.Increment(ref requestCounter); }); config.GlobalEventHandler.PostInvokeHandlers.Add(context => { // Do stuff after an API method is called or file has been accessed. // Examples: Logging responses, writing cookies, adding headers, ending timers, etc. }); // Serves up all methods in the Customer class under the URL: /api/customer/methodName config.AddMethods <Customer>(); config.AddMethods <ComplexObject>(); // We can also create event handlers that are not global. // This can be useful when certain APIs do or do not need logging, authentication, etc. var eventHandler = new Nano.Web.Core.EventHandler(); // Let's add a custom header as a demonstration. eventHandler.PreInvokeHandlers.Add(context => { context.Response.HeaderParameters.Add("X-Server-HostName", Dns.GetHostName()); }); // Add all static methods in the Time class as well as use custom event handler config.AddMethods <Time>(eventHandler: eventHandler); // Handles all requests for URL: /hi config.AddFunc("/hi", context => "Hello World!"); // Handles all requests for URL: /howdy // Example: http://localhost:4545/howdy?person={"PersonId":1,"FirstName":"Clark","LastName":"Kent"} config.AddFunc("/howdy", x => { // Looks for a complex request parameter named 'person' to bind to a 'Person' class var model = x.Bind <Customer.Person>("person"); return(model); }); // Example of how to serve up a single file. It's much easier to map an entire directory though. config.AddFile("/MultipartTester", @"\www\MultipartTester\index.html"); // When the Debugger is attached, map two folders up so that you can live edit files in Visual Studio // without having to restart your application to get the files copied to your bin directory. config.AddDirectory("/", Debugger.IsAttached ? "../../www" : "www", returnHttp404WhenFileWasNotFound: true); // Enables CORS ( Cross-origin resource sharing ) requests config.EnableCors(); // Configures a background task to run every 30 seconds that outputs some server stats like uptime and // the number of processed requests and errors encountered. config.AddBackgroundTask("Status Update", 30000, () => { var result = string.Format("Uptime {0:dd\\.hh\\:mm\\:ss} | Requests Handled: {1} | Errors: {2}", DateTime.Now - startupDateTime, requestCounter, errorCounter); Console.WriteLine(result); return(result); }); return(config); }
public static void Init(NanoConfiguration nano, string webRoot) { Log.Information("wwwRoot: {webRoot}", webRoot); nano.AddDirectory("/", webRoot, returnHttp404WhenFileWasNotFound: true); }
public void Start(string url) { #region NanoSetup var exitEvent = new ManualResetEvent(false); Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; exitEvent.Set(); }; var validatedUrls = ValidateUrls(url); var config = new NanoConfiguration(); config.EnableCorrelationId(); config.AddDirectory("/", Debugger.IsAttached ? "../../www" : "www", returnHttp404WhenFileWasNotFound: true); #endregion //you will need to provide a connection string in your app.config for this to produce any events. //constructor will set default hardcoded values, you can then override any of those values here ( below values listed are the default values ) var spokeConfig = new Spoke.SpokeConfiguration { DefaultAbortAfterMinutes = 60, LiveRetryAbortAfterMinutes = 60, EventProcessingMutexTimeToLiveMinutes = 2, EventSubscriptionMutexTimeToLiveMinutes = 2, FailedEventsLookbackMinutes = 1440, FailedEventsThresholdMinutes = 60, FailedNotificationsThresholdMinutes = 60, MutexAcquisitionWaitTime = 1, ClockBackfillTotalMinutes = 10, ClockBackfillOffsetMinutes = 2, ClockBackfillMutexTimeToLiveMinutes = 2, ClockSleepMilliseconds = 10000, SendClockMessages = true, AppName = $"{Environment.MachineName}-{AppDomain.CurrentDomain.FriendlyName}", UserName = WindowsIdentity.GetCurrent()?.Name, GetApiUri = x => x.Uri, WasApiCallSuccessfulHandlers = new Dictionary <string, Func <Spoke.Models.WasApiCallSuccessfulInput, bool> > { { "DEFAULT", response => response.HttpResponse.Exception == null && response.HttpResponse.Response != null && response.HttpResponse.Response.StatusCode == HttpStatusCode.OK } }, JsonSerializer = new Spoke.Utils.JsonSerializer(), Database = () => new Spoke.DatabaseIO.SpokeSqlDatabase(), DatabaseConnectionString = () => ConfigurationManager.ConnectionStrings["spoke"].ConnectionString, SchemaName = "Spoke" }; //you can add support for "service types" by adding WasApiCallSuccessfulHandlers instead of the default. spokeConfig.WasApiCallSuccessfulHandlers.Add( "OTHER_SERVICE_TYPE", //the key for the new service type response => response.HttpResponse.Exception == null //func to evaluate if the service call was successful or not. ); var spoke = new Spoke(spokeConfig); spoke.Start(); config.AddMethods <Spoke.ExternalApi>("/Api/Events"); config.AddMethods <Spoke.InternalApi>("/Api/Events/Internal"); #region NanoSetup config.AddBackgroundTask("GCCollect", 30000, () => { GC.Collect(); return(null); }); config.GlobalEventHandler.UnhandledExceptionHandlers.Add((exception, context) => { try { if (!EventLog.SourceExists(_applicationName)) { EventLog.CreateEventSource(_applicationName, "Application"); } var msg = new StringBuilder() .AppendLine("Nano Error:") .AppendLine("-----------").AppendLine() .AppendLine("URL: " + context.Request.Url).AppendLine() .AppendLine("Message: " + exception.Message).AppendLine() .AppendLine("StackTrace:") .AppendLine(exception.StackTrace) .ToString(); EventLog.WriteEntry(_applicationName, msg, EventLogEntryType.Error); } catch (Exception) { // Gulp: Never throw an exception in the unhandled exception handler } }); _server = HttpListenerNanoServer.Start(config, validatedUrls); if (Debugger.IsAttached) { Process.Start(_server.HttpListenerConfiguration.GetFirstUrlBeingListenedOn().TrimEnd('/') + "/ApiExplorer/"); } Console.WriteLine("Nano Server is running on: " + _server.HttpListenerConfiguration.GetFirstUrlBeingListenedOn()); #endregion }
/// <summary> /// Gets the <see cref="NanoConfiguration"/> used by all of the demo projects. /// </summary> /// <returns><see cref="NanoConfiguration"/> instance.</returns> public static NanoConfiguration GetNanoConfiguration() { DateTime startupDateTime = DateTime.Now; int requestCounter = 0; int errorCounter = 0; // Every Nano app begins with the creation of an instance of a NanoConfiguration. // This is *the* entry point into Nano and how all of Nano is configured. var config = new NanoConfiguration(); config.GlobalEventHandler.UnhandledExceptionHandlers.Add((exception, context) => { // Log your exception here, etc. Interlocked.Increment(ref errorCounter); }); config.GlobalEventHandler.PreInvokeHandlers.Add(context => { // Do stuff before an API method is called or file is accessed. // Examples: Logging requests, authentication, authorization, adding headers, starting timers, etc. Interlocked.Increment(ref requestCounter); }); config.GlobalEventHandler.PostInvokeHandlers.Add(context => { // Do stuff after an API method is called or file has been accessed. // Examples: Logging responses, writing cookies, adding headers, ending timers, etc. }); // Serves up all methods in the Customer class under the URL: /api/customer/methodName config.AddMethods<Customer>(); // We can also create event handlers that are not global. // This can be useful when certain APIs do or do not need logging, authentication, etc. var eventHandler = new Nano.Web.Core.EventHandler(); // Let's add a custom header as a demonstration. eventHandler.PreInvokeHandlers.Add( context => { context.Response.HeaderParameters.Add( "X-Server-HostName", Dns.GetHostName() ); }); // Add all static methods in the Time class as well as use custom event handler config.AddMethods<Time>( eventHandler: eventHandler ); // Handles all requests for URL: /hi config.AddFunc("/hi", context => "Hello World!"); // Handles all requests for URL: /howdy // Example: http://localhost:4545/howdy?person={"PersonId":1,"FirstName":"Clark","LastName":"Kent"} config.AddFunc("/howdy", x => { // Looks for a complex request parameter named 'person' to bind to a 'Person' class var model = x.Bind<Customer.Person>("person"); return model; }); // Example of how to serve up a single file. It's much easier to map an entire directory though. config.AddFile( "/MultipartTester", @"\www\MultipartTester\index.html" ); // When the Debugger is attached, map two folders up so that you can live edit files in Visual Studio // without having to restart your application to get the files copied to your bin directory. config.AddDirectory("/", Debugger.IsAttached ? "../../www" : "www", returnHttp404WhenFileWasNotFound: true); // Enables CORS ( Cross-origin resource sharing ) requests config.EnableCors(); // Configures a background task to run every 30 seconds that outputs some server stats like uptime and // the number of processed requests and errors encountered. config.AddBackgroundTask("Status Update", 30000, () => { var result = string.Format("Uptime {0:dd\\.hh\\:mm\\:ss} | Requests Handled: {1} | Errors: {2}", DateTime.Now - startupDateTime, requestCounter, errorCounter); Console.WriteLine(result); return result; }); return config; }