Share via


ASP.Net Core: Custom Code-Generator

In this post, we will get an overview and generate a basic label code using our database table column that helps in development. The main thought behind the sample was to generate the common types of code easily. 

Back to top


Introduction

The Single page application is built with ASP.Net Core & AngularJS, here's the execution environment & API service is in .Net Core to generate code. In front-end have used AngularJS.

Let's dive into the code, first let's get started with back-end work. We have connected our database server using a connection string. 

Back to top


Back End

Let's Work with Back-End, Connect to Database: Lets' create an API Controller to get all our operation done. In our controller class let's put a connection string to get connected with our databases.

private string conString = "server=DESKTOP-80DEJMQ; uid=sa; pwd=";

Get All Databases:

Let's create a method to get all database list from the database server. Below SQL query to get all databases.

SELECT name from sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') ORDER BY create_date

Here's is the Get method to list all our databases in server.

// api/Codegen/GetDatabaseList
[HttpGet, Route("GetDatabaseList"), Produces("application/json")]public List<vmDatabase> GetDatabaseList(){ List<vmDatabase> data = new List<vmDatabase>(); using (SqlConnection con = new SqlConnection(conString)) { int count = 0; con.Open(); using (SqlCommand cmd = new SqlCommand("SELECT name from sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') ORDER BY create_date", con)) { using (IDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { count++; data.Add(new vmDatabase() { DatabaseId = count, DatabaseName = dr[0].ToString() }); } } } } return data.ToList();}

Get all Table Column:

Here we are getting all tables from the selected database.

// api/Codegen/GetDatabaseTableList

[HttpPost, Route("GetDatabaseTableList"), Produces("application/json")]public List<vmTable> GetDatabaseTableList([FromBody]vmParam model){ List<vmTable> data = new List<vmTable>(); string conString_ = conString + " Database=" + model.DatabaseName + ";"; using (SqlConnection con = new SqlConnection(conString_)) { int count = 0; con.Open(); DataTable schema = con.GetSchema("Tables"); foreach (DataRow row in schema.Rows) { count++; data.Add(new vmTable() { TableId = count, TableName = row[2].ToString() }); } }  return data.ToList();}

Choose Column:

Below SQL query to get all table columns.

SELECT COLUMN_NAME, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH,0), IS_NULLABLE, TABLE_SCHEMA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + model.TableName + "' ORDER BY ORDINAL_POSITION

Here's is the Get method to list all selected table column in server.

// api/Codegen/GetDatabaseTableColumnList

