This project was created with AVR for .NET 14.x (for use with Visual Studio 2015) but will work as-is with AVR 15.x (for use with Visual Studio 2017). It may work with lower AVR for .NET versions but has not been tested with them.
Several years ago, Microsoft provided its Web API facility for .NET. This Web API makes it easy to create RESTful services with C# and VB.NET. This AVR for NET project provides a subset of MS's Web API—intended specifically for AVR. You can copy this project and use it as the basis for a new project or you can open it and then save it as a template for new projects. See this article on ASNA.com for instructions on how to save an AVR project as a new project template.
In many cases, RESTful services return Json data. Json data is generally fetched with JavaScript and used to dynamically populate a Web page--but it is also used as a data transfer format business-to-business services. When used to populate a page, that resulting Json may be used to populate an autocomplete lookup or a custom grid element like DataTables or Tabulator.
This AVR for .NET ASP.NET RESTful template lets you quickly scaffold up an ASP.NET program that has :
- ASP.NET page routing
- Json API routing
- RESTful API endpoints that return Json results
- Bootstrap 4 CSS framework
- jQuery JavaScript library
- FontAwesome icons
jQuery is included because Bootstrap 4 needs it. There was a time when jQuery was indespensible. For most cases today it's no longer necessary. Even though this example includes jQuery, it's included only because some of the BootStap 4 components need it (a decision BS4 eecision-makers probably rue now). It's best to try to avoid using jQuery in your code. See this site for tips on how to avoid needing jQuery.
This template includes two external DLLs:
- ASNA.JsonRestRouting.dll — this provides the routing engine for REST web APIs and it provides a base controller that converts its methods to Json.
- Newtonsoft.Json.dll — this is a free .NET DLL that converts objects to Json. This is a very popular .NET DLL, its been downloaded more than 149 million times and is the defacto standard for Json work in .NET. If you're doing any Json work with AVR, this DLL is highly recommended. The Newtonsoft DLL was discussed in this ASNA.com article. Although this template includes the Newtonsoft.Json.dll, it may not be the latest version available. Consider downloading your own fresh copy of this DLL.
This text doesn't attempt to explain REST and routing. Rather it assumes some familiarity with REST and routing and its purpose is to show how to quickly get started using the template.
You can read more about ASP.NET routing here:
- MS article on using ASP.NET routing with Web forms
- An AVR-centric article that discusses using ASP.NET routing
You can read more about Json here:
The web is full of articles and blog posts about REST. Here are a few to get you started:
This template is intended to serve as a jumping off place for you to build your own web sites and APIs. To use the template, start a new AVR for .NET ASP.NET project selecting the AVR for .NET ASP.NET RESTful template (as shown below).
When you run the template, it first shows the home page shown below in Figure 1a.

Figure 1a. The RESTful template's home page.
Notice the URL in the browser doesn't include an ASPX page, even though the views/index.aspx page is being shown. ASPX page routing done by the built-in ASP.NET routing engine. We'll take a look at that configuration in a minute.
Clicking on the api/customers/345 link shows the Json that represents a single customer as shown below in Figure 1b.

Figure 1b. Raw Json API output showing a single customer
Clicking on the api/customers link shows the Json that represents a list of customers as shown below in Figure 1c.

