<<

Masaryk University Faculty of Informatics

Ticket Reservation System using

Bachelor’s Thesis

Peter Bolfa

Brno, Fall 2020 Masaryk University Faculty of Informatics

Ticket Reservation System using Blazor

Bachelor’s Thesis

Peter Bolfa

Brno, Fall 2020 This is where a copy of the official signed thesis assignment and a copy ofthe Statement of an Author is located in the printed version of the document. Declaration

Hereby I declare that this paper is my original authorial work, which I have worked out on my own. All sources, references, and literature used or excerpted during elaboration of this work are properly cited and listed in complete reference to the due source.

Peter Bolfa

Advisor: Ing. Lukáš Grolig

i Acknowledgements

These are the acknowledgements for my thesis, which can span multiple paragraphs.

ii Abstract

This thesis goal is to implement a free ticket reservation system for smaller cinemas using a new framework from called Blazor. Firstly the current state of web application development is re- viewed, giving a summary on each of the well-known, currently most used JavaScript frameworks (Vue, React, ). It can be hard to decide what framework to pick. That is why the comparison section examines the popularity and performance factors of these frameworks. The implementation part was built using WebAssembly hosting model. In the WebAssembly chapter, the thesis quickly reviews what WebAssembly is, how this innovative works, and where it should be used. WebAssembly brought benefits and drawbacks, which are described in this chapter as well. Various advanced patterns were used throughout the implementa- tion and are explained in the architecture chapter, which focuses on the most important ones. Multiple cinemas should be able to use the resulting web applica- tion. This possibility opened up a new problem called multi-tenancy. The known approaches to solve multi-tenancy and what approach was used are described in the multi-tenancy chapter. In the last section of the theoretical part, a detailed inspection is given into the Blazor framework, reviewing Blazor’s internals, describ- ing its most essential features, which are also used in the implementa- tion part. The implementation part is separated into a database, back-end, and front-end part, speaking of problems that occurred during devel- opment and a way of resolving them. In the last chapter, a reader can find a listing of recommendations that should be followed when designing similar solutions in Blazor.

iii Keywords

Blazor, C#, WASM, JavaScript, ASP .NET Core, SQLite, EFCore

iv Contents

1 Introduction 2

2 Current state of web development 3 2.1 Approaches in creating JavaScript solutions ...... 3 2.1.1 Bundler ...... 3 2.1.2 Components ...... 4 2.1.3 DOM ...... 4 2.2 React ...... 5 2.2.1 JSX ...... 5 2.2.2 Virtual DOM ...... 5 2.2.3 Example of React application ...... 6 2.3 Vue ...... 6 2.3.1 Template Syntax ...... 7 2.3.2 Interpolations ...... 7 2.3.3 Directives ...... 7 2.3.4 Example of Vue application ...... 7 2.4 Angular ...... 8 2.4.1 Regular DOM ...... 8 2.4.2 Directives ...... 8 2.4.3 Example of Angular application ...... 9 2.5 Comparison ...... 9 2.5.1 Popularity comparison ...... 9 2.5.2 Conclusion ...... 10 2.5.3 Performance comparison ...... 11 2.5.4 Conclusion ...... 12

3 WebAssembly 13 3.1 Pros and cons ...... 13 3.2 When to use ...... 13 3.2.1 Performance ...... 14 3.2.2 Portability ...... 14 3.3 Conclusion ...... 14

4 Architecture 15 4.1 Tools ...... 15 4.1.1 ...... 15

v 4.1.2 JavaScript interop ...... 15 4.2 Patterns ...... 15 4.2.1 Dependency injection ...... 15 4.2.2 API ...... 16 4.2.3 Repository pattern ...... 16 4.2.4 CQRS ...... 17

5 Multitenancy 18 5.1 Known approaches ...... 18 5.1.1 Database-per-tenant ...... 18 5.1.2 Separate schema ...... 19 5.1.3 Tenant column ...... 19 5.2 Conclusion ...... 19

6 Blazor 21 6.1 Razor ...... 21 6.2 Routing ...... 22 6.3 Hosting models ...... 22 6.3.1 WebAssembly hosting model ...... 22 6.3.2 Server hosting model ...... 23 6.3.3 Visual comparison of hosting models ...... 24 6.4 Component lifecycle methods ...... 24 6.5 Conclusion ...... 26

7 Implementation 27 7.1 Solution structure ...... 27 7.1.1 Client ...... 27 7.1.2 Server ...... 27 7.1.3 Shared ...... 27 7.2 Database ...... 27 7.2.1 SQLite ...... 28 7.3 Database schema ...... 28 7.4 Backend ...... 29 7.5 Services ...... 30 7.5.1 Mail service ...... 31 7.5.2 Payment timeout service ...... 31 7.5.3 API ...... 32 7.6 Front-end ...... 32

vi 7.6.1 Components ...... 32 7.6.2 General ...... 33 7.6.3 SeatAdder ...... 33 7.6.4 ShowSeatAdder ...... 34 7.7 Reservation Flow ...... 36 7.8 Front-end services ...... 38 7.8.1 Authentication service ...... 38 7.9 Deployment and testing ...... 38

8 Recommendations 40 8.1 Do’s and Don’ts ...... 40 8.1.1 Do ...... 40 8.1.2 Do not ...... 40 8.2 Solution structure ...... 41 8.2.1 Client ...... 41 8.2.2 Server ...... 41 8.2.3 Shared ...... 42 8.3 Recommended libraries to use ...... 42 8.3.1 Blazorise ...... 42 8.3.2 HangFire ...... 43 8.3.3 ...... 43 8.3.4 BCrypt ...... 43 8.3.5 Stripe ...... 43 8.3.6 SendGrid ...... 44

9 Conclusion 45

Bibliography 46

vii List of Tables

2.1 Frameworks popularity - GitHub Stars(02.12.2020), NPM (22.11.2020), SO(03.12.2020) 10 2.2 Frameworks profiled by LightHouse - average of 5 runs 12

viii List of Figures

6.1 Visual comparison of Blazor hosting models, taken from [31] 24 6.2 Blazor lifecycle methods, taken from [32] 25 7.1 Schema of a database used in the application 29 7.2 Diagram of which layers does the incoming request gets through in the application 30 7.3 Example of a form which handles creating of a new hall 33 7.4 Creating hall layout 34 7.5 Show seat picking - bought seats are marked red, reserved orange and currently picked blue 35 7.6 Diagram of actions which are done when users reserves a seat 37

ix List of Codes

2.1 Button with counter in React ...... 6 2.2 Button with counter in Vue ...... 7 2.3 Button with counter in Angular ...... 9 6.1 Button with counter in Razor ...... 21

1 1 Introduction