[HttpPost, Route("GetDatabaseTableColumnList"), Produces("application/json")]public List<vmColumn> GetDatabaseTableColumnList([FromBody]vmParam model){ List<vmColumn> data = new List<vmColumn>(); string conString_ = conString + " Database=" + model.DatabaseName + ";"; using (SqlConnection con = new SqlConnection(conString_)) { int count = 0; con.Open(); using (SqlCommand cmd = new SqlCommand("SELECT COLUMN_NAME, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH,0), IS_NULLABLE, TABLE_SCHEMA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + model.TableName + "' ORDER BY ORDINAL_POSITION", con)) { using (IDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { count++; data.Add(new vmColumn() { ColumnId = count, ColumnName = dr[0].ToString(), DataType = dr[1].ToString(), MaxLength = dr[2].ToString(), IsNullable = dr[3].ToString(), Tablename = model.TableName.ToString(), TableSchema = dr[4].ToString() }); } } } } return data.ToList();}

Server code

Now let's overview the server code that is producing the generated code based on our database column.

[EnableCors("AllowCors"), Produces("application/json"), Route("api/Codegen")]public class CodegenController : Controller{ private readonly IHostingEnvironment _hostingEnvironment; private string conString = "server=DESKTOP-80DEJMQ; uid=sa; pwd=;";  public CodegenController(IHostingEnvironment hostingEnvironment) { _hostingEnvironment = hostingEnvironment; }  #region ++++++ Database +++++++ // api/Codegen/GetDatabaseList [HttpGet, Route("GetDatabaseList"), Produces("application/json")] public List<vmDatabase> GetDatabaseList() { List<vmDatabase> data = new List<vmDatabase>(); using (SqlConnection con = new SqlConnection(conString)) { int count = 0; con.Open(); using (SqlCommand cmd = new SqlCommand("SELECT name from sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') ORDER BY create_date", con)) { using (IDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { count++; data.Add(new vmDatabase() { DatabaseId = count, DatabaseName = dr[0].ToString() }); } } } } return data.ToList(); }  // api/Codegen/v [HttpPost, Route("GetDatabaseTableList"), Produces("application/json")] public List<vmTable> GetDatabaseTableList([FromBody]vmParam model) { List<vmTable> data = new List<vmTable>(); string conString_ = conString + " Database=" + model.DatabaseName + ";"; using (SqlConnection con = new SqlConnection(conString_)) { int count = 0; con.Open(); DataTable schema = con.GetSchema("Tables"); foreach (DataRow row in schema.Rows) { count++; data.Add(new vmTable() { TableId = count, TableName = row[2].ToString() }); } }  return data.ToList(); }  // api/Codegen/GetDatabaseTableColumnList [HttpPost, Route("GetDatabaseTableColumnList"), Produces("application/json")] public List<vmColumn> GetDatabaseTableColumnList([FromBody]vmParam model) { List<vmColumn> data = new List<vmColumn>(); string conString_ = conString + " Database=" + model.DatabaseName + ";"; using (SqlConnection con = new SqlConnection(conString_)) { int count = 0; con.Open(); using (SqlCommand cmd = new SqlCommand("SELECT COLUMN_NAME, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH,0), IS_NULLABLE, TABLE_SCHEMA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + model.TableName + "' ORDER BY ORDINAL_POSITION", con)) { using (IDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { count++; data.Add(new vmColumn() { ColumnId = count, ColumnName = dr[0].ToString(), DataType = dr[1].ToString(), MaxLength = dr[2].ToString(), IsNullable = dr[3].ToString(), Tablename = model.TableName.ToString(), TableSchema = dr[4].ToString() }); } } } } return data.ToList(); } #endregion  #region +++++ CodeGeneration +++++ // api/Codegen/GenerateCode [HttpPost, Route("GenerateCode"), Produces("application/json")] public IActionResult GenerateCode([FromBody]object[] data) { List<string> spCollection = new List<string>(); try { string webRootPath = _hostingEnvironment.WebRootPath; //From wwwroot string contentRootPath = _hostingEnvironment.ContentRootPath; //From Others var tblColumns = JsonConvert.DeserializeObject<List<vmColumn>>(data[0].ToString());   string fileContentSet = string.Empty; string fileContentGet = string.Empty; string fileContentPut = string.Empty; string fileContentDelete = string.Empty; string fileContentVm = string.Empty; string fileContentView = string.Empty; string fileContentNg = string.Empty; string fileContentAPIGet = string.Empty; string fileContentAPIGetById = string.Empty;  //SP fileContentSet = SpGenerator.GenerateSetSP(tblColumns, webRootPath); fileContentGet = SpGenerator.GenerateGetSP(tblColumns, webRootPath); fileContentPut = SpGenerator.GeneratePutSP(tblColumns, webRootPath); fileContentDelete = SpGenerator.GenerateDeleteSP(tblColumns, webRootPath); spCollection.Add(fileContentSet); spCollection.Add(fileContentGet); spCollection.Add(fileContentPut); spCollection.Add(fileContentDelete);  //VM fileContentVm = VmGenerator.GenerateVm(tblColumns, webRootPath); spCollection.Add(fileContentVm);  //VU fileContentView = ViewGenerator.GenerateForm(tblColumns, webRootPath); spCollection.Add(fileContentView);  //NG fileContentNg = NgGenerator.GenerateNgController(tblColumns, webRootPath); spCollection.Add(fileContentNg);  //API fileContentAPIGet = APIGenerator.GenerateAPIGet(tblColumns, webRootPath); spCollection.Add(fileContentAPIGet); } catch (Exception ex) { ex.ToString(); }  return Json(new { spCollection }); }  #endregion}

In our code-generation mechanism the .txt template use to representing the real structure. Below folder we have all the formatted template to present the real structure in generated code.

Back to top


#Generator app

Let's expand the generator. Here's the list that we are  generated by this app

  1. API Controller
  2. ViewModel
  3. Stored Procedure
  4. AngularJS Controller
  5. HTML-Form

API-Generator:

Below code method will generate the API Controller using a formatted text file.

public static dynamic GenerateAPIGet(List<vmColumn> tblColumns, string contentRootPath)
{
 TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
 StringBuilder builderPrm = new StringBuilder();
 StringBuilder builderSub = new StringBuilder();
 builderPrm.Clear(); builderSub.Clear();
 string fileContent = string.Empty; string queryPrm = string.Empty; string submitPrm = string.Empty;
 
 string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema;
 string path = @"" + contentRootPath + "\\template\\WebAPI\\APIController.txt";
 
 // API Controller
 string routePrefix = "api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString()));
 string apiController = textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "Controller";
 string collectionName = "List<" + tableName.ToString() + ">";
 string listObj = tableName.ToString() + "s";
 string getDbMethod = "_ctx." + tableName.ToString() + ".ToListAsync()";
 string entity = tableName.ToString();
 string urlApiGet = "api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/GetAll";
 string urlApiGetByID = "api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/GetByID/5";
 string urlApiPost = "api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/Save";
 string urlApiPut = "api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/UpdateByID/5";
 string urlApiDeleteByID = "api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/DeleteByID/5";
 
 //Enity Fields
 foreach (var item in tblColumns)
 {
 //parameter
 builderPrm.AppendLine();
 builderPrm.Append("entityUpdate." + item.ColumnName + " = model." + item.ColumnName + ";");
 }
 submitPrm = builderPrm.AppendLine().ToString();
 
 using (StreamReader sr = new StreamReader(path, Encoding.UTF8))
 {
 fileContent = sr.ReadToEnd()
 .Replace("#RoutePrefix", routePrefix.ToString())
 .Replace("#APiController", apiController.ToString())
 .Replace("#Collection", collectionName.ToString())
 .Replace("#ListObj", listObj.ToString())
 .Replace("#DbMethod", getDbMethod.ToString())
 .Replace("#Entity", entity.ToString())
 .Replace("#UrlApiGet", urlApiGet.ToString())
 .Replace("#UrlGetByID", urlApiGetByID.ToString())
 .Replace("#UrlPostByID", urlApiPost.ToString())
 .Replace("#UrlApiPut", urlApiPut.ToString())
 .Replace("#ColUpdate", submitPrm.ToString())
 .Replace("#UrlDeleteByID", urlApiDeleteByID.ToString());
 }
 
 return fileContent.ToString();
}

API Controller Format:

 

In this portion, we have read the text as it is till the end line then replace those #tag property using c# dynamically. This is the main trick that used in others code generation.

[Route("#RoutePrefix"), Produces("application/json")]public class #APiController : Controller{ private dbContext _ctx = null; public #APiController(dbContext context) { _ctx = context; }  // GET: #UrlApiGet [HttpGet, Route("GetAll")] public async Task<object> GetAll() { #Collection #ListObj = null; try { using (_ctx) { #ListObj = await #DbMethod; } } catch (Exception ex) { ex.ToString(); } return #ListObj; }  // GET #UrlGetByID [HttpGet, Route("GetByID/{id}")] public async Task<#Entity> GetByID(int id) { #Entity obj = null; try { using (_ctx) { obj = await _ctx.#Entity.FirstOrDefaultAsync(x => x.Id == id); } } catch (Exception ex) { ex.ToString(); } return obj; }   // POST #UrlPostByID  [HttpPost, Route("Save")] public async Task<object> Save([FromBody]#Entity model) { object result = null; string message = ""; if (model == null) { return BadRequest(); } using (_ctx) { using (var _ctxTransaction = _ctx.Database.BeginTransaction()) { try { _ctx.#Entity.Add(model); await _ctx.SaveChangesAsync(); _ctxTransaction.Commit(); message = "Ok"; } catch (Exception e) { _ctxTransaction.Rollback(); e.ToString(); message = "Error"; }  result = new { message }; } } return result; }  // PUT #UrlApiPut  [HttpPut, Route("UpdateByID/{id}")] public async Task<object> UpdateByID(int id, [FromBody]#Entity model) { object result = null; string message = string.Empty; if (model == null) { return BadRequest(); } using (_ctx) { using (var _ctxTransaction = _ctx.Database.BeginTransaction()) { try { var entityUpdate = _ctx.#Entity.FirstOrDefault(x => x.Id == id); if (entityUpdate != null) { #ColUpdate  await _ctx.SaveChangesAsync(); } _ctxTransaction.Commit(); message = "Ok"; } catch (Exception e) { _ctxTransaction.Rollback(); e.ToString(); message = "Error"; }  result = new { message }; } } return result; }  // DELETE #UrlDeleteByID [HttpDelete, Route("DeleteByID/{id}")] public async Task<object> DeleteByID(int id) { object result = null; string message = ""; using (_ctx) { using (var _ctxTransaction = _ctx.Database.BeginTransaction()) { try { var idToRemove = _ctx.#Entity.SingleOrDefault(x => x.Id == id); if (idToRemove != null) { _ctx.#Entity.Remove(idToRemove); await _ctx.SaveChangesAsync(); } _ctxTransaction.Commit(); message = "Ok"; } catch (Exception e) { _ctxTransaction.Rollback();  e.ToString(); message = "Error"; }  result = new { message }; } } return result; }}

ViewModel-Generator:

For specific data model we need to generate some view model, below method will generate those data models.

public static dynamic GenerateVm(List<vmColumn> tblColumns, string contentRootPath){ StringBuilder builderPrm = new StringBuilder(); StringBuilder builderBody = new StringBuilder(); builderPrm.Clear(); builderBody.Clear(); string fileContent = string.Empty; string queryPrm = string.Empty;  string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema; string path = @"" + contentRootPath + "\\template\\ViewModel\\vmModel.txt"; string className = "vm" + tableName.ToString(); foreach (var item in tblColumns) { //parameter builderPrm.AppendLine(); builderPrm.Append("  public " + TypeMap.GetClrType(item.DataType) + " " + item.ColumnName + " { get; set; }"); }  queryPrm = builderPrm.AppendLine().ToString();  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd().Replace("#ClassName", className.ToString()).Replace("#Properties", queryPrm.ToString()); }  return fileContent.ToString();}

Stored Procedure-Generator Insert-SP: This is a minimum label  sp generate query template for insert operation, in application we need to modify those with our own additional logic.

//CREATE

public static dynamic GenerateSetSP(List<vmColumn> tblColumns, string contentRootPath){ StringBuilder builderPrm = new StringBuilder(); StringBuilder builderBody = new StringBuilder(); builderPrm.Clear(); builderBody.Clear();  string path = @"" + contentRootPath + "\\template\\StoredProcedure\\InsertSP.txt"; string fileContent = string.Empty; string fileld = string.Empty; string fileldPrm = string.Empty; string queryPrm = string.Empty; string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema;  string spName = ("[" + tableSchema + "].[Set_" + tableName + "]").ToString(); foreach (var item in tblColumns) { fileld = fileld + item.ColumnName + ","; fileldPrm = fileldPrm + "@" + item.ColumnName + ",";  //parameter builderPrm.AppendLine(); if ((item.DataType.ToString() == "nvarchar") || (item.DataType.ToString() == "varchar")) builderPrm.Append("  @" + item.ColumnName + " " + item.DataType + "(" + item.MaxLength + "),"); else builderPrm.Append("  @" + item.ColumnName + " " + item.DataType + ","); }  queryPrm = builderPrm.Remove((builderPrm.Length - 1), 1).AppendLine().ToString(); //queryPrm = builderPrm.ToString().TrimEnd(',');  //Body builderBody.Append("INSERT INTO [" + tableSchema + "].[" + tableName + "]("); builderBody.Append(fileld.TrimEnd(',') + ") "); //builderBody.AppendLine(); builderBody.Append("VALUES (" + fileldPrm.TrimEnd(',') + ")");  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd().Replace("#Name", spName.ToString()).Replace("#Param", queryPrm.ToString()).Replace("#Body", builderBody.ToString()); }  return fileContent.ToString();}

Get-SP: This is a minimum label  sp generate query template for get operation, in application we need to modify those with our own additional logic.

//READ

public static dynamic GenerateGetSP(List<vmColumn> tblColumns, string contentRootPath){ StringBuilder builderPrm = new StringBuilder(); StringBuilder builderBody = new StringBuilder(); builderPrm.Clear(); builderBody.Clear();  string path = @"" + contentRootPath + "\\template\\StoredProcedure\\ReadSP.txt"; string fileContent = string.Empty; string fileld = string.Empty; string fileldPrm = string.Empty; string queryPrm = string.Empty; string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema;  string spName = ("[" + tableSchema + "].[Get_" + tableName + "]").ToString(); foreach (var item in tblColumns) { fileld = fileld + item.ColumnName + ","; fileldPrm = fileldPrm + "@" + item.ColumnName + ","; }   //Body builderBody.Append("SELECT " + fileldPrm.TrimEnd(',') + " FROM [" + tableSchema + "].[" + tableName + "]");  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd().Replace("#Name", spName.ToString()).Replace("#Body", builderBody.ToString()).Replace("#OrdPrm", fileldPrm.TrimEnd(',').ToString()); }  return fileContent.ToString();}

*Update-SP: *This is a minimum label  sp generate query template for the update operation, in the application, we need to modify those with our own additional logic.

//UPDATE

public static dynamic GeneratePutSP(List<vmColumn> tblColumns, string contentRootPath){ StringBuilder builderPrm = new StringBuilder(); StringBuilder builderBody = new StringBuilder(); builderPrm.Clear(); builderBody.Clear();  string path = @"" + contentRootPath + "\\template\\StoredProcedure\\UpdateSP.txt"; string fileContent = string.Empty; string fileld = string.Empty; string fileldPrm = string.Empty; string queryPrm = string.Empty; string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema;  string spName = ("[" + tableSchema + "].[Get_" + tableName + "]").ToString(); foreach (var item in tblColumns) { fileld = fileld + item.ColumnName + ","; fileldPrm = fileldPrm + item.ColumnName + " = @" + item.ColumnName + ",";  //parameter builderPrm.AppendLine(); if ((item.DataType.ToString() == "nvarchar") || (item.DataType.ToString() == "varchar")) builderPrm.Append("  @" + item.ColumnName + " " + item.DataType + "(" + item.MaxLength + "),"); else builderPrm.Append("  @" + item.ColumnName + " " + item.DataType + ","); }  queryPrm = builderPrm.Remove((builderPrm.Length - 1), 1).AppendLine().ToString();  //Body builderBody.Append("UPDATE [" + tableSchema + "].[" + tableName + "] SET " + fileldPrm.TrimEnd(',') + " WHERE [CONDITIONS]");  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd().Replace("#Name", spName.ToString()).Replace("#Param", queryPrm.ToString()).Replace("#Body", builderBody.ToString()).Replace("#OrdPrm", fileldPrm.ToString()); }  return fileContent.ToString();}

Delete-SP: This is a minimum label  sp generate query template for the delete operation, in the application, we need to modify those with our own additional logic.

//DELETE

public static dynamic GenerateDeleteSP(List<vmColumn> tblColumns, string contentRootPath){ StringBuilder builderPrm = new StringBuilder(); StringBuilder builderBody = new StringBuilder(); builderPrm.Clear(); builderBody.Clear();  string path = @"" + contentRootPath + "\\template\\StoredProcedure\\DeleteSP.txt"; string fileContent = string.Empty; string fileld = string.Empty; string fileldPrm = string.Empty; string queryPrm = string.Empty; string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema;  string spName = ("[" + tableSchema + "].[Delete_" + tableName + "]").ToString(); foreach (var item in tblColumns) { fileld = fileld + item.ColumnName + ","; fileldPrm = fileldPrm + "@" + item.ColumnName + ",";  //parameter builderPrm.AppendLine(); if ((item.DataType.ToString() == "nvarchar") || (item.DataType.ToString() == "varchar")) builderPrm.Append("  @" + item.ColumnName + " " + item.DataType + "(" + item.MaxLength + "),"); else builderPrm.Append("  @" + item.ColumnName + " " + item.DataType + ","); }  queryPrm = builderPrm.Remove((builderPrm.Length - 1), 1).AppendLine().ToString();  //Body builderBody.Append("DELETE FROM [" + tableSchema + "].[" + tableName + "] WHERE [CONDITIONS]");  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd().Replace("#Name", spName.ToString()).Replace("#Param", queryPrm.ToString()).Replace("#Body", builderBody.ToString()).Replace("#OrdPrm", fileldPrm.ToString()); }  return fileContent.ToString();}

Let's Work with Fron-End, AngularJS Controller-Generator: In our frontend, we also used the same mechanism that is used to generate API Controller.

public static dynamic GenerateNgController(List<vmColumn> tblColumns, string contentRootPath){ TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; StringBuilder builderPrm = new StringBuilder(); StringBuilder builderSub = new StringBuilder(); builderPrm.Clear(); builderSub.Clear(); string fileContent = string.Empty; string queryPrm = string.Empty; string submitPrm = string.Empty;  string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema; string path = @"" + contentRootPath + "\\template\\AngularJS\\Controller.txt";  //Controller Name string ctrlName = textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "Controller"; string serviceInjected = "'$scope', '$http'"; string srvParam = "$scope, $http"; string urlApiGet = "'/api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/GetAll'"; string url_GetByID = "'/api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/GetByID/'+ parseInt(model.id)"; string url_Post = "'/api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/Save'"; string url_Put = "'/api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/UpdateByID/'+ parseInt(model.id)"; string url_Delete = "'/api/" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(tableName.ToString())) + "/DeleteByID/'+ parseInt(model.id)";  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd() .Replace("#ControllerName", ctrlName.ToString()) .Replace("#ServiceInjected", serviceInjected.ToString()) .Replace("#SrvParam", srvParam.ToString()) .Replace("#UrlGet", urlApiGet.ToString()) .Replace("#Url_GetByID", url_GetByID.ToString()) .Replace("#Url_Post", url_Post.ToString()) .Replace("#Url_Put", url_Put.ToString()) .Replace("#Url_Delete", url_Delete.ToString()); }  return fileContent.ToString();}

HTML-Generator (Form): Using below method we have generated Html form that embedded with angular tag.

public static dynamic GenerateForm(List<vmColumn> tblColumns, string contentRootPath){ TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; StringBuilder builderPrm = new StringBuilder(); StringBuilder builderSub = new StringBuilder(); builderPrm.Clear(); builderSub.Clear(); string fileContent = string.Empty; string queryPrm = string.Empty; string submitPrm = string.Empty;  string tableName = tblColumns[0].Tablename; string tableSchema = tblColumns[0].TableSchema; string path = @"" + contentRootPath + "\\template\\HtmlForm\\Form.txt";  //Form Name string frmName = "name='frm" + tableName.ToString() + "' novalidate";  //Form Fields foreach (var item in tblColumns) { //parameter builderPrm.AppendLine(); builderPrm.Append(" <div class='form-group'>"); builderPrm.AppendLine(); if (item.ColumnName.Contains("email") || item.ColumnName.Contains("Email")) { builderPrm.Append("  <label for='" + item.ColumnName + "' class='control-label'>" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(item.ColumnName)) + "</label>"); builderPrm.AppendLine(); builderPrm.Append("  <input type='email' class='form-control' ng-model='vmfrm." + item.ColumnName + "' name='" + item.ColumnName + "' required />"); } else if (item.ColumnName.Contains("password") || item.ColumnName.Contains("Password")) { builderPrm.Append("  <label for='" + item.ColumnName + "' class='control-label'>" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(item.ColumnName)) + "</label>"); builderPrm.AppendLine(); builderPrm.Append("  <input type='password' class='form-control' ng-model='vmfrm." + item.ColumnName + "' name='" + item.ColumnName + "' required />"); } else { builderPrm.Append("  <label for='" + item.ColumnName + "' class='control-label'>" + textInfo.ToTitleCase(Conversion.RemoveSpecialCharacters(item.ColumnName)) + "</label>"); builderPrm.AppendLine(); builderPrm.Append("  <input type='text' class='form-control' ng-model='vmfrm." + item.ColumnName + "' name='" + item.ColumnName + "' required />"); } builderPrm.AppendLine(); builderPrm.Append(" </div>"); } queryPrm = builderPrm.AppendLine().ToString();  //Form Submit builderSub.Append(" <div class='form-group'>"); builderSub.AppendLine(); builderSub.Append("  <input type='submit' name='reset' value='Reset' ng-click='Reset()' />"); builderSub.AppendLine(); builderSub.Append("  <input type='submit' name='update' value='Update' ng-click='Update()' />"); builderSub.AppendLine(); builderSub.Append("  <input type='submit' name='submit' value='Save' ng-click='Save()' />"); builderSub.AppendLine(); builderSub.Append(" </div>");  submitPrm = builderSub.AppendLine().ToString();  using (StreamReader sr = new StreamReader(path, Encoding.UTF8)) { fileContent = sr.ReadToEnd().Replace("#frmName", frmName.ToString()).Replace("#frmGroup", queryPrm.ToString()).Replace("#frmSubmit", submitPrm.ToString()); }  return fileContent.ToString();}

Generated Code: We have used multiple tab to represent all the generated code. Below is our HTML section that shows how we are presenting generated code.

<div class="tab-struct custom-tab-2 mt-0"> <ul role="tablist" class="nav nav-tabs" id="myTabs_15"> <li class="active" role="presentation"> <a data-toggle="tab" id="views_tab_1" role="tab" href="#views" aria-expanded="false">HTML Views</a> </li> <li role="presentation" class=""> <a data-toggle="tab" id="angular_tab_1" role="tab" href="#angular" aria-expanded="false">AngularJS</a> </li> <li role="presentation" class=""> <a data-toggle="tab" id="csharp_tab_1" role="tab" href="#csharp" aria-expanded="false">WebAPI</a> </li> <li role="presentation" class=""> <a data-toggle="tab" id="model_tab_1" role="tab" href="#model" aria-expanded="false">Model</a> </li> <li class="" role="presentation"> <a aria-expanded="true" data-toggle="tab" role="tab" id="sql_tab_1" href="#sql">SQL</a> </li> </ul> <div class="tab-content" id="myTabContent_15"> <div id="views" class="tab-pane fade  active in" role="tabpanel" style="max-height:450px; overflow-y: auto;"> <pre class="pa-10" lang="html"><xmp id="genCodeVu"></xmp></pre> </div> <div id="angular" class="tab-pane fade" role="tabpanel" style="max-height:450px; overflow-y: auto;"> <pre class="pa-10" lang="sql"><xmp id="genCodeAngular"></xmp></pre> </div> <div id="csharp" class="tab-pane fade" role="tabpanel" style="max-height:450px; overflow-y: auto;"> <pre class="pa-10" lang="sql"><xmp id="genCodeAPI"></xmp></pre> </div> <div id="model" class="tab-pane fade" role="tabpanel" style="max-height:450px; overflow-y: auto;"> <pre class="pa-10" lang="cs"><xmp id="genCodeVm"></xmp></pre> </div> <div id="sql" class="tab-pane fade" role="tabpanel" style="max-height:450px; overflow-y: auto;"> <pre class="pa-10" lang="sql"><xmp id="genCodeSql"></xmp></pre> </div> </div></div>

We have use pre-formatted & HTML Example Element tag in HTML to present the generated code.

<pre lang="sql"><xmp id="genCodeAPI"></xmp></pre>

Here's the code generation frontend function that is interacting with API's, then getting the generated content which is representing by writing the DOM in Html page.

$scope.generate = function () { $('.nav-tabs a[href="#views"]').tab('show');  var rowGen = []; var elementIDSql = 'genCodeSql'; var elementIDVm = 'genCodeVm'; var elementIDVu = 'genCodeVu'; var elementIDNg = 'genCodeAngular'; var elementIDApi = 'genCodeAPI';  if ($scope.collist.length > 0) { var models = "[" + JSON.stringify($scope.collist) + "]";  $http({ method: 'POST', url: '/api/Codegen/GenerateCode', data: models, dataType: "json", contentType: 'application/json; charset=utf-8' }).then(function (response) {  $('#genCodeSql').text(''); $('#genCodeVm').text(''); $('#genCodeVu').text(''); $('#genCodeAngular').text(''); $('#genCodeAPI').text(''); rowGen = response.data.spCollection;  if (rowGen.length > 0) { for (var i = 0; i < rowGen.length; i++) { //SP if (i == 0) document.getElementById(elementIDSql).innerHTML += "--+++++++++ SET SP +++++++ \r\n" + rowGen[i] + "\r\n"; else if (i == 1) document.getElementById(elementIDSql).innerHTML += "--+++++++++ GET SP +++++++++ \r\n" + rowGen[i] + "\r\n"; else if (i == 2) document.getElementById(elementIDSql).innerHTML += "--+++++++++ PUT SP +++++++++ \r\n" + rowGen[i] + "\r\n"; else if (i == 3) document.getElementById(elementIDSql).innerHTML += "--+++++++++ DELETE SP +++++++++ \r\n" + rowGen[i] + "\r\n"; //VM else if (i == 4) document.getElementById(elementIDVm).innerHTML += "// +++++++++ MODEL PROPERTIES +++++++++ \r\n" + rowGen[i] + "\r\n"; //VIEW else if (i == 5) document.getElementById(elementIDVu).innerHTML += "<!-- +++++++++ HTML FORM +++++++++ --> \r\n" + rowGen[i] + "\r\n"; //ANGULAR else if (i == 6) document.getElementById(elementIDNg).innerHTML += "// +++++++++ AngularJS Controller +++++++++ \r\n" + rowGen[i] + "\r\n"; //API else if (i == 7) document.getElementById(elementIDApi).innerHTML += "// +++++++++ API Controller +++++++++ \r\n" + rowGen[i] + "\r\n"; else document.getElementById(elementIDSql).innerHTML += " Error !!"; }; }; }, function (error) { console.log(error); }); } else { rowGen = []; $('#genCodeSql').text(''); $('#genCodeVm').text(''); console.log("Please Choose a Column!!"); };};

OutPut: As we can see the final out put in the below screen.

Back to top


Download

Source Code: Download source - 10.3 MB.

Back to top


Summary

In this post, i just focused on how to make development faster using own custom generated code. This is a basic label of code generation, hope this will help :)