In This Topic
Tutorials / Other Technologies / Angular 10 / Your first Angular 10 application with DocuVieware

Your first Angular 10 application with DocuVieware

In This Topic

1. A brief introduction

Angular 10 became generally available as a production release on June 24, 2020.

The major upgrade to the Google-developed, TypeScript-based framework puts more emphasis on quality, tool, and ecosystem improvements than new features.

It may not appear as impactful as the version 9 but embarks some notable changes:

  • New Date Range Picker
  • Warnings about CommonJS imports
  • Optional Stricter Settings
  • Keeping Up to Date with the Ecosystem
  • New Default Browser Configuration
  • Angular Team Fixit
  • Deprecations and Removals

At the end of this tutorial, you will be able to run an Angular 10 application on Visual Studio with DocuVieware.

This tutorial includes a clean-up panel, which is not necessary for the application to work. But it will show how to implement a DocuVieware custom feature.

1.1. Set up your Visual Studio project

As a prerequisite, of course, you need Virtual Studio updated and the latest version of DocuVieware.

For this tutorial, we used Microsoft Visual Studio Enterprise 2019 version 16.6.4.

1.2. Set up the Angular 10 application

As a prerequisite, you need Node.js to be installed and set up properly in the PATH environment variable. You can verify it by writing “node -v” into the command prompt. For this tutorial, we used Node.js 12.18.2.

Check also your Angular version by typing “ng –v”, and in case you have the old version, update it with this command:

→ ng update @angular/cli @angular/core

2. Create your Visual Studio project

→ Launch Visual Studio

→ Create a new project

→ Create an ASP.NET Core Web Application

→ Give a name to your project

→ Choose “Angular”

Your project is now created, this is what you should see after running it:

Delete all files and references related to the VS project template. They will be useless for the rest of this tutorial.


→ WeatherForecast.cs

→ Controllers/WeatherForecastController.cs

→ Folder ClientApp

3. Create your Angular 10 application

At the moment, Visual Studio does not create an Angular 10 app automatically. So we need to create the client app manually with the command prompt in our VS project.

Warning: close your Visual Studio for creating properly the Angular 10 application inside. If you don’t do this, Visual Studio will create the node modules dependencies and it will generate tons of errors.

→ In a command prompt go to your VS Project folder

→ ng new ClientApp

→ Yes


Open Visual Studio, you can see there is no “node_modules” folder, Visual Studio linked it to the dependencies itself.

Your Angular 10 app is now created into your VS project, but there are some errors. It is normal, at the moment, Visual Studio is not configured to accept an Angular 10 native app.

For linking properly the Angular app to your project you need to modify the JSON files.

Copy the tsconfig.base.json (into ClientApp/tsconfig.json) and paste it into the tsconfig.json
Into package.json, change the <“start”: “ng serve”> parameter under <“script” to: "start": "echo hello && ng serve">.

This little piece of JSON is really important and will block your application if you don’t modify it.

By doing this, everything should work fine, so launch the application!

4. Add DocuVieware

Now, let’s take a look at how to add your DocuVieware SDK into the project.

For this, right-click on “dependencies” and select “Add project reference”, then, in the “browse” section, select “ GdPicture.NET.14.WEB.DocuVieware.Core.dll”. You will find it at C:\GdPicture.NET 14\Redist\DocuVieware (.NET Core 3.0)).

Our SDK is now well implemented to your solution, you should be able to get functionalities by adding an assembly: using GdPicture14.WEB;

Now create a new folder called “assets” in ClientApp/src/app/ and add docuvieware.min.js and docuvieware.min.css. You can find these files in the path C:\GdPicture.NET 14\Redist\DocuVieware (Resources).


To link the app and DocuVieware js/css you need to refer the angular.json like this:

"styles": [ "src/styles.css", "src/app/assets/docuvieware-min.css" ], "scripts": [ "src/app/assets/docuvieware-min.js" ]

5. Code!

Now, let’s code.