In these challenging times of COVID-19, many businesses had to be closed because of financial problems. One of the businesses that are closed is cinemas. Smaller local cinemas do not have sufficient amount of finances to secure their run. The open-source implementation of a ticket reservation system was created to support them. Most of the local cinemas still do not have any reservation system. This implementation can be used by any cinema, even if the cinema is beginning. These beginning cinemas can then spend their finances on obtaining movies, advertisements and attracting more clients rather than spending money on buying system. One of the requirements that had to be satisfied was that the im- plementation would be programmed in a C#. Because of that, Blazor seemed like the smartest choice. It is considered to be still young since its production version came out only about half-a-year ago. Blazor provides two hosting models. One is a server model where a server is created and then the front-end communicates with this server. The other model is the WebAssembly model, which opens a new door into web development, mainly because of its speed and porta- bility. WebAssembly is a new format of a low-level assembly-like lan- guage run by any modern . Thanks to its low-levelness, it should run faster than a language mainly used in the web development area, JavaScript. The implementation was built in conventional order, starting from the database using SQLite as a provider, which appeared as the most straightforward choice for application needs. The back-end part was then created, including obliged services and a RESTful API, thanks to what the front-end can communicate to the back-end. In the last step, a front-end was created using the already mentioned Blazor.

2 2 Current state of web development

When creating a new web application today, there is not much to choose from, speaking of programming languages. From these lan- guages, JavaScript has been around for the longest time and has gained massive popularity, which resulted in being the most used program- ming language in the world right now[1]. With the arrival of WebAssembly technology, the situation has slightly changed as it brings a new and different way of web develop- ment. More about WebAssembly can be found in chapter 3. The main problem with JavaScript frameworks is that the devel- opment environment changes quickly and often, meaning that many frameworks just come and go. There exist three main JavaScript frameworks which established over time, and have been used for a few years now, namely React, Angular, and Vue[2].

2.1 Approaches in creating JavaScript solutions

Most of the front-end frameworks share similar concepts of building solutions and approaches in creating applications.

2.1.1 Bundler

The application usually consists of multiple JavaScript files bundled together into one final file executed in the browser. Example ofsuch bundler nowadays can be parcel or . Module bundler is required because[3]: • Browser does not support module system, although this is not entirely true nowadays • It helps you manage the dependency relationship of your code, it will load modules in dependency order for you. • It helps you to load your assets in dependency order, image asset, asset, etc. During the packaging process, there is one step where the code is transpiled from the modern JavaScript or TypeScript code into the

3 2. Current state of web development

old ES5 JavaScript code that can run in any browser, including the old ones. For this, is used, a JavaScript transpiler that converts edge JavaScript into plain old ES5 JavaScript that can run in any browser (even the old ones). It makes available all the syntactical sugar that was added to JavaScript with the new ES6 specification, including classes, arrows and multiline strings[4].

2.1.2 Components

When creating an application in some OOP1 language, the central unit is an object/class. In web development, the central unit is a component. A component is a reusable independent piece of code that repre- sents a single component in the result page. In most frameworks, each component should be located in a single file. Data passed between components can be passed either by events, indicating passing data from a child to its parent, or properties, indi- cating passing data from parents down to the children. Events are usually callbacks, which are being called when a child calls some action, such as mouse-clicking.

2.1.3 DOM

The (DOM) is a programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects. That way, programming languages can connect to the page[5]. When there is a change made in the front-end page, the framework calls DOM methods to change its representation, and the page is re- rendered.

1. Objected-oriented programming

4 2. Current state of web development 2.2 React

React is a declarative, efficient, and flexible JavaScript library for build- ing user interfaces. It lets you compose complex UIs from small and isolated pieces of code called “components”[6]. From the view of the classic MVC2 model, React cares only about the view layer, unlike Angular. The view layer handles how the data will be presented to the user. React was developed by Facebook in 2013. Thanks to its small size, it is considered more a library than a framework, which brings a few disadvantages in a lack of built-in tools, such as routing, complex state management, or an HTTP3 client. React applications are built using a special syntax called JSX. An- other interesting approach used by React is a virtual DOM concept, which is an in-memory copy of the real DOM.

2.2.1 JSX

JSX is an XML/HTML-like syntax used by React that extends EC- MAScript so that XML/HTML-like text can co-exist with JavaScrip- t/React code[7]. Code written in JSX is translated by Babel into cor- responding form, which is a lot of React.createElement calls. That is because JSX is just a syntactic sugar for the React.createElement function.

2.2.2 Virtual DOM

The virtual DOM (VDOM) is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory and synced with the “real” DOM by a library such as ReactDOM. This process is called reconciliation[8]. For every DOM object, there is a lightweight virtual DOM object. React stores these in memory, so doing any operation on it is incredibly fast. When component (re)renders, every virtual DOM object gets updated.

2. Model-View-Controller 3. Hyper-Text Transfer Protocol

5 2. Current state of web development

Once the virtual DOM is updated, React compares the updated virtual DOM with the virtual DOM snapshot captured before updating. By doing this, React will exactly know which objects have changed and will re-render those.

2.2.3 Example of React application

1 import React,{useState} from 'react'; 2 const App = () => { 3 const [counter, setCounter] = useState(0); 4 return ( 5 <> 6 9 Counter value:{counter} 10 11 ); 12 } 13 export default App;

Listing 2.1: Button with counter in React

2.3 Vue

