Click here to Skip to main content
15,867,308 members
Articles / Web Development / ASP.NET / ASP.NET Core

Custom Code-Generator Using ASP.NET Core

Rate me:
Please Sign up or sign in to vote.
5.00/5 (16 votes)
1 May 2018CPOL3 min read 32.4K   881   31   16
In this post, we will get an overview and generate a basic level code using our database table column that will help in development.

Introduction

The main thought behind the sample was to generate the common types of code easily.

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, I have used AngularJS.

Content Focused

  • Connect to database server
  • Get all database list then
  • Get all Table Column by selecting a particular table
  • Choose column then
  • Generate code, that’s it

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

Let's Work with Back-End, Connect to Database

Let's create an API Controller to get all our operations 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=sa@12345;";

Get All Databases

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

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

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

C#
// 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 selected database.

C#
// 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 is the SQL query to get all table columns.

SQL
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 the Get method to list all selected table columns in server.

C#
// 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();
}

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

C#
[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=sa@12345;";

    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 is used to represent the real structure. In the below folder, we have all the formatted templates to present the real structure in generated code.

Image 1 

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

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

API-Generator

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

C#
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 is used in others' code generation.

C#
[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. The below method will generate those data models.

C#
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.

C#
//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.

C#
//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 update operation, in application we need to modify those with our own additional logic.

C#
//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 delete operation, in application, we need to modify those with our own additional logic.

C#
//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 Front-End, AngularJS Controller-Generator

In our frontend, we also used the same mechanism that is used to generate API Controller.

C#
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 the below method, we have generated HTML form that is embedded with angular tag.

C#
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.

HTML
<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 used pre-formated & HTML Example Element tag in HTML to present the generated code.

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

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

JavaScript
$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

You can see the final output in the below screen:

Image 2

Source Code

I’ve uploaded the full source code to download/clone @github, Hope this will help. 🙂

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) s3 Innovate Pte Ltd
Bangladesh Bangladesh
Hi, I am Shashangka Shekhar,

Working with Microsoft Technologies. Since March 2011, it was my first step to working with Microsoft Technologies, achieved bachelor’s degree on Computer Science from State University of Bangladesh(Dhaka). Have 12+ years of professional experience, currently working as Technical Lead at Surbana Jurong Private Limited.

I believe in desire of learning & also love to be a part of .Net Community by sharing knowledge’s.

Comments and Discussions

 
Questionmy vote 5 Pin
User 418025413-Jun-18 3:23
User 418025413-Jun-18 3:23 
QuestionDo you have another gen that will create site using generated webapi/angular Pin
bashamn9-May-18 14:22
bashamn9-May-18 14:22 
AnswerRe: Do you have another gen that will create site using generated webapi/angular Pin
Shashangka Shekhar10-May-18 5:16
professionalShashangka Shekhar10-May-18 5:16 
QuestionTemplates?? Pin
per593-May-18 6:14
per593-May-18 6:14 
AnswerRe: Templates?? Pin
Shashangka Shekhar3-May-18 16:59
professionalShashangka Shekhar3-May-18 16:59 
GeneralRe: Templates?? Pin
Duzher27-Sep-18 4:24
Duzher27-Sep-18 4:24 
GeneralMy vote of 5 Pin
Member 108261493-May-18 3:35
Member 108261493-May-18 3:35 
GeneralRe: My vote of 5 Pin
Shashangka Shekhar3-May-18 5:41
professionalShashangka Shekhar3-May-18 5:41 
GeneralMy vote of 5 Pin
ZahidOnAir2-May-18 19:54
professionalZahidOnAir2-May-18 19:54 
GeneralRe: My vote of 5 Pin
Shashangka Shekhar2-May-18 20:07
professionalShashangka Shekhar2-May-18 20:07 
GeneralMy vote of 5 Pin
Burak Ozdiken2-May-18 1:51
Burak Ozdiken2-May-18 1:51 
GeneralRe: My vote of 5 Pin
Shashangka Shekhar2-May-18 1:56
professionalShashangka Shekhar2-May-18 1:56 
GeneralMy vote of 5 Pin
labib1231-May-18 22:50
labib1231-May-18 22:50 
GeneralRe: My vote of 5 Pin
Shashangka Shekhar1-May-18 23:37
professionalShashangka Shekhar1-May-18 23:37 
GeneralMy vote of 5 Pin
Shamim Uddin1-May-18 20:25
professionalShamim Uddin1-May-18 20:25 
Thank you Guru for your nice article
GeneralRe: My vote of 5 Pin
Shashangka Shekhar1-May-18 20:27
professionalShashangka Shekhar1-May-18 20:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.