But before, just for verification, at the end of this part, you should have this tree:

5.1 Controllers

Controllers are in charge of controlling the application by getting the input. It transfers order to the view from the model and orders from the view to the model.

Create a folder “Controllers” at the root of your application.

→ Right-click on projects

→ “Add”

→ “New folder”

→ Name it “Controllers”


Then, add the class.

→ Right-click on the created folder (Controllers)

→ Click “Add”, then “New Item..”

→ Choose “API Controller Class – Empty”

→ Name your file “DocuVieware3.cs”

This file is used to implement the HTTP communication method.

namespace WebApp.Controllers { [ApiController] [Route("api/DocuVieware3")] public class DocuVieware3 : ControllerBase { // http get example [HttpGet("ping")] public string ping() { return "pong"; } } }


The file DocuViewareRESTController is where the controls are. In this file, you can choose to enable/disable and change some parameters like the maximum upload size.

You can find them in our documentation.

→ Right-click on the created folder (Controllers)

→ Click “Add”, then “New Item..”

→ Choose “API Controller Class – Empty”

→ Name your file “DocuViewareRESTController.cs”

namespace WebApp.Controllers { [ApiController] [Route("api/DocuVieware")] public class DocuViewareController : ControllerBase { [HttpPost("[action]")] public ActionResult GetDocuViewareControl(DocuViewareConfiguration controlConfiguration) { if (!DocuViewareManager.IsSessionAlive(controlConfiguration.SessionId)) { if (!string.IsNullOrEmpty(controlConfiguration.SessionId) && !string.IsNullOrEmpty(controlConfiguration.ControlId)) { DocuViewareManager.CreateDocuViewareSession(controlConfiguration.SessionId, controlConfiguration.ControlId, 20); } else { throw new Exception("Invalid session identifier and/or invalid control identifier."); } } using DocuViewareControl docuVieware = new DocuViewareControl(controlConfiguration.SessionId) { AllowPrint = controlConfiguration.AllowPrint, EnablePrintButton = controlConfiguration.EnablePrintButton, AllowUpload = controlConfiguration.AllowUpload, EnableFileUploadButton = controlConfiguration.EnableFileUploadButton, CollapsedSnapIn = controlConfiguration.CollapsedSnapIn, ShowAnnotationsSnapIn = controlConfiguration.ShowAnnotationsSnapIn, EnableRotateButtons = controlConfiguration.EnableRotateButtons, EnableZoomButtons = controlConfiguration.EnableZoomButtons, EnablePageViewButtons = controlConfiguration.EnablePageViewButtons, EnableMultipleThumbnailSelection = controlConfiguration.EnableMultipleThumbnailSelection, EnableMouseModeButtons = controlConfiguration.EnableMouseModeButtons, EnableFormFieldsEdition = controlConfiguration.EnableFormFieldsEdition, EnableTwainAcquisitionButton = controlConfiguration.EnableTwainAcquisitionButton, MaxUploadSize = 36700160 }; using StringWriter controlOutput = new StringWriter(); docuVieware.RenderControl(controlOutput); return Ok(new DocuViewareResponse { HtmlContent = controlOutput.ToString() }); } } }

5.2 Models

Models are in charge of providing the data to the application and store it too. But I don’t think there is an explicit link with the getter and setter.

→ Right-click on projects

→ Add

→ New folder

→ Name it “Models”


This file is used to define the getters and setters of our application.

Add the class.

→ Right-click on the created folder (Models)

→ Click “Add”, then “New Item..”

→ Choose “API Controller Class – Empty”

→ Name your file “DocuViewareConfiguration.cs”

namespace WebApp.Models { public class DocuViewareConfiguration { public string SessionId { get; set; } public string ControlId { get; set; } public bool AllowPrint { get; set; } public bool EnablePrintButton { get; set; } public bool AllowUpload { get; set; } public bool EnableFileUploadButton { get; set; } public bool CollapsedSnapIn { get; set; } public bool ShowAnnotationsSnapIn { get; set; } public bool EnableRotateButtons { get; set; } public bool EnableZoomButtons { get; set; } public bool EnablePageViewButtons { get; set; } public bool EnableMultipleThumbnailSelection { get; set; } public bool EnableMouseModeButtons { get; set; } public bool EnableFormFieldsEdition { get; set; } public bool EnableTwainAcquisitionButton { get; set; } } }


Add the class.

→ Right-click on the created folder (Models)

→ Click “Add”, then “New Item..”

→ Choose “API Controller Class – Empty”

→ Name your file “DocuViewareResponse.cs”

This file is used to define the auto-properties of the HTML content. The client will ask the server what it wants, the server will load web content and will send it back to the client.


namespace DVClient.Models { public class DocuViewareResponse { public string HtmlContent { get; set; } } }

5.3 Docuvieware functionalities

The clean-up panel part will implement classes related to the DocuVieware custom features. For this tutorial, we will implement the image quality improvement.

5.3.1 Clean-up Panel

The clean-up panel of DocuVieware is a functionality adding a panel of multiple tools to the application for improving the quality of the document.

Info: This part is optional and the app will work without it.

In a command prompt:

→ Go to DVClient/ClientApp/src/app/

→ ng g c cleanup-panel


import { Component, OnInit } from '@angular/core'; declare var DocuViewareAPI: any; @Component({ selector: 'app-cleanup-panel', templateUrl: './cleanup-panel.component.html', styleUrls: ['./cleanup-panel.component.css'] }) export class CleanupPanelComponent implements OnInit { DOCUVIEWARE_CONTROL_ID = 'DocuVieware1'; constructor() { } ngOnInit() { } applyFilter(customActionName: string) { const pages = DocuViewareAPI.GetSelectedThumbnailItems(this.DOCUVIEWARE_CONTROL_ID); const roi = DocuViewareAPI.GetSelectionAreaCoordinates(this.DOCUVIEWARE_CONTROL_ID); if (pages.length === 0) { pages[0] = DocuViewareAPI.GetCurrentPage(this.DOCUVIEWARE_CONTROL_ID); } const param = { Pages: pages, RegionOfInterest: roi }; DocuViewareAPI.PostCustomServerAction(this.DOCUVIEWARE_CONTROL_ID, true, customActionName, param); } }


import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { CleanupPanelComponent } from './cleanup-panel.component'; describe('CleanupPanelComponent', () => { let component: CleanupPanelComponent; let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [CleanupPanelComponent] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(CleanupPanelComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });


The HTML structure of our panel, you can copy it from the sample folder (provide the folder path)


In the CSS design of our panel, you can copy it from the sample folder (provide the folder path)

5.3.2 Image Cleanup

→ Create a folder at the project level and name it “DocuViewareDemo

→ Right-click on the “DocuViewareDemo” folder

→ Click “Add”, then “Class”

→ Name your file “ImageCleanupDemo.cs”

This code contains the image quality improvement methods of our file. It will implement the clean-up panel by using “e.actionName”, the application gets the user’s action and chooses the right clean-up action according to that.


switch (e.actionName) { case "automaticRemoveBlackBorders": status = gdPictureImaging.DeleteBlackBorders(imageId, 10, false); break; case "autoDeskew": status = gdPictureImaging.AutoDeskew(imageId); break; case "punchHoleRemoval": status = gdPictureImaging.RemoveHolePunch(imageId, HolePunchMargins.MarginLeft | HolePunchMargins.MarginRight | HolePunchMargins.MarginBottom | HolePunchMargins.MarginTop); break; case "negative": status = gdPictureImaging.FxNegative(imageId); break; case "despeckle": status = gdPictureImaging.FxDespeckle(imageId); break; case "rotate-90": status = gdPictureImaging.RotateAngle(imageId, 270); break; case "rotate+90": status = gdPictureImaging.RotateAngle(imageId, 90); break; }

5.4 Docuvieware

The DocuVieware folder contains the style and code which will run our solution on the client-side and the integration part of it.

To create the folder and files inside:

→ In a command prompt, go to ClientApp/src/app folder

→ ng g c docuvieware

-docuvieware.component.css → Where you define the DocuVieware look you need.

-docuvieware.component.html → The HTML which will be injected into the main HTML.

<div id="dvContainer" style="width:100%; height:100%;"></div>

docuvieware.component.spec.ts → Typescript spec code

docuvieware.component.ts → the code for injecting the HTML properly into the “dvContainer” div.

import { Component, OnInit } from '@angular/core'; import { DocuviewareClientApiService } from '../services/docuvieware-client-api.service'; @Component({ selector: 'app-docuvieware', templateUrl: './docuvieware.component.html', styleUrls: ['./docuvieware.component.css'] }) export class DocuviewareComponent implements OnInit { constructor(private dvApi: DocuviewareClientApiService) { } htmlMarkup: any; private static insertInDOM(content: string): void { const fragment = document.createRange().createContextualFragment(content); document.getElementById('dvContainer').appendChild(fragment); } ngOnInit() { this.dvApi.getDocuViewareMarkup().subscribe( response => DocuviewareComponent.insertInDOM(response.htmlContent), error => this.htmlMarkup = error as any ); } }

5.5 Application models

The model folder defines the REST service structure:

→ In a command prompt, go to DVClient/ClientApp/src/app/

→ ng g m models

→ rename the created file to “docuvieware-response.ts”


This file defines the structure of the HTML content of the server response.

export class DocuviewareResponse { htmlContent: string; }

5.6. Services folder

The model folder contains the REST layer to communicate with the server properly.

→ In a command prompt, go to DVClient/ClientApp/src/app/

→ ng g s services/docuvieware-client-api


The code providing the REST communication with the API URL and all the controls configuration to activate/deactivate functionalities into your app.

This is where you can choose if you want to display the controls in your application.

You will find all properties in our online documentation.

import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { DocuviewareResponse } from '../models/docuvieware-response'; @Injectable({ providedIn: 'root' }) export class DocuviewareClientApiService { DOCUVIEWARE_CONTROL_ID = 'DocuVieware1'; DOCUVIEWARE_ENDPOINT_BASE_URL = 'http://localhost:5000/api/DocuVieware'; DOCUVIEWARE_GETMARKUP_ENDPOINT = 'GetDocuViewareControl'; constructor(private httpClient: HttpClient) { } getDocuViewareMarkup(): Observable { const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; const docuViewareConfig = { SessionId: 'mySessionId', // Set to an arbitrary value, should be replaced by the session identifier from your session mechanism ControlId: this.DOCUVIEWARE_CONTROL_ID, AllowPrint: true, EnablePrintButton: true, AllowUpload: true, EnableFileUploadButton: true, CollapsedSnapIn: true, ShowAnnotationsSnapIn: true, EnableRotateButtons: true, EnableZoomButtons: true, EnablePageViewButtons: true, EnableMultipleThumbnailSelection: true, EnableMouseModeButtons: true, EnableFormFieldsEdition: true, EnableTwainAcquisitionButton: true, }; return`${this.DOCUVIEWARE_ENDPOINT_BASE_URL}${this.DOCUVIEWARE_GETMARKUP_ENDPOINT}/`, docuViewareConfig, httpOptions); } }

5.7 Setting main files

→ Right-click on the project

→ Click “Add”, then “Class”

→ Name the file “Globals.cs”


using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; using System; using System.Collections.Generic; using System.IO; using GdPicture14.WEB; using WebApp.DocuViewareCoreDemo; namespace WebApp { public static class Globals { private static readonly string m_rootDirectory = Directory.GetCurrentDirectory(); public static readonly int SESSION_TIMEOUT = 20; //Set to 20 minutes. use -1 to handle DocuVieware session timeout through session mechanism. public const bool STICKY_SESSION = true; //Set false to use DocuVieware on Servers Farm witn non sticky sessions. public const DocuViewareSessionStateMode DOCUVIEWARE_SESSION_STATE_MODE = DocuViewareSessionStateMode.File; //Set DocuViewareSessionStateMode.File is STICKY_SESSION is False. public static string GetCacheDirectory() { return m_rootDirectory + "\\cache"; } public static string GetDocumentsDirectory() { return m_rootDirectory + "\\documents"; } public static string BuildDocuViewareControlSessionID(HttpContext HttpContext, string clientID) { if (HttpContext.Session.GetString("DocuViewareInit") == null) { HttpContext.Session.SetString("DocuViewareInit", "true"); } return HttpContext.Session.Id + clientID; } public static DocuViewareLocale GetDocuViewareLocale(HttpRequest request) { if (request != null) { IList acceptLanguage = request.GetTypedHeaders().AcceptLanguage; if (acceptLanguage != null) { foreach (StringWithQualityHeaderValue language in acceptLanguage) { object docuviewareLocale; if (Enum.TryParse(typeof(DocuViewareLocale), language.Value.Value, true, out docuviewareLocale)) { return (DocuViewareLocale)docuviewareLocale; } } } } return DocuViewareLocale.En; } public static void CustomActionDispatcher(object sender, CustomActionEventArgs e) { switch (e.actionName) { case "automaticRemoveBlackBorders": case "autoDeskew": case "punchHoleRemoval": case "negative": case "despeckle": case "rotate-90": case "rotate+90": ImageCleanupDemo.HandleImageCleanupAction(e); break; } } } }


/!\ Do not forget to replace your API key to make it work! /!\

using GdPicture14.WEB; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.SpaServices.AngularCli; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace WebApp { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; DocuViewareLicensing.RegisterKEY(Configuration["YOUR_API_KEY"]); //Unlocking DocuVieware. Please set your demo or commercial license key here or in config file. DocuViewareManager.SetupConfiguration(Globals.STICKY_SESSION, Globals.DOCUVIEWARE_SESSION_STATE_MODE, Globals.GetCacheDirectory(), "http://localhost:5000", "api/docuvieware3"); DocuViewareEventsHandler.CustomAction += Globals.CustomActionDispatcher; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); // In production, the Angular files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger logger) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); } app.UseCors(cors => cors.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowAnyMethod()); app.UseStaticFiles(); if (!env.IsDevelopment()) { app.UseSpaStaticFiles(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller}/{action=Index}/{id?}"); }); app.UseSpa(spa => { spa.Options.SourcePath = "ClientApp"; if (env.IsDevelopment()) { spa.UseAngularCliServer(npmScript: "start"); } }); } } }


using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using WebApp; namespace DocuviewareAngular10Demo_proofreading { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } }


import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; export function getBaseUrl() { return document.getElementsByTagName('base')[0].href; } const providers = [ { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] } ]; if (environment.production) { enableProdMode(); } platformBrowserDynamic(providers).bootstrapModule(AppModule) .catch(err => console.log(err));


In this file, we need to put the two different HTML parts we made, the DocuVieware interface and the cleanup panel.

<app-cleanup-panel></app-cleanup-panel> <app-docuvieware style="width:100%; height:100%;"></app-docuvieware>


import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { DocuviewareComponent } from './docuvieware/docuvieware.component'; import { CleanupPanelComponent } from './cleanup-panel/cleanup-panel.component'; @NgModule({ declarations: [ AppComponent, DocuviewareComponent, CleanupPanelComponent ], imports: [ BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), HttpClientModule, FormsModule, RouterModule.forRoot([]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

6. Enjoy your app!

Now, launch the app, and let’s see what happens!

DocuVieware Angular 10 application screenshot

Our DocuVieware Angular 10 application is well created with all the basic controls.

You can also add TWAIN communication and much more, check the documentation for more info.

Let us know if you have any questions, and we'll be happy to help!