Documente Academic
Documente Profesional
Documente Cultură
MAY
JUN
2020
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 8.95 Can $ 11.95
Stay at
Home!
200+ Sessions
100+ Microsoft and industry experts
Full-day workshops Evening events
SCOTT SCOTT
GUTHRIE HANSELMAN
Executive Vice President, Principal Program
Cloud + AI Platform, Manager, Web
Microsoft Platform, Microsoft
Features
8 Modern Authentication Columns
With so many different definitions for authentication, it’s hard to know
what’s involved. Sahil provides the basics to get you up to speed.
Sahil Malik
52 T alk to an RD:
Ciprian Jichici and Markus Egger
16 se the MVVM Design Pattern
U Ciprian and Markus talk about what’s coming in artificial
US subscriptions are US $29.99 for one year. Subscriptions outside the US pay $49.99 USD. Payments should be made in US dollars drawn on a US bank. American Express,
MasterCard, Visa, and Discover credit cards are accepted. Bill Me option is available only for US subscriptions. Back issues are available. For subscription information,
send e-mail to subscriptions@codemag.com or contact Customer Service at 832-717-4445 ext. 9.
Subscribe online at www.codemag.com
CODE Component Developer Magazine (ISSN # 1547-5166) is published bimonthly by EPS Software Corporation, 6605 Cypresswood Drive, Suite 425, Spring, TX 77379 U.S.A.
POSTMASTER: Send address changes to CODE Component Developer Magazine, 6605 Cypresswood Drive, Suite 425, Spring, TX 77379 U.S.A.
Soldiering On
Times are dramatic. You don’t need me to tell you that. The issue you’re currently reading—and I’d like
to call it “the issue you’re holding in your hands,” but this may or may not be the case—was meant to
be one of celebration and happiness. This is our twentieth year of publication, and we had planned
various things to celebrate the occasion. All of labor of love, and a personal passion of mine. It’s how we managed to recover. I think it will be an
this now had to be pushed out. not a cut-throat competitive publication. We’ve interesting read and hopefully help people to
always gotten along well with other developer prevent this kind of attack from happening, or
For CODE Magazine, the last six to nine months publications. I even wrote for MSDN Magazine at least to recover from it as quickly as possible.
have been a rollercoaster of emotions. During (and others) myself. I had friends there. Many (Note: No data leaks occurred. No data was sto-
spring and summer 2019, we planned various pointed out that we should try to take advantage len. But our ability to operate the business was
new initiatives for our publication. We were excit- of the situation and move MSDN Magazine sub- greatly impacted.)
ed and things were going well. One of the major scribers to CODE Magazine as a great business op-
steps was a partnership with Microsoft that gives portunity. Instead, we offered a free subscription I also want to take this opportunity to apologize
all Visual Studio subscribers, as well as MS Dev to MSDN Magazine readers who were looking for to readers who experienced a delay in getting
Essentials users, access to CODE Magazine free of another option for a print publication. their magazine delivered or getting online ac-
charge. cess. We did our best to serve all of our custom-
All in all, things were still very good until mid-De- ers (including all of the new customers that have
Things were good and looking up. Then things cember. Just before Christmas, really. As we were come onboard from the Microsoft partnership),
took a bit of a step back for the magazine busi- in the process of wrapping up the year, we were and we realize that it isn’t the best way to start a
ness, when MSDN Magazine ceased to publish. hit by a massive ransomware attack. I remember new relationship, but the attack was so severe, it
Many thought this was good news for us, but I was coming back from my last customer meeting, simply wasn’t possible to proceed with business
sad. CODE Magazine is a side-business for us. A thinking it was time to lean back and relax during as usual.
the Christmas holidays. Instead, every single one
of our servers and workstations was wiped out All of this, of course, now pales in comparison to
by this attack. We’re still working through the COVID-19 pandemic. As I write this, I’m work-
the aftermath of all that. Once we’re ing from home and only being in contact with
completely back on our feet, my friends and colleagues online. That part was
we’ll publish a detailed relatively easy for us, as we’ve always been set
article about what up for remote working. It’s still strange to not be
happened and able to see anyone in person. And the fear that
friends, co-workers, or family may be infected is
crippling. The logistics of publishing a magazine
have been made much harder by this also. As I
write this, I don’t know whether our printshop
will be deemed essential enough to print this is-
sue. I also realize that there probably are more
important things to do at this point than print
a software developer’s magazine. At this point,
we’ll just have to wait and see.
Markus Egger
6 Editorial codemag.com
OLD
TECH HOLDING
YOU BACK?
Are you being held back by a legacy application that needs to be modernized? We can help.
We specialize in converting legacy applications to modern technologies. Whether your application
is currently written in Visual Basic, FoxPro, Access, ASP Classic, .NET 1.0, PHP, Delphi…
or something else, we can help.
codemag.com/legacy
832-717-4445 ext. 9 • info@codemag.com
codemag.com
ONLINE QUICK ID 2005021
Modern Authentication
What does this “Modern Authentication” phrase mean to you? This is the challenge. Something so critical to our applications
doesn’t even have a good definition. I’m confident that now, many of you are wondering what this article is all about. This article
is about the absolute basics of authentication. When was the last time you wrote an application that didn’t need any information
about the user using the application? Almost never, right? worker has been. They’re just working from home. They just
Authentication is as essential as it gets. And yet the chal- fire up Microsoft Teams or similar, and it’s business as usual.
lenge is mixed with the jargon of keywords and chasing In fact, I’d argue that working remotely, done right, is more
ever-changing standards of security and identity. The field productive than sitting in an office, dealing with a commute
of authentication can appear overwhelming. for two hours a day, paying for, and maintaining all that
real estate, etc.
The result is poorly written applications. Think about it,
poorly written applications that concern user identity. Ouch! All of this is made possible because companies today have
the confidence that they can fire up Microsoft Teams or their
Sahil Malik The goal of this article is to simplify all of this, so you’re browsers, or other applications, authenticate to the corpo-
www.winsmarts.com better equipped to talk back smartly when someone throws rate network securely, and work. Although this act of join-
@sahilmalik all that technical identity jargon at you. The goal is to share ing an online meeting or opening a document on SharePoint
the absolute basics of identity that I wish everyone was on may appear banal, there are two very important tenets at
Sahil Malik is a Microsoft play here:
the same page about.
MVP, INETA speaker,
a .NET author, consultant,
• The organization is confident that this data is going
and trainer. What Is Modern Authentication? to be secure.
Sahil loves interacting with Let’s start with the first challenge. There’s no clear defini- • The employee or contractor finds this experience easy
fellow geeks in real time. tion of this term “Modern Authentication” and yet everyone and convenient to use.
His talks and trainings are throws the term around. So let’s attempt to define it first, at
full of humor and practical least for the purposes of this article. Although enabling such seamless productivity wherever you
nuggets. are, or whoever you are, and whatever device you are using,
The challenge is that we’ve had pretty good solutions for is the work of many technologies and many disciplines, a
His areas of expertise are authenticating and managing users for a while now. In the key enabler here is modern authentication.
cross-platform Mobile app Microsoft world, we’ve used Active Directory. But the con-
development, Microsoft cepts aren’t unique to active directory. There are protocols With that long-drawn out background, let me attempt to
anything, and security such as NTLMv2 and Kerberos that have been in use for some define what I mean by modern authentication.
and identity.
time now. The problem is that neither of these protocols are
perfect for an Internet world. Legacy Authentication
Legacy authentication is what we used for our dinosaur ap-
NTLMv2 relies on point-to-point exchange; to simplify, with- plications—protocols such as NTLMv2, Kerberos, or similar,
out sending my password over the wire, using some sort that you’ve typically used on-premises, are legacy authen-
of shared understanding between me and the recipient tication.
(server), the server is able to ascertain that I’m providing
the correct credential. This has a serious downside in that No, I’m not calling them extinct, they’re still our bread
my credentials can’t be forwarded by the server to another and butter. And those dinosaurs are being brought into
server. the modern authentication world kicking and screaming,
whether they like it or not.
To alleviate that issue, a protocol called Kerberos was creat-
ed. In Kerberos the domain controller hands out tickets for The reality is that organizations have a lot of investment in
creating sessions between the client and the server or the these classic/legacy identities. And as much as we’d like to,
domain controller itself. Kerberos is great and has served us many critical products, including those that run in Azure or
very well in corporate environments. Where it breaks down, AWS, don’t yet support modern identities properly. There’s
of course, is when you try to take things to Internet scale. a lot of investment in bridging this gap. For instance, there
For instance, Kerberos is extremely chatty and requires a lot are things such as Azure AD connect that let you bridge on-
of network ports to be opened for it to work. Now, organiza- premises Active Directory identities to Azure AD identities,
tions have really stretched the boundaries of what Kerbe- or products such as SQL in Azure or Azure Storage, that are
ros can do. There are concepts such as trusts, VPNs, and so making progress in working with modern identities.
much more that have enabled us to stretch the boundaries
of what was intended to be a single-organization solution. A lot of work still needs to be done here. I don’t have rose-
colored glasses on, and I must assert that these legacy iden-
The modern workplace is different. As I write this article, tities will be with us for quite a while.
the world is hunkering down due to the COVID-19 pandemic,
and a lot of businesses are getting really hurt. Restaurants, Modern Authentication
airlines, cruise ships—I can’t imagine the damage they’re Modern authentication refers to authentication established
experiencing right now. But compared to similar previous by protocols that are better designed for Internet scale and
crises, I’m simply amazed at how unfazed the information management. Although I realize that this is a very amor-
First, SAML works with SAML 2.0 tokens. Wait, isn’t this con- • Give your name and email address
fusing? Is SAML a protocol or a token? It’s both. WS Fed uses • Give your “friends” list
SAML 1x tokens, and SAML protocol uses SAML 2x tokens. • Let them access your information at any time
• Allow them to post on your behalf
Secondly, SAML gives you a lot more flexibility around who • Draw your blood (just kidding!)
starts the whole flow, what claims are needed for the ap-
plication to work, and how they are encrypted. Clearly, there has been abuse. And this has forced the hand
of many of these companies to limit the abuse.
Finally, SAML is newer, so it was back-fitted into scenarios
it was never intended for, such as SAML to JWT token trans-
formations or vice versa, or making SAML work on mobile OpenID Connect
platforms. OpenID Connect is a more formalized version of OAuth,
where the world agreed to agree on certain minimum stan-
As of today, SAML continues to be a very important protocol dards that protocols must follow for each major platform.
SPONSORED SIDEBAR: and will remain so for many years to come. They agreed on a certain basic set of tokens, and some basic
claims that must be present in those tokens that the world
Are Your Legacy Apps can rely on to know the user’s identity.
Stuck in the Past? OAuth
OAuth, isn’t an authentication protocol. It’s a delegation As of today, OpenID Connect is perhaps the main protocol
Need FREE advice on protocol. that all new development is being done under. Standards
migrating yesterday’s are powerful and it makes a lot of sense to get behind the
legacy applications to
Have you ever landed on a site where someone published standards. Azure AD v2 flows, for instance, are OpenID
today’s modern platforms?
an article so absurd that you were compelled to comment? Connect compliant. The main thrust of this article will be
Take advantage of CODE
Around the comment box, it says that you need to log-in OpenID Connect.
Consulting’s years of
experience migrating first. And some of the options include logging in using your
legacy applications by Facebook, Twitter, or Google accounts. There are three main things you need to know about OpenID
contacting us today to Connect:
schedule your free hour Here’s how that works. Let’s say that you pick Facebook. The
of CODE consulting with site then redirects you to Facebook, where you provide your • Tokens
our expert consultants. credentials. And then you’re redirected back to the site (the • Public client vs. confidential client
Get answers! No strings. SP), which now knows who you are and lets you log in. • Grant types or flows
No commitment.
For more information Here’s what’s really going on. You’re redirected to Facebook, Tokens
visit www.codemag.com/ not to authenticate yourself, but for the application to do In OpenID Connect, you perform token exchange. There are
consulting or email us certain things on your behalf. But who are “you” in that three kinds of tokens you should know of. Before I mention
at info@codemag.com. “your behalf” part? Well, that’s where you need to authen- what kinds of tokens, I should mention that the most common
ticate yourself. And what are those “certain” things? It’s format you’ll see for these tokens is the JWT format. Although
things like accessing your name and email address. This al- JWT isn’t a hard and fast requirement, it’s the most common
lows the application to know who you are, so it sort of works format you’ll run across. JWT is simply three JSON strings en-
like an authentication protocol, even though it was never coded in base64 format with the “.” character between them.
intended to be one. The first part is the header, the second is the body, and the
third is the signature. When an IdP issues a JWT token, it signs
In that sense, OAuth is a pseudo-authentication protocol. it with its private key, and using its public key, the consumer
of that token can ensure that the token hasn’t been tampered
with. It’s as simple as that. Oh yes, one other very important
thing, these tokens are sent over various protocols and must
In a sense, OAuth is a pseudo- not be leaked. The world has agreed that end-to-end encryp-
authentication protocol. tion, such as HTTPS/TLS, is a 100% hard-and-fast requirement
for these tokens to remain secure, so please keep that in mind.
Listing 1: Client Credential Flow • And what if the application is cloned? With ROPC,
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 you’re opening your users to be phishable. You have
Host: login.microsoftonline.com no idea if the application is closed or not.
Content-Type: application/x-www-form-urlencoded • Performance will be bad because you’ll have hashing
encryption of credentials.
client_id=<guid>
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default • Your server can’t distinguish the user from the app.
&client_secret=<secret> • Credentials are exposed to the client app. Credentials
&grant_type=client_credentials should never be anywhere else except the user and
the server. Frankly, when you can help it, not even the
user. Passwordless is what you should strive for.
• The client can now request any scope without an okay
Listing 2: Request for an auth-code
from the user. So, imagine that you can now access
https://login.microsoftonline.com/ the calendar app without the user knowing you’re ac-
{tenant}/oauth2/v2.0/authorize? cessing the calendar.
client_id=<clientid>
&response_type=code • There’s no support for federation.
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F • There’s no support for MFA.
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read • Advanced threat protection and conditional access be-
&state=12345 come less useful.
• There’s no SSO.
• It’s against the OAuth best practice guidelines
then also allows you to do interesting things, such as roles (RFC8252)
on headless processes. An important note about client cre-
dential flow: the access token returned is valid for an hour, Long story short, if someone asks you to use ROPC, run like
which is the default, but has configurable duration in Azure hell. Don’t do it.
AD. However, there’s no refresh token. To get a new access
token, you simply repeat the request. The request to get Here’s an interesting side note. Did you know that the Pow-
an access token using client credential flow can be seen in erShell commandlet Connect-MSOLservice, when logging in
Listing 1. For the eagle-eyed among you, the scope I’ve re- using saved credentials, uses ROPC behind the scenes? It’s a
quested here is https://graph.microsoft.com/.default. This good thing they deprecated the MSOnline module.
will give me a token for all scopes that have been consented
to. You’re required to use the ./default shortcut in CC flow. Authorization Code Grant Flow is a pretty good protocol.
It’s perfect for signing into a website and requesting ac-
Resource Owner Password Credentials grant flow, or ROPC, cess tokens for secure Web APIs. It works in two steps. First,
is where you play a username/password to an endpoint. you redirect the user to the authorization endpoint, where
Long story short, try not to use it. You have to use it when the user provides their credentials and authenticates them-
you must have 100% control on the UX for sign in, but the selves. Hold on! I thought authorization and authentication
downsides far outweigh the upsides. Here are some reasons were separate concepts? Yes, they are, and this nomencla-
why you should avoid using ROPC: ture can be off putting. But remember, an authorization step
is when you have a chance of showing a user interface, and
• ROPC is very hacker-friendly, and you’re taking on a there is where the user authorizes that such and such appli-
big responsibility for securing a much larger attack cation is allowed to do such and such actions. This process
surface now. For instance, it’s now your responsibility is called consent. So the name, authorization endpoint,
to protect against brute force, password spray, dic- makes sense. The request to the authorization endpoint
tionary attacks, etc. looks like Listing 2. It’s worth mentioning that requesting
• You’re between a rock and a hard place—the rock the auth-code is just one possible mechanism here.
being taking responsibility to secure the user’s cre-
dentials on a public client and the hard place being There are some interesting things going on in Listing 2.
prompting the user for frequent sign ins. Guess what Let’s try to understand them. First of all, it’s a simple GET
most people do then? Store credentials in public cli- request. The request must include things like who are you
ent, which is a bad idea!!! (client ID), what you’re asking for access to (scope), and,
The request for an access token, if successful, returns an ac- Scopes also allow me to request access tokens, where the
cess token to all the scopes you have previously consented scp claim of the scope includes the audience against which
to. There are some important things to know about the re-
quest you see in Listing 3.
Listing 3: Asking for an access token
First, that it’s a POST request played to the token endpoint. POST /{tenant}/oauth2/v2.0/token HTTP/1.1
If you asked for a refresh token in scopes, you can also play Host: https://login.microsoftonline.com
that refresh token to this endpoint to get new access tokens Content-Type: application/x-www-form-urlencoded
without asking the user to sign in again. You request a re-
client_id=<appid>
fresh token using the scope offline_access. Effectively, this &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
means that the user allows you to access functionality on &code=<authcode>
their behalf, when offline. That is, the user doesn’t need to &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
sign in every time you ask for an access token. A common &grant_type=authorization_code
&client_secret=<secret>
poor architecture is to store access tokens on durable stor-
age, or to reuse refresh tokens across multiple nodes via
durable storage, such as databases. This is a terrible idea
and breaks the concept of non-repudiation.
my access token must work. For instance, a valid scope is consent. Consent can be granted either during log in, by the
https://graph.microsoft.com/user.read. When I ask for this user, as can be seen in Figure 3, or by an administrator dur-
scope, I’m asking for an access token that has the ability to ing log in, ahead of time via an API, or via the Azure Portal,
read the currently logged-in user’s profile on an API called as can be seen in Figure 4.
Microsoft Graph.
Some specific scopes require an administrator consent. For
This means that the user must allow the act of reading the instance, you wouldn’t want some random user in your or-
user’s profile being read. This allowing act is called granting ganization to grant the permission to register new apps,
right?
Summary
ADVERTISERS INDEX This article is loaded with information, so if you read this
far, congratulations. I don’t pat myself on the back often,
but the information in this article is very hard to find in a
Advertisers Index succinct, accurate, and easy to understand manner. I wish
this basic information about identity was common knowl-
CODE Consulting edge to everyone. It would really make many tasks so much
www.codemag.com/consulting 76 simpler.
You’re going to be guided step-by-step building an MVC elements on the page, the POST method in the controller
Core application using the Entity Framework (EF) and a view accepts the view model as its parameter and all the bound
model class to display and search for product data. properties are filled in automatically.
For many of you, the only thing that might be a little differ- For example, I’m going to create my project under the D:\
ent is the addition of the view model classes. The focus of Samples folder. Once I open a terminal window, I type in
this article is to show how to simplify your controllers and the command:
move most of your logic into view model classes. A second-
ary focus is to illustrate how to build a multi-layered project CD D:\Samples
in Visual Studio Code with .NET Core.
Once you’re in your development folder, create a new folder
In this article, you’re going to be using the SalesLT.Product named MVVMSample using the MKDIR (or the MD) com-
table in the AdventureWorksLT database. You’ll first learn to mand:
build an HTML table to list all products in this table. Next,
you add search capabilities so you can search on one or mul- MKDIR MVVMSample
tiple columns. The logic to build the listing and searching is
created in the view model class instead of in the controller. Change to the new directory using the CD command in the
terminal window, as shown in the command below.
The ProductController class (1a in Figure 1) has both an
instance of a ProductViewModel class (2a) and an imple- CD MVVMSample
mentation of an IProductRepository (3b) injected into it by
MVC Core. The implementation is a ProductRepository class Create a new MVC Core project in the MVVMSample folder by
(3c), which also has an instance of the AdvWorksDbContext executing the dotnet new mvc command.
class (3a) injected into it by MVC Core.
dotnet new mvc
The ProductRepository is passed into the constructor of the
ProductViewModel class by the DI service in MVC Core. A Once the command has run, open the folder in VS Code by
method named HandleRequest() is called on the view model clicking the File > Open Folder… menu. A few seconds after
to retrieve the data from the Product table using the Entity opening the folder, you should be prompted with a dialog
Framework, which is implemented in the ProductRepository that looks like Figure 2. Click on the Yes button to add the
class. Each row of data in the Product table is represented required assets to the new project.
by the entity class Product (4a). A generic list of Product
objects is placed into a Products property of the Product-
ViewModel. This view model class is used as the model to the
Products page to create the HTML table.
The dotnet new classlib command creates a class library Create the Data Layer Project
project with the minimum number of references to .NET Core The next project to create is the Data Layer project in which
libraries. Now that you’ve created this new project, add it you place all your repository classes. These repository class-
to your Visual Studio Code workspace by clicking the File > es interact with the tables in your database through the
Add Folder to Workspace… menu. Select the MVVMEntity- Entity Framework. Each repository class should implement
Layer folder and click on the Add button. You should see the an interface. Having both a class and an interface allows
MVVMEntityLayer project added to your VS Code workspace. you to use DI to inject the concrete implementation of the
To create this project, open a terminal by clicking on the Add Product Interface Class
Terminal > New Terminal menu. Go to your development Our repository class needs a single method named Get()
directory (in my case, that was D:\Samples). Type in the used to retrieve all records from the Product table. Before
following commands to create a new folder named MVVM- creating the repository class, add an interface with the con-
DataLayer. tract for this Get() method. Create a new file in the Reposi-
toryInterfaces folder named IProductRepository.cs. Add
MD MVVMDataLayer the code shown in the code snippet below.
CD MVVMDataLayer
using System.Collections.Generic;
dotnet new classlib using MVVMEntityLayer;
Add this new project to your Visual Studio Code workspace, namespace MVVMDataLayer
by clicking the File > Add Folder to Workspace… menu. {
Select the MVVMDataLayer folder and click on the Add but- public interface IProductRepository
ton. You should now see the MVVMDataLayer project added {
to your VS Code workspace. Save your workspace by clicking List<Product> Get();
on the File > Save menu. You can go ahead and delete the }
Class1.cs file, as you won’t be needing that. }
a reference from the MVVMSample to both the MVVMEntity- to be kept track of, so where do you put it? You don’t want
Layer and the MVVMDataLayer projects, all three projects to add it to your entity class as you then need to add ad-
are built. Select the Terminal > Run Build Task… menu and ditional attributes to mark them as not mapped to the table.
select the MVVMSample project. Watch the output in the ter- Plus, you’re going to need these properties on many differ-
minal window and you should see that it compiles all three ent pages, and you don’t want to copy and paste them from
projects. one entity class to another.
create the class in the POST method of your controller. The output in the terminal window and you should see that it
other constructor is passed an instance of a ProductReposi- compiles all projects.
tory class when the ProductViewModel is created by the DI
system in MVC Core.
Set Up the MVC Project
Two public properties are needed in the view model. One is Now that you have the entity, data, and view model proj-
for the repository object. This allows you to set the reposi- ects created to support retrieving and modifying data in the
tory object in the POST method of your controller. The other Product table, it’s now time to set up the MVC project for us-
property is a list of Product objects that will be loaded with ing these classes. The AdvWorksDbContext class needs to be
all the products returned from the table. It’s from this prop- injected using the DI service, so you need to add a reference
erty that the HTML table is built. to the Entity Framework in your MVC project. Select Termi-
nal > New Terminal and ensure that the terminal prompt is
Two methods are created in this first iteration of your view in your MVVMSample project folder. Type in the following
model. The protected LoadProducts() method is responsible command to add the Entity Framework to your MVC project:
for calling the Get() method on the Repository object and
retrieving the list of product objects. The public HandleRe- dotnet add package
quest() method is called from the controller to retrieve the Microsoft.EntityFrameworkCore.SqlServer
product data. In the future, more logic is added to the Han-
dleRequest() method to perform other functions such as Modify the Startup Class
searching, paging, adding, editing, and deleting of product In the Startup class is where you inject your classes into the
data. The HandleRequest() method should be the only pub- MVC DI service. Open the Startup.cs file and add three us-
lic method exposed from this view model class. By making ing statements at the top. You need one each for your Data
all other methods not visible outside the class, your control- Layer, View Model Layer, and for the Entity Framework.
ler only needs to ever call a single method.
using MVVMDataLayer;
Reference View Model Layer from MVVM Sample Project using MVVMViewModelLayer;
using Microsoft.EntityFrameworkCore;
The DI service requires an instance of the ProductViewModel
class to insert into your control, so reference the view model
Next, create a new method in the Startup class named In-
layer project from your MVC Core project. Click on the Ter-
jectAppServices() as shown in Listing 5. This method is
minal > New Terminal menu and select the MVVMSample
where you inject your application-specific classes. I like
folder. Set a reference to the MVVMViewModelLayer project
creating a separate method so I don’t have an overly-large
using the following command.
ConfigureServices() method. Add a call to the InjectAppSer-
vices() method from within the ConfigureServices() method
dotnet add . reference
as shown in the code snippet below.
../MVVMViewModelLayer/MVVMViewModelLayer.csproj
Listing 5: Build a separate method to inject your classes into the MVC DI service
private void InjectAppServices(
Create a Product List Page
IServiceCollection services) I hope you agree that you now have a very elegant, reus-
{ able, and testable design with the code you’ve written so
// Get connection string from appsettings.json
string cnn = Configuration[
far. It’s now time to see the fruits of your labor expressed in
"ConnectionStrings:AdvWorksConnectionString"]; a controller of your MVC application. Create a new Product-
Controller.cs file in the Controllers folder and add the code
// Add AdventureWorks DbContext object shown in Listing 6 to this new file.
services.AddDbContext<AdvWorksDbContext>(
options => options.UseSqlServer(cnn));
The MVC DI service injects an instance of the ProductRepository
// Add Classes for Scoped DI and the ProductViewModel classes into the ProductController
services.AddScoped<IProductRepository, class. Two private variables hold each of these instances passed
ProductRepository>();
services.AddScoped<ProductViewModel>(); in. When the user navigates to the Product/Products path in
} the MVC application, the HandleRequest() method is called on
the view model. This method loads the products into the Prod-
ucts property in the view model. The view model is then passed
Listing 6: The controller logic is very simple because of DI and the MVVM design pattern to the Products.cshtml page, which you’re creating next.
using Microsoft.AspNetCore.Mvc; Add a Product Page
using Microsoft.Extensions.Logging;
using MVVMDataLayer; Add a Product folder under Views folder in which to put
using MVVMViewModelLayer; the MVC pages for displaying your product data. Create a
Products.cshtml file in this new Product folder and enter
namespace MVVMSample.Controllers
{
the code shown in the snippet below.
public class ProductController : Controller
{ @model MVVMViewModelLayer.ProductViewModel
private readonly IProductRepository _repo;
private readonly ProductViewModel _viewModel;
@{
public ProductController( ViewData["Title"] = "Products";
IProductRepository repo, }
ProductViewModel vm)
{
_repo = repo; <h1>Products</h1>
_viewModel = vm;
} <partial name="_ProductList" />
public IActionResult Products()
{ Add a Product List Partial Page
// Load products Add a partial page named _ProductList.cshtml in the Product
_viewModel.HandleRequest(); folder. Add the code shown in Listing 7 to this new partial page
file. You’re going to be adding more functionality to the product
return View(_viewModel);
} page as you progress through this series of articles, so it makes
} sense to break your page into multiple partial pages. This is a
} good separation of concerns design pattern for Web pages.
Listing 7: Create a partial page for the display of the Product table
@using MVVMEntityLayer @Html.DisplayFor(m => item.Name)
</td>
<table class="table table-bordered table-hover"> <td>
<thead> @Html.DisplayFor(m => item.ProductNumber)
<tr> </td>
<th>Product Name</th> <td class="text-right">
<th>Product Number</th> @Html.DisplayFor(m => item.StandardCost)
<th class="text-right">Cost</th> </td>
<th class="text-right">Price</th> <td class="text-right">
</tr> @Html.DisplayFor(m => item.ListPrice)
</thead> </td>
<tbody> </tr>
@foreach (Product item in Model.Products) { }
<tr> </tbody>
<td> </table>
<div class="list-group">
<a asp-action="Products"
asp-controller="Product"
class="list-group-item">
Product List
</a>
</div>
Try It Out
Run the application and click on the Product List link. If
you’ve done everything correctly, you should see the list of
products from the Product table in the AdventureWorksLT
database, as shown in Figure 4.
<button type="button"
data-custom-cmd="search"
class="btn btn-success">
Search
</button>
To get the command and send it to the view model, you’re going
to write a little bit of JavaScript to put the value “search” into
a hidden field on this product page. That hidden field is bound
to the EventCommand property in the view model base class. In
the HandleRequest() method you’re going to check to see if the
EventCommand is filled in with a value, in this case “search”,
and if it is, call a Search() method instead of the LoadProducts()
method you called before to display all products.
Instantly Search
} Looking to create a new
or convert an existing
Terabytes
Because you added a virtual HandleRequest() method in application to .NET Core or
the view model base class, add the override keyword to the ASP.NET Core? Get started
HandleRequest() method declaration in the ProductView- with a FREE hour-long
Model class. CODE Consulting session
to make sure you get
public override void HandleRequest()
started on the right foot.
CODE consultants have
Modify the HandleRequest() method to check the EventCom-
been working with and dtSearch’s document filters
contributing to the .NET support:
mand property to see if there’s a value in it. If there’s no
Core and ASP.NET Core
value, call the LoadProducts() method as before. However, teams since the early pre- • popular file types
if there’s a “search” value in the EventCommand property,
call the SearchProducts() method you just created. The Han-
release builds. Leverage • emails with multilevel
our team’s experience
dleRequest() method should now look like the code snippet and proven track record
attachments
below. to make sure your next • a wide variety of databases
project is a success. No • web data
public override void HandleRequest() { strings. No commitment.
switch (EventCommand.ToLower()) { For more information
case "search": visit www.codemag.com/
SearchProducts(); consulting or email us at Over 25 search options
break; info@codemag.com. including:
default: • efficient multithreaded search
LoadProducts(); • easy multicolor hit-highlighting
break;
• forensics options like credit
}
}
card search
Getting the Sample Code be posted back to the view model in the POST method of only products that start with the letters “HL” displayed in
the Product controller. Open the Products.cshtml page and the product table.
You can download the sample replace the previous <partial> tag with the code shown in
code for this article by visiting the following snippet.
www.CODEMag.com under Summary
the issue and article, or by <form method="post"> In this article, you got a taste of how to architect an MVC
visiting www.pdsa.com/ <partial name="~/Views/Shared/ Core application with multiple projects. Separating your
downloads. Select “Fairway/
_StandardViewModelHidden.cshtml" /> entity, data, and view model classes into separate projects
PDSA Articles” from
<partial name="_ProductSearch.cshtml" /> provides you with the most flexibility and helps you focus on
the Category drop-down.
Then select “Use the
<partial name="_ProductList" /> each layer as you develop. You also learned how little code
MVVM Design Pattern in </form> you need in your controller. Using a hidden field makes it
MVC Core - Part 1” from easy to communicate commands to your view model. In the
the Item drop-down. Post the Form Using JavaScript next article, you’ll learn how to do sorting and paging using
On the Search button, you set the button’s type attribute to the MVVM design pattern.
button, which means that it won’t post the form back to the
controller. It’s now time to see how you’re going to accom- Paul D. Sheriff
plish that. At the bottom of the Products page, add a section
for some JavaScript and enter the code shown in Listing 10.
[HttpPost]
public IActionResult Products(
ProductViewModel vm)
{
vm.Repository = _repo;
vm.HandleRequest();
return View(vm);
}
Try It Out
Run the application, enter some data, like “HL” for the
Product Name, in the Search field and click on the Search
button. If you’ve done everything correctly, you should see
many of AWS’s services. I didn’t know any of this and when Go to aws.amazon.com/freetier to create the account. It
it was being relayed to me for the first time, I was surprised does require a credit card. You’ll initially create what is
and a little embarrassed. Not embarrassed that I wasn’t ex- called a “root account.” That’s like a master account and
pert in any of this but just that I hadn’t thought to look at once that exists, you can create Identity and Access Man-
any of this until now. agement (IAM) users in the root account. AWS strongly rec-
ommends, as a best practice, that you only use IAM users
So where to begin? Well, there are also a host of database to build apps and services, not the root account. When you
engines in AWS and, given my long relationship with Entity create an IAM user, you can associate two access types: pro-
Framework and EF Core, that seemed like a good first stop grammatic and management console access. You don’t need
Julie Lerman for me. What I’ll do in this article is take an existing small to create the IAM account in advance as the AWS Toolkit
thedatafarm.com/blog ASP.NET Core API that uses EF Core, use EF Core migrations for Visual Studio (which I’ll walk you through below) will
twitter.com/julielerman to create a database on AWS, interact with the database, give you some helpful guidance for creating IAM user cre-
and explore secrets management for the database creden- dentials and even importing them into the toolkit. But you
Julie Lerman is a Microsoft do need to have the root account before you start. Here’s a
tials both locally and for a deployed app.
Regional Director, Docker
link to additional information about identities in your AWS
Captain and a long-time
RDS is the acronym for Amazon’s Relational Database Ser- account: https://docs.aws.amazon.com/IAM/latest/User-
Microsoft MVP who now
counts her years as a coder vice. Amazon RDS is a database service that provides access Guide/id.html.
in decades. She makes to several relational databases on AWS: SQL Server, Oracle,
MariaDB, MySQL, and PostgreSQL. It also has a database
her living as a coach and
called Amazon Aurora, which is Amazon’s cloud-native, dis-
Setting Up the AWS Toolkit
consultant to software
teams around the world. tributed relational database that’s MySQL and PostgreSQL with Your Credentials
You can find Julie present- compatible. And Aurora is fast; according to Amazon (aws. The AWS Toolkit for Visual Studio can be installed from the
ing on Entity Framework, amazon.com/rds/aurora): five times faster than access- Visual Studio extensions. There’s also an AWS Toolkit for Vi-
Domain Driven Design and ing MySQL directly through RDS and three times faster sual Studio Code (https://aws.amazon.com/blogs/develop-
other topics at user groups than PostgreSQL. With the exception of Aurora and Aurora er/announcing-aws-toolkit-for-visual-studio-code/), which
and conferences around Serverless (aws.amazon.com/rds/aurora/serverless/), the is focused on creating serverless functions and applications.
the world. Julie blogs at RDS databases are also available via AWS’s free tier, which
thedatafarm.com/blog, makes them great targets for exploring AWS databases with When you first use the Toolkit’s Explorer, a Getting Started
is the author of the highly existing EF Core database providers. page prompts you connect the toolkit to your IAM account
acclaimed “Programming or create an IAM account. Once you’ve associated an IAM
Entity Framework” books, An important concept about RDS databases is that you start account, the explorer lets you see everything tied not just
the MSDN Magazine Data by creating a database instance that’s like a server. When to that particular IAM account but filtered by regions. I’d
Points column and popular creating an instance, you configure it for the type of data- done my first RDS experimentation online, creating a SQL
videos on Pluralsight.com. base you want (e.g., SQL Server or MySQL) along with other Server and a PostgreSQL database, then interacting with
Follow Julie on twitter
attributes that affect performance, scaling, and cost. Then them through Azure Data Studio. This was one of those silly
at julielerman.
you can create databases inside of an instance. More on this exciting moments in the life of a developer when I first got
later. everything connected. Satisfied that I’d worked this out cor-
rectly, I moved on to Visual Studio and the AWS Toolkit. I’ll
I’ll take an existing small ASP.NET Web API and retarget it to walk you through the AWS Toolkit path for creating the IAM
SQL Server Express on RDS to see what the experience is like. account and your first database instance, and then you’ll let
If you want to follow along, you can download the starting EF Core create a database using migrations.
example from github.com/julielerman/codemagawsrds or
on the CODE Magazine page associated with this article. The Toolkit’s Getting Started page (Figure 1) provides a link
to the AWS Console and also lists a small set of steps to per-
form so that you can avoid getting caught up in credential
Setting Up an Account with management. Following these steps, I began by signing into
AWS Free Tier the AWS Console with my root account and then added a
You’ll need an AWS account in order to do any of this work. new IAM user named JulieCodeMag, checking the Program-
And if you don’t have an account, it’s easy to create one matic access type as instructed by the Getting Started page.
using the Free Tier (aws.amazon.com/freetier) which gives The next step is to either add the user to an existing permis-
access to a variety of services that are always free, others sions group or directly to one of the AWS policies. Again, as
that are free for some amount of use (e.g., number of GBs or per the instructions, from the possible power user policies,
hours), others that are free for 12 months, as well as access I chose AdministratorAccess, which is okay for my purposes,
to free trials for some additional services. The RDS services not production. After this, I just left the last few options at
are in the 12 months bucket, giving you up to 750 hours their default and let AWS create the user. Finally, I clicked
a month, 20 GB of storage and 20 GB of backup—certainly the Download .csv button, saved the file and then imported
enough to start exploring. the CSV file into the toolkit using an option on the Getting
Figure 2: Ensure that Publicly accessible and Add current IP are checked.
Started page. Note that the CSV file doesn’t populate one As a result, the AWS Explorer was then populated with nodes
of the fields—Account Number—and that’s okay. Next, I re- for all of the services that the toolkit provides access to.
named the profile from default to JulieCodeMag and saved And because the JulieCodeMag user has broad access, I was
the credentials. able to see services tied to any of my IAM accounts created
Deploying
in the specific region. I’d created my test database instanc- each instance (see Figure 3) so you can see when the new
You can learn more about es in the US East (Ohio) region so if the explorer is filtered instance (in my case “codemagmicro”) is available. I did ex-
deploying at https://docs. on that region, I’ll see those instances. If I changed the periment with creating various types of database instances
aws.amazon.com/toolkit- explorer region, I wouldn’t see those database instances. from the Toolkit. As I expected, both PostgreSQL and MySQL
for-visual-studio/latest/ instances took less time than SQL Server although the dif-
user-guide/deployment- ference wasn’t significant
beanstalk.html. Creating an RDS Instance Through
the Toolkit Once the instance is available, I can use EF Core migrations
You will need a database instance (remember, this is like against my little sample application to create a database in
a running server) before EF Core can create databases in the instance. You can download the sample or create a new
that instance. And you can create new instances through ASP.NET Core API. As I’m using VS, I’m doing that through
the toolkit, so let’s do that. the create project workflow, not the CLI. I left defaults as
they are: e.g., no authentication and configured for HTTPS.
Right-click on the Instances node under Amazon RDS, then Given that this is using Amazon’s cloud, the model goes back
choose Launch Instance. That means to launch (create) a to Amazon’s roots with authors and books. And keeping it
new instance. You’ll then see a list of the possible engines simple, one author can write multiple books but there are no
for which you can create an instance including various SKUs co-authors, therefore it’s a strict one-to-many relationship.
of Microsoft SQL Server and all of the other RDS options. I’ll
choose SQL Server Express. For those of you who’re used to public class Author
using EF Core’s Windows default, SQL Server LocalDB, for de- {
velopment, LocalDB is a slice of Express (https://docs.micro- public Author()
soft.com/en-us/sql/database-engine/configure-windows/ {
sql-server-express-localdb?view=sql-server-ver15). But it’s Books = new List<Book>();
not a separate option from Express. Once you’ve selected }
the engine, you’ll be prompted to configure the instance to public int AuthorId { get; set; }
specify the database version, memory (“DB Instance class”) public string Name { get; set; }
for which I chose the smallest: micro and storage. You’ll also public List<Book> Books { get; set; }
be prompted to set up a user name and password. The highest }
version available as I’m writing this is SQL Server 2017.
public class Book
The next page of the configuration, Network and Security, {
has a critical setting that you need to enable, which is to public int BookId { get; set; }
make the database publicly available (see Figure 2) for the public int AuthorId { get; set; }
sake of this exploration. Do keep in mind that it’s not a public string Title { get; set; }
best practice for production. Although the Toolkit will be }
able to see the instance, you won’t be able to connect to
it from your code or from any tools like Server Explorer in Starting with ASP.NET Core 3.0, EF Core is no longer included
Visual Studio, SSMS, Azure Data Studio, etc. By default, the in the default dependencies, so you’ll have to add Microsoft.
databases are locked down and only accessible from within EntityFrameworkCore.SqlServer to the project via NuGet.
the VPC that RDS creates to host the instance. Therefore Additionally, because you’ll be using migrations, add the
it’s also necessary to allow a specific IP address (or range) Microsoft.EntityFrameworkCore.Tools package, which gives
to access RDS so that other Visual Studio tools, such as the you the PowerShell version of the migration commands and
SQL Server Object Browser, are able to connect. To do that, the design time logic.
be sure to check the “Add current IP” option also shown in
Figure 2. With EF Core included, I then added a simple DbContext class
called BookContext. Note the constructor that’s needed for
There’s one more page with configuration for backups and ASP.NET Core to use Dependency Injection (DI).
maintenance. By default, RDS backs up the instance im-
mediately after creation and then performs backups daily. public class BookContext:DbContext
For this exploration, I recommend changing that setting to {
“No Automated Backups,” which makes the instance avail- public BookContext
able more quickly. The rest of the defaults are okay for our (DbContextOptions<BookContext>
purposes. The grid for DB Instances shows the status of options) : base(options) { }
Now it’s time to wire up the API with the database instance
and specify a database to work with. I’ll name mine Books-
Database because I’m a very creative human. More impor-
tantly, I’ll need the server name.
"ConnectionStrings": {
"BooksDb" :
"Server=codemagmicro.***.us-east-2
.rds.amazonaws.com,1433;
Database=BookDatabase"
},
Getting the Secrets on AWS Finally, you’ll tell the application (in program.cs) to load
for the Deployed App the AWS parameters into the ASP.NET Core’s configurations.
So far, the database connection credentials are stored on The new code, the italicized ConfigureAppConfiguration
my computer using ASP.NET Core Secret Manager. When I method in this code snippet, goes in the CreateHostBuilder
deploy the API to the AWS Cloud, it’ll need access to those method in program.cs.
secrets. AWS provides a few ways to store secrets and make
them available to other AWS services. Because I’m relying public static IHostBuilder
on ASP.NET Core’s ability to read parameters, I’ll use the CreateHostBuilder(string[] args) =>
AWS Systems Manager Parameter Store to tuck away my user Host.CreateDefaultBuilder(args)
and password values. .ConfigureAppConfiguration(
(context, builder) =>
There are a few steps involved. {
Now that you have confidence that this is working, you may
want to go back to reading from the local secrets while de-
veloping and the AWS parameters in production. To do that,
you can force the app to only load the AWS configurations
when the application environment is production, not devel-
opment.
.ConfigureAppConfiguration(
(context, builder) =>
{
if (context.HostingEnvironment
.IsProduction())
{
builder.AddSystemsManager
("/codemagapi");
}
})
Even though I’m not walking you through the final bit of
deploying the API, I did publish the API to AWS Elastic
Beanstalk in order to see for myself that everything was
working as expected. See the deployment article noted in
the sidebar to learn more about deploying apps to AWS from
the toolkit.
The Angular CLI prompts you with a set of questions to bet- ng generate library auth
ter customize the experience for your own needs and re-
quirements. My answers to those questions are listed here: This command creates a new library named auth inside a
folder located under the root-level projects folder. The An-
• Would you like to add Angular routing? Yes gular CLI places all libraries under this root-level projects
• Which stylesheet format would you like to use? SCSS folder. The Auth library generates an Auth module that
The command scaffolds a new auth.service.ts file inside the To logout a user, the Auth service defines this function:
services folder inside the auth library. Listing 1 defines the
login() function. logout() {
localStorage.removeItem('currentUser');
The code initiates a POST /auth/login request to the back- this.currentUserSubject.next(null);
end REST API passing over the username and the password }
that the user has entered on the login form. If the back-
end server successfully authenticates the user and returns a The function removes the user details from the LocalStorage
The Source Code
valid accessToken (JWT), the function: and also resets the user details inside the currentUserSubject.
You can find the source code
of this article and the rest • Stores the user details including the JWT inside Lo- Add Auth Guard
of this series in this repo: calStorage The Auth guard decides if a user can access a requested
https://github.com/bhaidar/ • Populates a private currentUserSubject with the user Route. Depending on whether the user is authenticated or
nestjs-todo-app details not, the Auth guard responds accordingly. Start by generat-
ing a new guard by running the following command:
import {
ActivatedRouteSnapshot,
RouterStateSnapshot,
CanActivate,
Router
} from '@angular/router';
import { AuthService } from './services/auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router,
private authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot) {
const currentUser = this.authService.currentUserValue;
if (currentUser) {
// logged in so return true
return true;
}
this.router.navigate(['/login'], { queryParams: {
returnUrl: state.url } });
return false;
}
}
Figure 3: Auth library
• Making sure the form is valid. For this reason, I’ll add and implement an Angular Inter-
• It then calls the AuthService.login() function passing ceptor that will perform a lookup prior to sending any re-
to it the username and password entered by the user. quest to the server. It checks if there is a valid user record
stored in the Auth Service, extracts the token from the re-
cord, and adds a Bearer Authentication Header token onto
Listing 5: JWT Interceptor the request. This is exactly what the back-end REST API
is expecting to properly verify and authenticate the user
import {
HttpInterceptor, request.
HttpRequest,
HttpHandler, Listing 5 defines the JWT Interceptor.
HttpEvent,
HTTP_INTERCEPTORS
} from '@angular/common/http'; • An Angular interceptor implements the HttpInterceptor.
import { Observable } from 'rxjs'; • It implements a single function named
import { Injectable } from '@angular/core'; intercept(request: HttpRequest<any>, next:
import { AuthService } from './auth.service';
HttpHandler): Observable<HttpEvent<any>>.
@Injectable() • The Angular infrastructure passes to the intercept()
export class JwtInterceptor implements HttpInterceptor { function the current HTTP Request and the next han-
constructor(private authService: AuthService) {} dler in the pipeline (could be another interceptor).
intercept( • The function then accesses the currentUserValue
request: HttpRequest<any>, property on the Auth Service.
next: HttpHandler • If the property has a valid user and a valid access to-
): Observable<HttpEvent<any>> { ken, it clones the current request and sets the Autho-
// add authorization header with jwt token if available
const currentUser = this.authService.currentUserValue; rization header to a Bearer {JWT} string.
if (currentUser && currentUser.accessToken) { • Finally, it returns a call to the next.handle(request)
request = request.clone({ so that other handlers in the request pipelines are ex-
setHeaders: { ecuted all the way to reach the back-end REST API.
Authorization: `Bearer ${currentUser.accessToken}`
}
}); The last line in the listing defines an Angular Provider for
} this interceptor. You’ll provide this interceptor in the App
return next.handle(request);
main module. This way, you ensure that any request the ap-
} plication sends to the back-end REST API has an Authoriza-
} tion header set properly.
export const jwtInterceptorProvider = {
provide: HTTP_INTERCEPTORS, Add Error Interceptor
useClass: JwtInterceptor, The back-end REST API returns a 401 Unauthorized response
multi: true when it can’t verify and authenticate a user. It also returns
}; other types of responses including 400 Bad Request, 403
Forbidden and others. The front-end application needs a Listing 7: TypeORM migration
way to capture the “bad” response from the back-end REST
import { MigrationInterface, QueryRunner } from 'typeorm';
API and act.
export class SeedUserRecord1565812987671 implements
For instance, if the back-end REST API returns a 401 Un- MigrationInterface {
authorized response, this means that the application is public async up(queryRunner: QueryRunner):
Promise<any> {}
requesting a secured API endpoint while the user is not
logged in to the application (no Authorization Header) on public async down(queryRunner: QueryRunner):
the request. In this case, the front-end app should redirect Promise<any> {}
the user to the Login page to authenticate themselves with }
the back-end REST API.
await userRepo.save(user);
}
I’ll add and implement a new Angular Interceptor to handle
the error responses from the back-end REST API properly. // tslint:disable-next-line: no-empty
public async down(queryRunner: QueryRunner):
Listing 6 defines the ErrorInterceptor class. Promise<any> {}
}
• This interceptor hooks into the response payload.
• If the response HTTP Status Code is 401 and the user
is not on the Login page, it’s likely that the user isn’t classes and styles to render a better Popup or Modal
authenticated or a token has expired. In this case, the dialog to show the errors to the user.
interceptor redirects the user back to the Login page. • Finally, the interceptor throws the errors to signal to
• Any other error received from the back-end REST API is the Angular infrastructure that the response was not
properly handled and stored inside a variable named okay.
error.
• The current interceptor simply alerts the error to the The last line in the listing defines an Angular Provider for
user. You can be fancier and use some Bootstrap 4 this interceptor.
Navigate to the server folder of this application, where the • The code uses the queryRunner.manager object to
back-end REST API source code exists, and run the following get access to a Repository instance for the UserEntity.
command: • It then creates a new User entity record.
• Finally, it saves the new entity into the database.
ts-node ./node_modules/typeorm/cli.js
-f ormconfig.json migration:create -n To run the migration and seed your database with a new
SeedUserRecord user record, run the following command:
This command uses the TypeORM CLI to create an empty mi- npm-run-all -s -l clean build:server && ts-node
gration file. Listing 7 shows the file contents. ./node_modules/typeorm/cli.js -f ormconfig.json
migration:run
The up() function() runs when the migration is running.
The down() function runs when rolling back a migration. The command cleans any previous builds of the back-end
REST API source code, it then builds and transpiles the Type-
Script code to proper JavaScript code and finally runs the
migration.
It’s very important to use the
queryRunner.manager object as you If this confuses you, refer to part two of this series and read
Angular CLI Docs
about NestJS and databases.
Angular CLI is by far the most
guarantee that this migration will
popular tool used by Angular use the same Transaction instance Build Application Layout
developers to generate and
establish new Angular apps.
that runs all the migrations rather Let’s quickly build the layout of the application and set up
Make sure you read the docs than creating a new sub-transaction. some routes so that you can start testing things like the
here: https://angular.io/cli Login page. Navigate back to the Angular application.
Listing 14: AuthService login() action This command starts the NestJS application in development
async login(loginUserDto: LoginUserDto): mode. Back to the front-end application, at the root folder,
Promise<LoginStatus> { create a new proxy.conf.json file. Replace its content with
// find user in db the content in Listing 13.
const user =
await this.usersService.findByLogin(loginUserDto);
Angular uses the proxy configuration settings to redirect
// generate and sign token requests to the back-end and to the correct port where the
const token = this._createToken(user); NestJS app is running.
return {
username: user.username, Now run the application once again by issuing the following
...token, command:
};
}
ng serve --proxy-config proxy.conf.json --open
The command runs the app by using the proxy configuration Let’s go back to the back-end REST API source code and remem-
file. The application detects that you’re not authenticated ber how you’ve implemented the login logic there. When you en-
and logged in so it redirects you to the Login page like that ter your details on the Login page, the application sends a POST
in Figure 5. /auth/login request to the back-end REST API. It also appends
the username and password data into the payload of the request.
You enter your details and hit the Submit button. If the back-
end REST API can successfully verify you, the application redi- On the back-end REST API level, NestJS chooses the corre-
rects you to the Home page once again. sponding Controller and Action to handle this request. In this
case, the login action that you’ve defined on theAuthCon- The login action expects an instance of LoginUserDto containing
troller class. It’s responsible to receive all back-end requests to the username and password. The action then delegates its task to
either log in or register a new user. You may refer back to part the login() function that the AuthService defined in Listing 14.
three of this series to learn more about user authentication:
https://codemag.com/Article/2001081/Nest.js-Step-by-Step- This function starts by:
Part-3-Users-and-Authentication.
• Querying the database for a user given its username
@Post('login') • Creating a new signed JWT when the user exists
public async login(@Body() loginUserDto: • Returning an object containing the username and the
LoginUserDto): Promise<LoginStatus> { signed token
return await
this.authService.login(loginUserDto); Then, it’s the role of the AuthController.login action to re-
} turn the response back to the front-end app.
As you know, the JwtInterceptor intercepts the response, The component splits the screen into two sections. The first
extracts the user details including the JWT, and stores the hosts the Todo lists and the second hosts the Tasks under
data inside LocalStorage. The next time the user initiates each Todo list.
a new request to the server, the front-end application re-
trieves the JWT and attaches it to the existing request. Todo Create Component
Generate a new Todo Create component by running the fol-
Let’s add more features and build the Todo module next. lowing command:
This new library introduces a new module hosted inside The component is fairly simple. It defines a Textbox allowing
todo.module.ts. the user to enter a new Todo List name and hit Enter to save
the Todo List in the database.
Todo Home Component
Let’s add the landing component of this library by running The component listens to the Enter key on the Textbox and
the command: then emits an Output action containing the type of add-todo
and a payload of the name of the Todo List itself. It emits this
ng generate component todo-home --project=todo – action to the outside world, that a new Todo List name has
skipTests --inlineStyle --inlineTemplate been entered. You will see shortly how to make use of this
Output action to store the new Todo List in the database.
This command generates the TodoHomeComponent. Re-
place the content of this component with the content in Todo List Component
Listing 15. Navigate to the Todo link on the home page and Generate a new Todo List component by running the follow-
see the results in Figure 6. ing command:
The command creates a new TodoListComponent inside the The component emits an Output action containing the
components folder in the todo library. Replace the content type of delete-todo and a payload of the Todo List item
of this file with the content in Listing 17. itself. It emits this action to the outside world once the
import { switchMap, tap } from 'rxjs/operators'; public doAction({ type, payload }: DoAction): void {
switch (type) {
import { DoAction } case 'add-todo':
from 'projects/app-common/src/public-api'; this.createTodo(payload);
break;
import { Todo } from '../models/todo.model'; case 'delete-todo':
import { TodoService } from '../services/todo.service'; this.deleteTodo(payload);
import { Router } from '@angular/router'; break;
default:
@Component({ console.log('Unknown action type');
selector: 'lib-todo', }
template: ` }
<lib-todo-create (action)="doAction($event)">
</lib-todo-create> private createTodo(todo: string): void {
<lib-todo-list this.todoService
[todos]="todos$ | async" .create({ name: todo })
(action)="doAction($event)" .subscribe(() => this.refresh$.next(''));
></lib-todo-list> }
`
}) private deleteTodo(todo: Todo): void {
export class TodoComponent implements OnInit { if (
public todos$: Observable<Todo[]>; confirm('Are you sure you want to delete this item?')) {
private refresh$ = new BehaviorSubject<any>(''); this.todoService.delete(todo.id).subscribe(() => {
this.refresh$.next('');
constructor( this.router.navigate(['/todo']);
private readonly router: Router, });
private readonly todoService: TodoService }
) {} }
}
ngOnInit() {
Listing 21: TodoController create() action Async Pipe. Whenever this observable changes, the Todo-
@Post() ListComponent receives a new fresh array of Todo Items to
@UseGuards(AuthGuard()) display and render to the user.
async create(
@Body() createTodoDto: CreateTodoDto, As a recap, the TodoCreateComponent emits the add-todo
@Req() req: any,
): Promise<TodoDto> { action while the TodoListComponent emits the delete-todo
const user = req.user as UserDto; action. The TodoComponent handles both actions inside the
doAction($event) function in Listing 18.
return await this.todoService.createTodo(user,
createTodoDto);
}
If the action emitted is of type add-todo, the function
calls another function named createTodo() together with
the payload of the action. If the action emitted is of type
delete-todo, the function calls another function named
Proxying a Back-End Server ng generate component components/todo – deleteTodo() together with the payload of the action.
project=todo --skipTests --inlineStyle –
You can read more about inlineTemplate The createTodo() function, in turn, calls the TodoService.
proxying a back-end server create() function, passing to it a Todo model object as fol-
on the Angular website. The command above creates a new TodoComponent inside lows:
(https://angular.io/guide/ the components folder in the todo library. Replace the con-
build#proxying-to-a-back-
tent of this file with the content in Listing 18. private createTodo(todo: string): void {
end-server)
this.todoService
This component listens to the Output actions of both com- .create({ name: todo })
ponents as follows: .subscribe(() => this.refresh$.next('’));
}
<lib-todo-create
(action)="doAction($event)"></lib-todo-create> The deleteTodo() function, in turn, calls the TodoService.
<lib-todo-list [todos]="todos$ | async" delete() function passing to it the ID of the Todo List object:
(action)="doAction($event)"></lib-todo-list>
private deleteTodo(todo: Todo): void {
The TodoComponent defines the todos$ observable that if (confirm(`Are you sure you want to delete
passes it over to the TodoListComponent by means of an this item?`)) {
The function sends a POST request to the back-end REST The AuthGuard, if you’ve been through part three of this
API, passing along a request payload containing the Todo series, shows you that it will look for a JWT inside the re-
List object and some options. It finally handles any errors quest Authorization header and verify it. Upon a successful
generated out of this call to a dedicated function named verification of the user, the create() action executes and
handleError() defined in the service in Listing 19. returns a response to the front-end app.
The service defines the httpOptions variable as follows: You can find the source code of this article and the rest of
this series in this repo: https://github.com/bhaidar/nestjs-
const httpOptions = { todo-app.
headers: new HttpHeaders({
'Content-Type': 'application/json'
}) Conclusion
}; This is the final part in this series on learning NestJS Step-
by-Step. I’ve introduced a front-end application written in
The remaining components related to Task management Angular to connect to the back-end REST API. You can see
have similar implementation to these components. I’ll leave how easy it is to connect the two. There’s nothing different
it to you to go and check the source code accompanying this from any other front-end application or other technology,
article to see their implementations. like ASP.NET Core or PHP.
Test Todo NestJS is a large framework and covers so much more than I
Back to Listing 15, find the following section inside the can fit into a four-part series. I recommend that you always
TodoHomeComponent: check the rich documentation website they offer, as it is
always up to date and includes further details that could be
<div class="row"> useful while developing and using the NestJS framework.
<div class="col-md-12 my-2">
</div> Bilal Haidar
</div>
<div class="row">
<div class="col-md-12 my-
<lib-todo></lib-todo>
</div>
</div>
In this feature, we eavesdrop on a conversation between Ciprian Jichici and Markus Egger, both seasoned Regional Directors.
Talk to Ciprian about: Talk to Markus about:
Cloud Computing, Azure, Big Data, Mobile machine learning and AI, ASP.NET, HTML apps
Development, Software Development, IoT, DevOps, (including Angular, Vue.js, etc.), the cloud,
Microservices, Azure, SaaS, PaaS, Data Analytics, Azure, Microservices, Windows applications,
NoSQL, iOS, Android, Visual Studio, ASP.NET, or C#. software strategy, and much more.
You can contact him at ??? You can contact him at markus@eps-software.com
Ciprian Jichici is an IT professional with a business focus living in Timisoara, Markus Egger is not just an RD, but as the founder and publisher of CODE
Romania. His primary executive position is CEO at Genisoft, one of the most Magazine, he’s also directly associated with this publication. In his main
innovative Microsoft partner companies in Romania. He is also vice-president job, he is the President and Chief Software Architect of EPS Software Corp.
of the board of directors at Timisoara International Airport. Previously, he acted (a company better known for its CODE brands such as CODE Consulting,
as Chairman of the Urban Planning Committee at the City Council of Timisoara CODE Training, CODE Staffing, and CODE Magazine). He is also the founder
and as a member of the Directory Council of Timisoara Basketball Club. of other business ventures, such as Tower 48, Wikinome, and others. In his
own words, he spends his time “like most software developers, writing
The sixteen years he spent researching and teaching computer science at the production code” both for consulting and custom app-dev customers,
West University of Timisoara laid the theoretical and practical foundation of his and also for his own companies. He has worked for some of the largest
cloud computing technical focus. Today he spends most of his professional time companies, including many Fortune 500 companies, such as Microsoft.
designing, architecting, and managing the development of cloud computing Markus often takes on the role as a “CTO for hire.”
solutions on Microsoft Azure. An important part of this activity is helping top-
level business decision-makers realize the potential of cloud computing. The
challenges, complexity, and awesomeness of the many technologies he has to
deal with is what drives and motivates him to learn more every day.
Ciprian: Yeah. Well, speaking of all that, you degree of true or false to the statement, but rather the dark side. Obviously, my take is a balance.
could call me a failed physicist. Most probably if find out that, for example, in the western part of You shouldn’t be overexcited about everything
I hadn’t ended up being an IT guy, I would have the United States there were 525 other people who you can do with machine learning and AI. Nei-
ended up somewhere in quantum physics. That’s were saying a very similar thing. Something that’s ther should you be deeply rooted in the dark side.
one of the fields that’s been my passion ever since very close, semantically and linguistically, to the Like “this is going to kill the world,” right? And
I was a child. And it’s amazing to see that that’s statement that it’s raining in Vegas. It might come if you look throughout our history as a human
now becoming a thing in terms of quantum com- as a surprise, but this is the type of thing that a lot race, it’s always been like this. Think about...oh,
puting. Coming back to your question though, at of companies are interested in. They’re interested I don’t know... E = mc2, perhaps. That equation
the present time, I do a lot of work in exploratory because mostly the companies who have a well- brought us nuclear energy, which is still one of
customer behavior analysis. There are some very developed social consciousness are the ones who’re the cleanest types of energy that we know of. But
interesting developments. There are lots and lots really interested in what is being said. What’s the it also brought us the nuclear bomb. So there’s
of companies who have a real need, a measurable perception about them? Yes, the first level is senti- no reason for me to think that something as pow-
need, for these types of solutions. ment analysis, but I believe this is a deeper level, erful—and make no mistake, machine learning
a level that’s also much more difficult to achieve. and AI are very powerful things—but I have no
And by the way, I think you touched a very im- reason to believe that we’ll deal with them in a
portant point earlier, which is still challenging in This is another very practical area in which we radically different way. And you said it very well:
machine learning today. It’s identifying the com- work. We also do work in IoT. As a matter of fact, The power, specifically the computing power that
pelling business case. You have to fight so much in addition to speaking at the conference, I, to- we have today at our fingertips is already being
hype today. You have to fight so many wrong per- gether with my colleagues and some clients, have used to do harm as well, via machine learning. It
ceptions. Then, when it comes to actually building delivered a two-day workshop on combining IoT might come as a surprise to lots of people, but as
a business case that’s based on hard, measurable with machine learning. This is a very interest- of today, we only need maybe 20 to 30 minutes of
returns on investment, which enables the customer ing field and there’s already a lot happening. We somebody’s decent voice recording to use sophis-
to really measure the performance of your data sci- started with pure IoT and the challenges of typical ticated machine learning to make that person say
ence, we see many, many teams and many compa- IoT solutions, but then we move into how these virtually anything that we want. And it’s not only
nies failing at this very point. They are failing when solutions can be improved. How can they benefit with audio, it’s possible also with video.
it comes to providing a compelling business case. from applying machine learning approaches to
the vast amounts of data. Mostly streaming data
We also do a lot of work in natural language pro- that is generated in the world of IoT.
cessing and text analytics. This is another very, I’m not a believer in the
very interesting area that we’re involved in a lot. Markus: To switch gears a little bit, what do you
We do very practical and hands-on types of proj- make of the threats of all of this? A lot of peo-
“Singularity,” that “Terminator
ects, ranging from classification based on natural ple go, “Oh, I know AI is going to take over the Moment.” But I am a believer
language processing and coding, and going all the world.” They’re going to have a Terminator-like in the duality of any kind
way to processing things like media and use data. scenario. I’m not a big believer in that but what I
do worry about is a different angle of all of this. of powerful technology.
Markus: You essentially take in an audio stream, The deep fakes, the derailing of fact-fullness. The
right? You start, not with the written word, but more sophisticated phishing messages people en-
with the audio of a sentiment. Potentially, you do counter. Isn’t there a real issue in attacks of that
transcriptions and then take it from there, or how nature becoming so sophisticated that it’s really Markus: Yes, absolutely. Which is very interest-
do we imagine that? difficult to battle that? And I do wonder if AI can ing, when you think of what’s going on politically
help us battle it as well, but it seems that’s a lot in the world, among other things.
Ciprian: It’s a little more complicated than that more difficult than to come up with the actual
or a little bit more elaborate in the sense that we malicious content. Ciprian: Exactly.
mostly work with text from online written media.
One of the challenges that we’re aiming or plan- Ciprian: Yeah, it is. And by the way, that “Termina- Markus: Or even just the Orwellian scheme, right?
ning to solve is understanding the real structure of tor Moment,” we have a name for that in machine The Chinese say they can identify anyone, within
information out there in the wild. These days you learning and data science. It’s called the “Singu- a second, using face analysis. Anyone within
see a lot of initiatives around classifying news as larity.” It’s that very moment when a machine, or China, that is. And globally, they have the power,
fake or legitimate news, and things like that. I think a set of machines, exceed the capabilities of the even though not the data sources perhaps, to
that’s not too harsh of a term, but I think it’s a little human brain in all aspects. It has been projected identify anyone within two seconds. Those are, in
bit simplistic. The types of projects we’re involved that the singularity would occur sometime around a way, scary things. And I often wonder: Does it
in are the projects where we aren’t looking to pro- 2010 and then it was updated to 2020. Now it’s take more computing power to create deep fakes
vide a measure of quality for what’s been said out been moved to around 2050. I’m not a believer or to detect them?
there in the public. Rather it’s about estimating the in that either. But I’m a believer in the duality of
support for any statement. Think about a simplified any kind of powerful technology or mechanism or Ciprian: Well, that’s the typical kind of a chicken
situation like this. “Markus said, ‘it’s raining in Ve- theory that we—humankind—get access to. Be- and egg problem. The real problem is—and this ap-
gas’.” What we’re trying to do is not assign a certain cause it’s always a game of the bright side and plies to a certain extent to deep fakes—that deep
fakes are not yet so sophisticated as to be extreme- Ciprian: It’s very important because the Microsofts, pany, we use the Custom Vision and Computer Vi-
ly difficult to detect. But they’re getting there. The Facebooks, Amazons, and Googles of the world, I sion APIs. Microsoft has Face ID and things that
same applies where we have adversarial attacks, believe, together with their immense business suc- are really powerful and probably industry-leading
which basically play on the fundamental differ- cess, also have huge responsibility in terms of what by quite a margin. And there are tons of other
ences between the way the human brain works and they deliver to the world. What’s preventing some providers out there. Who else do you work with?
way the machine brain works. No matter what folks of the really powerful stuff that they’re developing Do you use an AWS or any of those things as well?
will tell you, we’re light years away from mimick- from being used in a non-ethical or non-responsi-
ing the real behavior of the human brain. Even ble way? It’s really encouraging to see that at the Ciprian: We use a wide range of technologies. If you
the smartest machine learning model today has a highest levels starting from the board and the CEO look at some of the most important tool sets and
completely different internal way of working than of the company, Microsoft really gets it and really frameworks today, they’re really vendor agnostic.
the human brain. And there are documented ways understands the importance of driving responsible Think about data preparation and data engineering
of attacking that specific difference. You see these, AI and of driving responsibility in this field. workloads, as an example. By a large margin, Spark
for example, in autonomous self-driving cars. There is the place to go. And fortunately, Spark is avail-
are documented ways in which you can take a few able in Microsoft Azure as Azure Databricks. Spark
rectangular stickers, stick them on a road sign, and is available in AWS. Spark is available in the Google
all of a sudden, yield becomes interpreted as “turn Microsoft really gets it and cloud. This is one very interesting place that we’re
right” or “turn left.” We’re not aware of any proven really understands the in, especially in data engineering and in data sci-
mathematical models that would guarantee success ence through the immense success of open source
in fighting against these things. importance of responsible AI. platforms and various technologies. I’d dare to say
that you have almost a common denominator and
We’re quite far from being clear on whether we then it obviously boils down to either personal pref-
can be effective in dealing with these things. Markus: Some of it always seems to me isn’t erence and perception on whether to use Microsoft
And, as it happened many times in history, even- even just that super high-level. One of the things or AWS or Google. Or it was down to things such as
tually the solution isn’t in the theory and isn’t that’s probably easier to do than a lot of other perceiving Microsoft as being more ethical than one
in the technical part. The solution is in educat- things is to mine the data of people and figure of its competitors. Or it boils down to the sheer cost
ing people to be responsible about these tech- out who the people are that are most easily de- of the platform. So yes, we do a lot of work with
nologies. The solution is in creating a worldwide frauded, and what’s a group of people I can get other vendors as well. It’s true. But most of our work
framework that will help govern the way in which through to, to reach a tipping point. I think if I and most of our workloads run on Microsoft Azure.
these technologies are used. Again, it might seem remember correctly in one of your presentations,
a little bit of a stretch, but it’s a great comparison you talk about Brexit and how a certain subgroup Markus: Have you done anything with any of the
with what happened with nuclear weapons. One of people was identified that was influenced, Asian vendors?
of the reasons why they weren’t used, except for which was enough to sway the vote toward leav-
testing, and except for the end of World War II, ing the EU, rather than remaining. Ciprian: Not yet, no. No. Haven’t had the chance
was because of these frameworks that were cre- yet. To be very honest with you, I’m a firm believer
ated around the world. Ciprian: Yeah. That was one of the cases where in competition and competitive markets. And in
these types of misuse of technology happened way the world of data science, I fear monopoly. This is
You already see this starting. You already see big before the world had the chance to organize itself why I’m so happy that I see, for example, PyTorch
companies, like, for example, Microsoft is really against that type of abuse. We all know the story of slowly but steadily starting to balance TensorFlow.
driving concepts like responsible AI. You see in- Cambridge Analytica, and how social media was lit- Because I don’t want to live in a world where the
dependent bodies doing the same. For example, erally exploited by certain individuals. And as bad only option for doing serious deep learning is Ten-
folks who’ve created the declaration of Montreal as this was, it’s also a very important wake up call. sorFlow. I want to have options. And that can only
on Responsible AI. People are starting to feel I believe it has an important role increasing knowl- be good for us as data scientists, but also for the
this threat. And what’s encouraging for me is edge and awareness on what the bad things are field in its entirety.
that they start realizing that the solution is at a that can happen when machine learning is used in
different level. It’s not necessarily at the techni- a non-ethical and non-responsible way. Markus: I couldn’t agree more.
cal level because that’s a chicken and egg prob-
lem. We’ll get better at creating, for example, Markus: Now to switch to something a little more It’s been a pleasure talking to you, as always.
deep fakes, and then we’ll get better at detecting positive and forward looking again: Both of us Unfortunately, we are out of time, because both
them, and then we’ll get better at creating them, use a lot of Microsoft technologies. In my com- of us have to run off to our next presentations.
and so on and so forth. Good luck with your upcoming talk!
Markus: You and I don’t work for Microsoft, but we The Cambridge Analytica Ciprian: This has been an absolutely great conver-
have a relationship with them. It’s nice to see that scandal was a very sation. We’ll do it again, maybe at the upcoming
a company like Microsoft takes the ethics of all of Regional Director and MVP Summit in Redmond!
that very seriously. Microsoft just been voted the
important wake-up call
most ethical company in North America. It’s very for the industry. Markus Egger
interesting to see that sort of stuff.
Introduction to SwiftUI
If you’ve been developing for iOS, you’re no doubt familiar with Storyboard, Apple’s visual tool for developing the user interfaces
of iOS applications. And depending on how early you got started in iOS development, you might even be familiar with
Interface Builder and XIBs. Last year, Apple announced SwiftUI at the WWDC 2019. With SwiftUI, Apple aims to update the iOS
txtText.font = UIFont(
name: "AppleSDGothicNeo-Bold",
size: 20)
txtText.layer.cornerRadius = 8.0;
txtText.layer.masksToBounds=true
txtText.layer.borderColor =
UIColor.lightGray.cgColor
txtText.layer.borderWidth = 2.0
txtText.textAlignment =
NSTextAlignment.center
txtText.addConstraint(
txtText.heightAnchor.constraint( Figure 1: The button and text field in SwiftUI
TextField("", text: $text) To alter the behaviour of each view, you use modifiers, which
.multilineTextAlignment( are basically functions that you apply to a view or another view
TextAlignment.center) modifier, thereby producing a different version of the original
.padding(15) view. Examples of modifiers in this example are padding(),
.frame(maxWidth: .infinity, overlay(), font(), and so on.
alignment: .center)
.foregroundColor(Color.black) Figure 1 shows the how the UI looks in SwiftUI when the
.font(.custom( button is clicked.
"AppleSDGothicNeo-Bold",
size: 20.0))
.overlay( Getting the Tools
RoundedRectangle( To start developing using SwiftUI, you need the following:
cornerRadius: 8)
.stroke(Color.gray, • Xcode version 11 or later
lineWidth: 2) • A deployment target (simulator or real device) of iOS
) 13 or later
Select Single View App and click Next (see Figure 3).
In Xcode, if you don’t see the Canvas,
Name the project HelloSwiftUI and select the various op- you can bring it up again through
tions, as shown in Figure 4. For the User Interface option,
ensure that SwiftUI is selected. Click Next and save the the Editor > Canvas menu. To
project to a location on your Mac. preview your UI, click the Resume
You should see the project created for you (see Figure 5).
button on the Canvas. You should
The ContentView.swift file contains the user interface for now be able to see the preview.
your application’s main screen.
You can click on the Resume button to start the preview Button(action: {
(see Figure 8). self.text = "Hello, SwiftUI!"
}) {
Let’s now modify the ContentView.swift file with the code Text("Button")
that you’ve seen earlier (see Figure 9). .padding(EdgeInsets(
top: 10, leading: 10,
bottom: 10, trailing: 10))
.foregroundColor(.red)
If you don’t see the Resume button }
when trying to preview your SwiftUI
Note that the automatic update feature of Preview doesn’t
UI, make sure you are running always work. There are times where you have to click Try
macOS Catalina (10.15) or later. Again button to rebuild the preview (see Figure 11).
Live Preview
You may notice that the automatic preview has paused. This If you recall, the code changes the text on the TextField
sometimes happens when the file you’re previewing has when the button is clicked (or tapped on a real device).
some changes that caused the containing module to be re- However, if you try clicking on the button on the preview
built. When that happens, click the Restore button and you canvas, you can observe that there’s no reaction. This is
should now see the preview again (see Figure 10). because the preview canvas only allows previewing of your
UI and doesn’t run your application. To run the applica- device, you can modify the ContentView_Previews struct as
tion, you need to click on the Live Preview button (see follows (see also Figure 14):
Figure 12).
ContentView().previewDevice("iPhone 8")
Once the Live Preview mode is turned on, the background
of the simulator turns dark (see left of Figure 13). You can
now click on the button and the text on the TextField will be Creating a News Reader Application
updated (see right of Figure 13). The best way to learn a new framework or tool is to actually
create an application using it. In this section, you will build
a news reader application to download the news headlines,
Generating Different Previews display them in a List view, and allow the user to tap on a
Notice this block of code at the bottom of ContentView. particular news item to read more about the news.
swift?
Examining the Structure of the News Headline Feed
struct ContentView_Previews: PreviewProvider { For this example, you’ll use the free service provided by
static var previews: some View { News API (https://newsapi.org). This is a JSON-based API
ContentView() that provides you with breaking news headlines and allows
} you to search for articles from over 30,000 news sources
} and blogs. To register for your own API key, go to https://
newsapi.org/register.
The ContentView_Previews struct conforms to the Preview-
Provider protocol. This protocol produces view previews in For your project, you’ll retrieve all the top business head-
Xcode so that you can preview your user interface created lines in the US. The URL looks like this: https://newsapi.
in SwiftUI without needing to explicitly run the application org/v2/top-headlines?country=us&apiKey=<API_Key>.
on the iOS Simulator or real devices. Essentially, it controls
what you see on the Preview canvas. As an example, if you The news headline API returns a JSON string containing
want to preview how your UI will look on an older iPhone 8 the details of the news headlines. You can paste the URL
import SwiftUI
Figure 11: If the preview fails, click Try Again struct Result: Codable {
var articles: [Article]
}
onto a Web browser and obtain the content. Once the JSON
content is displayed on your browser, copy and paste it struct Article: Codable {
into a JSON validator website, such as http://jsonlint. var url: String
var title: String
com, and you’ll have a good idea of the structure of the
var description: String?
JSON content. Figure 15 shows the structure of a sample var urlToImage: String?
of the JSON content: }
Observe that the value of the articles key is an array of struct ContentView: View {
items each containing the details of each article. In each var body: some View {
article, you want to retrieve the following details: Text("Hello, World!")
}
• title: the title of the news item }
• url: the link containing the details of the news item
• description: a synopsis of the news item By conforming to the Codable protocol, the Result and Figure 12: Turn on Live Preview
• urlToImage: the link containing the image for the ar- Article structs are now able to map Swift Objects to JSON to test your application
ticle data, and vice versa. explicitly running it
To fetch the news headlines, you shall define the fetchData() The List view is bound to the articles state variable,
function as shown in Listing 1. and for each row in the List view you use a VStack view
to display the title and description of each article. The
You use the dataTask() method of the URLSession.shared onAppear() modifier to the List view specifies that the
object instance to fetch the news headlines. Once the JSON fetchData() function be called when the List view first
content is downloaded, you use the JSONDecoder() ob- appears.
Figure 13: Turning on Live Preview allows you to test your application without explicitly running it
Listing 3: Adding the statements to load remote images using the URLImage view
import SwiftUI )!),
import URLImage delay: 0.25,
processors:
struct Result: Codable { [Resize(size:
var articles: [Article] CGSize(width: 100.0,
} height: 100.0),
scale: UIScreen.main.scale)],
struct Article: Codable { content: {
var url: String $0.image
var title: String .resizable()
var description: String? .aspectRatio(contentMode:.fit)
var urlToImage: String? .clipped()
} }
).frame(width: 100.0, height: 100.0)
struct ContentView: View { }
private let url = "https://newsapi.org/v2/top-
headlines?country=us&apiKey=<API_KEY>" VStack(alignment: .leading) {
Text(item.title)
@State private var articles = [Article]() .font(.headline)
Text(item.description ?? "")
func fetchData() { .font(.footnote)
... }
} }.onAppear(perform: fetchData)
}
var body: some View { }
List(articles, id: \.url) { item in
HStack(alignment: .top) { struct ContentView_Previews: PreviewProvider {
URLImage( static var previews: some View {
(( URL(string:item.urlToImage ?? ContentView()
"https://picsum.photos/100") }
?? nil }
To make use of the URLImage view, you need to add its Figure 18 shows the image displayed next to each news
package to your project. You can do so by going to Xcode headline.
and selecting File > Swift Packages > Add Package De-
pendency…. Enter this URL: https://github.com/dmytro- Wrapping the List View in a NavigationView
anokhin/url-image (see Figure 17). Now that you have managed to populate the List view with
the various news headlines, you can wrap the List view in a
Click Next in the current page as well as the next page. Final- NavigationView:
ly, click Finish. The package will now be added to the project.
var body: some View {
With the URLImage package added to the project, add the NavigationView {
following statements in bold to the ContentView.swift file, List(articles, id: \.url) { item in
as shown in Listing 3. ...
}.onAppear(perform: fetchData)
The bold statements add the URLImage view (of size .navigationBarTitle("News Headlines")
100x100) to each row in the List view. You need to check }
whether each news headline contains an image (through }
Figure 18: Displaying image next to each news headline Figure 19: Displaying the navigation bar title
The NavigationView is a view for presenting a stack of views By conforming to this protocol, you need to implement the
representing a visible path in a navigation hierarchy. Figure following methods:
19 shows the List view displayed within a NavigationView
with the navigation bar title set. • makeUIView: creates the view object
• updateUIView: updates the state of the view object
You can make the text in the navigation bar title smaller by
setting its display mode to inline:
.navigationBarTitle("News Headlines",
displayMode: .inline)
To display the news using its URL, you need to use a Web
browser. In the current version of SwiftUI, not all the views
are implemented yet, and this includes the implementa-
tion of the Web browser, which is available in the existing
WebKit framework and known as the WebView. What you
need to do now is make use of the WebView in your SwiftUI
application.
To do so, let’s add a new SwiftUI View file to the project and
name it as NewsView.swift. Add the following statements
in bold to the NewsView.swift file, as shown in Listing 4.
Figure 20: Reducing the font size of the navigation bar title Figure 21: Previewing the detail page
Figure 22: Tapping on a news item displays the news in more detail
Figure 23: The detail page with an empty space below the navigation bar
WebView(request: URLRequest(url:
URL(string:url)!))
.navigationBarTitle("News Details",
displayMode: .inline)
}
}
.navigationBarTitle("",
Figure 24: The empty space below the navigation bar is gone displayMode: .inline)
Subscribe online at
Be well and let’s lookout for each other. We at www.codemag.com
CODE Magazine are here with all of you.
CODE Developer Magazine
6605 Cypresswood Drive, Ste 425, Spring, Texas 77379
John V. Petersen Phone: 832-717-4445
On Forcing Functions
As I write this column, the entire world is in engaged in a battle against the novel coronavirus named
COVID-19. It will be several weeks before this May/June 2020 issue is in printed and delivered. What’s
in store for us? Where will we be? Which of us will become ill? What will the state of our businesses be?
How will we or our loved ones and friends fare? no choice in the matter. Our industry has always store for us. This situation is worse. Nevertheless,
I don’t have a crystal ball. What I do know for been about adapting or dying. That’s not such society tends to be able to undertake the heavy
certain are the characteristics that will lead to an abstract saying anymore. What’s your source lifting necessary to carry on. Our industry is go-
a chance at prevailing in this battle. Words that code strategy? Is pair programming a core prac- ing to be at the forefront of easing that burden’s
come to mind are sacrifice, unselfishness, ac- tice for your team? Are you disciplined enough to lift. We have an opportunity to provide unprec-
countability, responsibility, discipline, and em- work remotely? How will you overcome and adapt edented solutions to difficult problems. Will you
pathy. Whatever plans were made, they need to to these changed circumstances? be ready to help deliver those solutions? The first
be discarded. step to answering that question is whether, as a
member of a community, are you acting respon-
Perhaps agility has never been more relevant. sibly—which has nothing to do with technology
Whether you are an independent contractor or an The Cone of Uncertainty or skill!
employee, you’ll encounter challenges that are we each are subject
common to some and unique to yourself. Never in Before putting the final period on this install-
many of our lifetimes, have we been confronted to has expanded. ment, you’ll notice the back page has a new oc-
with an issue that so clearly has a path to success cupant. I started writing for CODE Magazine back
that depends on what we all do as individuals. in 2000. Besides taking off for a few years when
Local and national governments can lay out all On source code control, if you’re not using Git, I was in law school and practicing law full time,
the plans it wants. At the end of the day, success you may want to strongly consider its adoption I’ve been in just about every issue. I’m thrilled to
begins and ends with us as individuals. And in because it’s optimized for distributed version be taking on this new assignment. I still plan to
this case, it’s a matter of life and death whether control. Even if you use Git, do you embrace the cover technical content in regular contributions.
that be in the context of a person or a business. pull-request model? Are your developers locally This space is about focusing on the non-technical
integrating work from other developers in their aspects of our industry, whether they be legal,
COVID-19 is the mother of all forcing functions. workstation? Is unit-testing a practice you em- philosophical, political, public policy, etc. I’ve
ploy? These and many more items will need to given this space a new name: CODA. In music, the
Mike Tyson said it best, “Everybody has a plan be carefully considered as we continue to grapple coda is the concluding section. One of my goals
until they get punched in the face.” The philo- with the “new normal.” is that when CODE Magazine focuses on a theme,
sophical roots of that saying go back to Prussian this space will add a different, unique, and to
Field Marshal von Moltke, “No plan survives con- “Technical debt” isn’t just limited to our code. some, a provocative perspective on that theme.
tact with the enemy.” The ancient Chinese curse It can also apply to our individual skill set. The For those of you who know me personally, you
is “May you live in interesting times.” Interesting entire premise for how we work is changing. Even know that I’m not shy about sharing my opinions
times indeed. We must be ready to overcome and if the change isn’t so great for you, that may not on a given topic. I look forward to expanding my
adapt at a moment’s notice. The Cone of Uncer- be the case for others you interact with, which participation in CODE Magazine!
tainty we each are subject to has expanded. We means that whether you realize it or not, it’s go-
each need to be responsible because we have ing to be a big change for us all. It means that
our respective obligations. We each need to be we must continually be in learning mode and we
Time Warp, April 4, 2020:
accountable because we must justify our actions. must always be seeking ways to keep our saws How are you doing?
In another context, what I’m describing is being sharp. In this issue of CODE, as always, continual You’re now going to get some insight into our ed-
a good professional. In principle, that’s never a learning is a hallmark. A crisis quickly reveals iting process. I submitted this article on March
discretionary thing. Now, by hook or crook, we’re weaknesses. How will you respond? The knowl- 21, 2020 for editing. On April 4, 2020, I’m going
going to need to “live the sermon” in practice. edge, skill, and—dare I say—gravitas that we through those edits with our awesome editor Mel-
bring to bear on the effort has never been more anie Spiller! That’s a period of two weeks. What
Chances are likely that in the middle of March, important. happened? For reference, you may want to book-
you received directive to work remotely as part mark the Wikipedia Page: https://en.wikipedia.
of a social-distancing strategy to “flatten the I remember 9/11 as if it were yesterday and I re- org/wiki/Timeline_of_the_2019%E2%80%9320_
curve.” In my opinion, COVID-19 will forever member well talking to my best friend Rod Pad- coronavirus_pandemic#Case_statistics that
change our society and as a result, will change dock (CODE Magazine’s intrepid Editor-In-Chief) keeps track of the Coronavirus statistics. On
the way we work and interact. And with that, on the phone while he was grappling with a com- March 21, there were approximately 24K con-
if you’ve not done so, you need to take time to plete transportation lockdown. The conference firmed cases and 300 deaths in the United States.
review your infrastructure and review your skills he was at came to a grinding halt and for those
on how you go about building software. You have first few hours, nobody knew what fate had in (Continued on page 73)
codemag.com/magazine
832-717-4445 ext. 8 • info@codemag.com
UR
GET YO R
O U
FREE H
TAKE
AN HOUR
ON US!
Does your team lack the technical knowledge or the resources to start new software development projects,
or keep existing projects moving forward? CODE Consulting has top-tier developers available to fill in
the technical skills and manpower gaps to make your projects successful. With in-depth experience in .NET,
.NET Core, web development, Azure, custom apps for iOS and Android and more, CODE Consulting can
get your software project back on track.
Contact us today for a free 1-hour consultation to see how we can help you succeed.
codemag.com/OneHourConsulting
832-717-4445 ext. 9 • info@codemag.com