Overview
Building the enterprise application was not an easy task for all of us, even if you are a big software company or professional outsourcing company.
We mostly have the same problem. Starting with the simple case and trying to reach the first release ASAP and not care much about infrastructure. Just think, I will improve later. Awesome, we delivered on time! Then the manager required more and more releases that needed to be delivered on time also. Yeah, no problem, we can do that. The first and second release were on time.
I definitely could say that the team and manager were proud of us and think that we did an amazing job.
Yeah, we succeeded in building the enterprise system which many other companies failed to do. For now, we start working on features for the third release and strongly believe that the team could also deliver on time along with promising plan, bonus from manager, ...
OK, time up, it was release date today, there was around 15% of work that needed to be completed. (Leader said) let me ask the manager to delay the delivery for us by "some days".
OK, no problem, the manager say. But after "some days", none in the team can say when the delivery could come and around 30% of work needed to be completed. What's up? Did we fail for this release?
The manager did the investigation, and found that the team was still working hard as usual but the productivity was lower and lower, they looked tired, most of the time was used for bug fixing, improvement tasks.
Doing the team meeting, we found that the infrastructure was not stable, so integrating a new feature usually produced a lot of bugs, needed more time and potential issues. So mostly, the team was struggling with issues, not much value added.
Building the enterprise application, we try to create the "runnable app". It was not enough. It needed to satisfy some requirements for EA, such as: maintainable, extensible, scalable, .....
I understood those problems, and created this series of videos "TinyERP: SPA for Enterprise Application". Hopefully, this can help you solve the above problems.
For now, let's start “The first look at TinyERP: SPA for Enterprise Application".
TinyERP follows Client-Server model.
Let's Start Client First
Check out the source code from Github at https://github.com/tranthanhtu0vn/TinyERP.git and check out develop branch.
Currently, there is no source code in the master branch and we also use "Branching Model" for each new section in this series of article. If you are not familiar with "Git & Branching Model", please have a look at "GIT & Branching Model".
If you open the client folder in Visual Studio code, this is the structure you will see:
I will explain in detail the role and format of each file/ folder in a later article. Now let's start to run the code by "installing missing node packages":
It takes a little time to download the necessary packages. Remember to move to "client" folder before running "npm install
" command.
The source code was written in typescript format, so we need to compile and convert them to js, so the browser can understand:
There are many way to run the app, let's try with lite-server first:
Run on node:
Run on IIS:
Run on docker.
For this case, we need to compile the project in production mode and add into docker image. The steps are given below:
Check the "<root>/client/Dockerfile", there are some simple commands:
FROM microsoft/iis
RUN powershell -NoProfile -Command Remove-Item -Recurse C:\inetpub\wwwroot\*
WORKDIR /inetpub/wwwroot
COPY . .
from "<root>/client", run "npm run build
" and wait for minutes:
Check "<root>/client/dist/" folder, this is where the compiled source code was located:
Currently, we have the draft version of deployment script for you to use during development time. more and more interesting things will come in the "Deployment" part in this series.
There are a few files in compiled code, some files were bundled together.
There some notes:
- Delete web.config file in "<root>/client/dist". We need to install url-rewrite module to use this. Remove now.
- Change
development.mode
to DeploymentMode.PROD
in "<root>/src/apps/dashboard/config/appConfig.ts" before running "npm run build
" command.
- Uncomment js script references in "<root>/client/dist/index.html":
Copy Docfile from "<root>/client" to "<root>/client/dist" and run the following command. If you want to learn more about Docker, please search the appropriate course on "http://coaching.edu.vn" or articles on "http://tranthanhtu.vn":
Ok, we have the docker image for TinyERP (client) on your local, you can run and check it yourself. Let run the image by:
docker run -d -p 8000:80 --name tinyerp-running tinyerp-docker
Ok, now we can deploy TinyERP and run from docker images.
Those are pure static files (such as: html, css, images, ....) so you can deploy to any webserver (such as: Apache, Nginx, ....)
Until now, we can compile and run the client side, This was not enough for a SPA (web application) which uses Client-Server model.
TinyERP - API (Server side)
It is rather simple for the server side as below:
- Create new
WebApi
project, please Google if you do not know how to do. - Add some basic nuget packages, such as:
TinyERP.Common
, TinyERP.Common.Email
, TinyERP.Context
.
- Add new "
appconfiguration
" section into web.config/configuration/configSections:
<configSections>
<section name="appconfiguration" type="TinyERP.Common.Configurations.Configuration,
TinyERP.Common" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<appconfiguration configSource="config\configuration.debug.config"></appconfiguration>
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\\log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
- Exclude unnecessary C# code:
- Change your Global.asax.cs as below:
[assembly: Microsoft.Owin.OwinStartup(typeof(TinyERP.Api.WebApiApplication))]
namespace TinyERP.Api
{
using TinyERP.Common.Application;
using TinyERP.Common;
public class WebApiApplication : BaseWebApiApplication
{
public WebApiApplication() : base() { }
protected override ApplicationType GetApplicationType()
{
return ApplicationType.WebApi;
}
protected virtual void Application_Start()
{
this.application.OnApplicationStarted();
}
}
}
- Let's try to create the simple "Controllers/SystemController.cs" controller:
namespace TinyERP.Api.Controllers
{
using System.Web.Http;
using TinyERP.Common.MVC;
using TinyERP.Common.MVC.Attributes;
[System.Web.Http.RoutePrefix("api/system")]
public class SystemController : BaseApiController
{
[Route("getMyName")]
[HttpPost()]
[ResponseWrapper()]
public string GetMyName() {
return "TU Tran";
}
}
}
- Check to make sure it works, use rest client and make the call to
GetMyName
method:
- Ok, so cool. I can run both client and server part for TinyERP. is that enough for this part.
- The answer is NO.
- Oh my ghost, the article was long.
- Do not worry, Just a small part, integrate client part with server part.
- Ok, start please.
Integration Between Client and Server Part
Let's change "<root>/client/modules/support/pages/sayHello.ts":
import { Component } from "@angular/core";
import { BasePage } from "@app/common";
import {ISystemService, SystemService} from "../_share/services/systemService";
@Component({
templateUrl: "src/modules/support/pages/sayHello.html"
})
export class SayHello extends BasePage<any>{
public myName: string = "Tu Tran local";
protected onReady(): void {
let self = this;
let service: ISystemService = new SystemService();
service.getMyName().then((name: string) => {
self.myName = name;
});
}
}
There are 2 new classe/ interface (ISystemService
and SysteService
). Let's add a new systemService.ts in "<root>/client/modules/support/pages/_share/services/":
import {Promise, BaseService, IConnector, IoCNames} from "@app/common";
export interface ISystemService{
getMyName():Promise;
}
export class SystemService extends BaseService implements ISystemService{
public getMyName():Promise{
let uri="http://localhost:56622/api/system/getMyName";
let connector: IConnector = window.ioc.resolve(IoCNames.IConnector);
return connector.post(uri);
}
}
In this code, we use hard value for "http://localhost:56622/api/system/getMyName" uri and replace this with appropriated uri on your local PC.
Let's run "npm run tsc
" in "<root>/client" and "node node_server.js" after that. We have the result:
We can see in the picture, the browser makes the call to serverside with the uri "..../getMyName" (1) and receives the response from server (2), then it displays that value on the UI (3) even if the local variable was changed to "TU Tran local" (4).
So up to now, we can compile and run both client and server and they can also integrate each other.
For the sample code in this part, please checkout "feature/overview" from https://github.com/tranthanhtu0vn/TinyERP repository.
Other articles in the series:
For learning Angular2, I think you should follow the list of articles as below (click on the links to see detail page):
- Overview: This will provide you an overview about Angular2 before you write your first code for your Angular2 application.
- Routing: This will help us understand how Angular2 displays the page and passing parameters in-between.
Thank you for reading,
CodeProject
Note: Please like and share with your friends if you think this is a useful article, I would really appreciate it.