Skip to content

bdcoder2/rmp

Repository files navigation

Routemap pages (rmp) for .NET websites WITHOUT MVC, Razor or Blazor

An experiment in which we build a website using routemap attributes for website API and/or page endpoints. The goals being:

  1. No need to use MVC, Razor or Blazor UI frameworks.
  2. Reduce the overhead required for simple websites (since no framework must be loaded)
  3. Simplify and reduce the code required for simple websites.
  4. Easy to understand.

The [routemap] attribute

One or more [routemap] attributes are placed above any method in a static or instance class that can process an HTTP request. Each routemap pattern must be unique. If a duplicate routemap pattern is detected an exception will be thrown.

Syntax

    [routemap( "{route-pattern}", [http_methods], [order] )]

Parameters

route-pattern

Required. The route-pattern defines an endpoint. An endpoint is something that can be selected, by matching the URL and HTTP method(s) provided. A route-pattern may contain any number of route-constraints.

http_methods

Optional. Used to indicate the allowed HTTP methods for the given route-pattern. Valid HTTP method verbs are:

  • routemap.http_methods.CONNECT
  • routemap.http_methods.DELETE
  • routemap.http_methods.GET
  • routemap.http_methods.HEAD
  • routemap.http_methods.OPTIONS
  • routemap.http_methods.POST
  • routemap.http_methods.PUT
  • routemap.http_methods.TRACE
  • routemap.http_methods.PATCH

If no methods are provided, then the HTTP GET and POST methods are used by default. Multiple HTTP methods can be specified by using the logical OR operator (|) between method verbs, for example, to allow the GET or DELETE methods:

routemap.http_methods.GET | routemap.http_methods.DELETE

order

Optional. The order for this routemap. May be any value greater than or equal to zero. Default is zero. A lower value will have higher priority.

Examples

  • Match the URL /do_get for HTTP GET requests only:
   [routemap( "/do_get", routemap.http_methods.GET )]
  • Match the URL /do_delete for HTTP DELETE requests only:
   [routemap( "/do_delete", routemap.http_methods.DELETE )]
  • Match the URL /do_something for HTTP GET, POST and HEAD requests:
   [routemap( "/do_something", routemap.http_methods.GET | routemap.http_methods.POST | routemap.http_methods.HEAD )]
  • Matches the URLs such as /product/ or /product/123 for HTTP GET and POST requests. The {id:int?} segment, indicates an optional integer can be supplied after the /product/ segment:
   [routemap( "/product/{id:int?}/" )]
  • Matches the URLs such as /widget/ or /widget/val1/val2/val3 for HTTP GET requests. The {*queryvalues} segment, with the leading asterisk indicates that this is a wildcard parameter that can accept any additional segments in it:
   [routemap( "/widget/{*queryvalues}", routemap.http_methods.GET )]
  • Matches the URL /api/v1/test for HTTP GET and POST requests. The api_test_v2 method will be executed because the order has a lower value than the api_test method.
   [routemap( "/api/v1/test", order: 1 )]
   public static async Task api_test_v2( HttpContext context ) { ... }

   [routemap( "/api/v1/test", order: 2 )]
   public static async Task api_test( HttpContext context ) { ... }

Usage

  1. Create an empty .Net website project and include the file rpm.cs from this repository in your project (or simply clone this respository). For example, the class "my_pages" shown below contains two two methods "page1_render" and
    "page2_render", each of which handles HTTP requests.

     using rmp;
    
     public class my_pages
     {
       
        private Int32 m_page1_render_count;
        private Int32 m_page2_render_count;
    
        // A default constructor is required when using [routemap] attributes
        // in a non-static class ...
    
        public my_pages()
        {
    
           m_page1_render_count = 0;
    
           m_page2_render_count = 0;
    
        }
    
    
        [routemap( "/" ) ]
        [routemap( "/page1")]
        private async Task page1_render( HttpContext http_context )
        {
    
           m_page1_render_count++;
    
           await http_context.Response.WriteAsync( $@"Page 1, render count: {m_page1_render_count}" );
    
           return;
    
        }
    
        [routemap( "/page2" ) ]
        private async Task page2_render( HttpContext http_context )
        {
    
           m_page2_render_count++;
    
           await http_context.Response.WriteAsync( $@"Page 2, render count: {m_page2_render_count}" );
    
           return;
    
        }
    
     }
    
  2. Add the routemap pages service and middleware as shown in the example below:

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    using rmp;
    using System.Threading.Tasks;
    using System;
    
    namespace mywebsite
    {
    
       public class Program
       {
    
          private static Microsoft.AspNetCore.Builder.WebApplication web_app;
    
          public static async Task Main( String[] args )
          {
    
             try
             {
    
                web_app = web_app_create( args );
    
             }
             catch ( Exception ex )
             {
    
                web_app = null;
    
                Console.WriteLine( ex.ToString() );
    
             }
    
             if ( web_app is not null )
             {
    
                await web_app.RunAsync();
    
             }
    
          }
    
          private static Microsoft.AspNetCore.Builder.WebApplication web_app_create( String[] args )
          {
    
             Microsoft.AspNetCore.Builder.WebApplicationOptions web_app_options;
    
             Microsoft.AspNetCore.Builder.WebApplicationBuilder web_app_builder;
    
             Microsoft.AspNetCore.Builder.WebApplication web_app;
    
    
             // Set web app options and create web app builder ...
    
             web_app_options = new WebApplicationOptions()
             {
    
                Args = args,
    
             };
    
    
             web_app_builder = WebApplication.CreateBuilder( web_app_options );
    
             services_configure( web_app_builder );
    
    
             web_app = web_app_builder.Build();
    
             middleware_configure( web_app );
    
    
             return web_app;
    
          }
    
          private static void middleware_configure( WebApplication app )
          {
    
             app.UseRouting();
    
             app.use_rmp();
    
          }
    
          private static void services_configure( WebApplicationBuilder builder )
          {
    
             builder.Services.add_rmp();
    
          }
    
       }
    
    }
    
    
  3. Build and launch the website. The [routemap] patterns defined will be mapped to the appropriate handler, for example:

    • / => will invoke the my_pages.page1_render method
    • /page1 => will invoke the my_pages.page1_render method
    • /page2 => will invoke the my_pages.page2_render method

About

Using routemap attributes for website endpoints WITHOUT the need of MVC or Razor.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published