Vue (pronounced /vju/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects[9]. Vue was created by Evan You in February 2014 and is being main- tained by the active core team, which member is also Evan[10]. The critical properties of Vue are template syntax, interpolations, and special v- prefixed directives.

6 2. Current state of web development 2.3.1 Template Syntax

Vue.js uses an HTML-based template syntax that allows you to declar- atively bind the rendered DOM to the underlying Vue instance’s data. All Vue.js templates are valid HTML that can be parsed by spec- compliant browsers and HTML parsers. Under the hood, Vue compiles the templates into Virtual DOM render functions. Combined with the reactivity system, Vue is able to intelligently figure out the minimal number of components tore- render and apply the minimal amount of DOM manipulations when the app state changes.[11].

2.3.2 Interpolations

Vue uses a double curly braces syntax, also called "Mustache" syntax, to render any JavaScript code into the HTML code.

2.3.3 Directives

Directives are special attributes with the v- prefix. Directive attribute values are expected to be a single JavaScript expression[11]. Except for the built-in attributes, Vue also accepts the custom ones. Some of the built-in attributes, v-if, v-else, v-on, v-for, v-bind.

2.3.4 Example of Vue application

1 var example1= new Vue({ 2 el: '#example-1', 3 data:{ 4 counter: 0 5 } 6 })

7

8

9 Add 1 10

The button above has been clicked{{ counter}} times.

11
Listing 2.2: Button with counter in Vue

7 2. Current state of web development 2.4 Angular

Angular is a platform and framework for building single-page client applications using HTML and TypeScript. Angular is written in Type- Script. It implements core and optional functionality as a set of Type- Script libraries that you import into your apps. The architecture of an Angular application relies on certain funda- mental concepts. The basic building blocks of the Angular framework are Angular components that are organized into NgModules. NgModules collect related code into functional sets; an Angular app is defined by a set of NgModules. An app always has at leasta root module that enables bootstrapping, and typically has many more feature modules.[12]. Angular is often being referred to as a platform because of all the tools and features it provides. It was created by Google in September 2014. Angular differs from the previous frameworks by not using a "spe- cial" copy of DOM, but instead, it uses a regular DOM. Similarly to Vue, Angular provides its version of directives, in this case with a ng prefix.

2.4.1 Regular DOM

Compared to Vue and React, Angular does not use virtual DOM. Instead, it uses a regular DOM, which may be a bottleneck while changing multiple components because of recalculating all the needed changes to be made.

2.4.2 Directives

There are three kinds of directives in Angular[13]: • 1.Components—directives with a template. • 2. Structural directives—change the DOM layout by adding and removing DOM elements - ngFor, ngIf. • 3. Attribute directives—change the appearance or behavior of an element, component, or another directive - ngStyle.

8 2. Current state of web development 2.4.3 Example of Angular application

1 import { Component} from '@angular/core'; 2 @Component({ 3 selector: 'app-product-list', 4 templateUrl: './product-list.component.html', 5 styleUrls:['./product-list.component.css'] 6 }) 7 export class ProductListComponent{ 8 public counter = 0;

9

10 public increment() { 11 this.counter++; 12 } 13 }

14

15 Click me 16 {{counter}} Listing 2.3: Button with counter in Angular

2.5 Comparison

Each comparison requires some key based on which the items will be compared. The comparison here will be split into popularity and performance, as these two aspects are important factors for me when deciding to pick the right tool.

2.5.1 Popularity comparison

The popularity factor is an important one because as more people use the tool, the more resource material and tutorials can be found. This also means that more libraries are developed and also more online answers can be found. In this comparison, the numbers were taken from the popular websites targeted for developers: GitHub, NPM, and StackOverflow. • GitHub - GitHub is a code hosting platform for version control and collaboration. On this platform, repositories are created,

9 2. Current state of web development

where each repository represents a specific project. A user can star a repository to keep track of projects which he is interested in. Each of the compared frameworks(except Blazor, Microsoft moved it under .NET) has its repository on GitHub. The numbers below, shown in the table, were taken from these repositories. • NPM (Node ) - When a JavaScript developer wants to add a new library(dependency) into his solution, he either has to install it manually or use a package manager. Cur- rently, there exist two popular managers, yarn and npm. For this comparison, npm was used for no specific reason. Adding new dependency is done via a terminal by using command npm install , which is comfortable for a devel- oper. Each of the compared JavaScript frameworks is installed via npm. Numbers in the table say how many downloads of each framework there was last year. • StackOverflow - The biggest forum for developers, where they post questions tagged with labels, i.e., React, JavaScript, Vue. A framework’s trend is then calculated as NumberOfQuestionsWithTag / NumberOfAllQuestions and then presented as a percentage.

Framework GitHub Stars NPM Downloads/Year SO Trends React 159,962 8,152,612 4.6% Vue 176,129 1,893,959 1.25% Angular 68,386 2,013,743 2.1% Blazor 9297(20207) - 0.2% Table 2.1: Frameworks popularity - GitHub Stars(02.12.2020), NPM (22.11.2020), SO(03.12.2020)

2.5.2 Conclusion

Table 2.1 shows that React would probably be a perfect choice when developing a web application using a JavaScript framework.

10 2. Current state of web development

Since C# was picked as the primary language, there was no possi- bility of using either React, Angular or Vue. Therefore the only choice I was left with was Blazor. Looking at Blazor numbers, which are the lowest among them, there is no significant community of users yet, which means that there will be problems finding 3rd-party libraries and support when developing an app.

2.5.3 Performance comparison

When speaking about performance, the size of a framework that needs to be downloaded is essential for the user. It will affect a page loading time, which may play a significant role in the user’s overall experi- ence. The recommended loading time in 2020 is at a maximum of 3 seconds[14]. The most decisive performance advantage expected from the Bla- zor over JavaScript is code execution speed since it is compiled directly into WebAssembly code. On the other hand, a little disadvantage is that when loading the Blazor app for the first time, then .NET RunTime, WebAssembly, and additional assemblies need to be loaded. Their overall size is some- where between 2-3MB. The sizes of Blazor downloaded files can be found in Chrome DevTools under the Network tab. There are listed all files downloaded via a browser, so a filter must be applied. To get the files which are downloaded only because of Blazor are the ones with .dll since this extension is meant for Windows (.NET) assemblies plus also a .wasm for WebAssembly. On the second reload, all of these files will be cached, and the page loading time will be drastically shorter, but so will be in the case of JavaScript frameworks. To get a real performance benchmark, there is a tool called Light- house, which is an automatic open-source tool for profiling websites by multiple factors: Performance, Accessibility or Best Practices. Here a GitHub repository was used, which provides the same Medium clone built by multiple frameworks, including back-end and front-end, and then run a Lighthouse inspection on each of these.

11 2. Current state of web development

Framework Performance Accessibility Best practices Size React 90 64 93 43KB Vue 91.8 76 93 23KB Angular 94.2 70 93 143KB Blazor 93.2 84 100 2500KB Table 2.2: Frameworks profiled by LightHouse - average of 5 runs

2.5.4 Conclusion

The Blazor framework’s size looks too big than the JavaScript ones, but it is not that massive problem as it may appear so. For the first time, the files of this size need to be downloaded, but once they are cached, Blazor beats the others in terms of page respon- siveness, site switching, and overall page operation speed, which is also confirmed by table 2.2. It is worth to mention that the Blazor’s average was ruined by the first run, where it got only 75, the next run was 94 and the last three runs were all 99.

12 3 WebAssembly

As was already told, the application will be hosted on Blazor’s We- bAssembly model. Since it is modern technology, it would be essential to understand what it is and when it should be used. WebAssembly is a new type of code that can be run in modern web browsers — it is a low-level assembly-like language with a compact binary format that runs with near-native performance and provides languages such as C/C++, C and Rust with a compilation target so that they can run on the web. It is also designed to run alongside JavaScript, allowing both to work together[15]. Announced in 2015, implemented in 2017 by all major browsers, currently supported by 92% of all browsers. It is the fourth language after HTML, JS, and CSS, which can be run natively in browsers. Before WebAssembly came out, there were already two solutions that had brought a high-level code into a native code run in a browser, which is deprecated nowadays. One of them is Native Client, a sandbox solution developed by Google. The other one, asm.js, is a highly optimized JavaScript subset, which allows running a C/C++ in a browser by compiling code into bytecode using ahead-of-time compilation[16].

3.1 Pros and cons

+ The code can be written in multiple languages + Faster than JavaScript + Portability + Flexibility

− No direct access to DOM − Initial download time

3.2 When to use

The two main use-cases of using WebAssembly is when considering performance and portability.

13 3. WebAssembly

WebAssembly was designed for speed. High-level code is being compiled into the low-level WebAssembly, which brings a lot of speed potential, as the low-level code should run faster.

3.2.1 Performance

A usage of WebAssembly can be considered in cases where a pure computational power is needed. This includes[17]: • Web emulators • Image / video editing • VR and augmented reality • Games • Scientific visualization and simulation • Physics simulations

3.2.2 Portability

WebAssembly is portable as it provides a common ground for mul- tiple languages to come to the web, it can be run in all kinds of host applications and platforms using runtimes, and WebAssembly can be easily bundles into new and existing package managers. Thus, you may want to use WebAssembly, if you want your library or code to be flexible, sandboxed, and easily bundled, to be shared across many platforms[18].

3.3 Conclusion

WebAssembly is an exciting technology that may open new web de- velopment ways, especially for solutions requiring performance. Its popularity will rise since new developers who already know a programming language such as Rust or C++ will not need to learn JavaScript/TypeScript. They will be able to code web apps directly in the language they are already used to.

14 4 Architecture

The implementation part uses some architectural patterns and tools which are explained in this chapter.

4.1 Tools

4.1.1 Entity Framework

Entity Framework, or a newer Entity Framework Core, is a lightweight, open-source, and cross-platform object-relational mapper (ORM) framework, which provides an abstraction over an under-laid database and allows developers to handle data operations via .NET classes[19].

4.1.2 JavaScript interop

Blazor updates the DOM via JavaScript. Hence it also provides a possibility to call the JavaScript code directly from a .NET code and vice-versa. In this solution, there was not much need for calling a JavaScript code. The only case that occurred was when creating a payment via Stripe API. This interop is a function that receives a token- sessionId and pkToken- API key as parameters and calls Stripe API to create a checkout session.

4.2 Patterns

4.2.1 Dependency injection

Dependency Injection (DI) is a best-practice software development technique for ensuring classes remain loosely coupled and making easier[20]. It brings a high level of abstraction since the implementation will depend on interfaces, not classes. It is widely used in .NET appli- cations, also in Blazor. This pattern is used when registering a new service, defining how this service will be injected.

15 4. Architecture

4.2.2 API

The front-end communicates with the back-end via the Application programming interface (API). Nowadays, there are multiple types of API, including REST, SOAP or GraphQL. A REST (Representational state transfer) API was chosen as it provides a simple structure and is easy to implement. There are five methods that each RESTful API may implement, depending on the needs and requirements[21]: • GET - Get a resource, f.e. GET/movies . There can also be end- points for a specific item, f.e. GET/movies/1 , which would usu- ally return a Movie with Id = 1. What property would be com- pared to the parameter(1) depends on the implementation • POST - Creates a new resource with data contained in the body of the request. POST/movies would create a new movie • PUT - Replaces a resource with another resource contained in the request’s body. Id or another unique property must be defined to specify what item is going to be replaced. PUT/movies/1 would replace a movie with Id = 1. • PATCH - Updates a resource by data contained in the body of the request. Unlike the PUT method, PATCH does not replace the resource. • DELETE - Deletes a resource with a specific Id, i.e. DELETE /movies/1/

4.2.3 Repository pattern

Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer[22]. As a best practice each table in the database is encapsulated by one repository class.

16 4. Architecture

4.2.4 CQRS

CQRS stands for Command Query Responsibility Segregation. As it says, this pattern segregates (or separates) the models into the one for reading data(Query) and the other one for updating data(Command). In this solution, it works as a middle-ware between the Repository and API. A new Command or Query is created when a request comes to the API, depending on the request type. According to Martin Fowler, a well-known software developer, creator of Refactoring, is the use of CQRS in most cases unreasonable and should be avoided because it is a major mental leap unless the benefits are worthy of such a jump[23]. Usage of CQRS in this solution was mostly to learn new approaches and is not necessary since the back-end logic is not complicated. CRUD operations here would be sufficient.

17 5 Multitenancy

In multi-tenant software architecture—also called software multite- nancy—a single instance of a software application (and its underlying database and hardware) serves multiple tenants (or user accounts). A tenant can be an individual user, but more frequently, it’s a group of users—such as a customer organization—that shares common ac- cess to and privileges within the application instance. Each tenant’s data is isolated from, and invisible to, the other ten- ants sharing the application instance, ensuring data security and pri- vacy for all tenants[24].

5.1 Known approaches

Currently, there exist 3 approaches:

5.1.1 Database-per-tenant

Each tenant would get its own database with its own data, which are separated from others’ data. While this architecture provides data isolation and speed, it does not scale so well. When the number of tenants/clients on the app is small, this design is effective, but when tenants are larger, resource compromisation is bound to occur. As the number of tables increases, the number of queries increases, so is these tables’ size. Thus, there is a need for continued scaling of resources as more tenants are added[25]. Pros and cons of this approach are:[26] + Data isolation between different tenants can be maintained + This approach is easiest to implement as the database design need not be modified. Tenant-specific connection information would be required to ensure that tenants connect to the correct database + Database backup and recovery process would be easy and will not affect other tenants

18 5. Multitenancy

− The number of tenants per database server would be limited as per SQL Server settings

5.1.2 Separate schema

In this approach, multiple tenants’ data is stored in the same database with separate schemas containing tenant-specific tables. Each tenant would have access only to the specific schema. Shared tables will be stored in a common schema to which all the tenants would have access. Pros and cons of this approach[26]: + Data isolation between different tenants can be maintained by creating database users that have access only to specific schemas + As there are no database design changes, it is easy to implement + More number of users can be hosted per database server

− Data backup and recovery process needs to be defined for each tenant − Additional security features need to be implemented to ensure data isolation

5.1.3 Tenant column

In this approach, the database and schema are shared across the ten- ants. Data tables will have data for all tenants and will be identified using the TenantId field. Pros and cons of this approach[26]: + Amongst these 3 approaches, this can host the maximum num- ber of tenants per server

− Database design would change and hence there would be addi- tional development effort − Any changes to the database design even for one tenant would impact all other tenants − Data backup and recovery needs to be defined for each tenant

5.2 Conclusion

Another approach for a problem with the application used by multiple users is to deploy the application individually for each customer. This

19 5. Multitenancy

is called a multi-instance approach and this was also used in the implementation. This will be solved in Azure, where each cinema would deploy its own copy of the application. The multi-instance approach brings several advantages: • 1. Data separation - Each cinema gets has its data separated from others • 2. Scalability - If each instance gets deployed on an individual ma- chine, then it would be easier to add additional resources(CPU1, GPU2) • 3. Customizability - Each instance can be customized individu- ally by the needs of a customer • 4. Reliability - If one instance fails, then it will not influence other instances

1. Central processing unit 2. Graphics processing unit

20 6 Blazor

In this chapter, Blazor is reviewed, which was used to create an im- plementation. Blazor, short for Browser + Razor, is a Single-Page- Application front-end framework for building interactive client-side web UI with .NET[27]. It was created by .NET Foundation, an organization incorporated by Microsoft in 2018 as an experimental project. Later in 2020, Blazor WebAssembly finally got its fully released version. Blazor came up with a React-like Component model, built-in Rout- ing, Forms and Validation, Dependency Injection, JS interop, and many more. It also provides two hosting models, a server-hosted one and a WebAssembly-hosted one. Similar to JSX in React, Blazor uses its special syntax called Razor.

6.1 Razor

Razor is a markup syntax for embedding server-based code into web- pages. The Razor syntax consists of Razor markup, C#, and HTML.[28] Razor uses a unique character @ to identify Razor and HTML syntax. All expressions followed by @ are first evaluated by Razor and then rendered as HTML.

1 @page"/" 2

Counter: @currentCount

3 4 @code{ 5 private int currentCount = 0; 6 private void IncrementCount() 7 { 8 currentCount++; 9 } 10 }

Listing 6.1: Button with counter in Razor

21 6. Blazor 6.2 Routing

Routing handles switching across multiple pages. It is a built-in feature in Blazor. It is defined at the beginning of the code block of thepage we want to route to. Using @page directive we can define a rules to specify a string that should a path match. @page"/Books/{Id:int}" . These strings can contain a routing constraint (int in this case), which enforce a type matching route to the component. Following constraints are available in Blazor[29]: bool, DateTime, decimal, double, float, guid, int, long

6.3 Hosting models

Blazor provides two hosting models solutions, WebAssembly hosted and server hosted. The WebAssembly model was chosen because of its speed and portability.

6.3.1 WebAssembly hosting model

The more interesting hosting model for Blazor is running web appli- cations directly in the browser using WebAssembly. The production version of this model came out later than the server one. The first thing is that the browser downloads the app’s static files, dependencies, and .NET RunTime - Mono. Since WebAssembly lacks direct access to DOM, changes are made using a JS interop. Pros and cons of using this model[30]: + No server-side dependency. After the app is downloaded, a server connection is no required at all + Client-sided - All work is passed down from the server to the client + PWA - Blazor WASM apps can run easily as a PWA when the user can download the app into their device and run it offline

− Initial load time - when loading the app for the first time, it takes a longer time to download. All the files are usually cached when loading in the future

22 6. Blazor

− Browser support - Some app parts may be limited by browser capabilities − HW & SW - Capable client hardware and software is required − No multi-threading - WebAssembly model does not support multi-threading yet, and each interaction runs on the UI thread

6.3.2 Server hosting model

The server hosting model is a model when the app is hosted on the server from within an ASP.NET Core app. JavaScript calls, event han- dling, or UI updates are handled via a SignalR connection. Pros and cons of using this model:[30] + Speed - Application does not need to download .NET RunTime (mono.wasm) neither .NET assemblies, which means that app loads much faster + Compatibility - Some browsers do not support a WebAssembly yet. Therefore the server model is a safer choice + Security - The app’s code, including component code, is not served to the clients + .NET API - Our code is running on the server, and therefore we can use .NET APIs, for example, access database directly + Tooling - Possibility to debug the code in Visual Studio

− Higher latency - every user UI interaction involves a SignalR call to the server − No offline support - if the connection to the server fails, then the app stops working − Scalability - server manages multiple connections

23 6. Blazor 6.3.3 Visual comparison of hosting models

It can be seen in the picture that the server hosting model contains more components than the WebAssembly one.

Figure 6.1: Visual comparison of Blazor hosting models, taken from [31]

6.4 Component lifecycle methods

Blazor’s component lifecycle methods are very similar to those in the JS frameworks. One significant change is that some Blazor methods may have its asynchronous version, which waits for the Task to be returned and then render the component. All lifecycle methods which are being called are shown in the picture below.

24 6. Blazor

Figure 6.2: Blazor lifecycle methods, taken from [32]

25 6. Blazor 6.5 Conclusion

Blazor, specifically the WebAssembly model, does not exist to replace JavaScript in web development. However, there are occasions where using Blazor might bring more benefits than using JavaScript. If there is a company or some team of developers that program mainly in C#, then learning JavaScript might not be the right way, but since they are used to C#, using Blazor would be the way here.

26 7 Implementation

This chapter reviews the process of implementing the application. First, it shows the solution’s structure and what subsolutions it was decomposed to. Consequentially, the thesis reviews each of the application’s essen- tial parts - the database, the back-end, and the front-end.

7.1 Solution structure

Implemented solution consists of 3 separate .NET sub-solutions:

7.1.1 Client

Client sub-solution represents a front-end created in Blazor, containing pages and components folders.

7.1.2 Server

Server sub-solution serves as a REST API to handle between the database and the front-end.

7.1.3 Shared

As the name of this sub-solution suggests, it is used to share items between front-end and back-end sub-solutions. It was used to create models that were used by both the Client and Server parts.

7.2 Database

The database was created as the first part. As a database provider, the SQLite database was chosen thanks to its simplicity and easement of usage. EFCore provides the Code-first approach in creating database solutions. Code First workflow begins with classes that describe the conceptual model and then Entity Framework generate a database from that model automatically[33].

27 7. Implementation

The database schema can be found below in the form of the picture of the corresponding diagram.

7.2.1 SQLite

Using SQLite as a database provider gives a hand-in-hand solution with the multi-instance approach since each cinema will have its local copy of a table. SQLite served as a perfect choice for the implementation since the cinema will not have many requests, say hundreds of thousands at once, the bottleneck in this case. Documentation for SQLite says that hitting hundred-of-thousands requests per day should be fine. However, this is not the upper limit, and the documentation says that SQLite has been demonstrated to work with ten times that amount of traffic[34].

7.3 Database schema

The database schema was created from scratch as the top-bottom approach (starting from the Cinema table) and was changing during the application development because of the requirements changing a bit from time to time.

28 7. Implementation

Figure 7.1: Schema of a database used in the application

7.4 Backend

The back-end part was created as a .NET solution, specifically in ASP .NET Core. It consists of 3 levels: Repository in the bottom, CQRS as a middle-ware, and API above these two. A repository pattern was implemented to handle communication with the database, which brings an abstraction over the database and Entity Framework. CQRS serves as a middle-ware communicator, so the Repository data can be passed to the API and vice-versa. As the top layer, there is the RESTful API(Controller).

29 7. Implementation

Figure 7.2: Diagram of which layers does the incoming request gets through in the application

7.5 Services

A service object’s role is to encapsulate specific business rules, espe- cially how data is communicated between the client and server[35, p. 101].

30 7. Implementation

7.5.1 Mail service

Mail service is a service created to send emails with tickets to the cus- tomers once the reservation was paid. The format of the sent email was created as simple as possible without providing any extra information. Multiple ideas came up, but in the end, sending QR-image as an attachment seemed like the best option. QR code contains informa- tion such as Number_of_tickets, Show or Reservation_ID, so the cin- ema employee can tell when he scans QR, whether it is legit or not. Reservation_ID was attached to avoid the situation when multiple customers would use one ticket. The disadvantage to this solution is that they have to keep track of already checked Reservation_IDs. The first attempt to send an email via .NET Core was via SMTP Client, where an email and password to that email account where required. This would bring many problems when speaking of security be- cause that password would have to be stored in the database, but not as plain text. Therefore a 3rd-party service for sending emails was used, called SendGrid. The front-end calls an API endpoint /sendemail with needed data, and the back-end will do the rest.

7.5.2 Payment timeout service

Payment timeout service was created to prevent a situation where a user would get into a payment gateway and close the browser. This means that the reserved seats would stay reserved forever. All it does is that it creates a new job in the background with a timer of 7 minutes. After observing multiple cinemas, where the reservation time was 6-8 minutes, 7 minutes is adequate to pay for the reservation. Creating a timer-based background job that would take care of deleting such expired reservations was a bit trickier since implement- ing this would also include implementing a queue to handle all in- coming requests. Instead, a Hangfire was used, which is the open-source framework for handling background tasks. Its usage is easy and straightforward. All that needs to be specified is when an action(method) should be fired, and what method it should be.

31 7. Implementation

To see en-queued, processed, and completed jobs, Hangfire pro- vides its dashboard on the URL /mydashboard. Once the timer expired, a method CancelPayment is fired.

7.5.3 API

Complete documentation to the API was generated via Swagger UI, which automatically generates excellent summary docs. A user can directly try how a particular endpoint works, what parameters it takes, and what kind of object/data it returns.

7.6 Front-end

Front-end was created mostly as the last part since it needed the API from the back-end. As previously mentioned, it is created in Blazor, and the whole solution is created in C#.

7.6.1 Components

Most of the application components are pure forms to handle CRUD1 operations on cinemas, movies, halls, and shows. However, except those, there are also more complex components that take care of seat picking, hall layout creating, and show picking. The two most complicated components which should be described are: SeatAdder component takes care of the layout of a new hall and ShowSeatAdder handles seat reservations.

1. CRUD - Create/Retrieve/Update/Delete

32 7. Implementation

Figure 7.3: Example of a form which handles creating of a new hall

7.6.2 General

General layout of the application is created by NavigationMenu, Body and a Footer part. The content of NavigationMenu is rendered conditionally based on the authorization of the user. If the user is admin, he can see all the items that navigate to the dialogs handling CRUD operations. If the user is employee, he can only see those items he is allowed to Create/Edit, which default is movies and shows. Otherwise, an ordinary user(customer) can see only the shows. In the Footer part, there are multiple links available. Currently, there are some made-up links with meaningless content to show off this feature.

7.6.3 SeatAdder

When an employee, who is authorized to, wants to set up a new hall, he has to specify the information containing the name of the hall, seat dimensions, and the cinema which should be the hall added to, in case of having multiple cinemas. All of this is handled in a simple form at the top of the page. The main problem here was that some real halls do not have a simple layout consisting only of the regular seats. There are often those that have a few seats at the beginning of the row, then there is a

33 7. Implementation

staircase, then a long row of seats and another staircase on the other side. Sometimes there is also a particular type of seat for disabled peo- ple, located in the bottom part of the hall, as the upper ones are not reachable because of the staircase. All of this is handled in this application. The employee creat- ing the hall can create a custom layout of seats with Normal/Dis- abled(staircase)/Handicapped(for disabled people) type. Switching among these is secured via repeated clicking on the specific seat. If there is a number on the seat, then it is in Classic mode. If there is a letter ’D,’ then it is intended for the disabled people. The letter ’D’ can be a little bit misleading as it can be interpreted as Disabled in both ways. Finally, if it is empty, showing just a blank square, then it is Disabled, and the seat will not be pick-able in the future.

Figure 7.4: Creating hall layout

7.6.4 ShowSeatAdder

This component is visually similar to the SeatAdder one, except this one is meant for the seat picking.

34 7. Implementation

At the top, the user has to specify how many of the tickets he will buy, the maximum being six, and what kind of tickets there will be. The constant six was determined after taking the inspection of the real-world cinema. Once he gets all the tickets, he can proceed to the seat picking. The seats which are colored orange or red can not be reserved. The orange ones are already reserved, meaning they were not paid yet, and the red ones were already bought. The colors were also inspired by real-world cinema. There is a buy tickets button under the seats, which reveals an Email field, where the user enters his email where the tickets should be sent to. After this input, there is another button, proceed to payment, which redirects the user to the payment gateway, showing details of his reservation, including the expiration date for payment.

Figure 7.5: Show seat picking - bought seats are marked red, reserved orange and currently picked blue

35 7. Implementation 7.7 Reservation Flow

When a user wants to buy tickets for a show, first, he has to pick the corresponding movie and show he wants to go to. He has to enter the amount of each type of ticket he wants (adult, child) and pick specific seats he wants to buy. On the same page,he will also enter an email to where the tickets will be sent. After this, he is redirected into the payment gateway, where pay- ment needs to be made via credit card. At the same time of being redirected, a background task, which handles payment timeout, is created. If the user pays the tickets within 7 minutes, he is redirected to the page, which confirms that payment was successful and gets the tickets into the email. Once the time expires and the user still wants to pay, after clicking the pay button, he would get a warning that this payment has already been canceled. Then he gets redirected to the page, which says that his reservation has been canceled. The same happens if he cancels the payment before the timeout limit. The diagram corresponding to these actions can be seen below.

36 7. Implementation

37

Figure 7.6: Diagram of actions which are done when users reserves a seat 7. Implementation 7.8 Front-end services

Services can also exist in the front-end, not just in the back-end. The purpose of these is not to communicate with the back-end but mostly to remember an app state. In our case, it is a service that remembers the currently logged-in user.

7.8.1 Authentication service

Since our application allows users to Login & Sign up, creating a service, which would handle these operations was necessary. The authorization consists of 2 roles, admin and employee. Admin can create new accounts, do create/update/delete operations on the cinemas, halls, shows and movies. The employee is only able to create movies and create/update/delete shows for those movies. Authentication service holds an instance of the currently logged-in user and communicates with API to authenticate and authorize a user. This service implements IAuthenticationService, which contains the method: • bool AuthenticateUser(string email, string password) - Method receives email and password from the front-end. Firstly a user with such a unique email is fetched, getting his and hashed password from the database. The incoming password is then hashed similarly, using his salt, and the resultant hash is com- pared to the stored hash. If they match, then the user is authen- ticated. Authorization is done by checking if the user contains the admin’s instance. This service also holds an instance of an event, which is fired when the user Logs in and Logs out. The event is necessary to let the NavigationBar know that its state has changed and should re-render, as the logged-in user should see the Logout button, and the admin should also see the Sign-up button.

7.9 Deployment and testing

The application is deployed via Azure.

38 7. Implementation

Microsoft Azure, formerly known as Windows Azure, is Microsoft’s public cloud . It provides a range of cloud services, including compute, analytics, storage and networking[36]. The implementation consists of two independent parts that need to be deployed individually, the API part and the application part. The application part is hosted as an App Service, a service for hosting web applications. The API is hosted as an API Management service. Testing was done by usability testing in the local environment.

39 8 Recommendations

This chapter contains a summary of the experience gained during the development, listing multiple recommendations to help people who decide to use Blazor as their tool.

8.1 Do’s and Don’ts

The tips listed below are only recommendations based on experience gained during the system implementation. It means that they may not be necessarily accurate for everyone, based on their preference.

8.1.1 Do

• Use Blazor WASM if there is a recommendation that application should run fast • Use .NET CLI1 to generate a Blazor template so there is some- thing you can start from • Use Visual Studio debugger if there is a need for it, it works great • Use isolated CSS for each component/page • Call StateHasChanged if you want to be sure state gets updated • Use 3rd-party libraries which increase productivity • Use IJSRuntime if there is a need for JS interop

8.1.2 Do not

• Use Blazor generally if a reader wants a framework with a high support • Use Blazor WebAssembly model if a reader wants an application to be run in all browsers • Use Blazor Server model if a reader wants an application that scales well • Use Blazor Server model if a reader wants a server-less deploy- ment

1. Command Line Interface

40 8. Recommendations

• Use Blazor Server model if a reader needs an application with lower latency

8.2 Solution structure

Solution structure is partly a thing of a subjective matter. However, there are some essential points which should be fulfilled. Similar to the folder structure used in this implementation, the full-stack application should be divided at minimum into three parts, client, server, and shared.

8.2.1 Client

The client part takes care of the visual representation of the solution(front- end). Here can be found mostly the pages and the components files. The next thing which is also important is storing static files, such as JavaScript scripts, images or CSS files. Recommended folder structure for Client is: • Components - Folder for all the components • Pages - Folder for all the pages • Shared - Folder for the components/pages which are shared across the application, such as navigation bar • Services - Folder for the front-end services • wwwroot - Auto-generated folder for static files

8.2.2 Server

The server part contains the most files when comparing to the other two parts. It is quite logical, as it handles multiple things such as communication with the database, APIs, multiple services and others. The recomended folder structure for the Server is: • Controllers - Folder for the API controllers • Data - Folder for the files which handle/transform data, such as Repository pattern, CQRS pattern or database context • Migrations - Folder for the auto-generated migration files • Models - Folder for the class models that are used in the back-end code • Services - Folder for the back-end services

41 8. Recommendations 8.2.3 Shared

The shared part is used for files that are shared across multiple subso- lutions. In the full-stack application, it is between the client and the server. Typically domain-level objects(DLO) and data-transfer objects(DTO) should be stored here, ideally separately in two folders. Recommended folder structure for Shared is: • DLO - Folder for the DLO files • DTO - Folder for the DTO files

8.3 Recommended libraries to use

List of all external libraries and packages that were used throughout the implementation. The packages were downloaded and installed via NuGet package manager, built-in package manager inside Visual Studio, making it more comfortable. Sometimes there was a problem with versions when NuGet would download the wrong version, which was solved by manually choosing the correct version. As there are not many people using Blazor, the development time for these 3rd party component libraries is longer than in the JavaScript case. All of the used libraries are recommended as they served their purpose and the usage was simple.

8.3.1 Blazorise

Blazorise is an open-source user-interface component library made on top of Blazor and CSS frameworks such as Bootstrap or Material. In this solution, a Bootstrap version was used because of previous experience with it. Working with Blazorise was not that bad; neither was it great. The best choice for a UI library would be Syncfusion, but this is not free. Another smart choice would be MadBlazor.

42 8. Recommendations 8.3.2 HangFire

Hangfire package was probably the one that was easiest to workwith. It was used in the back-end part to create jobs that would cancel seat reservations after 7 minutes. Hangfire provides multiple versions, including a free one, which was enough for this implementation. The biggest struggle with this was a problem with where to store all upcoming cancel requests. Since creating a custom MySQL server would be overkill for this solution, an in-memory one seems to be enough.

8.3.3 Swagger

Swagger (OpenAPI) is a language-agnostic specification for describing REST APIs. It allows both computers and humans to understand a REST API’s capabilities without direct access to the source code. The two main OpenAPI implementations for .NET are Swash- buckle and NSwag[37]. For API in this implementation, a Swashbuckle was used for no particular reason. Integrating Swagger was effortless. Only a few lines of code were added to the middle-ware block of the back-end. Swagger then auto- matically generated full documentation from Controllers and Routes.

8.3.4 BCrypt

BCrypt package was used for the password encryption/decryption. Since the password could not be stored in plain text, additional encryption using salt was needed. BCrypt also provides a possibility to generate salt.

8.3.5 Stripe

Implementing an own custom payment gateway would be too difficult. Therefore a third-party implementation was necessary. Stripe provides a nice simple API to handle communication with their payment gateway, where a user is redirected to when he wants to pay for the tickets.

43 8. Recommendations

In their documentation, there can be found a necessary integration with multiple back-end tools, including .NET. Integration took a while, but this library would still be choice number one when using Blazor. The only more significant problem was implementing a checkout session as Stripe API provides implementation only via JavaScript.

8.3.6 SendGrid

SendGrid is the service for sending custom emails. In this implementation, it was used to send emails containing QR codes of the tickets to the customers. Integration was smooth and the reason this was used over SMTP clients was that client required a plain password to the email account, while in SendGrid, there is only an API key specified. This key can be obtained from their site. There are some limits to a free version of this service. The main one is the number of possible emails sent per day, which is 100 in this case. Migrating to the paid version would not be a problem as SendGrid was already integrated. There is an excellent short example of integrating this service into the solution on their site, particularly for .NET. This service is sug- gested in many cases where there is a need to send emails.

44 9 Conclusion

The thesis’s goal was to implement a working ticket reservation system for cinemas using the Blazor framework. The system was successfully created and is ready to be used. Speaking of Blazor, using it hand-in-hand with an ASP .NET Core was a new, mostly positive experience. However, not in all ways, as Blazor is still too young and needs to "grow up", so it reaches a more significant community of developers. Unfortunately, there is an assumption that Blazor will be touched only by developers from the .NET community as it requires a code to be written in C#. This language is more challenging to learn than JavaScript, especially for new incoming developers. Plus, a current Blazor state, when there is a lack of support, does not give Blazor any advantage. The lack of support from forums and the internet was disappoint- ing, although it can be expected. This slightly ruined an overall plea- sure from using Blazor. Nevertheless, Blazor is a production-ready framework, which would be recommended if there was a need for WebAssembly usage. On the other hand, developing the back-end solution, including database handling and SQLite, was a pleasant experience. EFCore is an excellent tool that makes it simple for developers to handle communication with the database. In the application, there are still some areas of improvement that will be handled in the future, hopingly with the help of other devel- opers who would like to participate in this solution.

45 Bibliography

1. The 10 most popular programming languages, according to the Microsoft-owned GitHub [online]. 2019 [visited on 2020-11-30]. Available from: : / / www . businessinsider . com / most - popular-programming-languages--2019-11. 2. Developer Survey Results 2019 [online] [visited on 2020-11-30]. Available from: https://insights.stackoverflow.com/survey/ 2019#technology-_-web-frameworks. 3. What is module bundler and how does it work? [online] [visited on 2020-12-27]. Available from: https://lihautan.com/what- is-module-bundler-and-how-does-it-work/. 4. What is Babel, and how will it help you write JavaScript? [online] [visited on 2020-11-30]. Available from: http://nicholasjohnson. com/blog/what-is-babel/. 5. Introduction to the DOM [online]. Brno: Mozzila, 2020 [visited on 2020-11-30]. Available from: https://developer.mozilla.org/ en-US/docs/Web/API/Document_Object_Model/Introduction. 6. Tutorial: Intro to React [online]. Brno: Facebook [visited on 2020- 12-27]. Available from: https://reactjs.org/tutorial/tutorial. . 7. What Is JSX? [online] [visited on 2020-11-30]. Available from: https://www.reactenlightenment.com/react-jsx/5.1.html. 8. Virtual DOM and Internals [online]. Brno: ReactJs [visited on 2020-12-27]. Available from: https://reactjs.org/docs/faq- internals.html. 9. Introduction [online]. Brno: VueJs [visited on 2020-12-27]. Avail- able from: https://vuejs.org/v2/guide/. 10. Meet the Team [online]. Brno: VueJs [visited on 2020-11-30]. Avail- able from: https://vuejs.org/v2/guide/team.html. 11. Template Syntax [online]. Brno: VueJs [visited on 2020-11-30]. Available from: https://vuejs.org/v2/guide/syntax.html.

46 BIBLIOGRAPHY

12. Introduction to Angular concepts [online]. Brno: Angular [visited on 2020-12-27]. Available from: https://angular.io/guide/ architecture. 13. Attribute directives [online]. Brno: Angular [visited on 2020-12- 27]. Available from: https://angular.io/guide/attribute- directives. 14. How Quickly Should a Page Load in 2020? [online]. 2020 [visited on 2020-12-27]. Available from: https://www.searchenginejournal. com/how-quickly-should-page-load/375799/. 15. WebAssembly [online]. Brno: Mozzila [visited on 2020-12-27]. Available from: https://developer.mozilla.org/en-US/docs/ WebAssembly. 16. ROURKE, Mike. Learn WebAssembly: Build web applications with na- tive performance using Wasm and C/C++. 1st ed. Packt Publishing, 2018. ISBN 1788997379. 17. Use Cases [online]. Brno: WebAssembly [visited on 2020-12-27]. Available from: https://webassembly.org/docs/use-cases/. 18. About [online] [visited on 2020-12-27]. Available from: https: //madewithwebassembly.com/about/. 19. Entity Framework Core [online]. Brno: Microsoft, 2020 [visited on 2020-12-23]. Available from: https://docs.microsoft.com/en- us/ef/core/. 20. Blazor University [online] [visited on 2020-12-22]. Available from: https://blazor-university.com/dependency-injection. 21. RESTful API (REST API) [online]. 2020 [visited on 2020-12-23]. Available from: https://searchapparchitecture.techtarget. com/definition/RESTful-API. 22. Design the infrastructure persistence layer [online]. 2018 [visited on 2020-12-30]. Available from: https://docs.microsoft.com/ en-us/dotnet/architecture/microservices/microservice- ddd - cqrs - patterns / infrastructure - persistence - layer - design. 23. CQRS [online]. 2011 [visited on 2020-12-23]. Available from: https://martinfowler.com/bliki/CQRS.html.

47 BIBLIOGRAPHY

24. What is Multi-Tenant? [online]. 2020 [visited on 2020-12-24]. Available from: https://www.ibm.com/cloud/learn/multi- tenant. 25. Multi-tenant Application Database Design [online]. 2020 [visited on 2020-12-23]. Available from: https://blakebhowe.medium. com/multi-tenant-application-database-design-e4c2d161f3dd. 26. Multi-tenant Database: Shared Database Separate Schema in SQL Server [online]. 2011 [visited on 2020-12-24]. Available from: https://www.experts-exchange.com/articles/6539/Multi- tenant- Database- Shared- Database- Separate- Schema- in- SQL-Server.html. 27. Introduction to ASP.NET Core Blazor [online]. Brno: Microsoft, 2020 [visited on 2020-10-07]. Available from: https : / / docs . microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore- 3.1. 28. Razor syntax reference for ASP.NET Core [online]. Brno: Microsoft, 2020 [visited on 2020-10-07]. Available from: https : / / docs . microsoft.com/en-us/aspnet/core/mvc/views/razor?view= aspnetcore-3.1. 29. ASP.NET Core Blazor routing [online]. Brno: Microsoft, 2020 [vis- ited on 2020-11-01]. Available from: https://docs.microsoft. com / en - us / aspnet / core / blazor / fundamentals / routing ? view=aspnetcore-5.0. 30. ASP.NET Core Blazor hosting models [online]. Brno: Microsoft, 2020 [visited on 2020-11-01]. Available from: https : / / docs . microsoft.com/en-us/aspnet/core/blazor/hosting-models? view=aspnetcore-5.0. 31. IVAN DEREVIANKO. Blazor - It’s Time to Forget JavaScript. 2019. Available also from: https://ivanderevianko.com/wp-content/ uploads/2019/07/blazor-hosting-models.png. [Online; ac- cessed December 29, 2020]. 32. BLAZOR UNIVERSITY. Component lifecycles. Available also from: https://blazor-university.com/wp-content/uploads/2020/ 07/component-lifecycle-1.jpg. [Online; accessed December 29, 2020].

48 BIBLIOGRAPHY

33. Code First [online] [visited on 2020-12-29]. Available from: https: //entityframeworkcore.com/approach-code-first. 34. Appropriate Uses For SQLite [online]. Brno: SQLite [visited on 2020-12-23]. Available from: https://www.sqlite.org/whentouse. html. 35. HIMSCHOOT, Peter. Blazor Revealed: Building Web Applications in .NET. 1st ed. Apress, 2019. ISBN 9781484243435. 36. Microsoft Azure [online]. 2020 [visited on 2020-12-30]. Avail- able from: https://searchcloudcomputing.techtarget.com/ definition/Windows-Azure. 37. ASP.NET Core web API documentation with Swagger / OpenAPI [online]. Brno: Microsoft, 2020 [visited on 2020-12-29]. Avail- able from: https : / / docs . microsoft . com / en - us / aspnet / core/tutorials/web-api-help-pages-using-swagger?view= aspnetcore-5.0.

49