AspCoreGen 2.0 Razor Express is a free ASP.NET Core 2.1 Razor Code Generator software. You can download it absolutely free. AspCoreGen 2.0 Razor Express
generates a full solution with 2 projects; An ASP.NET Core 2.1 Razor Web Application project (main application - UI), and a .NET Core 2.1 Class Library Project (business tier, data tier, and shared libraries). The
optional ASP.NET Core 2.1 Web API project can only be generated using the Professional Plus Edition. It generates code by looking at your Microsoft SQL Server Database's tables.
The major objects generated are:
- Razor Pages (.cshtml)
- Razor Page Models (.cshtml.cs)
- Middle-Tier code (class)
- Data Tier code (class)
- Models (class)
- Miscellaneous items
- Items that make up the rest of the Web Application project. E.g. Layout page, helper classes, css, images, javascript, jquery, and a lot more.
Unlike the Professional Plus Edition, the Express Edition is limited. One of the main differences is the later will only generate Unbound Razor Pages, these
are Razor Pages not bound to the database. In the page shown
here, there are 17 generated razor pages, only
1 is generated by the Express Edition (#16, Unbound Pages). Even with this limitation, the amount of code generated is absolutely outstanding. It can generate about a million lines of code in about
a minute depending on the amount of tables you have in the database, and it can do all this in One Click**.
Because the generated code is not connected to the database, this tutorial will show you how to add your own code to connect the generated Razor Pages to the database.
Now that I'm done with my marketing spiel let's get on with the tutorial.
You will need the following things for this tutorial:
- Microsoft Northwind Database (please Google it)
- Microsoft SQL Server 2003 and above (you can also use an Azure SQL)
- You will need an Admin username/password or enough rights in the MS SQL Server. A blank username/password will not work.
- Visual Studio 2017 (the generated code will not work in Visual Studio 2015 and below)
- AspCoreGen 2.0 Razor Express
1. Download AspCoreGen 2.0 Razor Express here:
https://junnark.com/Products/AspCoreGen2Razor/DownloadExpress.
2. Install it. Just follow all the prompts. If you need a tutorial go here:
https://junnark.com/Products/AspCoreGen2Razor/Tutorials/ and click on the Installation Guide link.
3. Open AspCoreGen 2.0 Razor Express, go to the
Database Settings tab and enter the following information shown in the snapshot below.
Note: Use your database's username and password instead of the one's shown below. A blank password will not work.
4. Go to the
Code Settings tab and enter the
Web Application Name, and the
Directory where you want the generated code to be in. You can use the browse button next to the
Directory Box to choose the
directory where you want the code to be generated. You can keep the suggested
Business Layer and Data Layer API (Class Library Project) Name or change it, it's up to you.
5. Click the
Generate Code for All Tables or the
Generate Code for Selected Tables Only button. AspCoreGen 2.0 Razor Express will start generating code and you will see a message once code generation is done.
6. Close (or not) AspCoreGen 2.0 Razor Express. Go to the
Directory you specified and double-click the Solution file (.sln).
7. The solution will open in Visual Studio 2017. The Visual Studio Solution Explorer window shows 2 generated projects in the solution. Run the web application by pressing F5.
8. The home page shows all the major objects that was generated by AspCoreGen 2.0 Razor Express. The black bars represents the separate projects. Below each black bar are categories of
objects (blue bar) generated for that specific project. Clicking the blue bar will toggle visibility of the list of items for that category. Items under the
Pages Folder are Razor Pages (.cshtml) and are clickable to
demonstrate each Razor Page's functionality.
9. Click on one of the web page links, e.g. the
Products/Products_Unbound. You will notice that each field in the Products table are
shown here. Foreign keys are also shown as a Select List web control. There's also validation, for example Product Name here is a
required field. Note: AspCoreGen 2.0 Razor Express generates Unbound Razor Pages, these are Razor Pages that are not bound to a database. Because these Razor Pages are not bound to the database, you will notice that
the Select List for the Supplier ID and Category ID does not have data, and when you click Submit button nothing happens, it will not Insert or Update something in the database.
10. Close the web page and then go back to Visual Studio.
11. Since AspCoreGen 2.0 Razor Express does not generate code that binds razor pages to the database, let's bind the Razor Page to the database by adding
logic to the
Products_Unbound.cshtml.cs file under the
Pages/Products folder. Open the class
ProductsExample.cs under the
CodeExamples folder and then copy the code from
the
Insert method to the
Products_Unbound.cshtml.cs's
OnPostSubmit method.
Note: We will use a Layering approach (3-tier, n-tier), so, the Razor Page (Presentation Layer/Front End) will access the
Products.cs (Business Object), and then the
Product.cs
will access the
ProductsDataLayer.cs (Data Layer) code. The Data Layer code would then access our database (MS SQL).
Products Example Class, Insert Method
Products_Unbound Razor Page Model (Products_Unbound.cshtml.cs) - OnPostSubmit() Method
12. Copy Insert Example code to the Page Model's OnPostSubmit() method as shown below.
a. Copy this code:
b. Here:
13. Update the sample values to the
Products property bound by the Razor Page. The highlighted code
below accesses the Products's
Insert (Business Object) method. In short, the
Page Model which is a part of the
Front End accesses the
Middle Layer (Business Object).
*** Quick Note: You probably noticed that we're using some fields with a suffix "Hidden" above, such as UnitsInStockHidden, or ReorderLevelHidden. For the sake of continuing the flow
of this tutorial, I will discuss this at the end.
14. The Products's
Insert (Business Object) method accesses it's respective Data Layer method as shown in the highlighted code below.
15. Note that the Products's
Insert Data Layer method shown below has no code, just a code throwing a NotImplementedException error. This is one of the main difference with AspCoreGen 2.0 Razor Express and
Professional Edition, that's why Express generated Razor Pages are not bound to a database.
16. Needless to say, you still need to add code in the
ProductDataLayerBase.cs Insert method which will insert the passed values to the database.
Note: Code below is
just an example.
In the ProductDataLayerBase's
Insert method, delete the code:
throw new NotImplementedException();
and then assign the Middle Tier values passed by the UI tier to whatever objects you have. Your objects could be an Entity Framework, or whatever you wish to
use that will interact with your database. Or you can just buy the AspCoreGen 2.0 Razor Professional Plus so that you don't even need to worry about the data layer, it should
generate this part as well as the respective Linq-to-Entities classes (EF Core), ore Stored Procedures, or Ad-Hoc SQL (sorry for the marketing spiel).
...and we're done.
Last Words:
** One Click. As programmers we develop for one project until we're done or get pulled to another project. This means using the same database over and over again, adding more tables or
fields to existing tables and/or views, or updating them. The "
One Click" feature becomes really handy the next time you generate code for the same database, all you
have to do is click the
Generate Code for All Tables button when working on the same database, and that's it. AspCoreGen 2.0 Razor Express is absolutely free, no need to
register, no pop-ups asking you to buy the Professional Plus edition, no marketing/unsolicited emails whatsoever, yup - it's absolutely free.
*** About the Hidden suffix on the fields:
Html controls (input, select tags) on the
Razor Page (Products_Unbound.cshtml, #9 image above) are bound to a
Products property in the
Page Model (Products_Unbound.cshtml
.cs, #11 image above).
Razor Page: Showing just a partial code.
<tr>
<td class="editor-label"><label asp-for="Products.UnitsInStockHidden"></label>:</td>
<td></td>
<td class="editor-field"><input asp-for="Products.UnitsInStockHidden" /></td>
<td class="editor-field"><span asp-validation-for="Products.UnitsInStockHidden"></span></td>
</tr>
<tr>
<td class="editor-label"><label asp-for="Products.UnitsOnOrderHidden"></label>:</td>
<td></td>
<td class="editor-field"><input asp-for="Products.UnitsOnOrderHidden" /></td>
<td class="editor-field"><span asp-validation-for="Products.UnitsOnOrderHidden"></span></td>
</tr>
<tr>
<td class="editor-label"><label asp-for="Products.ReorderLevelHidden"></label>:</td>
<td></td>
<td class="editor-field"><input asp-for="Products.ReorderLevelHidden" /></td>
<td class="editor-field"><span asp-validation-for="Products.ReorderLevelHidden"></span></td>
</tr>
Page Model: Products property bound to html controls in the razor page above.
[BindProperty]
public RazorAppAPI.BusinessObject.Products Products { get; set; }
Each field or property in the
Razor Page is mapped to a
Model (not the Page Model) but more like a data Model for lack of a better term. This
Model
tells the Razor Page controls what label to display for the respective fields, what data type to use, and retricts data entered to a set of validation rules. You will notice that
properties for
UnitsInStock,
UnitsOnOrder, and
ReorderLevel have additional properties with the same name but with a suffix
"Hidden". These properties
are numerical types such as Int16, Int32, Int64, etc. The respective
"Hidden" properties are String type and
NotMapped
.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorAppAPI.Models.Base
{
/// <summary>
/// Base class for ProductsModel. Do not make changes to this class,
/// instead, put additional code in the ProductsModel class
/// </summary>
public class ProductsModelBase
{
/// <summary>
/// Gets or Sets ProductID
/// </summary>
[Display(Name = "Product ID")]
public int ProductID { get; set; }
/// <summary>
/// Gets or Sets ProductName
/// </summary>
[Required(ErrorMessage = "{0} is required!")]
[StringLength(40, ErrorMessage = "{0} must be a maximum of {1} characters long!")]
[Display(Name = "Product Name")]
public string ProductName { get; set; }
/// <summary>
/// Gets or Sets SupplierID
/// </summary>
[Display(Name = "Supplier ID")]
public int? SupplierID { get; set; }
/// <summary>
/// Gets or Sets CategoryID
/// </summary>
[Display(Name = "Category ID")]
public int? CategoryID { get; set; }
/// <summary>
/// Gets or Sets QuantityPerUnit
/// </summary>
[StringLength(20, ErrorMessage = "{0} must be a maximum of {1} characters long!")]
[Display(Name = "Quantity Per Unit")]
public string QuantityPerUnit { get; set; }
/// <summary>
/// Gets or Sets UnitPrice
/// </summary>
[RegularExpression(@"[-+]?[0-9]*\.?[0-9]?[0-9]", ErrorMessage = "{0} must be a valid decimal!")]
[Display(Name = "Unit Price")]
public decimal? UnitPrice { get; set; }
/// <summary>
/// Gets or Sets UnitsInStock
/// </summary>
[Range(typeof(Int16), "-32768", "32767", ErrorMessage = "{0} must be an integer!")]
[Display(Name = "Units In Stock")]
public Int16? UnitsInStock { get; set; }
[NotMapped]
[RegularExpression("([0-9]+)", ErrorMessage = "{0} must be a number!")]
[Range(typeof(Int16), "-32768", "32767", ErrorMessage = "{0} must be between {1} and {2}")]
[Display(Name = "Units In Stock")]
public string UnitsInStockHidden { get; set; }
/// <summary>
/// Gets or Sets UnitsOnOrder
/// </summary>
[Range(typeof(Int16), "-32768", "32767", ErrorMessage = "{0} must be an integer!")]
[Display(Name = "Units On Order")]
public Int16? UnitsOnOrder { get; set; }
[NotMapped]
[RegularExpression("([0-9]+)", ErrorMessage = "{0} must be a number!")]
[Range(typeof(Int16), "-32768", "32767", ErrorMessage = "{0} must be between {1} and {2}")]
[Display(Name = "Units On Order")]
public string UnitsOnOrderHidden { get; set; }
/// <summary>
/// Gets or Sets ReorderLevel
/// </summary>
[Range(typeof(Int16), "-32768", "32767", ErrorMessage = "{0} must be an integer!")]
[Display(Name = "Reorder Level")]
public Int16? ReorderLevel { get; set; }
[NotMapped]
[RegularExpression("([0-9]+)", ErrorMessage = "{0} must be a number!")]
[Range(typeof(Int16), "-32768", "32767", ErrorMessage = "{0} must be between {1} and {2}")]
[Display(Name = "Reorder Level")]
public string ReorderLevelHidden { get; set; }
/// <summary>
/// Gets or Sets Discontinued
/// </summary>
[Required(ErrorMessage = "{0} is required!")]
[Display(Name = "Discontinued")]
public bool Discontinued { get; set; }
}
}
When using ASP.NET Core MVC and/or Razor, adding a
Range to numerical types does not work. It will just spew a
Required! error when you enter values that are out of range instead of
saying that what you entered are out of range. So to achieve a range validation for numeric types (see #9 image above), we used a
String type (
Hidden properties) instead of the original property.
...and that's it.
As always, the code and the article are provided "As Is", there is absolutely no warranties. Use at your own risk.