Figure 1c. Raw Json API output showing a list of customers
The raw Json output from a web API is emitted from a method you provided. The ASNA.JsonRestRouting DLL provides the URL routing necessary to invoke that method. The output of a Json API is rarely, if ever, displayed in this raw fashion. It's usually consumed by JavaScript (and maybe a JavaScript library or control to dynamically populate a part of a page with Ajax.
Routes are configured in the Global.asax.vr source file. It includes two namespace directives to be able to use then System.Web.Routing and the ASNA.JsonRestRouting namespaces. The full source for Global.asax.vr is shown below in Figure 2.
<%@ Application Language="AVR" %>
<%@ Import namespace="System.Web.Routing" %>
<%@ Import namespace="ASNA.JsonRestRouting" %>
<script runat="server">
BegSr Application_Start
DclSrParm sender Type(*Object)
DclSrParm e Type(EventArgs)
// Code that runs on application startup.
RegisterRoutes(RouteTable.Routes)
EndSr
BegSr RegisterRoutes
DclSrParm routes Type(RouteCollection)
DclFld restRouter Type(ASNA.JsonRestRouting.Router)
restRouter = *New ASNA.JsonRestRouting.Router(routes)
// ASPX page routes.
// This support is provided directly by MS .NET.
routes.MapPageRoute("home", "", "~/views/index.aspx")
// Add as many routes here as needed.
// This support is provided by the ASNA.JsonRestRouting.Router.
RestRouter.Get("api/customers/{id}", "ShowAction", *TypeOf(CustomerController))
RestRouter.Get("api/customers", "ListAction", *TypeOf(CustomerController))
EndSr
</script>
Figure 2. The Global.asax.vr file is where routes are registered.
To ensure no URL is used as ASP.NET's start page when running your app from inside Visual Studio, be sure to set the Specific page to an empty string in your project's Property Pages as shown below in Figure 3. This ensure the home route configured in Figure2's code is invoked.

