Overview
Building the enterprise application was not an easy task for all of us, eventif you are a big software company or professional outsourcing company.
We mostly got the same problem. Starting with the simple case and trying to reach the first release SAP 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 need to be delivered on time also.
Yeah, no problem, we can do that. The first and second release were come on time.
I definitely could say that, the team and manager were proud of and think that we did amazing job.
Yeah, We success to build the enterprise system which many other companies were failed.
For now, we start working on features for the third release and strong 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 works need to be completed. (Leader said) let me ask the manager to delay the delivery for us "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 need to be completed. What 's up? did we fail for this release?
The manager did the investigation, and found that the team was still worked hard as normal but the productivity was low 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 new feature usually produced a lot of bugs, need 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 needs to satisfy some requirements for EA, such as: maintainable, extensible, scalable, .....
I understand those problem, and create this series of videos "TinyERP: SPA for Enterprise Application", hopefully, this can help you solve above problems.
For now, let start “the first look at TinyERP: SPA for Enterprise Application"
TinyERP follows Client-Server model.
Let start Client first
currently, there is no source code in master branch and we also use "Branching Model" for each new section in this series of article. If you did 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 later in later article. Now let start to run the code by "installing missing node packages":
It takes a little time to download 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 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. step by step as below:
Check the "<root>/client/Dockerfile", there are some simple command:
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 thing will come in "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 runing "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 appropriated 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 use 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>
<!-- other sections -->
<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 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 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 class/ interface (ISystemService and SysteService). Let add 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 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) eventif 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 series
Thank you for reading,CodeProject