Figure 3. Setting your project's start page to an empty string to invoke the home route.
The RegisterRoutes method is called in Global.asax.vr's Application_Start event handler. This registers the application routes for all users of the app. The line below in RegisterRoutesuses the routesobject (made available from System.Web.Routing) to define routes for ASPX pages.
routes.MapPageRoute("home", "", "~/views/index.aspx")
It names the route home, specifies its URL (in this case an empty string), and the page to show when that route is entered into the browser. Generally, you'd use a line like this to route to your app's home page. You'll register your app's ASPX pages here. For example, you may use this line to routine to a sales listing page:
routes.MapPageRoute("sales", "sales-listing", "~/views/sales-listing.aspx")
Routing ASPX pages like isn't necessary to use the RESTful API, but it keeps the ASPX URLs consistent with the API URLs. If this consistency isn't important or if there isn't any value in mapping rational URLs to your ASPX pages you can skip the processing of mapping ASPX pages. You can also map selected ASPX pages (highly used pages, for examples) and leave others alone.
The RESTful template provides a
viewsfolder for you to put your ASPX pages in. There isn't a functional reason for this—but it keeps the root of the web site clean. With this route, thesales-listingURL would display the sales-listing.aspxpage. You can also specify what are effectively query string values in route definitions. For example, this route:
ASP.NET's routing engine provides a way to pass values to a page. For example,
routes.MapPageRoute("sales", "sales-listing/2018", "~/views/sales-listing.aspx")
displays the sales-listing.aspx page and pass it 2018 as an argument (that can be read like a query string) to govern what sales listing data is displayed. See this article for more on route arguments.
This line in the web.config file registers an API route:
RestRouter.Get("api/customers/{id}", "ShowAction", *TypeOf(CustomerController))
RestRouter is an instance of ASNA.JsonRestRouting.Router. It has methods that correspond to HTTP methods. In this case, the Get method is used to register a method that corresponds to an HTTP GET request. Whenever an HTTP Get request is received coming from the URL specified (the first argument), the method provided (the second argument) in the class provided (the third argument) is called, passing to it any argument values specified in braces.
In this example, the ShowAction method in the CustomerController class is called, passing id to it. Controllers are classes (this template includes the example CustomerController class) . Controllers extend the ASNA.JsonRestRouting.Controller class and provide the code that returns a response to the incoming API request.
The template presented here includes the example controller shown below in Figure 4. Notice its name is CustomContoller and it has a ShowAction method. The route created above passes control to this ShowAction method, passing it the id argument. The names of any arguments provided in the URL must match the parameter names provided in the method.
Using System
// An example controller.
BegClass CustomerController Access(*Public) +
Extends(ASNA.JsonRestRouting.Controller)
// Example ShowAction method.
BegFunc ShowAction Access(*Public) Type(CustomerEntity)
DclSrParm Id Type(*Integer4)
// This method hardcodes a customer lookup.
// In production, you'd use the given Id value
// to look up the exact customer number in a data file
// or some other data store.
DclFld Entity Type(CustomerEntity) New()
Entity.CMCustNo = Convert.ToInt32(id )
Entity.CMName = 'Neil Young'
Entity.CMAddr1 = 'Broken Arrow'
Entity.CMCity = 'Santa Cruz'
Entity.CMState = 'CA'
Entity.CMCntry = 'US'
Entity.CMPostCode = '95603'
Entity.CMPhone = '(831) 205-3345'
Entity.CMFax = 8312053346
Entity.CMActive = '1'
// The ASNA.JsonRestRouting router implicitly maps the return type to Json.
LeaveSr Entity
EndFunc
BegFunc ListAction Access(*Public) Type(CustomerEntity) Rank(1)
DclFld EntityList Type(List(*Of CustomerEntity)) New()
// This method hardcodes customer list creation. In production, you'd loop over rows
// in a file.
DclFld Entity Type(CustomerEntity)
Entity = *New CustomerEntity()
Entity.CMCustNo = 1
Entity.CMName = 'Neil Young'
Entity.CMAddr1 = 'Broken Arrow'
Entity.CMCity = 'Santa Cruz'
Entity.CMState = 'CA'
Entity.CMCntry = 'US'
Entity.CMPostCode = '95603'
Entity.CMPhone = '(831) 205-3345'
Entity.CMFax = 8312053346
Entity.CMActive = '1'
EntityList.Add(Entity)
Entity = *New CustomerEntity()
Entity.CMCustNo = 2
Entity.CMName = 'Warren Zevon'
Entity.CMAddr1 = 'Heaven Lane'
Entity.CMCity = 'Big Sky'
Entity.CMState = 'ET'
Entity.CMCntry = 'US'
Entity.CMPostCode = '00001'
Entity.CMPhone = '(800) 205-3345'
Entity.CMFax = 8002053346
Entity.CMActive = '0'
EntityList.Add(Entity)
Entity = *New CustomerEntity()
Entity.CMCustNo = 3
Entity.CMName = 'Van Morrison'
Entity.CMAddr1 = 'Mystic Avenue'
Entity.CMCity = 'Belfast'
Entity.CMState = 'ET'
Entity.CMCntry = 'Ireland'
Entity.CMPostCode = '234-002'
Entity.CMPhone = '21-465-9123'
Entity.CMFax = 0
Entity.CMActive = '1'
EntityList.Add(Entity)
// The ASNA.JsonRestRouting router implicitly maps the return type to Json.
LeaveSr EntityList.ToArray()
EndFunc
EndClass
// Example entity class.
BegClass CustomerEntity Access(*Public)
DclProp CMCustNo Type(*Integer4) Access(*Public)
DclProp CMName Type(*String) Access(*Public)
DclProp CMAddr1 Type(*String) Access(*Public)
DclProp CMCity Type(*String) Access(*Public)
DclProp CMState Type(*String) Access(*Public)
DclProp CMCntry Type(*String) Access(*Public)
DclProp CMPostCode Type(*String) Access(*Public)
DclProp CMActive Type(*String) Access(*Public)
DclProp CMFax Type(*Packed) Len(9,0) Access(*Public)
DclProp CMPhone Type(*String) Access(*Public)
EndClass
Figure 4. The template's example controller.
In the interest of presenting example code concisely, the controller class's methods shown above in Figure 4 violate an important application design rule called the Single Responsibity Principle. In a production application you don't want logic embedded in a controller method—don't try to make controller methods do too much. Ideally, a repository class would provide the logic for fetching data. The controller's methods should only concern themselves with fetching data from that repository class and returning either the data returned or providing an error condition.
In a controller class that extends ASNA.JsonRestRouting.Controller function return types are implicitly converted to Json (via the Newtonsoft DLL). ShowAction returns an instance of the CustomerEntity class and ListAction returns an array of CustomerEntity instances (both of which is also in Figure 4 above). For example purposes these methods hardcodeCustomerEntity instances; in a production app you'd write code to create these object instances.
C:\Users\roger\Documents\Programming\AVR\Web\RESTful-Template
