0% found this document useful (0 votes)
49 views76 pages

CODEMagazine 2024 JulyAugust

Uploaded by

jvoyarzun81
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views76 pages

CODEMagazine 2024 JulyAugust

Uploaded by

jvoyarzun81
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 76

MAUI, AOP Programming, VS Code, Meta Quest, Apple Vision Pro

JUL
AUG
2024
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 8.95 Can $ 11.95

Realize 2D Interfaces
with Augmented
Reality Tools

Visual Studio Understanding Introduction


Code Tips Aspect-Oriented to .NET MAUI
and Tricks Programming
ARE YOU WONDERING
HOW ARTIFICIAL
INTELLIGENCE CAN
BENEFIT YOU TODAY?
©shutterstock
EXECUTIVE BRIEFINGS
Are you wondering how AI can help your business? Do you worry about privacy or regulatory issues stopping
you from using AI to its fullest? We have the answers! Our Executive Briefings provide guidance and
concrete advise that help decision makers move forward in this rapidly changing Age of Artificial Intelligence
and Copilots!

We will send an expert to your office to meet with you. You will receive:
1. An overview presentation of the current state of Artificial Intelligence.
2. How to use AI in your business while ensuring privacy of your and your clients’ information.
3. A sample application built on your own HR documents – allowing your employees to query
those documents in English and cutting down the number of questions that you
and your HR group have to answer.
4. A roadmap for future use of AI catered to what you do.

AI-SEARCHABLE KNOWLEDGEBASE AND DOCUMENTS


A great first step into the world of Generative Artificial Intelligence, Large Language Models (LLMs),
and GPT is to create an AI that provides your staff or clients access to your institutional knowledge,
documentation, and data through an AI-searchable knowledgebase. We can help you implement a first
system in a matter of days in a fashion that is secure and individualized to each user. Your data remains
yours! Answers provided by the AI are grounded in your own information and is thus correct and applicable.

COPILOTS FOR YOUR OWN APPS


Applications without Copilots are now legacy!
But fear not! We can help you build Copilot features into your applications in a secure and integrated
fashion.

CONTACT US TODAY FOR A FREE CONSULTATION AND DETAILS ABOUT OUR SERVICES.
codemag.com/ai-services
832-717-4445 ext. 9 • [email protected]
TABLE OF CONTENTS

Features
7 CODE: 15 Years Ago 58 S tore Application Performance
Markus continues his reflection on what the company, the magazine,
and the industry have been up to for the last decade and a half.
Metadata in a Database Using
Markus Egger AOP in ASP.NET Core
Joydip explores programming paradigms (object-oriented,
14 VS Code Tips procedural, and aspect-oriented programming) and looks at
how AOP (aspect-oriented programming) can help you optimize
Sahil looks at how Visual Studio Code, Microsoft’s free open-source
performance and store performance metadata in a database.
workhorse, lets you work on any platform, any operating system, and
Joydip Kanjilal
nearly any language.
Sahil Malik

20 E xploring .NET MAUI:


Getting Started Departments
In this first entry in a series on MAUI, Paul shows you how to develop
apps that run across all platforms. After examining some language
specifics, he’ll guide you through building your first app. 6 Editorial
Paul Sheriff
CODE Staffing:
12 
36 F rom Flat to Fantastic: Career Development and
Going Spatial with 2D Applications Staffing Reinvented!
You may think that 2D and 3D GUIs are something only available in sci-
fi movies, but the reality is closer than you think. Ed introduces some
technologies that will get your app-developing juices flowing. 30 Advertisers Index
Ed Charbeneau

74 Code Compilers

US subscriptions are US $29.99 for one year. Subscriptions outside the US pay
$50.99 USD. Payments should be made in US dollars drawn on a US bank. American
Express, MasterCard, Visa, and Discover credit cards are accepted. Back issues are
available. For subscription information, send e-mail to [email protected]
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.

4 Table of Contents codemag.com


EDITORIAL

One Fret Away from Harmony


The words from the guitar teacher were spoken with the soft forceful power that only a true mentor
can deliver. “If what you’re playing sounds awful, you’re only one fret away—just move one fret
in either direction. I distilled it down to harmony that’s one fret away”. This passage from musician

Adam Tepedelen’s book “Mud Ride: A Messy Trip I started building this process using simple es, disharmonies, and harmonic resolutions. We
Through the Grunge Explosion,” is a statement brute-force code. As a test of Occam’s Razor, make the music of our lives choosing what to
so powerful that it refuses to leave my head- would the simplest code work? I set about iter- play and how to play it. And occasionally, you
space. The simplicity that we may be only a ating through the 350 million records using LINQ need to change a fret or so to be more harmo-
minor change away from harmony is profound. to query the range tables that were loaded into nious.
memory. I immediately determined that this was
Early in my consulting career, I began teaching not a workable solution. My back-of-the-enve- NOTE: This editorial required a fret change or
developers for a company called ADTC. Before lope calculations figured it would take multiple two. I used my analog (walking) technique to
an instructor was allowed to teach their first hours (and maybe a day or more) to finish. figure out what fret to change to next.
public class, they had to shadow another in-
structor. As luck would have it, my instructor Time for a fret change. I looked for libraries or
was a fellow named David Anderson. David was tools that could help make this process work-
an amazing instructor (and good friend) and able. That process yielded no positive results.  Rod Paddock
I borrowed (some may say stole, LOL) many 
of his teaching techniques. One technique I Time for a fret change. I went into the analog
learned from David I’m still using some 30 years world (I went for a walk), thought about this
later. I learned this lesson from a question a problem, and the fret changes that I needed
student asked and how David responded. came into my head. I’d go back to the good
old algorithms I learned in college. Hmmmm….
David didn’t understand the question, so he Would a binary search work? Let’s change the
asked the student for assistance with this ques- tune…
tion: “Can you say that another way?” The stu-
dent reworded their question and, with that I went to work re-learning how to implement
fret change, student and instructor achieved a binary search algorithm using ranged tables.
harmony. With some Google-Fu and an accidental assist
from Microsoft’s Edge’s AI (I’ll talk about this
As an exercise, how many fret changes can you in a future column), I came up with the seeds
pull from that last scenario? of a workable algorithm to process this data
in fast fashion. You know what? It worked! I
• Fret Change One: Begin a teaching career was able to process the IPV4 addresses with a
• Fret Change Two: Meet David Anderson usable speed.
• Fret Change Three: Learn to ask students
“Can you ask that another way?” Then I went to classify the IPV6 addresses, and
soon realized I’d need yet another fret change.
This one experience yielded three significant This fret change was required because of the
fret changes that resonate with me to this very mathematics related to IPV6 address size. The
day. I’ll bet you didn’t think this was going to original code was written in the .NET Framework
be an SAT practice exam, but here we are. You’re (4.xx). which, I soon learned, has a limitation
welcome. <g> on the bit size of numbers it supports. IPV6 ad-
dresses are 128bit, double the 64 that the 4.xx
Programmers will understand the concept of framework supports. I changed the instrument
fret changes in their daily work. The art of pro- completely by putting the code into the newest
gramming is a constant state of fret changes version of .NET Core, which has native support
trying to achieve the harmony of working code. for 128bit numbers. My project had achieved
Earlier this year, I was tasked with geo-coding harmonic balance.
over 350,000,000 million IP4 and six addresses.
This is a huge challenge with the sheer volume These are just the highlights of the major fret
of records to process. The process is this: Take changes and chord progressions that the code
an IP address, turn it into its numerical repre- went through.
sentation, then look up that value in a range
table. The IPV4 and IPV6 have around 250,000 To conclude with a cheezie music metaphor, our
and 500,000 ranges, respectively. lives are a series of progressions, chord chang-

6 Editorial codemag.com
ONLINE QUICK ID 2408021

CODE: 15 Years Ago


In this next installment of the “30 Years of CODE Group” celebration articles, we’ve now reached the halfway point. I’m looking
back 15 years to roughly 2008 (give or take a year). I’m approaching a time that I start to perceive as “modern development.” Yes,
a lot has changed (especially over the last year or two), but a lot of things we now take for granted started about 15 years ago.

The “Cloud” was in its infancy (but already there). .NET Core better use of dedicated graphics hardware. As we came to
wasn’t quite a thing yet, but as we started developing Cloud find out, users didn’t want to jump through the hoops re-
apps, the early building blocks of Microsoft’s re-imagined quired to have a secure operating system. They just didn’t
.NET ecosystem were being put into place. Web development want anything bad to happen to them, while still happily
was already mainstream. Mobile development wasn’t quite running on Administrator accounts, with their machine’s
there yet but it was starting. Except for Artificial Intelli- defenses taking a back seat. As a result, Windows Vista
gence, a lot of the things we’re doing as developers today was one of the least liked Windows operating systems up
were already in place (although in different forms). But be- to that point, probably only topped by Windows 8, half a
fore I get ahead of myself, let’s survey the overall landscape decade later.
of software development and the technologies we used at Markus Egger
the time. In hindsight, Windows Vista wasn’t all bad. Yes, there [email protected]
were numerous valid points of criticism (hardware re-
quirements were high, driver compatibility was low, and Markus, the dynamic
Operating Systems all kinds of security measures made it less pleasant to founder of CODE Group and
For developers, the platform the code runs on is where it use than prior versions of Windows), but there were also CODE Magazine’s publisher,
is a celebrated Microsoft
all starts, so let’s take a look at the operating systems in a lot of good features. Utilization of GPUs is considered
RD (Regional Director) and
use 15 years ago. In the last issue’s article that looked a given in any modern operating system, but it was a
multi-award-winning MVP
20 years back, I talked about Windows XP. Surprisingly, revolutionary step in Vista. Previously, graphics hardware
(Most Valuable Profession-
Windows XP was still a very important platform in 2008. was almost exclusively used by games, which used DirectX al). A prolific coder, he’s
Admittedly, Windows XP was a very good operating system to generate high-performance output, and the “normal” influenced and advised top
for its time, but it also had serious shortcomings when Windows GUI was rendered in software through GDI (the Fortune 500 companies
it came to security. This was a problem Windows Vista Graphics Device Interface). This not only caused perfor- and has been a Microsoft
attempted to fix as one of its key themes, another being mance problems, but it also created an odd bifurcation contractor, including on
the Visual Studio team.
Globally recognized as
a speaker and author,
Markus’s expertise spans
Artificial Intelligence (AI),
.NET, client-side web, and
cloud development, focus-
ing on user interfaces,
productivity, and maintain-
able systems. Away from
work, he’s an enthusiastic
windsurfer, scuba diver,
ice hockey player, golfer,
and globetrotter, who
loves gaming on PC or
Xbox during rainy days.

Figure 1: Windows Vista used the GPU to render the user interface and thus gained features such as 3D projection and
transparency at high performance.

codemag.com CODE: 15 Years Ago 7


of UI technologies that didn’t always play well with each
other. Using GPUs to render all Windows user interface
The World Turns Mobile
elements not only offloaded all UI tasks to the graphics The Mac wasn’t the only success Apple was able to land
hardware (thus leaving more power to do other things for during that time. Apple released the original iPhone
the CPU) but it enabled modern UI paradigms, such as 3D (Figure 3) in 2007, and the iPhone 3G in 2008. The
and transparent windows. Figure 1 shows how Windows original iPhone was already a very attractive device, but
Vista handled task switching in this new world. the 3G version was what truly established the modern
era of smart phones. Not only was it faster, but it also
Nevertheless, Windows Vista never was a fan-favorite and established the App Store, and the “there’s an app for
was relatively swiftly replaced by Windows 7, which pre- that” era for mobile devices. Previously, Apple allowed
served many of Vista’s benefits, but packaged it in a much no custom development for their phone, famously quip-
more palatable fashion to an audience that had, by then, ping that “the web was the development model” for that
also grown used to a more secure setup. It was arguably device. Something that seems unthinkable today, but
also more user friendly and faster, too. Unlike Windows prior to 2008, developing for the Apple ecosystem was
Vista, Windows 7 holds a special place in the hearts of not a big thing for most developers, because the Mac
many users and remains one of the most beloved versions was a specialty platform and there was nothing else we
of the Windows operating system. It can be thought of as could develop for in the Apple world that promised com-
a much more polished version of Vista, with better sta- mercial success. All of that changed in 2008, and oodles
bility and reliability, better software compatibility, cool of developers (including yours truly) dove head-first
features, and ease of use. As a result, Windows 7 had into the painful world of Objective-C development with
some considerable staying power and longevity. We still X-Code. Thankfully, Apple later remedied the situation
encounter Windows 7 in the wild regularly, when working with the Swift programming language and better devel-
with our consulting customers. oper tools, overall.

Overall, the world had changed a bit, right around 2008 Then again, Apple wasn’t the only player in that mar-
or so, in that it wasn’t just a Windows world anymore. ket. Previously, Microsoft had made a really good mobile
Apple had, by then, made considerable inroads and es- platform, going back to Windows CE and Microsoft Smart-
tablished Mac OS X Leopard as a serious contender and Phone. Steve Balmer (at the time, CEO of Microsoft) had
a hip client operating system. It came with a somewhat this belief that only phones with a physical keyboard
modernized user interface, better performance, and many had any chance of being successful in commercial sce-
improvements to its core features, such as Finder. It was narios. Not his finest moment, and what condemned Mi-
a genuinely good operating system on its way into the crosoft to a role where most younger developers today
mainstream, after previously serving more of a niche-ex- can’t even conceive of a world where Microsoft was a
istence. This was in no small part due to the “Hello, I am leader in Mobile tech. (Not to mention Microsoft’s once
a Mac, and I am a PC” commercials (Figure 2) that ran awesome Tablet PC initiative, which failed to claim the
from 2006 to 2009 and were, arguably, one of the most market that was—years later in 2010—claimed by Ap-
effective commercials ever run. Microsoft had little to of- ple’s iPad).
fer in response.
Then again, it wasn’t just Steve Balmer who made that
mistake. Research in Motion (RIM) was still a big player
in the mobile market with their Blackberry devices. And
just like Balmer, RIM bet on a physical keyboard on the
device. A bet that paid off for a long time, but that
time had just about run out. RIM didn’t have much to
put up against Apple’s new offerings. That, as well as
some other leadership mistakes, sunk RIM’s boat. (For
an interesting topic that is beyond the scope of this
article, and for those interested in the “make my coun-
try great again” line of politics, ask your favorite AI to
recap RIM’s adventures in building factories in Tierra del
Fuego as part of Argentina’s attempts to protect their
local markets.)

The mobile market segment remained a key technology


battleground for quite some time. Microsoft tried to
mount a comeback with Windows Phone 7. Too little, too
late. Microsoft tried to out-Apple Apple with a slick tile-
based user interface. Although technically pretty darn
good (Microsoft’s touch-keyboard remained the best
such offering for quite some time), the overall offering
was too weak, and the UI didn’t cut it for most users.
When Microsoft released its phone, it simply had too
few apps, and even the big hitters, while present, only
Figure 2: Hello, I am a Mac (right), and I am a PC offered what must now be seen as skeleton versions of
(left)! Apple’s commercials reached cult-status and were their app that ticked the box but didn’t satisfy users. Mi-
amazingly effective in bringing Macs into the mainstream. crosoft also attempted a parallel product with the Micro-

8 CODE: 15 Years Ago codemag.com


soft Kin, a phone that was supposed to appeal to young The Cloud also drove various development trends in years
people, but was so ill-received that after an investment to come. Linux turns out to be an effective operating
of north of a billion dollars, the plug was pulled on that system to run Cloud-servers (and services), which is why
product less than two months in. If you don’t remember everyone seems to embrace it (to our surprise—at least
the Kin, then at least Microsoft did some decent damage at the time—even Microsoft embraced it). This ultimately
control, which was the best part of the whole affair. drove a re-imagining of the Microsoft .NET platform as a
modular, cross-platform development ecosystem. It also
All of this left Google as the only true competitor in the further pushed web development into the mainstream,
mobile device market, with the Android operating sys- which sparked many web frameworks, from jQuery (released
tem, which was first commercially released in the fall of in 2006) to ASP.NET flavors, Ruby on Rails, Angular, REACT,
2008. Android was (and still is) exceptionally successful and many others that are too numerous to list here.
as an Apple iOS competitor, at least in the mobile phone
market (although not so much for tablet devices). It’s
amazing to think that what played out 15 years ago is Software Development
still the status quo in mobile devices, several genera- For many of us, development was very Microsoft-centric.
tions of software later. Much of what was going on there, we still recognize to-
day. C#, JavaScript, the .NET Framework, ASP.NET, Visual
Studio, SQL Server, and so on. Then there were the things
The Birth of the Cloud we’d like to forget, such as Microsoft Silverlight (Figure
Not only does the mobile device world as we know it today 4), a competitor to both HTML and Adobe Flash. Boy,
go back about 15 years, but so does the Cloud. It still would I like the money back I invested in those tech-
seems to me like Cloud computing is relatively new, but it nologies. And on a serious note: The fallout of Silverlight
was in October of 2008 that Microsoft first announced its being abandoned still drives a lot of skepticism regarding
cloud initiative, then called “Windows Azure,” the operat- the longevity of Microsoft developer technologies today,
ing system that’s “out there.” We all weren’t quite sure whether that’s warranted or not. It wasn’t the first tech-
what to make of it. How was this different from data cen- nology Microsoft first pushed and then abandoned (Micro-
ters that hosted your servers? Why was it called a “Cloud soft Hailstorm and .NET My Services, anyone?) but it was
Operating System”? It made sense in some way, because it probably the most visible and, for many developers, the
was a “thing that ran your stuff,” just like a local operat- most expensive and painful instance. The lesson learned
ing system, but we were scratching our heads over all the here is that Microsoft’s developer story never fully recov-
details. And how the heck did you even pronounce “Azure?” ered from this episode.
“The color of the cloudless sky” seemed like an awfully odd
name for a Cloud operating system (and still does today). .NET was in its third major generation with .NET 3.0. It
had an amazing set of highly anticipated sub-technolo-
Again, Microsoft wasn’t the only player. Amazon (the on- gies. WPF (Windows Presentation Foundation) revolution-
line bookstore? Yes!) had previously released Amazon S3 ized Windows Desktop development in a way that was
(Simple Storage Service) in 2006, followed by Amazon super-powerful, and graphics accelerated. CODE Group did
EC2 (Elastic Compute Cloud) a few months later. There many projects on top of this platform. Ultimately, web
were other vendors of various sizes that dabbled in this development proved more enticing to a lot of companies,
market as well, but back then (as today), Microsoft and and WPF was also not necessarily for the faint of heart
Amazon were the biggest players in what grew into amaz- if you wanted to achieve truly great results. However,
ing platforms that make much of modern computing (in- if you’re interested in native Windows desktop develop-
cluding today’s artificial intelligence craze) possible. ment, it’s still one of the best choices available.

Windows Communication Foundation (WCF) was the highly


anticipated networking layer that provided remote service
calling using protocols such as SOAP, which made it more
efficient to build service-oriented systems and APIs. SOAP
wasn’t the only supported protocol. WCF features quite a
range of networking technologies, and many of the .NET
superstar developers were very invested in it (and, at the
time, rightfully so).

Figure 3: The original iPhone Figure 4: Microsoft Silverlight

codemag.com CODE: 15 Years Ago 9


Then there was the Windows Workflow Foundation (WWF),
which later had to be renamed to WF, because the World
Wildlife Fund complained about the acronym. It provided
a way to create—wait for it—workflows that could be
complex, long-running, and transactional. At the end,
this technology didn’t have much staying power com-
pared to some other parts of .NET 3, because it simply
didn’t cover as many scenarios as user interface and com-
munication technologies.

One of the huge aspects of .NET 3 was that it shipped


out of the box with Windows Vista, making deployment of
.NET 3 apps much easier and allowing various Microsoft
teams to use .NET to develop even parts of Windows itself.
This was a huge point of contention at the time (after
all, .NET was a big deployment package) and it reportedly
took the direct intervention of Bill Gates to finalize the
decision to ship it “in the box”.

Other Technologies and Trends


Figure 5: The Microsoft Xbox 360 gaming console 2008 was a tumultuous year. The global financial crisis had
a deep impact on many of us (while we were still recover-
ing from the dotcom bubble), and, in hindsight, it’s scary
how close we came to a complete systemic breakdown.
But there were also interesting and positive outcomes.
Arguably, the world created some additional checks and
balances (some efficient, others not so much), and cryp-
tocurrency was invented. It took a bit of time to catch
on, but the mysterious Satoshi Nakamoto published the
Bitcoin whitepaper, which laid the foundation for the first
decentralized cryptocurrency, which would go on to have a
profound impact on the world of finance and beyond.

Significant events in the world of software included the


launch of the Google Chrome web browser as well as the
launch of GitHub. Yup, GitHub has indeed been around
that long. It is, in fact, roughly the same age as the Large
Hadron Collider (LHC) in CERN, which is still the world’s
highest energy particle collider that has produced some
amazing scientific results. Some of these might be docu-
mented on GitHub, I suspect.

What else happened around that time? Microsoft launched


the BING search engine. NASA launched their Kepler mis-
sion, designed to discover Earth-sized planets around
other stars (and which has discovered thousands of exo-
planets). Amazon released the Kindle e-reader. And the
software developer community in general was pretty ex-
cited about this new thing called HTML 5.

Music, Movies, and Games


If you’re a geek like me, a look back a decade and a half
wouldn’t be complete without a look at the pop culture
of the day.

As discussed in last issue’s article, the music industry


never fully recovered from the Napster days, but good
music was being made nonetheless. Coldplay, Rihanna,
Beyonce, the Foo Fighters, and Justin Timberlake were in
the charts. And yes, even Taylor Swift was already in the
news with her album “Fearless.”

In the movies, we watched Batman: The Dark Knight,


Figure 6: BioShock took us into an amazing and creepy underwater dystopia. Slumdog Millionaire, WALL-E, Harry Potter and the Order of

10 CODE: 15 Years Ago codemag.com


Figure 7: Forza Motorsport 3 really looked pretty darn good 15 years ago!

the Phoenix, The Hangover, Avatar, Up, and J.J. Abram’s (my personal favorite—boy, did I waste hours on this
reboot of Star Trek. Yup, it’s already been 15 years! Some game!), Borderlands, Metal Gear Solid 4, Halo 3, Gears of
of these are still on my “to be watched soon” list that I War 2, Forza Motorsport 3 (Figure 7), Leage of Legends,
haven’t quite gotten to yet. and Minecraft.

Watching movies and TV series was about to be com- Meanwhile, World of Warcraft was still going strong, and
pletely uprooted, even though we didn’t yet know it then. social gaming had reached a whole new level with Xbox
Netflix moved from a DVD-based video rental company to Live and other online services. Valve had, at that point,
streaming online. In 2008, they launched an auxiliary a well-established a digital sales channel with its Steam
service called “Watch Now”, which seemed super-cool, service, and they still maintain a dominant position to-
but bandwidth limitations caused many to doubt that it day.
would really work well. Today, “Watch Now” is just known
as “Netflix” and most of us don’t even remember that You’ll have to excuse me now. I have to go and re-install
Netflix used to send you DVDs in the mail not all that long some of these classics!
ago. They were the early leader in the streaming market,
and they’re still the leader today. There have been times  Markus Egger
when more than half of the internet traffic was due to 
people watching Netflix content.

The highlight for me personally were the games that were


released a decade and a half ago. Oh, what a golden time
it was! Microsoft released the Xbox 360, (Figure 5) one of
the most enjoyable gaming devices ever made, if you ask
me. (And the complete re-launch of the user interface—
the NXE, the New Xbox Experience—of this consumer de-
vice was a ground-breaking step that hadn’t been seen up
till then). At the same time, Sony pushed the envelope
with PlayStation 3, and Nintendo decided to go in a com-
pletely different direction with the innovative (although
not very powerful) Nintendo Wii console. Meanwhile, the
PC was pronounced dead and revived as a gaming plat-
form numerous times, and kept churning out classic after
classic.

In gaming, it isn’t so much about the platform, of course;


it’s about the games. And boy, what a time for games it
was! Massive hits from the period include timeless clas-
sics such as BioShock (Figure 6), The Witcher, Crysis, Por-
tal (and the Orange Box together with Half-Life 2), Left
4 Dead, Fallout 3 (did you see the recent Amazon TV se-
ries?), Warhammer 40,000: Dawn of War II, Dragon Age

codemag.com CODE: 15 Years Ago 11


CODE STAFFING

Career Development and


Staffing reinvented!
You think great talent and cool positions only exist in Silicon Valley? Think again!

CODE Staffing is a high-tech, career develop- and a cool workplace culture with unlimited
ment, and - for the lack of a better term - upward career development opportunities.
“staffing company,” that provides a modern
workplace with the number one goal being the Many companies think they cannot provide a work
development of talent and careers. CODE Staff- environment that rivals the “cool Silicon Valley
ing was started to disrupt the traditional staff- startups,” and many employees think they won’t
ing industry. We provide an environment that be able to find such a workplace outside “The Val-
attracts top talent. We offer unrivaled benefits ley.” We have changed that equation!

12 Title article
Career Development and Staffing reinvented! codemag.com
CODE STAFFING

Our Mission ing technology teams to thousands of people


and have learned that the only way to succeed
competitive compensation, a sense of owner-
ship and pride, and continuous opportunities
CODE Staffing delivers unparalleled contingent is to invest in our own employees. Every key for growth in both their technical and interper-
technical staffing solutions to our clients. We client is assigned a member of our executive sonal skills.
empower their businesses with the talent and team as their contact – with regular quarterly
expertise they need to thrive. We focus on long- meetings to understand where they are heading Similar to our business philosophy, we priori-
lasting partnerships based on trust, transpar- – both as a business and with technology. This tize long-term investment in our staff over fill-
ency, collaboration and by providing access to approach enables us to ensure that our staff ing short-term positions. We are committed to
our extensive network of industry connections. receives training in the technologies that our developing the full potential of our employees
clients are moving towards, ensuring that we and supporting their career growth over time.
We provide a great environment for our em- are always prepared to meet their needs. To this end, we provide career mentorship op-
ployees so that we minimize churn for our cli- portunities, generous salaries and benefits, a
ents. Our rigorous focus on training and regular We are committed to training and profit-sharing plan that incentivizes everyone
meetings with clients’ executives ensure that adopting new technologies in a to work toward a common goal, and continuous
we understand their technological road map straightforward manner. comprehensive training in the latest technolo-
and guarantees that we provide the best people gies as well as in the industries our clients are
for their needs. Our dedication to keeping our staff well-trained focused on.
and informed on the latest technologies ensures
At CODE Staffing, we’re committed to deliver- they are fully equipped to tackle any project for At CODE Staffing, we believe that happy em-
ing exceptional value to our clients, providing our clients. Our commitment to training paired ployees lead to happy clients. By prioritizing
a fulfilling work experience for our employees, with our vast experience in the field gives our employee satisfaction and delivering outstand-
and building long-lasting partnerships within team the confidence they need to excel in every ing results for our clients, we can build strong,
our community. client engagement while staying up to date on lasting partnerships based on trust, transpar-
the latest technology. ency, and exceptional service.
Our Vision We leverage CODE Training, a division of the 
To achieve our mission, we focus on two core CODE group, to train not only our employees in
groups: our clients and our people. upcoming technologies, but we make the train-
ing available to our clients’ personnel as well.
By doing so, we enable their personnel to con-
For Our Clients centrate on their business operations, while we
Our business philosophy is centered on build- take charge of training both our own and our
ing strong, long-lasting partnerships with our clients’ employees in technology.
clients, rather than pursuing a large number
of short-term engagements. By fostering close We provide a clear legal differentiation
relationships with the organizations we serve, between clients’ employees and
we aim to become a trusted and integral part contractors, offering more flexibility.
of their operations, and to support their growth
and success over the short and long term. We The contractors we provide are our employees
are committed to working collaboratively and – with salary and benefits, as well as regular
transparently with our clients to enable their training. CODE takes the heavy lifting out of
teams to deliver continued value to their busi- managing (sometimes hundreds of) contractors,
nesses. leaving our clients more time to focus on their
projects and growing their business.
Our clients want to be able to focus on their
business, not on managing multiple vendors for We create a system to keep contractors
staffing. Here are some of the ways we help our with our clients for the long term.
clients build better software...
By employing great developers and providing
We act as a single vendor that knows ownership via profit sharing, CODE Staffing
our clients’ business. employees are incentivized to stay with us and
our clients for the long run. Focusing on train-
Prioritizing a few key accounts rather than a ing and the long-term investment in top talent
multitude of small accounts allows us to pro- not only helps the organizations we work with
vide personalized services tailored to each of achieve sustained success but ensures that in-
our clients. Our team works closely with our cli- stitutional knowledge doesn’t regularly disap-
ents’ organizations to gain a thorough under- pear.
standing of their intricacies and to better grasp
their overall goals and objectives.
For Our People
We act as trusted industry advisors CODE Staffing is centered around creating an
to our clients. exceptional workplace environment that at-
tracts and retains top talent, enabling us to
Our executive team at CODE is a group of tech- provide our clients with a stable and reliable
nologists who have owned long-standing, suc- team. We prioritize fulfilling our employees’
cessful businesses. They have experience grow- essential needs by providing engaging work,

Content paid for by codestaffing.com Career Development and Staffing reinvented! 13


ONLINE QUICK ID 2408031

VS Code Tips
I'm a huge fan of VS Code, and I suspect I'm not the only one. We’ve emerged from a world of very heavy IDEs (Integrated
Development Environments). Many of them are still around. They’re specialized IDEs that do some things very well, and a very
popular one is Visual Studio. Visual Studio has been around for quite some time. When Microsoft entered the IDE game around C++

and there were things like Microsoft Foundation Classes quick debugging, etc. It’s a really flexible application
(MFC), that’s when Visual Studio started taking off. Be- with many uses.
fore that, we had IDEs built into DOS. They would take
over your entire screen and they were text-based. IDEs
such as Turbo C++, or Turbo, by a company called Bor- VS Code Extensions
land, were the rage. Visual Studio has gone through some The first tip I have for you is that VS Code, when down-
twists and turns as well. We’ve had specialized IDEs, such loaded, is bare bones. That’s a good thing. When I’m writ-
as Visual Interdev for web-based scenarios or FrontPage ing code as a Python developer, I have zero use for Node.
Express for lightweight web page editing. There was a js-related paraphernalia loaded in memory bogging my
Sahil Malik time when a VB programmer had a different IDE than a computer down. There are some common things that are
www.winsmarts.com C++ programmer. applicable to every language, such as Git support, that are
@sahilmalik built right inside of VS Code. You can go far beyond that by
It wasn't until we had VS Code that we had an IDE that customizing VS Code further. VS Code is extremely custom-
Sahil Malik is a Microsoft
works with nearly every language, every platform, and yet izable. You can grab extensions to improve and customize
MVP, INETA speaker,
is fast, efficient, and super customizable. It runs on Mac, your dev experience from https://marketplace.visualstu-
a .NET author, consultant,
Linux, Windows—it even runs in a browser. It works on dio.com/search?target=VSCode or right within VS Code by
and trainer.
Python node.js, .NET, and anything else you can imagine. looking for the extensions button that’s shown in Figure 1.
Sahil loves interacting I'll go so far as saying that I'm hard-pressed to think of
with fellow geeks in real another application as good as VS Code. VS Code is built The process of writing your own extensions is also well
time. His talks and train- on Electron and a lot of people like to complain about documented, but 99 out of 100 times, I can find some
ings are full of humor and Electron being heavy, yet we all use VS Code. That alone really well-written extensions for my needs in the mar-
practical nuggets. is a testament to how well VS Code is built. ketplace.

His areas of expertise are In this article, I'm going to talk about some of my favorite
cross-platform Mobile app tips and tricks about my favorite IDE, VS Code. Although There Are Two VS Codes
development, Microsoft I’m writing this on a Mac, many of these concepts will Love it or hate it, in this internet-connected world, things
anything, and security port to Windows, so you may have to replace COMMAND change all the time. The application VS Code changes
and identity.
key, WIN key, etc. quite often. It has a vibrant community and dedicated
product managers who constantly look for ways to make
VS Code better. As a result, roughly once a month, VS
What Is VS Code? Code updates itself. Something I’ve found very valuable is
VS Code is a free application, built on open source by to keep up with the changes at https://code.visualstudio.
Microsoft, that you can download from https://code. com/updates/. You know that life gets busy, and the app
visualstudio.com. It’s designed to be a code editor, but updates and project deadlines mean that we can’t visit a
honestly, it’s so much more than that. It’s definitely de- website to keep up with these changes.
veloper-centric. I’ve personally used VS Code with .NET,
client- and server-side JavaScript projects, Python, and Right inside of VS Code, press COMMAND_P press the
GoLang. I wouldn’t trade it for anything else. Okay per- “greater than” sign (>) and type “Release notes”, which
haps .NET and Visual Studio are a good combination, but will show you the release notes. Ensure that you check
Visual Studio non-community edition can get expensive. the checkbox for “Show release notes after an update”
Speaking of developer-centric, although the canonical and get in the habit of periodically reading these release
use of VS Code is to fire up a code development project in notes for fun ’n’ learnin’. In fact, you can click the “gear”
your language of choice, I find myself using VS Code for icon, as shown in Figure 2, to create a shortcut for view-
Figure 1: Extensions taking quick notes as an alternative to a tabbed notepad, ing release notes. I really appreciate how the VS Code
team creates purposeful meaningful documentation that’s
easy to grok with my very limited attention span.

Although a monthly release is frequent enough for my liking,


sometimes I can’t wait to try out new features. VS Code also
has an insiders build that you can grab from https://code.
visualstudio.com/insiders/ that updates every day.

Keyboard Shortcuts
I’ll say one thing about creating shortcuts: VS Code is very
customizable, so don’t go nuts with shortcuts. Use it for
Figure 2: Release notes a while, see what you must have as a shortcut, see that

14 VS Code Tips codemag.com


it doesn’t interfere with your OS or other applications, and
then go ahead and create a shortcut for what you find valu-
able. Even if you don’t create shortcuts, many actions are ®
just a few key presses away. And, frequently, if you just
hover over an action item, it reveals what shortcut activates
an action. I’ll talk more about keyboard sleuthing shortly,
but here are some invaluable shortcuts that you must know.

To go back and forward, use CTRL_MINUS or CTRL_SHIFT_ Instantly Search


Terabytes
MINUS within your code. When you’re dealing with a com-
plex project and jumping from place to place, it’s nice to
be able to go back to where you were.

Another shortcut is F12, which is Go to Definition, but if you


want to just peek into the definition without losing your
place in code, you can press OPT_F12. The Go to Defini-
tion is incredibly useful when consuming libraries because
frequently a lot of documentation is embedded as comments
in the library. Try SHIFT_F12 to find all references for any dtSearch’s document filters support:
symbol in your code. You can simply hover your mouse on a • popular file types
symbol to see documentation in a nice large tooltip.
• emails with multilevel attachments
F2 is for renaming across your project. Honestly, I don’t
want to go through listing every key shortcut, so the best
• a wide variety of databases
thing I can say is, as you use VS Code, watch out for these • web data
shortcuts. If there’s an action you find yourself doing of-
ten, building the muscle memory for the shortcut is going
to make you more productive.

In fact, Microsoft has put together a commonly used


Over 25 search options including:
shortcuts reference you can find right from within VS • efficient multithreaded search
Code using CMD_K, CMD_R (also, see the next section
about COMMAND_P and search for “Shortcuts reference”). • easy multicolor hit-highlighting
This launches a PDF that’s specific to your OS and shows • forensics options like credit card search
the most commonly used shortcuts at http://aka.ms/
vscodekeybindings.

On Mac specifically, one shortcut I’d like to discuss is F11.


F11 is STEP_INTO when it comes to debugging. But MacOS Developers:
also likes to use F11 for spaces. Personally, I still switch
between Mac and Windows enough that I remapped F11 at
• SDKs for Windows, Linux, macOS
the operating system level. Of course, this really messes • Cross-platform APIs cover C++, Java
me up when I use XCode. Ugh, why can’t we just agree on and current .NET
shortcuts? Let me know if you have a better suggestion.
• FAQs on faceted search, granular data
COMMAND_P and SHIFT_COMMAND_P classification, Azure, AWS and more
This is a shortcut so valuable that it deserves its own sec-
tion. This is the shortcut that discovers everything you
care for.

At any point, you can press COMMAND_P, and it shows


a searchable list of all files in your current project. This Visit dtSearch.com for
makes it super easy to jump from file to file in a large • hundreds of reviews and case studies
project. Many route-based applications tend to use the
same filenames over and over again, such as index.js or • fully-functional enterprise and
index.html. You can search for the containing folder name developer evaluations
that coincides with your route and narrow down the file
you care for. This is pretty much how I navigate my proj-
ect most of the time. Very rarely do I use the tree view- The Smart Choice for Text
based navigation on the left.
Retrieval® since 1991
Speaking of that tree view-based navigation on the left,
you can put it on the right. This is controlled by a setting: dtSearch.com 1-800-IT-FINDS
"workbench.sideBar.location": "left"

codemag.com VS Code Tips 15


But there are preferences that are unique to me. For in-
stance, I like working on a Mac and the F11 key really
messes me up. So I customized the F11 key behavior and
kept that in user preferences. I set up a few shortcuts I
like to use often, and that also goes in my user prefer-
ences.

Such preferences are stored in a settings.json file. Work-


space preferences reside in a .vscode folder, so they get
checked in with your code. User preferences are in your
~/.vscode folder. You can choose to synch them across
your computers by signing in with GitHub.
Figure 3: Searching for symbols
You can also launch VSCode with the --user-code-dir
commandline option to load settings on the fly if you
My eyes aren’t all they used to be, so I like to work in wish, or pair it with symlinks to be as fancy as you like.
larger fonts. But the huge downside is that I see less code
on the screen. What I do is I move the sidebar to the
right and press COMMAND_B to hide or show it as needed. Hiding Files
Frankly, COMMAND_P pretty much removes my depen- There are many project types that create temporary or
dence on the sidebar anyway, but in case I need it, it’s interstitial files. A good example is TypeScript or any
there, and every time I hide or show it, it doesn’t move Node.js project. TypeScript doesn’t run directly; it runs
my code. And I have the whole screen width for code. Yay! through transpilation, so you usually generate JavaScript
files ahead of time. As your project gets bigger, you don’t
It would be nice if you could just remember all this, but want everything to get transpiled every time you wish to
you don’t need to. This is where the SHIFT_COMMAND_P debug. Inevitably, your view gets cluttered with a file-
comes in. You can either press COMMAND_P and type “>” name.js and a corresponding filename.ts. Sure, there are
to discover all the commands VS Code supports, or you workarounds like bundling, etc., but they create their own
can press SHIFT_COMMAND_P to land there directly. Here, set of problems.
you’ll find a treasure trove of commands.
A rather easy answer here is that, in addition to exclud-
One that I really like is COMMAND_K_Z, or Zen mode, ing those files from being checked in via .gitignore, you
which removes all distractions and full-screens my ap- can also hide such files via a setting. For instance, the
plication, so I can actually get some work done. setting below in your .vscode\settings.json folder hides
the node_modules folder from your view, even though it
You’ll also notice that many of these commands don’t may exist on the disk.
have assigned shortcuts. You can click the gear next to
any command, as shown back in Figure 2, and create a {
shortcut key if you desire. "files.exclude": {
"node_modules": true
Here’s another really nice power tip. You can press }
COMMAND_P and press # to do an exact search for a sym- }
bol. Or try my preference: press COMMAND_P and type @
to do a fuzzy symbol search. For instance, in my recent
CODE Magazine article around passkeys (https://www.
Multiple Cursors and
codemag.com/Article/2403031/Passkey-Authentication), Other Editing Hacks
I wish to see where I’m using “user.” I can simply do a Okay, this next tip, if you master it, is going to make you
search like that shown in Figure 3. really productive. You probably frequently end up writing
repetitive code. For instance, let’s say that you want to
I highly recommend opening your complex production create an HTML ULI element with five Lis. You can simply
project and trying this out. You’ll be amazed at how use- type this out like so:
ful this is.
<ul>
<li></li>
Settings and Preferences </ul>
VS Code is extremely customizable. I’m not sure if I men-
tioned that yet. Many of these customizations land in Now try and follow these keyboard shortcuts carefully. Go
your preferences. My preferences may not be the same as ahead and select the <li></li> line. You can easily move
my teammate’s preferences, so VS Code allows me to have this line up or down using OPTION_CURSORUP/DOWN
preferences at two levels, at the workspace level that I keys. To duplicate this line, you simply do SHIFT_OP-
intend to share with my team, and those that are specific TION_CURSORUP/DOWN. Go ahead and try it, and create
to the project. For instance, maybe I want to customize five <li> elements.
F5 to not just run, but do some action like spin up a
remote container and then run and attach, or maybe we Actually, this was too complex a way of creating five lis.
use spaces and not tabs and want to enforce three spaces, VS Code supports something called Emmet, which allows
etc. I could put that in workspace preferences. you to speedily hack up commonly used HTML and CSS

16 VS Code Tips codemag.com


structures. For instance, to generate exactly the same
code in an HTML file, type exactly this:

ul>li*5
Figure 4: Emmet in action
It should look like Figure 4.

Now when you hit enter, you get a ul with five lis inside. meeting notes. You can enable Emmet in any language
you wish.
Now, let’s say that you wish to add some text into these
five <li> elements. Carefully place your cursor in the mid- For instance, I love taking notes in markdown. I don’t
dle of the first <li></li> element, and press OPTION_COM- know why we all don’t do that. It’s simple, fast, and can
MAND_CURSORDOWN. You should now see multiple cur- be version controlled and compared. In fact, my editor
sors, as shown in Figure 5. insists that I write this article in MS Word, but you know
what? I first write it in markdown, and then copy paste it
Now any text you write will appear in all five places. You in Word. It’s just more productive.
can super charge this with text replacement and regex to
do some really amazing things. Anyway, here’s how you can enable Emmet in VS Code. Figure 5: Multiple cursors
In your settings (either user or workspace), add the fol-
What if I didn’t want to type exactly the same text in all lowing:
five places. Instead, I wanted to incrementally type 1,
2, 3, 4, 5? You can use the following Emmet expansion. {
"emmet.excludeLanguages": [],
ul>li{$}*5 "emmet.includeLanguages":
{"markdown": "html"},
I know this Emmet syntax feels a bit weird and alien. Once }
you get used to it, it’s not so bad. In fact, it feels quite
logical. So here’s a link that’s a great Emmet cheat sheet Now, open a markdown file, and try out an Emmet expan-
https://docs.emmet.io/cheat-sheet/. Of course, there’s sion. For instance, let’s say that you want to quickly cre-
an extension that makes this even easier. It’s called Text ate a list of five items. Try this:
Pastry and lets you do ranges, text etc.
{ $.}*5

Selecting Text Like a Pro You can start typing notes. For instance, Figure 7 shows
I just talked about multiple cursors. That’s very cool, but my to-dos for the weekend. Note that I have my mouse
sometimes you want to visually select a random column of cursor positioned in the left gutter. Just by indenting
text. You can see Figure 6 for what I mean. The way to do things in a certain way, I can collapse or expand sections
this is to press OPTION_SHIFT and drag your mouse cur- in my notes. Good luck doing that with Notepad. This
sor across whatever you wish to select. This can be useful collapse or expand works in any language that VS Code
when you want to cross edit or paste a vertical line of text. understands, including text.

Selecting code is also an art. I can’t tell you how many


times I’ve seen people just place their cursor somewhere,
hold the shift key down and press LEFT ARROW multiple
times to select a whole line. Just do COMMAND_L to select
a whole line. Now pair that with move line up or down as I
talked about earlier. You can certainly use all Mac or Win-
dows OS shortcuts to move between lines or words easily.

However, here’s a nice tip. Sometimes you want your se-


lection to be code aware. For example, you might want to Figure 6: Selecting a column of text
select this “if” block or select this method. In fact, let’s
say that you want to place your cursor somewhere, select
an if block, and maybe move it a few lines up.

Here’s how you do it. You use an ability to call an expand


or collapse selection. You can do so using CTRL_SHIFT_
OPTION_RIGHT/LEFT_Arrow keys. With the text selected,
you can move the whole section up, smartly, respect-
ing all the code logic and boundaries using OPTION_UP/
DOWN arrows.

Collapse Expand on Steroids


Remember, I mentioned that VS Code is incredible for
developers, but I use it for other purposes, like taking Figure 7: Collapse and expand works in any file type

codemag.com VS Code Tips 17


like. Even when I’m taking notes, I like to Git init\com-
mit simply because it gives me reference points when I’m
doing complex refactoring.

We all have those days where we make some changes,


mess up everything, and wish we had a commit. If we
knew we were walking toward a trap... Well, VS Code has
your back. This is a nifty trick hidden by default. Use
COMMAND_P and find Focus on timeline view. Now open
any file and you’ll see that VS Code has been monitoring
the work you’ve been doing in that file. This will work
whether or not you did a commit. You can see this in
action in Figure 9. You can select any previous version,
and it shows you a diff view of the changes between your
current version and the version from however long back.

Figure 8: The outline view Figure 9: The timeline view has my back.
Sticky Headers
A really nice feature of VS Code is sticky headers. Frequent-
The Outline View ly, as I’m scrolling through code, the methods become re-
Collapse and expand is nice, but it’s sometimes very nice ally long and I tend to lose context of where I was.
to view a top-down outline view of your code. For exam-
ple, what routes do I have configured in a long file? I’ve Sticky headers solve this problem for me. As I scroll,
found this to be especially useful in languages that tend sticky headers lock the scope I’m in at the top. If you pay
to get very verbose, such as Golang. Press COMMAND_P close attention to Figure 10, you’ll see that line #51 is
and look for “Focus on outline view”. You should see my scope, and line #52, 53, and 54 are scrolling under-
something similar to Figure 8. Please feel free to try this neath it. This also works in other scopes such as if/while,
with your incredibly complicated unwieldy long file with etc. This way, when I’m in the middle of a long method in
lots of code. line #8848, I can easily reference what the input param-
eters of my scope were.
The outline view is really useful because the overall struc-
ture of the code is now super clear. Now I can tell that I
have four routes and a few global variables. Hmm, maybe Extensions
I should restructure them into a const or something to VS Code has a vibrant extensions marketplace. Nearly ev-
clean up my code. Or maybe put them in their own scope. ery platform or language has its unique needs. VS Code
I’ll get back to refactoring later. out of the box remains fairly bare bones, but you can
add whatever you wish to it via extensions. There are UI
themes that are more suitable to HTML, for instance. But
The Timeline View it’s also true that a color picker, although incredibly use-
I mentally fought Git for many years. I felt it was over- ful in CSS, has little use in Python. This is where profiles
bearing and over-complex for simple things. I’m almost come in.
at a point now where I’ve seen the light. Even for simple
stuff, you can make Git as complex or as simple as you’d If you click on the gear icon in the activity bar, you can
create profiles. In a profile, you can capture extensions,
UI state, keyboard shortcuts, and settings. You can im-
port/export profiles, and you can create profiles unique
to dev scenarios.

For instance, at a place I used to work, all development


was done in a remote container. I wanted to try things
out locally as well. I just set up different profiles for
those. One profile had the extension that made the re-
Figure 10: Sticky headers mote container work seamless. Another didn’t.

Extensions can also get heavy. Some extensions do


too much. A perfect example is the “import cost” ex-
tension at https://marketplace.visualstudio.com/
items?itemName=wix.vscode-import-cost. For Node.js proj-
ects, this extension is incredible. As soon as you import
something, it’ll let you know exactly how big the depen-
dency is. The problem is that the extension that lets you
know how heavy a dependency is, is itself quite heavy.

How do you know which extension is slowing you down?


Periodically, it’s a good idea to view how much time your
Figure 11: File customization in search extensions are taking. Press COMMAND_P, and type “>Devel-

18 VS Code Tips codemag.com


Figure 12: The search editor

oper: Show running extensions”. This gives you a clear idea This window even maintains your search history and you
of which extensions are killing your battery life. Remember, can have multiple search editors open. The red arrow al-
SPONSORED SIDEBAR
you can set up profiles to selectively load extensions. This lows you to see lines of code around the matched search Adding Copilots
little bit of homework keeps your IDE zippity fast. result. For instance, clicking on that allows me to see the
line before and after the matched search result within the
to Your Apps
search results. This can be seen in Figure 12.
Search Like a Pro The future is here now
and you don’t want to get
VS Code can search through your code. That’s not a big
deal: Just type in a search term and hit enter, right? VS Summary left behind. Unlock the
true potential of your
Code’s search is quite powerful and all these nifty things Sometimes you take things for granted. I use VS Code ev- software applications by
are right under your nose. For instance, you can do “match ery day, including weekends. I seldom realize how amaz- adding Copilots.
case” or “match whole word” in search. You can even ing this tool is and how much muscle memory I take for
make search case specific. The best part is that you can granted. When I started writing this article, I was debat- CODE Consulting can
use regex expressions to search to make it truly powerful. ing whether I had enough tips. But as I started verbal- assess your applications
izing my thoughts with VS Code open on the side, I came and provide you with
Sometimes you need to search text that spans multiple up with one tip and then another. a roadmap for adding
lines. It’s easy. You just hit SHIFT_ENTER to make your Copilot features and
optionally assist you in
search box multiline. Believe me when I say this: I’m not done. Some of the
adding them to your
super-charging tips are a bit complex and require me to
applications.
Sometimes you want to narrow your search down by file describe my workflow and OS setup. Some of them are
types. You can easily click the triple dot below the search specific to Git and certain extensions that really simplify Reach out to us today
box and pick files to exclude or include, as shown in Fig- my Git life. Some of them are all about terminals host- to get your application
ure 11. ed inside VS Code so I don’t have to leave VS Code for assessment scheduled.
common tasks. Some are around debugging and logging www.codemag.com/ai
These textboxes are deceptively powerful. They allow you tricks. And there are many more.
to use glob pattern syntax in searches. For example, you
can use an asterisk (*) to match zero or more characters What code editor do you use? Do you have any favorite
in a path segment. Or you can use a question mark (?) to tips? Give a shout out to me on X or Twitter or wherever
match against one character in a path segment. You may you feel.
use double asterisks (**) to match any number of path
segments, including none. Until next time, happy coding in VS Code, or whatever
you prefer.
You can make your combine conditions using {}. For in-
stance {**/*.html,**/*.txt} matches all HTML and text  Sahil Malik
files. You can use [] to declare a range of characters to 
match. For example, use .[0-9] to match on example.0,
example.1, …). You can even negate criteria using !. For
example, use [!...] to negate a range of characters to
match (example.[!0-9] to match on example.a, example.b,
but not example.0).

Here’s another neat tip regarding searching your code-


base. You’re not limited to using the sidebar for searches.
Just press COMMAND_P and open search editor. Now you
have a full screen window for searches. Once you see your
search results, you can use CMD_CLICK to navigate to the
code occurrence without losing the search results.

codemag.com VS Code Tips 19


ONLINE QUICK ID 2408041

Exploring .NET MAUI: Getting Started


Unlock the true potential of cross-platform development with eXtensible Application Markup Language (XAML) and .NET MAUI
(Multi-platform App UI). Say goodbye to the frustration of writing code for each platform separately. With .NET MAUI, you
can develop powerful business applications that run seamlessly on Windows, Android, Mac, and iPhone devices. In this series

of articles, I’ll guide you through the process of building a and Android, the .NET runtime is implemented by Mono
complete business application from scratch, step by step. which is an implementation of the runtime designed for
those platforms. On Windows, the .NET CoreCLR provides
Starting with the fundamentals of XAML, you'll learn how to the execution environment.
create your first .NET MAUI application. From there, you’ll
dive into constructing various screens, including a detailed Instead of having to learn how each platform defines
view, and using grid, stack, and flex layouts. Witness first- their UI and how they express business logic in their
hand how effortless it is to craft screens that adapt flaw- different programming languages, .NET MAUI provides a
lessly to any screen size. Whether you're an aspiring de- single framework for building the UIs and business logic.
Paul D. Sheriff veloper or a seasoned pro, this article gets you started on .NET MAUI can create applications for either mobile or
http://www.pdsa.com building business applications using XAML and .NET MAUI. desktop. You may use a Windows computer to create ap-
If you’re a C# Windows Forms developer or a WPF developer plications that target either Windows or Android; how-
Paul has been working who wants to learn to use XAML in .NET MAUI applications, ever, to build applications for iOS or macOS does require
in the IT industry since this article is also for you. To get the most out of this ar- a Mac computer.
1985. In that time, ticle, I’m assuming that you’re very familiar with C#, .NET
he has successfully
Core, and object-oriented programming.
assisted hundreds of The Basics of XAML
companies’ architect
XAML is a declarative markup language like HTML. Unlike
software applications An Overview of .NET MAUI HTML, however, XAML is mapped directly to C# types de-
to solve their toughest
business problems. Paul .NET MAUI is a technology that helps you build native fined within the .NET API used by WPF or .NET MAUI. It’s
has been a teacher and applications on Windows, macOS, iOS, and Android, all interesting to note that you can write a WPF or .NET MAUI
mentor through various using a single C# codebase. To design the UI for your ap- application solely in C# without any XAML at all. This is
mediums such as video plications, use the XAML markup. The XAML you write is because each XAML control maps directly to a C# class in
courses, blogs, articles and translated into C# for the .NET runtime designed to run on the .NET library.
speaking engagements the target OS. XAML has been around for many years and
at user groups and was originally created for use in WPF applications to cre- Of course, it’s much simpler to use XAML because it’s more
conferences around the ate robust, resolution-independent screens. Like HTML, visual and can express controls with less code than writ-
world. Paul has multiple XAML uses a flow-layout instead of absolute positioning ing in C#. In addition, using XAML allows a designer to
courses in the www. to ensure that screens can adapt to devices of any size. create the UI for an application, and a C# programmer
pluralsight.com library focuses on the business logic. This saves time and is a
(https://bit.ly/3gvXgvj) The goal of .NET MAUI is to allow you to create multi- nice division of labor. XAML files are text files with a
and on Udemy.com platform applications using a single project and code- .xaml extension, thus making it easy to share these files
(https://bit.ly/3WOK8kX) base. You’re also allowed to add platform-specific source between the programmer and the designer.
on topics ranging from C#, code and resources if needed. Starting with .NET 6, .NET
LINQ, JavaScript, Angular, MAUI targets platform-specific frameworks (Figure 1) for
MVC, WPF, XML, jQuery,
creating apps on .NET Android, .NET iOS, .NET macOS,
and Bootstrap. Contact
and Windows UI 3 (WinUI 3). These frameworks all use
Paul at [email protected].
the same .NET Base Class Library (BCL). The BCL abstracts
the details of the underlying platform away from your
code. The BCL depends on the .NET runtime to provide
the execution environment for your code. For iOS, macOS,

Figure 2: An element consists of a start and end tag


with usually some content in between them.

XAML is simply XML, and thus, each element starts with


an opening tag such as <Button> or <Label>, as shown in
Figure 2. Each element ends with a closing tag such as </
Button> or </Label>. Both the start and end tags togeth-
er make up an XAML control or element. You’ll find that
Figure 1: .NET MAUI is built on top of several most developers use "tag" and "element" interchange-
technologies to ensure that it works across all platforms. ably, but technically, they’re different.

20 Exploring .NET MAUI: Getting Started codemag.com


One thing to note about the <Label> element shown in Fig-
ure 2 is that you’re setting the Text property of the <Label>
by including it between the start and ending tags. Not all
XAML elements allow you to set values in this manner. Most
use the attribute syntax, as described in the next section.

Set Properties Using Attribute Syntax


Tags such as <Button> or <Label> map directly to Button Figure 3: An attribute sets properties of an element.
and Label types in C#. To set properties of the class, you
use attributes. An attribute is represented by a name (the
property name in C#), followed by an equal sign, and then The second XML namespace xmlns:x="http://schemas.
the value you wish to set contained within quotes. Figure microsoft.com/winfx/2009/xaml" is also a Using state-
3 creates an instance of a Label class and sets the Text ment but has aliased any language construct within this
property to the value "First Name". namespace so it must use an x followed by a colon in
front of any name of a language construct used from this
Because all properties are set within the starting tag, namespace. Constructs you’ll use frequently within this
you don't need the closing tag at all. Instead, you may namespace include x:Class, x:Key, x:Name, and x:Type.
express the <Label> element shown in Figure 3 with the You’re also allowed to bring in your own XML namespaces
following code snippet. and set your own alias. Both of these techniques are illus-
trated a little later in this article.
<Label Text="First Name" />
XAML and Code-Behind Are Compiled Together
Set Properties Using Element Syntax The <ContentPage> element in the MainPage.xaml file
Instead of using attributes to set properties of a class, has an x:Class="AdventureWorks.MAUI.MainPage" at-
you may also use element syntax. Sometimes the value
you must set is unable to be set within quotation marks,
in this case, between the opening and closing tags, you Listing 1: Each XAML file must have only one defined container into which all other
may use the format <TypeName.PropertyName>Value</ XAML is contained.
TypeName.PropertyName>, as shown in the code snippet <ContentPage
below. As you can see, using the attribute syntax is often xmlns="http://schemas.microsoft
.com/dotnet/2021/maui"
more compact, but either method is acceptable. xmlns:x="http://schemas.microsoft
.com/winfx/2009/xaml"
<Label> x:Class="AdventureWorks.MAUI.MainPage">
<Label.Text> <Label Text="First Name" />
First Name
</Label.Text> </ContentPage>
</Label>

Create Elements Using C#


You’re allowed to create controls using C# in the code-
behind for a page. For example, to create the Label shown
in the last few examples, you write the C# code like this:

Label label = new () {


Text = "First Name"
};

Only One Root Element Is Allowed


In XAML and HTML, only one root element is allowed per file.
For example, in an HTML document, you must have one and
only one <html> tag within which all your other HTML is con-
tained. In a XAML file you must also only have one tag, such
as a <ContentPage>, <ContentView>, or <ResourceDictionary>.
All other XAML must be contained within the opening and
closing tags of these. An example of this is shown in Listing 1.

XML Namespaces
An XML namespace is like a C# namespace in that it contains
a set of classes that may be used without any prefixing.
For example, in C#, you may reference a File class direct-
ly if you’ve declared a Using statement to the System.IO
namespace at the top of the C# file. In the <ContentPage>
example you just looked at, the xmlns="http://schemas.
microsoft.com/dotnet/2021/maui" attribute is like a Us-
ing statement to specify which set of element names (<But-
ton>, <Label>, etc.) may be used without any prefix.

codemag.com Exploring .NET MAUI: Getting Started 21


tribute (Listing 1). The XAML in the MainPage.xaml file <Button Text="Save"
is parsed into a partial class using the namespace and Clicked="SaveButton_Clicked" />
class name specified in this x:Class attribute. This par-
tial class and the partial class located in the MainPage. The C# code you write in the code-behind looks like the
xaml.cs file (Listing 2) are compiled together to create following code snippet:
the final page to be displayed to the user.
private void SaveButton_Clicked(
Events in XAML object sender, EventArgs e)
Some controls can raise an event to which you can re- {
spond in the code-behind of your XAML page. One ex- // TODO: Respond to the event here
ample is a Button control that raises a Clicked event }
when the button is pressed upon by the user. In XAML,
define the name of the event procedure to call by adding The first parameter received into this event procedure is a
a Clicked attribute to the Button start tag. The value as- reference to the button that initiated the event. The sec-
signed to the Clicked attribute is the name of an event ond parameter is a generic EventArgs object. There are no
procedure located in the C# code-behind file. special event arguments passed to the Clicked event on a
button. Other objects may pass some event arguments for
different events that are raised.
Listing 2: The class name in the code-behind file is marked as partial so it can be
compiled with the parsed XAML file. Reference Controls from the Code-Behind
namespace AdventureWorks.MAUI; To change the property of a control on your XAML with C#
code, name your control uniquely on the page. For example,
public partial class MainPage : ContentPage if you have an Entry control that holds the First Name, as-
{
public MainPage() sign it a name using the construct x:Name="uniqueId",
{ as shown in the code snippet below.
InitializeComponent();
} <Entry x:Name="firstName" />
}
In the code behind, use C# to retrieve the value from this

Figure 4: Locate the Visual


Studio Installer utility. Figure 5: Install appropriate workloads for this class.

Figure 6: .NET 8.0 Runtime (Long Term Support) is required. Figure 7: .NET MAUI SDK for Windows is required.

22 Exploring .NET MAUI: Getting Started codemag.com


Figure 8: Google Android Emulator (local install) is required. Figure 9: Android SDK setup is required.

Entry control's Text property and display it on the console


using the following code.

Console.WriteLine(firstName.Text);

XAML Is Case-Sensitive Figure 10: Search for Turn Windows features on or off.
All element and attribute names are case-sensitive when
using XAML. This is because C# is case-sensitive and, to
compile XAML into C#, the names must match exactly. The Visual Studio Installer icon, click on it to launch the VS
values contained within the properties may or may not be Installer utility.
case-sensitive and will depend on what the property will
accept. If you’re setting a Text property, for example, you When the installer utility has launched, on the Workloads
may use any case you wish. If you’re setting a Boolean tab (Figure 5), ensure that you have the following checked.
property, you may use either true or True, because the
XAML parser knows to always convert True to lower-case • ASP.NET and web development
for C#. However, if the property you are trying to set is • .NET Multi-platform App UI development (MAUI)
a C# enumeration, you must spell it exactly or the XAML • .NET desktop development
parser will give you an error message.
Click on the Individual components tab and ensure that
you have the .NET 8 Runtime (Long Term Support) se-
Installing .NET MAUI lected, as shown in Figure 6.
You need to ensure that .NET MAUI has been installed
on your machine. Detailed directions are in this link: Locate the .NET MAUI SDK for Windows and ensure that
https://learn.microsoft.com/en-us/dotnet/maui/get- it’s selected, as shown in Figure 7.
started/installation?tabs=vswin. I’ve included the follow-
ing simplified instructions to get you going quickly. If you wish to run the Android Emulator, select the Google
Android Emulator (local install), as shown in Figure 8.
Bring Up the Visual Studio Installer Tool
In the search bar on your windows computer (Figure 4), The last item to select is the Android SDK setup, as
type in Visual Studio Installer, and when you locate the shown in Figure 9.

Figure 12: Turn on Windows Hypervisor Platform on your


Figure 11: Turn on Hyper-V on your Windows computer. Windows computer.

codemag.com Exploring .NET MAUI: Getting Started 23


.NET 8 The results from running this command should look some-
.NET 8 (or later) is the best version to use when develop- thing like the following output:
ing .NET MAUI applications, so be sure to download and
install it if you haven’t already done so. To see whether 8.0.xxx
you have .NET 8 installed, open a command prompt and
type in the following command: If you don’t have .NET 8, you can download and install
it from https://dotnet.microsoft.com/en-us/download/
dotnet --version dotnet/8.0.

Figure 13: Select Create a new project from the Visual Studio screen.

Figure 14: Select a .NET MAUI App from the list of templates.

24 Exploring .NET MAUI: Getting Started codemag.com


Figure 15: Set the project name and location.

Figure 16: Choose .NET 8 or later when creating a .NET MAUI application.

Activate Hyper-V on Your Computer been checked as well. These components help you have
In your Windows Search bar, type in Turn Windows fea- the best performance while developing your .NET MAUI
tures on or off to display the widget shown in Figure 10. applications.

Once you click on this widget, you should see the Windows
Features dialog appear (Figure 11). Scroll down and locate Build Your First .NET MAUI Application
the Hyper-V component and ensure that it’s checked. Now that you’ve learned a little about XAML and have
installed the necessary components for building a .NET
Scroll down a little further and locate the Windows Hy- MAUI application, let's dive right in and start building
pervisor Platform (Figure 12) and ensure that it has a .NET MAUI application. Open Visual Studio 2022 and

codemag.com Exploring .NET MAUI: Getting Started 25


click on Create a new project, as shown in Figure 13, to
advance to the next page.

On the Create a new project page (Figure 14), type .NET


MAUI into the search box (1). Select the C# language (2)
because this is the only language you may use, currently,
to develop .NET MAUI applications. From the list of tem-
plates, click on the .NET MAUI App (3) templates, and
then click the Next button to advance to the next page.

On the Configure your new project page (Figure 15),


set the Project name (marked as 1 on the image) of the
new project to AdventureWorks.MAUI. Set the Loca-
tion (marked as 2) to a folder on your hard drive where
you’d like to place your C# projects. Uncheck the Place
solution and project in the same directory (marked
as 3) as you’re going to be adding more projects to this
solution later and will want to place each of them into
a separate folder. Click the Next button to advance to
the next page.
Figure 17: Run the .NET MAUI application on Windows.
On the Additional information page (Figure 16), choose
.NET 8 (Long-Term Support), or a later version if you
have one installed on your computer. Click on the Cre-
ate button and Visual Studio creates your new .NET MAUI
application.

Try It Out
Once the application has been created, click on the Win-
dows Machine button (Figure 17) on the Visual Studio
toolbar to run this application on your windows comput-
er. The first time you try to run a .NET MAUI application,
the build process takes some time, as there are lots of
dependencies to load, and it must install the application
into your Windows operating system.

Once the application launches, you’ll see a screen that


looks like Figure 18. Click on the button Click me and the
text within the button changes to reflect how many times
you’ve clicked the button. This .NET MAUI application is
just like a normal Windows application in that you can re-
size the window, minimize, maximize, or close the window.

After you run the application using Visual Studio, go to


Figure 18: The .NET MAUI template application running Add or remove programs in Control Panel and find Ad-
on Windows. ventureWorks.MAUI as one of the installed applications.

Figure 19: Choose the Android Emulators > Pixel 5 – API 34.

26 Exploring .NET MAUI: Getting Started codemag.com


Try It Out on an Android Emulator
Close the Window or stop the application using Visual
Studio. Click the arrow next to the Windows Machine and
select Android Emulators > Pixel 5 – API 34 (Android
14.0 – API 34), as shown in Figure 19.

After selecting the Android emulator, it appears as the


configuration item (Figure 20). Click on this button to
run the Android emulator. Again, it may take a few min-
utes to run this emulator, so be patient. Even if the emu-
lator comes up, it may still take a few minutes for VS to
compile the application and deploy it to the emulator.
Keep an eye on the status bar at the bottom left of the
Visual Studio window, as it should show you the progress
and provide you with messages as to what’s happening. Figure 20: Run the application in the Android emulator.

Once the application is deployed, you should see a screen


that looks like Figure 21. This is the Android emulator
and shows you how this application would look on an
Android phone. Click on the button to see the button text
change to tell you how many times you have clicked on
the button.

Modify the Content Page


When you create a new .NET MAUI application, Visual Stu-
dio provides you with a MainPage.xaml that has some
controls on it. For just learning XAML and .NET MAUI, this
XAML might seem a little overwhelming, so let's delete it
and build up the sample slowly. Open the MainPage.xaml
file and remove lines 7 through 34. This is the <Scroll-
View> tag and everything down to (and including) the
closing </ScrollView> tag. Open the MainPage.xaml.cs
file and remove the code behind, except for the construc-
tor, as shown in the following code snippet.

namespace AdventureWorks.MAUI;

public partial class MainPage : ContentPage


{
public MainPage()
{
InitializeComponent();
}
}
Figure 21: The .NET MAUI template application
Add a Label running on the Android emulator.
Add the following <Label> element where the <Scroll-
View> element was located.

<Label Text="Adventure Works"


FontSize="Large"
VerticalOptions="Center"
HorizontalOptions="Center" />

A Label control is used to display textual information to


your user. Set the Text property to the value you wish to
display. In the code above, set the FontSize property to
the value Large to display the text in a larger font than
the default size. The VerticalOptions and HorizontalOp-
tions properties allow you to center the Label control
within the page by setting their values to Center.

Set the Title Property


Bring up the Properties window (Figure 22) by selecting
View > Properties Window from the VS menu. Click on Figure 22: The Properties window allows you to set properties on whatever control has focus.

codemag.com Exploring .NET MAUI: Getting Started 27


Figure 23: Setting
properties on the
<ContentPage> affects
the appearance of the
view.

Figure 24: Changes to


the application shell
are controlled by the
<Shell> element.

Listing 3: Add a method to change the window attributes.


#if WINDOWS OverlappedPresenter p) {
public static void p.Maximize();
SetWindowOptions(MauiAppBuilder builder)
{ //p.HasBorder = false;
builder.ConfigureLifecycleEvents(events => //p.HasTitleBar = false;
{ //p.IsAlwaysOnTop = false;
events.AddWindows(wndBuilder => //p.IsMaximizable = false;
{ //p.IsMinimizable = false;
wndBuilder.OnWindowCreated(window => //p.IsModal = false;
{ //p.IsResizable = false;
IntPtr hndl = WindowNative }
.GetWindowHandle(window); });
WindowId winId = Win32Interop });
.GetWindowIdFromWindow(hndl); });
AppWindow appWnd = AppWindow }
.GetFromWindowId(winId); #endif
if (appWnd.Presenter is

28 Exploring .NET MAUI: Getting Started codemag.com


line 2, so you’re focused on the <ContentPage> element URI-based navigation that can be defined through XAML
and you should see the Properties window refresh with the or C# code. The navigation structure can be defined as
list of properties you can set for the ContentPage element. tabs (menus), flyouts, and tab bars. Each tab or flyout
maps to a content page which, when clicked upon, dis-
Set the Title property of the ContentPage to Adventure plays that content page within the shell of the applica-
Works and press the Enter key. You should see that the tion. You’ll see examples of navigation later in this article
XAML has been written for you in the editor. Close the series.
Properties window, click just after the Title="Adventure
Works" attribute, and hit the spacebar. You should see an
IntelliSense window open in your editor that has the same Make the Window Maximized
list of properties you saw in the Properties window. Using When you run the application on Windows, notice that
IntelliSense, set the BackgroundColor attribute to Gray. the page isn’t being displayed as a full-screen window.
If you want your page to be full screen, open the Maui-
Try It Out Program.cs file and add a few Using statements at the
Run the application on Windows to see the new Title top of the file. These Using statements must be wrapped
attribute on the screen. Notice the Gray background, as within a #if WINDOWS conditional compile, as making a
shown in Figure 23. screen maximized is only applicable on a Windows operat-
ing system.
Leave the .NET MAUI application running, go back to
Visual Studio and remove the BackgroundColor property #if WINDOWS
from the ContentPage element. If you look at the running using Microsoft.Maui.LifecycleEvents;
application, you should see that the background color has using WinRT.Interop;
returned to the original color. You can also run this on the using Microsoft.UI;
Android emulator and see the same thing happen on that using Microsoft.UI.Windowing;
screen as well. #endif

The Using statements may look disabled; this is okay,


Change the Shell Properties as they’re applied when you run the .NET MAUI applica-
When the application is running on Windows, notice that tion using the Windows Machine start button within
the window title reads "AdventureWorks.MAUI". This is Visual Studio. Next, add a new method within the Maui-
the name of the project, but it’s probably not what you Program class named SetWindowOptions(), as shown in
want on the Window title. Open the AppShell.xaml file Listing 3.
and set the attributes on the <Shell> element shown in
bold below. It’s not important that you understand every line of code
in Listing 3. The important part is that you get access
<Shell x:Class="XamlBasicsMAUI.AppShell" to the current window's Presenter object and invoke the
xmlns="http://schemas.microsoft..." Maximize() method to set the page to full screen. There
xmlns:x="http://schemas.microsoft..." are several commented out properties that you may set
xmlns:local="clr-namespace:XamlBasicsMAUI" as well. I included them in the code so you can see the
Shell.TitleColor="Black" various properties you may manipulate on the current
Shell.BackgroundColor="Gray" window.
Title="Adventure Works"
Shell.FlyoutBehavior="Disabled"> The code in Listing 3 also looks disabled but is acti-
vated when run on a Windows machine. You now need to
Try It Out
Run the application on the Windows Machine and see
that the background of the title area is gray and the title
color is black (Figure 24). Also notice there is now a title
on the Windows title bar area. The title bar shows up on
Windows, but not on an Android emulator or iOS phone
emulator because cell phones don’t have a title bar area.

Remove the TitleColor and BackgroundColor attributes


you just added to the <Shell> element, as it's better to
not set colors for the shell. This allows your application
to pick up any theme colors set either in your OS, or from
global styles in your application, as will be explained
later.

The Shell Class


The first line in the AppShell.xaml file is a <Shell> el-
ement that provides the top-level element in which all
other elements are contained. The <Shell> element is like
the <html> element on an HTML page. This <Shell> ele-
ment is where you describe the navigation to allow you Figure 25: A standard data entry page typically has
to move from one page to another. The Shell class uses several rows and two columns.

codemag.com Exploring .NET MAUI: Getting Started 29


call the SetWindowsOptions() method by calling it within ent kinds of stack container controls that display controls
the CreateMauiApp() method. Just before the #if DEBUG either horizontally or vertically. You also have a Grid that
statement, call this new method, as shown in the follow- allows you to place controls into rows and columns.
ing code snippet:
A grid control is not for displaying rows and columns of
#if WINDOWS data from a database table. Instead, it’s for laying out la-
SetWindowOptions(builder); bels, text boxes, radio buttons, check boxes, and buttons
#endif into rows and columns. Look at Figure 25 and you can see
that there are eight rows and two columns defined in a
Try It Out Grid control. In rows one and two are Label controls that
Run the application on the Windows Machine and see display information about the page. Row three contains a
that the window is now full screen. If you ran this code BoxView control that makes the horizontal line to separate
on the Android emulator, the code is ignored because it’s the header information from the data entry portion of the
wrapped in the conditional compile statement #if WIN- page. In rows four through seven, there’s one Label control
DOWS. to tell the user what should be entered into the one Entry
control located in the second column. In the eighth row
and second column is a HorizontalStackLayout control
Using the .NET MAUI Grid Control into which two Button controls are placed so they appear
for Page Layout side-by-side. Don't worry, you’re going to learn about each
The ContentPage element has a single Content property of these controls as you work your way through this article.
that’s the area between the opening <ContentPage> tag
and the closing </ContentPage> tag. This content area is Defining Rows and Columns
a View class and is used to display a single control. If Within a <Grid> element, you may define rows and col-
you want to have more than one control on a page, those umns in two different ways. The first is to use the ele-
controls must be wrapped within a Container control. A ment-based approach as shown below.
Container control can have one or more controls within it.
How that container displays the controls depends on what <Grid>
kind of container it is. For example, you have a few differ- <Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
...
<RowDefinition Height="Auto" />
ADVERTISERS INDEX </Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Advertisers Index <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
CODE Consulting--AI Services ...
www.codemag.com/ai-services2 </Grid>

CODE Consulting The second method to define rows and columns is to use
www.codemag.com/Code 75 attribute-based XAML. Each row's height and each col-
CODE Legacy umn's width is separated by a comma, as shown in the
www.codemag.com/Legacy 53 following code snippet.

CODE Staffing <Grid RowDefinitions="Auto,Auto,...,Auto"


www.codemag.com/staffing76 ColumnDefinitions="Auto,*">
...
dtSearch
</Grid>
www.dtSearch.com 15
Advertising Sales:
Tammy Ferguson DevIntersection Auto and Star (*) Spacing
832-717-4445 ext 26
[email protected]
www.devintersection.com 38 The Width property of a ColumnDefinition element or the
Height of a RowDefinition element within a grid can be
LEAD Technologies
defined in one of three ways. If you use a single number,
www.leadtools.com 5
this is called Absolute spacing and is a device-indepen-
UAV Expo dent unit of measure. I highly recommend that you never
www.expouav.com 35 use this spacing, as it makes it hard for the controls to
adjust to different screen sizes. The second method is
to use a setting of Auto. This setting means the height
or the width is based on the largest-sized control within
that row or column.
This listing is provided as a courtesy
to our readers and advertisers. The third method is to set the Height or Width properties
The publisher assumes no responsi- to a Star (*). This tells the page layout engine to use
bility for errors or omissions. the rest of the available space within that row or column.
This method is called proportional spacing. You may also

30 Exploring .NET MAUI: Getting Started codemag.com


place a number before the star, such as 2*, in which case, ColumnSpan and RowSpan
that row or column will receive two times the height/ Looking at Figure 25, you can see that the first two la-
width as the rest of the rows/columns within the grid. bels seem to span across the two columns. This is accom-
This number can be any number you want, based on how plished by using the attached property Grid.ColumSpan.
large you want the row/column in relation to the others. The Grid.ColumnSpan attached property indicates how
Consider the following <Grid> definition: many columns the control it’s attached to should span
within a Grid control. Because the Grid in the example
<Grid> has two columns defined, set the ColumnSpan attribute
<Grid.RowDefinitions> to "2" to have the Label take up two columns, as shown
<RowDefinition Height="Auto" /> in the XAML below.
<RowDefinition Height="*" />
<RowDefinition Height="100" /> <Label Grid.Row="0"
</Grid.RowDefinitions> Grid.Column="0"
<Grid.ColumnDefinitions> Grid.ColumnSpan="2"
<ColumnDefinition Width="200" /> Text="User Information"
<ColumnDefinition Width="*" /> FontSize="Title" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> There is also a Grid.RowSpan attached property that indi-
... cates to the grid how many rows the control it is attached
</Grid> to should span.
Getting the Sample Code
In this grid, you have three rows: Auto, star (*), and the Create the ContentPage
You can download the sample
absolute value of 100. The grid first allocates 100 device- Let's now start creating the page shown in Figure 25.
code for this article by visiting
independent units to the third row. Next, it looks at all Open the MainPage.xaml file and replace the Label con- www.CODEMag.com under
controls within the first row and determines the largest trol you added earlier with the XAML shown in the fol- the issue and article, or by
height value of those and uses that number to set the lowing code: visiting www.pdsa.com/
Height property of the first row. The Height property of downloads. Select “Articles”
the second row is set to whatever value is left over after <Grid RowDefinitions="Auto,Auto,Auto" from the Category drop-
calculating the heights of the other rows. ColumnDefinitions="Auto,*"> down. Then select “Exploring
<Label Grid.Row="0" .NET MAUI: Getting Started”
There are three columns in this grid, of which the first one Grid.ColumnSpan="2" from the Item drop-down.
has an absolute value of 200 device-independent units. Text="User Information"
The grid allocates that column first, then subtracts that FontSize="Title" />
amount away from the width of the page on which this <Label Grid.Row="1"
grid is contained. Within the third column, it determines Grid.ColumnSpan="2"
the width of the largest control and assigns that value to Text="Use this Screen to
the third column's Width property. The remaining width Modify User Information."
is then allocated to the second column. FontSize="Body" />
<BoxView Grid.Row="2"
As you can imagine, there could be several columns that Grid.ColumnSpan="2"
both use a star (*) for the width. If that’s the case, after HeightRequest="1"
all other widths are calculated, the remaining width is Color="Black" />
split equally among those columns. </Grid>

Assigning Rows and Columns to Controls The BoxView Control


After you’ve created your <Grid> and set up the appropri- A BoxView control draws a rectangle with a specified
ate number of rows and columns, an "attached property" height and width. If you set the HeightRequest property
allows a child element of a Grid to attach itself to the grid to a one (1), this control draws a line. By default, the
in a certain row and column. For example, to place the line takes up the complete width of the container within
Label and the Entry control into the fifth row and the first which it’s drawn. Set the Color property to whatever color
and second column, respectively, as shown in Figure 25, you wish. In this case you are going to use the value
use the following XAML: Black.

<Label Grid.Row="4" Try It Out


Grid.Column="0" Run the application to see the two labels and the line
Text="First Name" /> appears on your main page.
<Entry Grid.Row="4"
Grid.Column="1"
Text="" /> Spacing, Margins, and Alignment
When you run the application, notice that there’s no
In the code above, you’re telling the Grid to place the La- spacing between the labels and the box view, and be-
bel control in the fourth row and the first column. The tween the labels and box view and the top and sides of
row and column numbering starts with zero, like all col- the page. Also note that the Label controls are lined up
lections in .NET. The Grid.Column="0" attribute doesn’t at the top of the Entry controls to the right of them. All
need to be set because zero is the default for any row or of these issues can be solved quickly by setting just a few
column. properties, as discussed in the next few sections.

codemag.com Exploring .NET MAUI: Getting Started 31


Use Row and Column Spacing for Separation of Controls <Grid RowDefinitions="Auto,Auto,Auto, ..."
The Grid control allows to you set RowSpacing and Col- ColumnDefinitions="Auto,*"
umnSpacing properties to determine how much space ColumnSpacing="10"
appears between each row and column respectively. Set RowSpacing="10"
each of these properties on the Grid start tag and set Margin="10"
them to a value of ten (10) for each, as shown in the fol- Padding="10">
lowing code snippet:
Try It Out
<Grid RowDefinitions="Auto,Auto,..." Run the application and see that the controls are now
ColumnDefinitions="Auto,*" spaced away from the page border. Because you’re using
ColumnSpacing="10" the RowSpacing and ColumnSpacing properties, you prob-
RowSpacing="10"> ably don't need to set the Padding property on the Grid.

Try It Out Add the Data Entry Fields


Run the application to see that the labels and the box Let's now add the Label and Entry controls to the Grid to
view controls now have a little room between them. make the page look more like Figure 25. Add four more
"Auto" heights to the RowDefinitions property on the
Apply Margin and Padding starting Grid tag. Add the XAML shown in Listing 4 below
Although you now have room between the labels and the the BoxView you added earlier.
box view, they’re still right against the top and left edge
of the page. The reason they’re flush with the page is The Entry Control
because the Grid control itself doesn’t have any separa- The Entry control is used to gather small, one-line pieces
tion from the ContentPage. The RowSpacing and Column- of data from a user, such as a login identifier, first name,
Spacing properties affect the rows and columns within last name, email address, etc. Some of the most common
the Grid. To put some distance between the Grid and the properties you might set on this control are Text, Key-
ContentPage, you need to use Margin property. As you board, IsReadOnly, and IsPassword. The Text property
can see in Figure 26, the Margin property affects the is the value that is placed into the entry area on the
area around the control to which it is applied. control. The Keyboard property can be set to values such
as Email, Numeric, Plain, Telephone, Text, or URL. These
The Margin property is a Thickness structure. This structure values don't do anything on Windows, but when they’re
has properties such as Top, Right, Left, and Bottom. The set on a mobile device, they’ll be used to display the
Thickness can be expressed as a single number, such as corresponding keyboard pop-up to allow for easy entry
Margin="10", in which case, it moves the left side, the top, by the user for the type of input you’re expecting. The
the right side, and the bottom and away from the contain- IsReadOnly is set to either a true or false value to not
er that surrounds the control by ten device-independent allow any entry of data into this control. If you want the
pixels. Margin may also be expressed with two numbers, user to enter a password, set the IsPassword property
Margin="5,10", with each number separated by a comma to true, and the values entered won’t be displayed on
in which case it applies the first number to the left and the page.
right sides, and the second number to the top and bottom.
Finally, Margin may be expressed with all four values, Mar- Try It Out
gin="2,4,6,8", in which case the values are applied to the Run the application and you should now see the addi-
Left, Top, Right, and Bottom in that order. tional label and entry controls displayed below the box
view control.
The Padding property is also of the type Thickness and
may be set the same as the Margin property. The Pad- Set the Alignment on the Labels
ding property places the spacing between the bor- When you run the application, notice that the Labels ap-
der of the control and the contents inside the control. pear aligned to the top of the Entry control. You might
Add a Margin and a Padding property to the Grid con- like these Labels to be more centered, or even toward the
trol, as shown in the following code snippet. To really bottom of the Entry control. The VerticalOptions prop-
see the difference between the two properties, set the erty on the Label can be set to a value of Start, Center,
BackgroundColor="Blue" on the Grid control and try dif- End, or Fill. Add VerticalOptions="Center" to each of
ferent Margin values. the Label controls (Login ID, First Name, LastName, and
Email Address) you just added.

Try It Out
Run the application again and you should now see that
each of the Label controls line up in the center of each of
the Entry controls they’re identifying.

Stack and Flex Layouts


Sometimes you don't need to place controls within a strict
row/column structure, such as a Grid. In this case, you
can use a Horizontal, Vertical, or a Flex layout in which
Figure 26: Use Margin and Padding to achieve separation controls are placed adjacent to one another defined by
between controls. the type of stack they are placed within.

32 Exploring .NET MAUI: Getting Started codemag.com


Listing 4: Add data entry fields to each row and column to the grid.
<Label Grid.Row="3" <Label Grid.Row="5"
VerticalOptions="Center" Text="Last Name" />
Text="Login ID" /> <Entry Grid.Row="5"
<Entry Grid.Row="3" Grid.Column="1"
Grid.Column="1" Text="" />
Text="" /> <Label Grid.Row="6"
<Label Grid.Row="4" Text="Email Address" />
Text="First Name" /> <Entry Grid.Row="6"
<Entry Grid.Row="4" Grid.Column="1"
Grid.Column="1" Keyboard="Email"
Text="" /> Text="" />

Listing 5: Use a FlexLayout to allow a set of controls to wrap if not enough space is available on a page.
<Label Grid.Row="7" <CheckBox />
Text="Is Enrolled?" /> </HorizontalStackLayout>
<FlexLayout Grid.Row="7" <HorizontalStackLayout Spacing="5">
Grid.Column="1" <Label Text="Health Care?" />
Wrap="Wrap" <CheckBox IsChecked="True" />
Direction="Row"> </HorizontalStackLayout>
<HorizontalStackLayout Spacing="5"> <HorizontalStackLayout Spacing="5">
<Label Text="401k?" /> <Label Text="Health Savings Account?" />
<CheckBox IsChecked="True"/> <CheckBox IsChecked="True" />
</HorizontalStackLayout> </HorizontalStackLayout>
<HorizontalStackLayout Spacing="5"> </FlexLayout>
<Label Text="Flex Time?" />

Stack Items Horizontally Try It Out


To stack items horizontally in relation to one another, use Run the application and see how the Label is placed be-
a HorizontalStackLayout control. The HorizontalStackLay- low the Entry control but still within the third row and
out control has a Spacing property of the type Double to the second column. Also notice that the third row is now
separate each item within the stack a specified amount a little larger than the other rows because it contains
of device-independent pixels from one another. Looking at both an Entry and a Label within that second column.
Figure 25, you can use the HorizontalStackLayout control
to encapsulate the two button controls: Save and Cancel. Flex Layout
Open the MainPage.xaml file and add one "Auto" height The FlexLayout control is a container that can arrange its
to the RowDefinitions property on the Grid. Add the fol- children horizontally and vertically in a stack. FlexLayout is
lowing XAML immediately before the closing </Grid> tag. based on the flex box model in CSS. FlexLayout can wrap its
children if there are too many to fit in a single row or col-
<HorizontalStackLayout Grid.Row="7" umn. FlexLayout can control orientation, alignment, and
Grid.Column="1" adapt to different screen sizes. Use FlexLayout when you
Spacing="5"> have a set of controls in a container that you want to keep
<Button Text="Save" /> together but want to wrap if the container shrinks, like a
<Button Text="Cancel" /> set of buttons, check boxes, or radio buttons.
</HorizontalStackLayout>
Let's add a set of check boxes to the page and wrap
Try It Out them within a FlexLayout. A CheckBox control doesn’t
Run the application and notice how the two buttons are have a Text property, so you need to use a Label con-
placed next to one another in the last row and the second trol next to each CheckBox to provide textual data for
column. the user to know what checking that check box means.
You should wrap each Label and CheckBox combination
Stack Items Vertically within a HorizontalStackLayout control, and the set of
The VerticalStackLayout control works similarly to the all HorizontalStackLayout controls wrapped within a
HorizontalStackLayout, but stacks items within it verti- FlexLayout.
cally. As an example of this, locate the Entry control just
below the <Label Text="Login Id" /> and replace that Open the MainPage.xaml file and add one more "Auto"
Entry with the XAML in the next snippet. Don't remove the to the Grid. Change the HorizontalStackLayout control
<Label Text="Login Id" />. that contains the Save and Cancel buttons to be in Grid.
Row="8". Just before the last HorizontalStackLayout
<VerticalStackLayout Grid.Row="3" that contains the Save and Cancel buttons, add the XAML
Grid.Column="1"> shown in Listing 5.
<Entry Text="" />
<Label FontSize="Micro" Set the Wrap property on the FlexLayout control to
Text="Please use a combination "Wrap" or the controls won't wrap to the next line. The
of letters and numbers." /> Direction property has a default of "Row", so technically
</VerticalStackLayout> you didn’t need to set it but, I like to add it for clar-

codemag.com Exploring .NET MAUI: Getting Started 33


Listing 6: Use nested grid controls to create a navigation and status bar area.
<Grid RowDefinitions="*,Auto" RowDefinitions="Auto,Auto,...,Auto"
ColumnDefinitions="Auto,*"> ColumnDefinitions="Auto,*"
ColumnSpacing="10"
<!-- Side Navigation Area --> RowSpacing="10"
<VerticalStackLayout Grid.Row="0" Margin="10"
Grid.Column="0" Padding="10">
Grid.RowSpan="2"
BackgroundColor="DarkGray" // REST OF THE XAML HERE
Spacing="10"
Padding="10"> </Grid>
<Button Text="Nav 1" />
<Button Text="Nav 2" /> <!-- Status Bar Area -->
<Button Text="Nav 3" /> <Label Grid.Row="1"
<Button Text="Nav 4" /> Grid.Column="0"
<Button Text="Nav 5" /> Grid.ColumnSpan="2"
<Button Text="Nav 6" /> BackgroundColor="LightGray"
</VerticalStackLayout> Padding="10"
Text="This is an area for
<!-- Page Area --> you to display status text" />
<Grid Grid.Row="0" </Grid>
Grid.Column="1"

Open the MainPage.xaml file and just before the Grid


control you already have there, add a starting <Grid> tag.
Add a closing </Grid> tag below the existing </Grid>
closing tag. Within the new Grid you just added, add a
VerticalStackLayout control to display in the first row and
column of this new Grid. Within this VerticalStackLayout
add a set of Button controls. Add two attached properties
to the original Grid control to set the Grid.Row="0" and
the Grid.Column="1". Just below the original closing </
Grid> tag and before the new closing </Grid> tag, add a
Label control, as shown in Listing 6.

Try It Out
Run the application and your screen should like
Figure 27.

Remove the Outer Grid


Creating this navigation and status bar area was for illus-
tration purposes only. You aren’t going to use the outer
Grid control, the side navigation buttons, or the Label at
the bottom, so go ahead and remove these items now.

Summary
Figure 27: Use a nested grid to add controls around other controls on a page. .NET MAUI and XAML are great for creating cross-plat-
form applications. In this article, you learned the basics
of XAML, XML namespaces, attributes, and elements. Af-
ity. Each HorizontalStackLayout control is considered the ter installing .NET MAUI from the Visual Studio Installer
child elements of the FlexLayout, thus each one of those utility, you created your first .NET MAUI application
are what is wrapped when you shrink the screen. and used label and entry controls to build a data-entry
page. The Grid control is ideal for laying out how a page
Try It Out should look to the user. With the flexibility of Auto and
Run the application and shrink the screen to see the la- Star (*) spacing, you can create pages that can easily
bels and their corresponding check boxes wrapped within respond to changes in screen size. Stack layouts help
the second column of the Grid control. you build a set of controls that can be displayed either
horizontally or vertically. In the next article in this se-
ries, you’ll create styles to keep your look consistent,
Nested Grids navigate from one page to another, create reusable UIs,
One of the most powerful features of .NET MAUI is the and use more .NET MAUI controls to build even richer
ability to nest one control within one another. Nesting UIs for your users that can run on Windows, Android, or
Grid controls can help you layout a side navigation area iOS operating systems.
on the left of the screen, a status bar area at the bottom,
and your input page within the rest of the page, as shown  Paul D. Sheriff
in Figure 27. 

34 Exploring .NET MAUI: Getting Started codemag.com


10 th Edition
SEPT. 3-5, 2024
CAESARS FORUM / LAS VEGAS

DRONES
IN ACTION
Register at
expouav.com CURRENT REALITIES & FUTURE FRONTIERS
Use code SAVE100 for
$100 off a conference pass
or a FREE exhibit hall pass

LEARN CONNECT EXPERIENCE


Expansive education program with Facilitated networking with drone Cutting-edge UAS solutions providers,
solutions-oriented presentations & industry professionals from around live outdoor flying demonstrations &
workshops from UAS thought-leaders the globe exclusive training

PRE SENTED BY: OFFICIAL A SSOCIATION PAR TNER: CO - LOC ATED E V ENT S:

Produced by Diversified Communications


ONLINE QUICK ID 2408051

From Flat to Fantastic:


Going Spatial with 2D Applications
The world of head-mounted display (HMD) hardware technologies is buzzing with recent advancements, sparking a
wave of fresh interest among consumers. From virtual reality (VR) and mixed reality (MR) to spatial computing, major tech
companies and new startups alike are actively investing the launch of the next generation of immersive computing devices.

This article will guide you through the rising popularity immerse them in the activity being performed in the ap-
of HMDs, demonstrate how to use your existing skills for plication.
these new platforms, and explore the potential of flat ap-
plications on the Meta Quest 3. Apple, Microsoft, Meta, and have all appeared on the mar-
ket with different approaches, technologies, capabilities,
Industry Overview and vocabulary for their HMDs.
Ongoing investments in HMD technology has improved
it over earlier generations of hardware. New HMDs, like • Apple Vision Pro: Apple is the latest to enter the
Meta’s Quest 3 and Apple’s Vision Pro, have enhanced market with the Apple Vision Pro. The Vision Pro is
Ed Charbeneau the tracking, camera, and display capabilities that en- marketed as the “first spatial computer.” Apple bor-
[email protected] able seamless mixed reality or spatial computing experi- rows technology from the telescope industry by us-
@EdCharbeneau ences. Using the device’s camera, the HMD displays a live ing catadioptric lenses (that combine refraction and
view of the real world around you while positioning high- reflection) in their HMD. An opaque high-density
Ed is a Microsoft MVP and
resolution 2D and 3D graphics within the environment. screen is viewed through the lenses immersing the
an international speaker,
Although 3D graphics are used for immersive experiences, user. HD cameras and a spatial processor produce an
writer, online influencer, a
you’ll find that 2D applications have found a more tradi- immersive “Spatial Computing” environment. Even
Pr. Developer Advocate for
Progress, and expert on all tional role within HMDs. Because of the high-resolution though the Vision Pro is capable of VR applications,
things Web development. Ed displays, users have gravitated toward using 2D applica- Apple has specifically targeted the device as an im-
enjoys geeking out to cool tions within the augmented environment, freeing them- mersive operating system. The focus of the Vision
new tech, brainstorming selves from desktop monitors. It’s still early, but HMDs Pro is its visionOS operating system (OS) for either
about future technology, are already cementing their future as office workstation immersive applications or flat applications displayed
and admiring great design. replacements. within its OS environment. The Vision Pro is meant
for a consumer audience and is priced at $3500.
Ed has shared his insights • HoloLens: Microsoft first entered the market with
and experiences through the HoloLens. The HoloLens device focuses on im-
training, live streaming, Using the device’s camera, mersive “holographic” MR applications. This HMD is
and podcasting at many the HMD displays a live view of a transparent visor to project holograms on top of
industry events around the the user’s space. The user interacts with the projec-
world including Microsoft the real world around you while tions using touch and voice gestures recognized by
Build, DevReach, Oredev, positioning high-resolution 2D the headset. Because the focus of this device is a
and Codemash. He’s a com-
and 3D graphics within holographic MR, it doesn’t typically make use of VR
munity builder who regu-
or other computing modes. HoloLens is targeted at
larly live streams on Twitch the environment. enterprise applications and priced between $3500
and shares knowledge at
meetups. Ed has defined, and $5200, depending on the model.
architected, and imple- • Quest 3: Meta has introduced four generations of
mented line-of-business Immersive Applications and Devices HMDs including the: Quest, Quest 2, Quest Pro, and
solutions with a touch of If you’ve used an HMD, it’s likely that you’ve experienced the newest model, Quest 3. Although Quest was tra-
style and UX best practices. a fully immersive application. This type of app completely ditionally a VR headset, Quest Pro introduced an MR
He continues to bring this changes the user’s environment for the purpose of virtual mode that was improved in Quest 3. The Quest 3
level of detail to the Telerik reality (VR) or mixed reality (MR). The most common type HMD uses pancake lenses commonly found in pho-
UI products. of immersive applications are VR games. In a VR game, tography. Like Apple’s device, the Quest 3 uses an
the user’s entire vision is replaced with a 3D-rendered opaque high-density screen viewed through the
environment and the user is completely immersed in the lenses, immersing the user. Two HD cameras and
virtual environment. a processor produce an immersive “Mixed Reality
Passthrough” environment. Quest 3 has its roots
Immersive MR experiences are less common because they in VR and is breaking into the MR gaming market.
require more advanced hardware and software capabili- In addition, Quest 3 has an immersive-capable
ties. In an immersive MR app, the HMD either needs to be Android-based OS. Meta is focused on creating VR/
transparent or uses cameras to capture the user’s view of MR “experiences” in the consumer audience and is
the real world and display it in real time. In addition, the priced at $350.
HMD needs to analyze spatial data including the user’s
surroundings, position, and objects within the space. The In immersive applications, the software takes exclusive
spatial data is then used to augment the user’s view and control over the user’s environment to make use of spa-

36 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 1: This is Microsoft Word running as a flat application in a mixed reality passthrough.

tial data and render elements in 3D. Usually, these ap-


plications are built using proprietary 3D engines such as
Unity, Unreal Engine, AR Core (Google), or AR Kit (Apple).
Developing immersive apps using these technologies re-
quires a set of tools, knowledge, and skills different from
those used for 2D applications. However, there’s an op-
portunity to reuse existing code and skills by deploying
Flat Applications for use in a spatial OS.

The Case for Flat Applications Figure 2: The Meta Quest taskbar in Mixed Reality
A flat application denotes a conventional 2D application Passthrough floats over the real-world environment.
(originally designed for desktop monitors, mobile screens,
or the browser) that has been modified or redeployed to
function within a spatial OS. As HMDs have evolved with Office suite, including Power Point, Excel, and Word, as
better representations of the real-world environment, us- shown in Figure 1. Although Meta may have fewer native
ers are considering HMDs as replacements for other com- flat apps, its focus on affordability, visual quality, and
puting activities. Having traditional 2D applications in a developer support makes it a compelling choice for bring-
spatial context gives users the ability to run these apps ing apps to the platform.
freely in virtual 3D space versus being constrained to a
physical screen. Flat applications can run directly on the The Meta Quest 3 Platform
device’s OS in floating resizable windows. The feeling of Despite having the fewest first-party flat apps, Meta’s
openness and lack of boundaries allows users to work from platform strategically emphasizes several key advantag-
anywhere while multitasking on limitless screen sizes. es. The Meta platform offers a low price point, making it
accessible to a wide range of users. Its high-resolution
Software companies have realized the potential of flat ap- display (2064 x 2208 resolution per eye) and full color
plications and have started preparing for the emergence passthrough is suitable for productivity purposes. Quest
market. Apple and Meta have designed their operating 3’s spatial OS allows multitasking with up to three flat
systems and app stores to accommodate flat applications applications at once. In addition, Meta has intentionally
and have delivered their first-party applications. Because created a low barrier to entry for developers by choos-
Apple isn’t focused on immersive apps, it relies on flat ap- ing the ubiquitous Android OS and supporting Progressive
plications to fill out its offering by including Safari, Mail, Web Applications (PWAs).
FaceTime, Keynote, Notes, Apple TV +, and many more.
Although Meta is focused on immersive apps, it does offer You’ll enter Quest's passthrough mode through the inter-
a few of its own with Meta Quest Browser, Instagram, and face shown in Figure 2, which is activated by double tap-
Quest TV. Other big names are releasing flat apps on both ping on the headset or pressing the Enter passthrough
platforms as well. Microsoft has released the Microsoft mode button from the system's taskbar. Once in

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 37


JOIN US AT THE 3 RD ANNUAL

SEPT 18–20 • Workshops: Sept 16, 17 & 21


MGM GRAND • Las Vegas, NV

CHARLES LAMANNA JEFF TEPER SANGYA SINGH KIM MANIS


Corporate Vice President, President – Microsoft Vice President, Microsoft Vice President of
Business Applications & Collaborative Apps and Power Automate, Product, Microsoft
Platforms, Microsoft Platforms, Microsoft Microsoft Fabric & Power BI,
Microsoft

NIRAV SHAH RYAN CUNNINGHAM ILYA GREBNOV OMAR AFTAB


Corporate Vice President, Vice President, Power Vice President, Chief Vice President,
Microsoft Dataverse, Platform Applications, Software Architect for Conversational AI,
Microsoft Microsoft Business Applications, Microsoft
Microsoft

REGISTER TODAY!
PowerPlatformConf.com @PowerPlatConf #PPCC24
Copilot • AI • ChatGPT • .NET • ASP.NET • GitHub • Visual Studios • Open AI • LLM • Azure AI Studio • and more…

co-located with the

SEPT 10-12 WORKSHOPS SEPT 8, 9 & 13


MGM GRAND, LAS VEGAS, NEVADA
Let the Experts Guide You on Your AI Journey:

ERIC BOYD SCOTT HANSELMAN SCOTT HUNTER KATHLEEN DOLLARD DAN WAHLIN
Corporate Vice Vice President, Vice President, Director Principal Program Principal Cloud
President, AI Platform, Developer Community, Product Management Manager, Microsoft Developer Advocate,
Microsoft Microsoft for Azure Developer Microsoft
Experience, Microsoft

JEFF FRITZ MADDY MONTAQUILA MARKUS EGGER ZOINER TEJADA MICHELE LEROUX
Principal Program Senior Program President and Chief CEO and Architect, BUSTAMANTE
Manager, Microsoft Manager, .NET MAUI, Software Architect, Solliance President & Architect,
Microsoft CODE Group Solliance

[email protected]
nextGenAIconf.com @ nextGenAIconf [email protected]

BONUS: AI for Decision Makers Track


Questions Answered, Strategies Defined, Relationships Built
Figure 3: The Quest 3 operating system multitasking with three applications displayed: (left to right) App Library,
Microsoft Word, Meta Quest Browser

passthrough, you'll see the live environment displayed Meta has made the platform accessible to developers, and
in real-time with the user interface and applications dis- you can deploy and submit your own applications to the
played spatially in your surroundings. Meta Store. Most applications that you’ve written for the
Android operating system that compile to an Android Pack-
In passthrough mode, you can open three flat applica- age Kit (APK) can also deploy to the device. In addition, the
tions from the taskbar, as shown in Figure 3. Applications ecosystem is open to Progressive Web Applications (PWAs)
you use in this mode can be resized and rearranged. Using as well. The only warning with PWAs is that they must be
the Quest controllers or gestures from the device’s hand deployed through the app store as an APK, which is accom-
tracking capabilities, you grab the edges of an applica- plished with Meta's command line tool. You'll find that the
tion as if you were using a mouse on the desktop. developer toolchain used for the Quest is quite intuitive as
the developer experience integrates with the headset.
Although multitasking is built into the system's OS, there
are third-party applications that offer additional capabili-
ties such as virtual monitors, remote desktop, and collab- Developer Tools
orative experiences. Because immersive experiences take Setting up the developer environment and making sure you
control over the full user experience, multitasking only have the prerequisites installed is necessary to be successful
works with flat applications. When you launch an immer- when writing applications for the Quest. You can consider
sive experience from within an app or from the taskbar, it developing for the Quest as “mobile development” because
hides the OS and all flat applications in your current view. it follows many of the same principles and uses similar tool-
ing. In addition to the typical development tools, there are
platform-specific tools as well. There’s an extensive list of
prerequisites with each item having its own purpose. You’ll
When you launch an immersive find a list of each tool in Table 1 categorized by application
name, type, and purpose. Every tool here is used in the Soft-
experience from within an app or ware Development Life Cycle (SDLC) from unlocking devel-
from the taskbar, it hides the OS oper mode on the device, to writing code, and to publishing.
and all flat applications in your
Quest Mobile App
current view. The Quest Mobile app is required to use the device and
part of the standard installation process when you buy a

40 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Application App Type Purpose
Quest Mobile App Phone Manage developer mode on the Quest headset.
Quest Developer Hub Desktop Manage the Quest device, app deployments, and casting.
Visual Studio Desktop Develop and debug applications using the ASP.NET and web development workload and .NET
multi-platform app UI development workloads. Access localhost with Dev Tunnels.
Chrome Desktop Remotely debug applications running web-based user interfaces.
Quest Create-PWA CLI Package PWAs as APK files to deploy on the Quest.
Quest Remote Desktop Quest Access the developmental desktop to use Visual Studio remotely.
Quest Web Browser Quest Test PWA applications before packaging them using the create-pwa command.

Table 1: Developer Tools

new headset. Using the app, you’ll connect to the headset


over Wi-Fi or Bluetooth. Once connected, you can man-
age basic features of the device, manage software bought
through the app store, and enable developer mode. To
enable developer mode on your device, follow the steps
shown in Figure 4. Start by choosing Headset settings
(marked as 1 on the image) on the desired device. Next,
from settings, choose Developer Mode (marked as 2). Fi-
nally, enable Debug Mode (marked as 3), which allows
you to connect the device to a PC using a USB cable. Once
debugging is enabled, you can use the Quest Developer
Hub on your device.

Quest Developer Hub


The Quest Developer Hub is a desktop application used to
manage the development experience on the Quest device.
This app helps you manage the development experience
of your device by connecting to the device and manag-
ing deployments and remote controlling actions on the
device, as shown in Figure 5. When you connect your
device to the PC via USB cable, your device is displayed
in the Devices section (marked as 1 on the image). In the
Devices section, you can reboot your device, power down,
and configure more settings. Below the Devices section
on the UI shown in Figure 5 is the Apps section (marked
as 2). In the Apps section, you’ll see applications that
have been loaded on the device. In addition, the Apps
section can be used to deploy apps to the device by click-
ing Add Build or dragging and dropping an APK file into
the section. The last section is the Device Actions section
(marked as 3), which has the most variety of uses. In the Figure 4: The Quest Mobile App is used to unlock a device’s developer mode by selecting
first column of the Device Actions section are the most settings (1), developer mode (2), and debug mode (3).
used features. From here you can cast the device’s display
to your PC screen, record videos, take screen captures,
and push URLs to the Meta Quest Browser. used to create a connection between devices that cannot
directly access each other. This feature is useful for test-
Visual Studio ing locally hosted web applications on the Quest.
Visual Studio is an essential development tool for writing
web, mobile, and desktop applications. There are several The second item is the .NET Multi-Platform App UI de-
workloads that you’ll need in order to write applications velopment (.NET MAUI) workload. This workload is what
for the Quest. Through the Visual Studio Installer, you’ll you’ll use to write applications that target the Android
manage your workloads as shown in Figure 6. OS. This includes the .NET MAUI application using XAML
or Blazor Hybrid, an application that uses HTML, CSS, and
First is the ASP.NET and web development workload. C#. Both types of app compile to APK and can be de-
You’ll need this workload to write Blazor PWAs and ASP. ployed to the Quest as a flat application.
NET Core for serving Blazor applications. When working
with web-based applications and the Quest, you’ll also Meta Quest CLI
make use of Visual Studio’s Dev tunnels, a feature that’s All publicly available applications for the Quest must be pub-
included in the ASP.NET workload. When working with lished through the official Quest store. This means that if
mobile devices like the Quest, the device needs access to you develop a PWA, it too must be published and installed
locally hosted web resources (localhost). Dev tunnels are via the app store. The Meta Quest create-app CLI tool is a

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 41


Figure 5: The Quest Developer Hub allows you to manage development activities on the Quest including Devices (1), App deployments (2), and Device
Actions (3).

packaging tool used to wrap your PWA as an APK so it can browser is built using the open-source Chromium ren-
be delivered through the app store. The tool requires other dering engine, commonly used in popular browsers.
dependencies on Java and the Android SDK. You’ll find the It’s optimized for WebXR and WebGL, allowing fully im-
full installation instruction in the Meta developer documen- mersive 3D experiences. Specifically designed for Meta
tation under PWA tools and Packaging (https://developer. Quest hardware, it offers fast performance and improved
oculus.com/documentation/web/pwa-packaging/). battery life. It’s important to note that the Meta Quest
Browser isn’t the same browser implemented by the
Quest Remote Desktop device’s Web View. When using Blazor Hybrid on .NET
The Quest Remote Desktop application is a Quest applica- MAUI, the WebXR APIs aren’t present in the device’s
tion that runs on the device and connects to a remote PC. Web View.
You’ll need to download and install a companion app on
the PC that will be connected. Remote Desktop isn’t nec-
essary for development, but it allows you to access your Flat Applications with .NET
development PC from within the Quest. Use Remote Desk- When creating spatial computing applications, you’ll
top to access Visual Studio while using the Quest. You’ll have a variety of languages and frameworks to choose
find that the developer experience here is quite good on from. For immersive app development, it’s necessary to
the Quest 3 due to the high-resolution display. This setup use specialized 3D software development tools, such as
also enables you to write, test, and debug flat applica- the .NET-based Unity platform. In contrast, the develop-
tions while wearing the device and multitasking with its ment of flat applications is more accessible, thanks to
spatial OS, as shown in Figure 7. .NET’s robust support for cross-platform development,
sidestepping the intricacies and demands of 3D applica-
Meta Quest Browser tion development. In addition, you may be able to update
The Meta Quest Browser is the default web browser existing .NET applications, allowing them to run as flat
that runs on the Quest device, shown in Figure 8. This applications.

42 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 6: The Visual Studio Installer’s workloads configuration screen. In this configuration, the ASP.NET and web development (1) and.NET Multi-
platform App UI development (2) workloads are installed.

Figure 7: The Quest Remote Desktop (right) displaying Visual Studio on a remote PC while debugging on a .NET MAUI
app running on the Quest (left)

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 43


Figure 8: The Meta Quest Browser running in mixed reality passthrough. The browser shows a webpage from
https://www.telerik.com.

Table 2 is a list of .NET stacks that are compatible with Hybrid, which is part of .NET MAUI. Blazor Hybrid gives
building flat applications for the Quest. First is .NET MAUI, you the benefits of .NET MAUI with the addition of Blazor’s
a cross-platform application framework. The unified ap- component model that uses HTML and CSS to render UI
proach of .NET MAUI abstracts the platform-specific de- components. The third choice is Blazor PWA. Blazor PWA
tails, allowing you to focus on building features rather apps use browser-based technologies to build native-like
than dealing with platform complexities. Second is Blazor experiences. All these options compile to APKs and deploy
on the Quest, and each choice comes with its own benefits.
When you build your first Hello World app with each plat-
Stack UI Platform form, you’ll be able to decide which stack works for you.
.NET MAUI XAML .NET MAUI, native UI
.NET MAUI
Blazor Hybrid HTML, CSS, XAML optional Browser API, .NET MAUI .NET MAUI uses the latest technologies for building native
Blazor PWA HTML, CSS Browser API, .NET Web Assembly apps on Windows, macOS, iOS, and Android, abstracting
them into one common framework built on .NET. You use
Table 2: Quest-Compatible .NET Stacks a single C# codebase and project system for all device tar-
gets to build apps that look and feel like native platforms.
The .NET runtime is the execution environment for MAUI
applications, even though the underlying implementations
of the runtime may be different, depending on the host.
For example, on Windows, WinRT provides the environment
with optimizations for the Windows platform and on Quest,
the environment is implemented by Mono, a .NET runtime
for Android. The Android features of .NET MAUI make it
possible to target the Quest with your application.

In a .NET MAUI application, the code you write mainly en-


gages with the .NET MAUI API, as seen in Figure 9 (marked
as 1 on the image). .NET MAUI then directly consumes the
native platform APIs, illustrated in Figure 9 (marked as 2).
In addition, the application code can directly invoke plat-
form APIs when necessary, shown in Figure 9 (marked as 3).

To create your .NET MAUI app, you need the .NET Multi-
Platform App UI development workload installed, as
you can see in Figure 10. With the workload installed,
the .NET MAUI App template is available in Visual Stu-
dio. Create a new project and choose the .NET MAUI App
Figure 9: A block diagram of .NET MAUI. The highlighted items show where Android is template, as highlighted in Figure 10, then click Next to
implemented in the stack. continue through the remaining prompts.

44 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 11: The .NET MAUI
project’s file structure. The
key files are highlighted:
MauiProgram.cs (1),
MainPage.xaml (2), and
Figure 10: The Create new project dialog in Visual Studio with the .NET MAUI App template highlighted MainPage.xaml.cs (3).

Once you’ve created a .NET MAUI project, you see the


project in Visual Studio’s Solution Explorer. The project’s
key files identified in Figure 11 are where you begin
working with the application. The first file, MauiPro-
gram.cs (marked as 1 on the image), is the entry point of
the application. In MauiProgram.cs, you’ll find the start-
up routines and configuration for the application. The
second file, MainPage.xaml (marked as 2), is the default
content page for your application’s user interface. The
third file, MainPage.xaml.cs (marked as 3), is the code-
behind logic for the main page’s user interface.

The main page consists of multiple controls that are


specified through XAML markup, as shown in the snipped Figure 12: The Start menu in Visual Studio expanded to
below. In the markup, you’ll find a button control that reveal a list of target platform options
provides basic functionality for the app. The button con-
trol here describes a UI element that renders a button
natively on the device. The button’s Clicked property in-
dicates that it’s assigned to the OnCounterClicked del- if (count == 1)
egate method found in respective code-behind file. CounterBtn.Text = $"Clicked {count} time";
else
<Button CounterBtn.Text = $"Clicked {count} times";
x:Name="CounterBtn"
Text="Click me" SemanticScreenReader.Announce(CounterBtn.Text);
SemanticProperties.Hint="Counts the number of }
times you click"
Clicked="OnCounterClicked" After reviewing the logic for the page, you’ll want to start
HorizontalOptions="Fill" /> the application and check the functionality. When you
work with .NET MAUI in Visual Studio, the Start menu
To see the logic for this page and the OnCounterClicked (shown in Figure 12) lets you choose target devices,
action, open and inspect the MainPage.xaml.cs file. In emulators, and platforms.
the OnCounterClicked method, you’ll see a simple rou-
tine that increases the value of the count field and dis- For the initial test run, choose Windows Machine from
plays the value in the button’s text. the start menu, then start with debugging. When you click
start, the application runs on the Windows desktop, shown
private void OnCounterClicked( in Figure 13. Test the app by clicking the counter button.
object sender, EventArgs e)
{ Once you feel familiar with the application, try start-
count++; ing the app on the Quest device. Begin by opening the

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 45


Quest Developer Hub and connecting your Quest via USB After connecting your Quest device, return to Visual Stu-
cable to the development machine. Once you connect the dio and use the start menu shown in Figure 15 (marked
device, you’ll see it displayed in Quest Developer Hub’s as 1) to select Android Local Devices (marked as 2),
devices section, shown in Figure 14. Make sure that the then Oculus Quest 3 (marked as 3).
developer mode is enabled on your device; if it doesn’t
appear in the Quest Developer Hub, look for any permis- After you’ve selected the Quest 3 option, start the ap-
sion prompts on the device's screen, or use the Device plication in debug mode. You’ll need to wait a moment
menu from Figure 14 and choose Set Up New Device. when deploying the project for the first time as it must
recompile and deploy. If you’re unsure of the process sta-
tus, you can check the Build Output window to inspect
the progress. The build process output should be like the
example below:

Found device: {your device id here}



2>Deployment was successful to Oculus Quest 3.
==========
Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped
==========
Build completed at 2:38 PM and took 13.972 seconds
==========
Deploy: 1 succeeded, 0 failed, 0 skipped ==========
==========
Deploy completed at 2:38 PM and took 13.972 seconds
==========
Done building project "MauiApp1.csproj".
Build succeeded.

Once the deployment is complete, you’ll see the applica-


tion appear in the Quest Developer Hub under the Apps
section, as shown in Figure 16.

Using the Quest, you’ll see the application displayed as a


floating window, as shown in Figure 17. From this view,
you can interact with the application using the Quest’s
controllers or using the device’s the built-in hand-track-
ing capabilities. The app can be resized and moved to one
Figure 13: The .NET MAUI sample project running on the Windows Desktop of three positions within your view.

Figure 14: The Quest Developer Hub’s Devices section with key elements highlighted: the active Quest device (1), the current user (2), and the Device menu (3)

You can debug the application running on the device from


Visual Studio. Instead of removing the device to debug
from the PC, you can use the Quest. First, drag the .NET
MAUI app to a secondary location on either side of the
center position. Then open the Quest Remote Desktop
app from the device. Next, connect to the PC where Visual
Studio is running and view the windows side-by-side, as
shown in Figure 18. Using the PC’s mouse and keyboard,
set a break point in the OnCounterClicked method. On
the running application, click the Count button until the
breakpoint triggers. When the app pauses for debugging,
it may cause the Quest to display the message “The app
Figure 15: The Visual Studio start menu expanded (1), and the Android Local Devices has stopped responding.” Choose “Wait” from the menu
selection (2) with the Oculus Quest 3 device shown (3) to continue.

46 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 16: The Quest Developer Hub’s Apps section with a highlight showing where deployed .NET MAUI apps are
listed

After familiarizing yourself with the basics of .NET


MAUI, you’ll want to test the platform integration as-
pects of .NET MAUI. .NET MAUI’s unified platform API
allows you to access native platform functionality when
supported by the platform. Because the Quest 3 isn’t a
smartphone, some common hardware doesn’t exist, or
the APIs are restricted by Meta. You can learn a lot from
the comprehensive set of platform integration examples
found in the PlatformIntergrationDemo project that’s
part of the dotnet/maui-samples repository https://
github.com/dotnet/maui samples. From Visual Studio,
select Clone Repository from the File menu and then
enter the repository location, as shown in Figure 19.

After you clone the repo, open the PlatformIntegra-


tionDemo solution. In this solution, you’ll find forty
samples of .NET MAUI APIs that support platform fea-
tures. Not every feature works on Quest, but the demo
serves as a quick way for you to discover and test the
Quest platform from .NET MAUI code. Use the Start menu
to select Oculus Quest 3, and then start the app with
debugging enabled. Explore the application using your
Quest, and then exercise the demos to see what features
work, as shown in Figure 20. If a feature isn’t sup-
ported, the application displays the message “Specified
method is not supported.”

In the File System demo, you’ll see how to read and


write to the Quest’s storage using the .NET File IO. Select
the file demo in the running application, as shown in
Figure 21.

Now inspect the corresponding code in ViewModels/


FIleSystemViewModel.cs. Find the DoLoadFile method Figure 17: The .NET MAUI sample app displayed in the Meta Quest 3’s spatial OS
and add a breakpoint to lines 43 and 50, as referenced
in the code snippet below. Next, click the Load button
on the application and you’ll see the breakpoint on line Async void DoLoadFile()
50 activate. This part of the code has checked the Quest {
filesystem for an existing text file that wasn’t found. if (File.Exists(localPath))
The next line then reads from a file in the application’s {
internal resource. Continue running the application and //Line 43
then click Save to create a new file in the filesystem. CurrentContents = File.ReadAllText(localPath);
Now that a file exists in storage, clicking the load but- }
ton a second time triggers the breakpoint at line 43. else
This time, the code reads the saved file from storage. {

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 47


Figure 18: Visual Studio via remote desktop debugging the .NET MAUI sample app from the Meta Quest 3’s spatial OS

Using (var stream = await FileSystem. skills from web development, you may be unfamiliar with
OpenAppPackageFileAsync(templateFileName)) .NET MAUI’s XAML implementation. For a web developer,
using (var reader = new StreamReader(stream)) Blazor Hybrid may be a better fit.
{
//Line 50 Blazor Hybrid with .NET MAUI
CurrentContents = await reader. Blazor Hybrid is built upon .NET MAUI’s API while add-
ReadToEndAsync(); ing in a web presentation layer powered by the Blazor
} framework. When you use Blazor Hybrid, you get platform
} API access and a rich HTML UI component model. Blazor
} Hybrid support is built into the .NET MAUI framework.
.NET MAUI includes the BlazorWebView control that per-
Now that you’re familiar with .NET MAUI, let’s explore mits rendering Razor components into an embedded Web
another UI option. If you’re a developer with technical View. By using .NET MAUI and Blazor together, you can
reuse one set of web UI components across mobile, desk-
top, and web. This approach is ideal if you’ve worked with
ASP.NET or have an existing Blazor application you want
to deploy beyond the web browser. Even third-party UI
component libraries, like Telerik UI for Blazor (https://
www.telerik.com/blazor-ui/blazor-hybrid), are supported
with Blazor Hybrid applications, giving you the ability to
use hundreds of UI components.

To create your Blazor Hybrid with .NET MAUI app, you


need the .NET Multi-Platform App UI development
workload installed. To do this, refer back to Figure 6.
With the workload installed, the .NET MAUI App template
is available in Visual Studio. Create a new project and
choose the .NET MAUI App template, as shown in Figure
22, then click Next to continue through the remaining
prompts.

Once you’ve created your Blazor Hybrid project, you’ll see


the project in Visual Studio’s Solution Explorer. The proj-
ect’s key files are identified in Figure 23, where you’ll
begin working with the application. The first file, Maui-
Program.cs (marked as number 1 on the figure) is the
entry point of the application. In MauiProgram.cs, you
Figure 19: The GitHub dialog box from Visual Studio cloning the maui-samples.git repo find the startup routines and configuration for the appli-

48 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


cation. The second file, MainPage.xaml (marked as num-
ber 2) is where the BlazorWebView gets rendered. Next are
the Razor components that are located under the Pages
folder (marked as number 3). The three files: Home.razor,
Counter.razor, and Weather.razor represent the examples
in the app with corresponding names (Home, Counter,
Weather).

The main page in Blazor Hybrid is written using XAML and


contains a BlazorWebView control. The BlazorWebView is
the root UI control for the application and displays Blazor
pages and components. When the application is initial-
ized, the BlazorWebView bootstraps Blazor, the HostPage
property defines the HTML file to use: wwwroot/index.
html. Next, the ComponentType property chooses the
Razor component that appears in the BlazorWebView. Be-
cause Routes is the app router and the Home.razor com-
ponent has the base route, the Home component is the
first component rendered by the application.

<BlazorWebView x:Name="blazorWebView"
HostPage="wwwroot/index.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app"
ComponentType="{x:Type local:Components.Routes}" />
</BlazorWebView.RootComponents>
</BlazorWebView>

After reviewing the logic for the page, you’ll want to start
the application and check the functionality. To test the
application, choose Oculus Quest 3 from the start menu,
then start with debugging. When the application starts,
you’ll be greeted with the Home page and a menu con-
taining three items. Choose the Counter menu item to
view the example shown in Figure 24. The Counter exam-
ple is like the .NET MAUI project’s sample, but the Blazor
Hybrid version uses HTML and Razor instead of XAML.
Figure 20: Running the Platform integration demos for the .NET MAUI application
In the Pages folder, you’ll find the Counter.razor com-
ponent that contains the code for the Counter page. An
excerpt is shown in the snippet below. The Counter uses a
standard HTML button element. The button’s onclick event
is bound using Razor syntax to delegate the event to the
IncrementCount method in C# code. When the Increment-
Count method is triggered, the currentCount field value is
updated and displayed in the preceding p element.

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary"


@onclick="IncrementCount">Click me</button>

@code {
private int currentCount = 0;

private void IncrementCount()


{
currentCount++;
}
}

With the application running in debug mode, you can in-


spect the contents of the WebView. To inspect the Web-
View, open a Chrome-based browser (Chrome or Edge) on
the host PC. Enter the address chrome|edge://inspect in
the browser’s address bar, then look for the application Figure 21: The File System demo featured in the platform integration demo app

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 49


Figure 22: The Visual Studio Create project dialog with the.NET MAUI Blazor Hybrid template selected (highlighted)

name to be displayed in the Remote Target heading, as form perspective, Blazor Hybrid offers the most flexibility.
shown in Figure 25. If you’d like to take a pure web approach, Blazor Progres-
sive Web Apps (PWAs) are an option.
Below the application name is the “inspect” link that
opens the debugger. Click the link to debug your app’s Blazor PWAs
rendered HTML, CSS, and JavaScript. For a seamless de- Blazor Progressive Web Apps use web standard technology
veloper experience, try using the Quest Remote Desktop to create applications that run in the browser and have
while debugging the application and running side-by-side features that parallel native platform applications. Blazor
in the Quest, as seen in Figure 26. PWAs use the .NET Runtime for WebAssembly to execute
.NET code in the browser. When a Blazor PWA runs on
Blazor Hybrid offers a balance between .NET and web de- Quest, it has complete access to the Meta Quest Browser
velopment by combining the two in a native package. and any APIs it supports. To test the Quest Browser’s API
With Blazor Hybrid, you can leverage .NET MAUI’s cross support, try visiting What PWA Can Do Today (https://
platform APIs directly from Razor code. From a cross-plat- whatpwacando.today/) using the Quest Browser.

You can also repackage existing Blazor WebAssembly ap-


plications with relative ease, thus making them discover-
able through the Quest Store and browser. Web apps that
have a PWA in the Quest Store prompt users to install it
on their devices, as shown in Figure 27.

To create your Blazor PWA app, you need the ASP.NET and
web development workload installed. To do this, refer
back to Figure 6. With the workload installed, the Blazor
Standalone App template is available in Visual Studio.
Create a new project and choose the Blazor Standalone
App template, as shown in Figure 28, and then click Next
to continue through the next prompts.
Figure 23: The file structure
of the Blazor Hybrid project On the Additional information menu, select the Progres-
with key files highlighted: sive Web Application option. Enabling this option adds
MauiProgram.cs (1), MainPage. the supporting resources required for your app to qualify
xaml (2), and Pages folder (3) Figure 24: The Blazor Hybrid application displaying the as a PWA, as shown in Figure 29. After enabling this op-
with three component samples counter page, viewed through the Quest 3 tion, click Create to generate the solution.

50 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 25: Using Edge via Quest Remote Desktop, the browser’s debug window is open showing the app running
remotely on the Quest.

Figure 26: Use Edge to remotely debug the HTML of the .NET MAUI WebView via Remote Desktop.

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 51


XR vs. Spatial
The technique of blending
computing with the real
world goes by many names
including Mixed Reality
(MR), Augmented Reality
(AR), Spatial Computing, or
the blanket term Extended
Reality (XR). The term mixed
reality dates to the 1990s
and refers to a Boeing HMD
invented in 1963. Spatial
computing was used in 2003
when an MIT researcher used
MR with various input devices.

In the software industry,


as with many terms, the
definitions frequently share
similarities, though they may
differ subtly. Although the
origins of each term came
from research on similar
methods of computing, today,
these terms are used broadly.

Companies pick and choose


among these terms as
marketing tools to differentiate
their hardware. Meta Figure 27: The Install App prompt is shown in the Quest Browser when a PWA can be installed from the Quest Store.
frequently uses the term Mixed
Reality Passthrough in their
marketing and Apple strictly Once you’ve created your Blazor PWA project, you’ll see The first file, Program.cs, is the entry point of the ap-
enforces using the term Spatial the solution in Visual Studio’s Solution Explorer. The proj- plication. In Program.cs, you’ll find the startup routines
Computing when referencing ect’s key files, as identified in Figure 30, are where you and configuration for the application. Next are the Razor
their Apple Vision Pro. Both begin working with the application. components that are located under the Pages folder. The
HMDs provide very similar
experiences to the end user.

Figure 28: The Visual Studio Create dialog with the Blazor WebAssembly Standalone App
template (highlighted)

52 From Flat to Fantastic: Going Spatial with 2D Applications 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.
©shutterstock

codemag.com/legacy
832-717-4445 ext. 9 • [email protected]

codemag.com Title article 53


Get familiar with the application by starting it locally on
your PC. Choose https and start with Debugging enabled
to launch the application. When your application is started,
it launches in the browser, and you’ll see localhost in the
browser’s address bar, as shown in Figure 31. As you explore
the app’s sample pages, you’ll notice that the project is
nearly identical to those found in the Blazor Hybrid project.

At this point, you’ll want to try the application on the


Quest’s browser, but the device can’t directly connect to
the localhost development server. Unlike .NET MAUI ap-
plications, a Blazor PWA project can’t be started directly
on the Quest. Instead, you need to host the application
locally and use the dev tunnels feature to access it. The
dev tunnels feature acts like a virtual private network
(VPN) but is scoped to your .NET application. The dev
tunnels feature is included with the ASP.NET workload
and appears in the expanded start menu. To create a new
dev tunnel, expand the Start menu and select Create a
Tunnel, as shown in Figure 32.

Next, configure the dev tunnel by connecting your Mi-


crosoft account, naming the tunnel, assigning a lifetime,
and setting the scope of access. The dev tunnels dialog,
shown in Figure 33 uses the settings, Name: demoTun-
Figure 29: The Additional information dialog for a Blazor WebAssembly Standalone App. nel, Tunnel Type: Persistent, and Access: Public. Once
A Progressive Web Application option is selected to include PWA support. the settings are entered, you’ll see a confirmation dialog
letting you know the process is complete.

three files, Home.razor, Counter.razor, and Weather.ra- With the dev tunnel created, expand the Start menu again
zor, represent the examples in the app with correspond- to choose the dev tunnel by name, as seen in Figure 34.
ing names (Home, Counter, Weather). The next notable Now start your application without debugging. When the
file is mainifest.webmainfest , which contains your ap- application starts, it opens a browser window and dis-
plication’s metadata. You set values in the manifest to plays an information message. Click Continue from the
represent your app’s name, home screen icon, and start dialog to access your app. The browser’s address bar dis-
URL. plays a generated address ending with devtunnels.ms.

Figure 31: The Blazor Progressive Web Application running in a web browser with the web address “localhost”

54 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 30: A Blazor
PWA project’s file
structure with key
files highlighted:
Program.cs (1),
the Pages folder
with three
component files
(2), and manifest. Figure 32: Visual Studio’s Start menu expanded to show the Create a Tunnel menu in the Dev
webmanifest (3) Tunnels section

You use this address to connect to your application from Now that you’ve successfully launched the app from the
any device outside your network. Copy the address from Quest, you’ll want to test it as a deployable PWA that
the browser’s address bar, as shown in Figure 35. Next, can be submitted to the Quest Store. A deployable PWA
open the Quest Developer Hub with your device connect- doesn’t use the browser directly; instead it looks like a
ed and paste the address into the Open URL field under standard platform application running on the Quest’s spa-
Device Actions. After you’ve entered the URL, click Open tial OS. For the application to be deployed, you’ll need to
to launch the Meta Quest Browser on the device using package it as an Android APK using Quest’s command line
your dev tunnel address. tool. Start by prepping your manifest by opening the file

Figure 33: Visual


Studio’s dev tunnels
configuration dialog
with the settings used
for this example

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 55


the Quest create-pwa tool and its prerequisites. Then
ensure that your application is running and the dev tun-
nel is working. Next, open a command window and tar-
get your app’s manifest file using create-pwa. An exam-
ple of the completed command is shown in the snippet
below.

ovr-platform-util.exe create-pwa
-o blazor-pwa-outputAPK
--android-sdk C:\{androidSDK path}
--package-name com.blazorapp1.pwa
--manifest-content-file ".\path\manifest.webmanifest"

Once the command completes, find the file specified by


the command’s output parameter. For this example, the
file name is blazor-pwa-outputAPK. To deploy the app,
drag-and-drop the file into the Quest Developer Hub from
the Windows File Explorer. After the deployment, you’ll
find the app in your Quest’s library under unknown sourc-
Figure 34: Visual Studio’s Start menu expanded to show the selected dev tunnel, demoTunne es, as shown in Figure 35.

The Blazor PWA opens on the Quest in a native applica-


and entering the dev tunnel’s URL as the start_url value, tion shell, as shown in Figure 36. The shell displays the
as shown in the snippet below. application so it appears as a native application to the
user.

"start_url": "https://your-url.devtunnels.ms/", If you’re a web developer using Blazor, the option of us-
… ing a PWA so you can deploy on Quest is compelling. With
this deployment model, it’s possible to “lift and shift” an
Next, you’ll need to use the Quest create-pwa command existing Blazor PWA by repackaging your application us-
line tool to create an APK from your application. Install ing Meta’s create-pwa tool.

Figure 35: Opening a web app that uses dev tunnels displays a connection prompt before
accessing the app

56 From Flat to Fantastic: Going Spatial with 2D Applications codemag.com


Figure 36: The Quest Library with Unknown sources (1) highlighted and the BlazorApp1 (PWA) application (2) listed
in the library

Figure 37: A Blazor PWA running on the Quest’s spatial OS in a native shell

Conclusion using the .NET stack including: .NET MAUI, Blazor Hy-
As HMD hardware and software advance, they open new brid, and Blazor PWA. Each stack complements a certain
possibilities for developers. These days, the market is .NET developer skill set, whether it’s XAML, HTML, or web
showing interest in consumers using HMDs as desktop standards. As a .NET developer, you should look at your
replacement options. As consumers shift from gaming on current flat applications and experiment with them on the
these devices to using them for daily computing tasks, Quest 3. There just may be an opportunity to bring your
the need for flat applications will follow. Because the app into the future using spatial computing.
Meta Quest 3’s platform uses Android as its operating
system, it’s accessible to many developers. There are cur-  Ed Charbeneau
rently three ways to deploy flat applications on the Quest 

codemag.com From Flat to Fantastic: Going Spatial with 2D Applications 57


ONLINE QUICK ID 2408061

Store Application Performance


Metadata in a Database Using AOP
in ASP.NET Core
Aspect-Oriented Programming (AOP) is a programming paradigm that attempts to increase the modularity, maintainability,
and flexibility of your application while overcoming the traditional Object-Oriented Programming (OOP) limitations. AOP adds a
new programming concept, known as an aspect, which are reusable, modular pieces of code that can solve common problems

like logging, performance management, exception han- Procedural Programming, Object Oriented programming,
dling, configuration management, and security. Aspects and Aspect Oriented programming are typical examples of
can be used to combine similar concerns into a single unit such paradigms.
and applied to an application's core logic via weaving.
Procedural programming is a programming paradigm
This article compares AOP to OOP and Procedural Pro- that was popular worldwide before the advent of object-
graming, and provides a deep dive into AOP, explaining oriented programming. Often contrasted with object-
why it’s useful, and illustrating how you can optimize oriented programming, procedural programming is one of
performance of an ASP.NET Core application using AOP the foundational programming paradigms that thrives on
Joydip Kanjilal and then store the captured performance metadata in a writing procedures or routines to execute tasks in a pro-
[email protected] database. gram. Typical examples of procedural programming lan-
guages are C, Pascal, Fortran, etc. The major downsides
Joydip Kanjilal is an MVP If you’re to work with the code examples discussed in this of procedural programming are code tangling and that it
(2007-2012), software article, you need the following installed in your system: didn’t support reusability. Object-oriented programming
architect, author, and was invented primarily to address the pitfalls of proce-
speaker with more than
• Visual Studio 2022 dural programming.
20 years of experience.
• .NET 8.0
He has more than 16 years
• ASP.NET 8.0 Runtime
of experience in Microsoft What Is Object-Oriented
.NET and its related
technologies. Joydip has If you don’t already have Visual Studio 2022 installed on Programming (OOP)?
authored eight books, your computer, you can download it from here: https:// Object-oriented programming (OOP) helps organize an
more than 500 articles, visualstudio.microsoft.com/downloads/. application in a more structured and modular way by rep-
and has reviewed more resenting real-world entities as objects, each with its own
than a dozen books. In this article, I'll examine the following points: set of attributes (or data) and behaviors (also known as
methods). Although OOP is a programming paradigm that
• Procedural, OOP, and AOP programming styles and focuses on encapsulation of data and behavior into ob-
their benefits jects, AOP extends OOP by focusing on the separation of
• AOP and its features, benefits, and downsides concerns in an application.
• The core concepts of AOP
• How to use Autofac to create a memory cache in- Features of OOP
terceptor The key concepts of OOP include the following:
• How to use PostSharp to build an application that
stores application performance metadata in a da- • Classes: A class is defined as a blueprint based on
tabase which instances of classes or objects are created.
• How to use PostSharp to store CPU and memory us- Classes are known as the building block of OOP that
age details in a database encompasses both data and the functions (in OOP,
functions are also known as methods) that operate
on the data.
What Is a Programming Paradigm? • Objects: Objects are defined as instances of classes
The term "paradigm" is analogous to an approach or that are created based on the template or structure
style used in programming to solve a specific problem. A as defined by a class. They can interact with one
number of programming paradigms have evolved over the another through method calls.
years, including imperative, structured, procedural, func- • Encapsulation: Encapsulation (also known as in-
tional, declarative, event-driven, object-oriented, and formation hiding) is a fundamental concept in OOP
aspect-oriented. Programming has evolved into a variety that involves combining data (attributes, proper-
of paradigms since its infancy, and we've witnessed the ties) and methods (functions, operations) that op-
emergence of several programming paradigms since the erate on data inside a single unit, known as a class.
early days of programming. These paradigms have fos- • Inheritance: Inheritance is a feature of OOP that
tered the growth of several new programming languages. enables a subclass or derived class to extend or in-

58 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
herit the attributes, properties, and methods of its
base class.
• Polymorphism: Polymorphism is a feature of OOP
that enables objects of multiple child classes to
be treated as pertaining to a common base class,
and thereby enabling the same method to behave
differently depending on the object that calls the
method.

Benefits of OOP
The key benefits of OOP include the following:

• Modularity: One of the key benefits of OOP is modu-


larity, which makes it easier to comprehend, man-
age, and maintain the source code.
• Reusability: In OOP, you can create new classes by
extending existing classes, thereby promoting reus- Figure 1: Cross-cutting concerns in an application
ability.
• Maintainability: You can take advantage of OOP to
alter components without affecting other parts of responsibility principle and the open/closed principle.
the application, thereby making it easier to main- You’ll learn how AOP can help overcome these challenges
tain the source code over a period of time. in the sections that follow.
• Flexibility: You can leverage polymorphism, a fea-
ture of OOP, to enable methods to perform differ-
ent actions depending on the object they are acting What Are Cross-Cutting Concerns?
upon. Typically, an application has two sorts of concerns: core
and cross-cutting. Core concerns in an application refer
Code Tangling and Code Scattering to the business logic and primary use cases of an applica-
Although there are benefits, there are certain downsides tion. Typical examples of core concerns include business
to using OOP as well. OOP can introduce complexity be- logic, data access, etc.
cause the additional layers of abstraction can lead to de-
graded performance. However, the two major downsides A cross-cutting concern is a specific aspect of the appli-
of OOP are code tangling and code scattering. cation that encompasses a collection of logic and func-
tionality with specified requirements and responsibilities.
Code tangling and code scattering are two of the ma- Cross-cutting concerns in an application represent func-
jor downsides of OOP. OOP requires that the application's tionality that cuts across multiple components and is or-
source code be organized around classes and objects. thogonal to core concerns. For example, an application's
However, you often have codebases that contain tightly business logic and data access layers often require you to
coupled code, i.e., code comprised of components that log data. An application's cross-cutting concerns include
are interdependent. If your application's source code is logging, security, performance, error handling, caching,
tightly coupled or interdependent, it makes isolating spe- and transaction management. You can see an example of
cific functionality difficult, which leads to tangled code. cross-cutting concerns in Figure 1.

Code tangling is an example of spaghetti code that often In an application, cross-cutting concerns help implement
occurs when an application's unrelated concerns are in- separation of concerns and is a design principle that pro-
tertwined in a particular class or module. Spaghetti code, motes modularity, reusability, easier maintenance, and
an outcome of bad programming practices, is a term that reduces inconsistencies in your application's codebase.
describes code that’s difficult to understand or maintain,
because it’s tangled, complex, and difficult to compre-
hend. When the application's source code is tangled, it
What Is Aspect-Oriented
can be challenging to comprehend and manage complex Programming (AOP)?
code bases, as changes to the code in one part of the ap- In traditional Object-Oriented Programming (OOP), it of-
plication can have unexpected consequences in another. ten becomes extremely difficult to manage the applica-
tion’s cross-cutting concerns because they’re entangled
Another downside of OOP is code scattering, which oc- with the application’s core concerns. Aspect-Oriented
curs when an application's related functionality is spread Programming (AOP) is a programming approach that de-
across multiple classes, making the codebase excruciat- couples the cross-cutting concerns of an application from
ingly difficult to understand and maintain. The codebase that application's core, resulting in enhanced code reuse
of an application will become easier to manage, under- and modularity.
stand, and maintain if its related functionality is orga-
nized coherently. The reuse of code between applications Object-oriented programming (OOP) and aspect-oriented
can become difficult if functionality is spread across mul- programming (AOP) are two widely used programming
tiple classes and tied to specific implementations. paradigms that have distinct characteristics. Although
Object-Oriented Programming (OOP) is centered on the
To reduce or eliminate code scattering, you can adopt concept of objects, Aspect-Oriented Programming (AOP)
object-oriented design principles, such as the single mainly emphasizes aspects. An aspect is a modularization

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 59
Aspects are a set of join points and pointcuts added to an
application's source code. As the name implies, join points
are specific points in the program's execution flow when
an aspect may be applied, such as method calls, object
creation, field accesses, and exception handling routines.
For example, a join point may indicate that an aspect be
applied to all method calls with a given name or class.

Pointcuts are one or more join points that indicate where


an aspect should be applied based on the names of meth-
ods, parameter types, or annotations. An advice refers
to the code used to implement an aspect's behavior at
a certain join point. Advice takes many forms, including
before, after, and around. As the names imply, a "before
advice" runs before to the execution of the join point, an
"after advice" runs after the execution, and an "around
advice" runs both before and after.

The following code snippet illustrates how you can imple-


ment a custom method interception aspect.

[Serializable]

public class
MyCustomInterceptorAspect :
Figure 2: The core concepts of AOP MethodInterceptionAspect
{
public override void
of a concern that cuts across several places in your ap- OnInvoke(MethodInterceptionArgs args)
plication's codebase. A typical example of an AOP aspect {
is a logging module. AOP doesn't replace Object-Oriented
Programming (OOP); rather, it complements OOP by add- }
ing reusable implementations. }

To implement AOP in your applications, you can take ad- You can implement weaving using several approaches,
vantage of code weaving, dynamic proxies, or bytecode ma- such as bytecode modification and dynamic proxies. By-
nipulation approaches. Each of these approaches allows you tecode modification is a technique used to modify the
to attach aspects without affecting the original program bytecode dynamically at runtime without altering the
code. Some of the widely used and most popular AOP frame- original source code. In AOP, a dynamic proxy is used
works include PostSharp, Castle Dynamic Proxy, Spring, and to create a proxy instance for a target object, thereby
AutoFac. In this article, I’ll discuss Autofac and PostSharp. enabling you to attach additional behaviors such as log-
ging, transaction management, exception handling, etc.
How Does AOP Work? There are several ways to implement weaving in AOP, in-
In this section, I’ll examine how AOP works and the re- cluding compile-time weaving, load-time weaving, and
lated concepts. Figure 2 illustrates all the bits of AOP. runtime weaving. By incorporating aspects into a pro-
gram, the AOP framework intercepts execution at the join
Note that weaving and method intersection are the two locations indicated by the pointcut and applies the advice
ways in which AOP links aspects to an application’s code. described in the aspect, as shown in Figure 3.
Weaving is a strategy adopted to untangle code by ap-
plying an aspect to an application's source code at the Implementing Cross-Cutting Concerns Using AOP
relevant join points. In AOP, method interception refers Let’s now understand how usage of AOP can help you
to the ability to intercept method calls, thereby enabling write cleaner, more manageable, and reusable code. Refer
additional behaviors to be injected either before, after, or to the following piece of code:
around the original method invocation.
public class CacheAspect:
You can isolate the cross-cutting concerns of an application OnMethodBoundaryAspect
from its code by intercepting method calls and injecting {
code at different points when the methods are in execution //Write your code here to cache data
at runtime. Method interception refers to the practice of }
altering the runtime behavior of methods. This is achieved
by splitting the methods into smaller chunks of functional- public class LogAspect:
ity known as aspects. These aspects are in turn integrated OnMethodBoundaryAspect
into the source code of a target method via proxies or deco- {
rators. An interceptor enables additional functionality to //Write your code here to log data
be added to a method call by intercepting method invoca- // to a pre-defined log target
tions and forwarding them to the target object. }

60 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
Implementing Cross-Cutting Concerns without AOP
public class OrderRepository If you didn’t use AOP here, the OrderRepository class
{ would have looked like this:
[CacheAspect]
public Task<IEnumerable<Order>> public class OrderRepository
GetAllAsync() {
{ public Task<IEnumerable<Order>>
//Code to return all orders GetAllAsync()
//from the database {
} //Code to return all orders
//from the cache or the
[LogAspect] //underlying database
public Task SaveAsync(Order order) }
{
//Code to save an order public Task SaveAsync(Order order)
//object to the database {
} //Code to save an order object
} //to the database and cache it
}
In the preceding code snippet, the aspects Logging }
and Caching have been applied on the GetAllAsync and
SaveAsync method respectively. In this example, I've lev- So, you might have to explicitly write your code to call
eraged AOP into the OrderRepository class. You can ap- the respective methods of the LogAspect and CacheAspect
ply aspects at the method level, property level, and the classes to retrieve data from the cache or persist data into
class level as well. Although aspects applied to a par- the cache. Most importantly, you’d have had to write such
ticular method are applicable for the particular method code at several places in your application wherever these
only, those applied at the class level are applicable for aspects were used, resulting in boilerplate code, which is
all members (i.e., methods and properties) of the class. difficult to manage and maintain over a period of time.

In the following code snippet, the LogAspect has been When Should I Use AOP?
applied at the class level and the CacheAspect has been You can use AOP in for one or more of the following:
applied at the method level.
• Logging: You can eliminate boilerplate code to le-
[LogAspect] verage AOP to log data in your application.
public class OrderRepository • Caching: You can leverage AOP to cache frequently
{ used, relatively stale data.
[CacheAspect] • Validation: You can use AOP to validate input data
public Task<IEnumerable<Order>> by enforcing validation rules.
GetAllAsync() • Security: You can use AOP to enforce security poli-
{ cies in your application in a consistent manner.
//Code to return all orders • Transaction Management: You can take advantage
//from the database of AOP to implement transaction management in
} your application.

public Task SaveAsync(Order order)


{
//Code to save an order
//object to the database
}
}

Figure 3: Weaving in action

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 61
• Performance Monitoring: You can use AOP to iden- ate a mapping between each dependency and its corre-
tify performance and scalability bottlenecks in your sponding implementation.
application.
The Autofac container resolves the dependencies based
on the provided mappings and provides the corresponding
Introducing Autofac instances when the application needs them. For example,
Autofac is a lean, open-source, Inversion of Control (IoC) if your application needs a service instance, you can de-
container used for resolving dependencies in .NET Frame- clare an interface for it and then develop a class that
work and .NET Core applications. You can use it to build implements it. You can then register this implementation
applications using .NET Framework or .NET Core, and such in the Autofac container and use one of the various injec-
applications are maintainable, manageable, adaptable, tion strategies to resolve the dependency as needed in
and loosely coupled. Autofac provides support for inter- the application.
ceptors; using them lets you inject your logic before and
after method calls, thereby enabling you to implement Benefits of Autofac over the Built-In DI Container
AOP. Autofac provides several benefits compared to the built-
in dependency injection (DI) container:
Key Features
Here are the key features of Autofac: • Flexibility: The built-in IoC container in ASP.NET
Core provides limited support for dependency injec-
• Component Registration: Autofac supports the reg- tion as you can only use constructor injection with
istration of components and their dependencies and it. However, you can leverage Autofac to implement
can resolve dependencies for registered components both constructor and property injection.
if needed. • Lifetime management: The Autofac lifetime man-
• Extensibility: Autofac supports a variety of ex- agement system lets you control the lifecycle of
tension points, including customized registration your objects and prevent memory leaks by using the
sources, middleware, and decorators. singleton instance per dependency, and instance per
• Modular Design: In Autofac, you can organize com- lifetime scope options.
ponent registrations into modules, which can be • Testing: Autofac makes making mock objects and
loaded and unloaded dynamically, thereby promot- stubs easy so that you can test your code seam-
ing the modularity and maintainability of applica- lessly.
tions. • Third-party integration: Autofac supports integra-
• Inversion of Control (IoC): Autofac adheres to the tion with popular third-party libraries, like Serilog,
IoC principle, enabling you to define how dependen- AutoMapper, and MediatR. Integrating these librar-
cies are resolved and managed in applications. ies into your application and configuring them with
• Lifetime Management: Autofac supports manag- Autofac is easy.
ing the lifetime of container objects for a particular • Performance: Autofac is fast, easily customizable,
request, including singleton, transient, and scoped and leverages lazy loading and compiled expressions
lifetimes. to optimize object creation and resolve dependen-
• Interception: Autofac supports interception, en- cies.
abling you to intercept method calls on registered
components and apply cross-cutting concerns such What Is a Dynamic Proxy?
as logging, caching, or security. A dynamic proxy is a programming approach to create a
• Integration with Frameworks: Autofac integrates proxy object at runtime, which, in turn, acts as an inter-
seamlessly with .NET and .NET Core frameworks, mediary between a real object and the client. Using this
thereby making it a preferred choice for implement- technique, you can attach aspects to objects dynamically,
ing dependency injection. such as at runtime, without altering their source code
and implement cross-cutting concerns such as transaction
What Are Interceptors? management, logging, and caching.
In Autofac, interceptors are components that enable you
to add behavior to a class, interface, or configuration
without modifying its implementation. Using Autofac,
Building a Memory Cache
you can intercept method calls and add custom behav- Interceptor Using Autofac
ior using interception frameworks such as Castle Dynam- A memory cache interceptor is a component that can in-
icProxy. In Autofac, interceptors are implemented using tercept method calls and cache the results in memory.
the Castle DynamicProxy framework, which creates a This helps you optimize the performance by decreasing
proxy object that intercepts method calls at runtime and the need to retrieve the same piece of data repeatedly. In
can modify them before passing them along to the target this section, you’ll implement a memory cache intercep-
object. tor. You’ll follow the following steps to build a memory
cache interceptor:
What Is an Autofac Container? Why Is It Needed?
An Autofac container is used to manage the lifecycle of 1. Create a model class.
objects, resolve dependencies, and ensure the creation 2. Create the data context.
and proper disposal of objects when they’re no longer 3. Prepare the seed data.
needed by your application. You can create dependen- 4. Create a memory cache interceptor.
cies by defining the required interfaces or concrete types, 5. Create and configure the Autofac container.
which are then registered in the Autofac container to cre- 6. Create the repository class.

62 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
7. Create the controller class. PM> Install-Package Autofac
8. Leverage the cache interceptor in the control- PM> Install-Package Autofac.Extensions.DependencyInjection
ler class. PM> Install-Package Autofac.Extras.DynamicProxy
9. Run the application.
You can also install this package by executing the follow-
Create a New ASP.NET Core MVC 8 Project in Visual ing commands at the Windows Shell:
Studio 2022
You can create a project in Visual Studio 2022 in several dotnet add package Autofac
ways. When you launch Visual Studio 2022, you'll see the dotnet add package Autofac.Extensions.DependencyInjection
Start window. You can choose "Continue without code" dotnet add package Autofac.Extras.DynamicProxy
to launch the main screen of the Visual Studio 2022 IDE.
Create the Model Class
To create a new ASP.NET Core MVC 8 Project in Visual Crate a new class named Customer in a file named Cus-
Studio 2022: tomer.cs inside the Models folder of the web application
project you created earlier and write the following code
1. Start the Visual Studio 2022 IDE. in there:
2. In the “Create a new project” window, select “ASP.
NET Core Web App (Model-View-Controller)” and click namespace OrderProcessingSystem.Models
Next to move on. {
3. Specify the project name and the path where it public class Customer
should be created in the “Configure your new proj- {
ect” window. public Guid Id { get; set; }
4. If you want the solution file and project to be cre- public string FirstName
ated in the same directory, you can optionally check { get; set; } = default!;
the “Place solution and project in the same direc- public string LastName
tory” checkbox. Click Next to move on. { get; set; } = default!;
5. In the next screen, specify the target framework and public string Address
authentication type as well. Ensure that the "Con- { get; set; } = default!;
figure for HTTPS," "Enable Docker," and “Do not use public string Email
top-level statements” checkboxes are unchecked be- { get; set; } = default!;
cause you won’t use any of these in this example. public string Phone
6. Click Create to complete the process. { get; set; } = default!;
}
A new ASP.NET Core MVC project is created. You’ll use this }
project in the sections that follow.

Install NuGet Package(s) Create the Data Context


First off, let’s install the necessary NuGet Package(s). To In Entity Framework Core (EF Core), a data context is a
install the required package into your project, right-click component used by an application to interact with the
on the solution and then select Manage NuGet Packages database and manage database connections, and to query
for Solution…. Now search for the package named Post- and persist data in the database. You’ll now create a data
Sharp in the search box and install it. Alternatively, you context class named CustomerDbContext. To create a data
can type the commands shown below at the NuGet Pack- context, create a class that extends the DbContext class
age Manager Command Prompt: of EF Core, as shown in Listing 1.

Listing 1: The CustomerDbContext class


namespace OrderProcessingSystem.DataAccess data);
{ }
public class CustomerDbContext : DbContext private Customer[] GenerateCustomerData()
{ {
public CustomerDbContext var customerFaker = new Faker<Customer>()
(DbContextOptions .RuleFor(e => e.Id, _ => Guid.NewGuid())
<ProductDbContext> options) .RuleFor(e => e.FirstName,
: base(options) f => f.Name.FirstName())
{ .RuleFor(e => e.LastName, f =>
} f.Name.LastName())
protected override void OnConfiguring .RuleFor(e => e.Address,
(DbContextOptionsBuilder optionsBuilder) f => f.Address.FullAddress())
{ .RuleFor(e => e.Email,
optionsBuilder.UseInMemoryDatabase (f, e) => f.Internet.Email
(databaseName: "OrderManagementSystem"); (e.FirstName, e.LastName))
} .RuleFor(e => e.Phone,
public DbSet<Customer> Customers { get; set; } f => f.Phone.PhoneNumber());
protected override void
OnModelCreating return customerFaker.
(ModelBuilder modelBuilder) Generate(count: 5).ToArray();
{ }
var data = GenerateCustomerData(); }
modelBuilder.Entity<Customer>().HasData( }

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 63
Listing 2: Index View of the Customer Model
@model IEnumerable <th></th>
<OrderProcessingSystem.Models.Customer> </tr>
@{ </thead>
ViewData["Title"] = "Customer View"; <tbody>
} @foreach (var item in Model)
{
<h1>Customer Details</h1> <tr>
<td>
<table class="table"> @Html.DisplayFor
<thead> (modelItem => item.FirstName)
<tr> </td>
<th> <td>
@Html.DisplayNameFor @Html.DisplayFor
(model => model.FirstName) (modelItem => item.LastName)
</th> </td>
<th> <td>
@Html.DisplayNameFor @Html.DisplayFor
(model => model.LastName) (modelItem => item.Address)
</th> </td>
<th> </tr>
@Html.DisplayNameFor }
(model => model.Address) </tbody>
</th> </table>

Listing 3: The MemoryCacheInterceptor class using OrderProcessingSystem.Models;


public class MemoryCacheInterceptor :
IInterceptor namespace OrderProcessingSystem.DataAccess
{ {
private IMemoryCache _memoryCache; public interface ICustomerRepository
public MemoryCacheInterceptor {
(IMemoryCache memoryCache) public List<Customer> GetAll();
{ public Customer GetById(int id);
_memoryCache = memoryCache; }
}
}
public void Intercept
(IInvocation invocation)
{ The CustomerRepository class implements the ICustomer-
//Write your custom code here Repository interface, as shown below.
//to intercept methods at runtime
}
} using OrderProcessingSystem.Models;
using Microsoft.EntityFrameworkCore;

Create the Index View for the Customer Model namespace OrderProcessingSystem.DataAccess
In ASP.NET Core MVC, views are used to present data to {
the user in a way that’s meaningful. In this section, you'll public class CustomerRepository :
create an Index view for the Customer model. To build the ICustomerRepository
Index view for the Customer model, follow these steps: {
private readonly CustomerDbContext _context;
1. Import model data onto the view to read and extract public CustomerRepository()
data pertaining to the Customer model. {
2. Access the properties of the Customer model. var options = new
3. Iterate through the Customer data using the @ DbContextOptionsBuilder<ProductDbContext>()
foreach loop. .UseInMemoryDatabase("OrderManagementSystem")
4. Access the Customer data inside the loop and .Options;
display it in the view using @Html.DisplayFor.
_context = new CustomerDbContext(options);
The complete source code of the customer view is given _context.Database.EnsureCreated();
in Listing 2. }
public List<Customer> GetAll() =>
Note that I’ve omitted the ID column for brevity in the
preceding code of the Index view of the Customer model. Create the MemoryCacheInterceptor
To create a custom interceptor, create a class that imple-
Create the CisustomerRepository ments the IInterceptor interface, as shown in Listing 3.
The customer repository will comprised of the ICustomer-
Repository interface and the CustomerRepository class. In Listing 3, write your custom code to intercept meth-
The code snippet given below shows the ICustomerRe- ods at runtime. It should be noted that this code, that
pository interface. is, the source code you need to write inside the Intercept

64 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
Listing 4: The complete source of MemoryCacheInterceptor class
public class MemoryCacheInterceptor : IInterceptor string? commaSeperatedArguments =
{ string.Join(", ", arguments);
private readonly IMemoryCache _memoryCache; string? cacheKey = $"
private TimeSpan cacheDuration = {declaringType}|{methodName}|
TimeSpan.FromSeconds(30); {commaSeperatedArguments}";

public MemoryCacheInterceptor if (!_memoryCache.TryGetValue


(IMemoryCache memoryCache) (cacheKey, out object? returnValue))
{ {
_memoryCache = memoryCache; invocation.Proceed();
} returnValue = invocation.ReturnValue;
_memoryCache.Set
public void Intercept(IInvocation invocation) (cacheKey, returnValue, cacheDuration);
{ }
Type? declaringType = else
invocation.Method.DeclaringType; {
string? methodName = invocation.Method.Name; invocation.ReturnValue = returnValue;
IEnumerable<string?> }
arguments = invocation. }
Arguments.Select(arg => }
(arg ?? string.Empty).ToString());

method, will be executed when a method is intercepted. Listing 5: The ContainerHelper class
This means that this code will be executed before and public static class ContainerHelper
after the intercepted method is invoked. {
public static WebApplication
The complete source code of the MemoryCacheInterceptor BuildContainer(WebApplicationBuilder builder)
{
is given in Listing 4.
builder.Host.UseServiceProviderFactory
Register the MemoryCacheInterceptor (new AutofacServiceProviderFactory()).
To register the MemoryCacheInterceptor, i.e., wire up the ConfigureContainer<ContainerBuilder>(builder =>
{
interceptor to the Autofac container, you can use the fol- builder.RegisterType<MemoryCacheInterceptor>();
lowing code. builder.RegisterType<CustomerRepository>()
.As<ICustomerRepository>()
builder.RegisterType<MemoryCacheInterceptor>(); .InstancePerDependency()
builder.RegisterType<CustomerRepository>() .EnableInterfaceInterceptors()
.InterceptedBy(typeof(MemoryCacheInterceptor));
.As<ICustomerRepository>() });
.InstancePerDependency()
.EnableInterfaceInterceptors() return builder.Build();
.InterceptedBy(typeof(MemoryCacheInterceptor)); }
}

Note that you can also register multiple interceptors as


shown in the code snippet given below.
start using your container, you must build it using the
builder.Host. Build method. When you invoke the Build method, the
UseServiceProviderFactory container validates the registrations and then creates the
(new AutofacServiceProviderFactory()). necessary components and their dependencies.
ConfigureContainer<ContainerBuilder>
(builder => You’ll create a new static class here that contains a static
{ method to encapsulate the logic of creating the con-
builder.RegisterType<MemoryCacheInterceptor>(); tainer, registering types, and specifying the interceptors.
builder.RegisterType<CustomerRepository>() Listing 5 shows how you can achieve this by creating a
.As<ICustomerRepository>() static method called BuildContainer inside a static class
.InstancePerDependency() named ContainerHelper.
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(LoggingInterceptor)) Call the BuildContainer method of the ContainerHelper
.InterceptedBy(typeof class in the Program.cs file, as shown in this code snip-
(TransactionM anagementInterceptor)) pet:
.InterceptedBy(typeof(MemoryCacheInterceptor));
}); var app = ContainerHelper.BuildContainer(builder);

Create the CustomerController Class


Create an Autofac Container Create a new ASP.NET Core MVC controller named Custom-
Let’s now create an Autofac container to register the ICus- erController in a file named CustomerController.cs inside
tomerRepository interface and its implementation type, the Controllers folder of the project. The following piece
i.e., the CustomerRepository class. To create a container, of code shows how you can take advantage of constructor
leverage the ContainerBuilder class. Note that before you injection to create an instance of type ICustomerReposi-

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 65
Listing 6: The CustomerController class
public class CustomerController : Controller {
{ return View();
private readonly }
ICustomerRepository _customerRepository;
public CustomerController [HttpPost]
(ICustomerRepository customerRepository, [ValidateAntiForgeryToken]
IMemoryCache memoryCache) public ActionResult Edit(int id,
{ IFormCollection collection)
_customerRepository = customerRepository; {
} try
{
public ActionResult Index() return RedirectToAction(nameof(Index));
{ }
return View(_customerRepository.GetAll()); catch
} {
public ActionResult Details(int id) return View();
{ }
return View(); }
}
public ActionResult Create() public ActionResult Delete(int id)
{ {
return View(); return View();
} }

[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public ActionResult Create public ActionResult Delete
(IFormCollection collection) (int id, IFormCollection collection)
{ {
try try
{ {
return RedirectToAction(nameof(Index)); return RedirectToAction(nameof(Index));
} }
catch catch
{ {
return View(); return View();
} }
} }
public ActionResult Edit(int id) }

tory and then call the GetAll method of it inside the Index
action method of the controller. public CustomerController
(ICustomerRepository
private readonly customerRepository,
ICustomerRepository IMemoryCache memoryCache)
_customerRepository; {
_customerRepository =
customerRepository;
Listing 7: The Program.cs file }
var builder = WebApplication.CreateBuilder(args);
// Add services to the container [LoggingAspect]
builder.Services.AddMemoryCache(); public ActionResult Index()
{
builder.Services.AddControllersWithViews();
return View(_customerRepository.
var app = ContainerHelper.BuildContainer(builder); GetAll());
}
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
The complete source code of the CustomerController class
app.UseExceptionHandler("/Home/Error"); is given in Listing 6.
}
app.UseStaticFiles(); The Program.cs File
The complete source code of the Program.cs file is given
app.UseRouting();
in Listing 7.
app.UseAuthorization();
When you execute the application and browse the /Cus-
app.MapControllerRoute( tomer endpoint, the customer records are displayed at the
name: "default",
pattern: "{controller=Home}/ web browser, as shown in Figure 4.
{action=Index}/{id?}");
Because caching has been enabled, and because you’ve al-
app.Run(); ready registered a memory cache interceptor, the customer

66 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
data is fetched from the cache and not from the database throughout the codebase. This leads to duplicate code
for all subsequent calls to the same endpoint. Figure 5 and a lack of code modularity. For example, you might
shows how the breakpoint set in the Intercept method of require logging at several places in an application. Here's
the MemoryCacheInterceptor class is hit when you refresh where PostSharp can help, by automatically addressing
the web page. these concerns, reducing boilerplate code, and increasing
code readability and modularity.
Programming AOP Using PostSharp PostSharp works by post-processing compiler output to add
Typically, developers find it challenging to handle cross- aspects and make changes to the intermediate assembly.
cutting concerns such as logging, caching, validation, After compilation, PostSharp reads and disassembles the
and error handling because the code is often entangled intermediate assembly, applies the necessary transforma-

Figure 4: Displaying the customer records in the web browser

Figure 5: The Intercept method of the MemoryCacheInterceptor is called.

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 67
Listing 8: The ProductDbContext class
public class ProductDbContext : DbContext products);
{ }
public ProductDbContext private Product[] GenerateProductData()
(DbContextOptions {
<ProductDbContext> options) var productId = 1;
: base(options)
{ var productFaker = new Faker<Product>()
} .RuleFor(x => x.Id, f => productId++)
protected override void OnConfiguring .RuleFor(x => x.Name,
(DbContextOptionsBuilder optionsBuilder) f => f.Commerce.ProductName())
{ .RuleFor(x => x.Description,
optionsBuilder. f => f.Commerce.ProductDescription())
UseInMemoryDatabase .RuleFor(x => x.Price,
(databaseName: "ProductDb"); f => Math.Round(f.Random.Decimal
} (1000, 5000), 2));
public DbSet<Product> Products { get; set; }
protected override void return productFaker.
OnModelCreating(ModelBuilder modelBuilder) Generate(count: 5).ToArray();
{ }
var products = GenerateProductData(); }
modelBuilder.Entity<Product>().HasData(

Listing 9: The ProductRepository Class A Real-World Use Case: Store


public class ProductRepository : IProductRepository Performance Metadata Using AOP
{
private readonly ProductDbContext _context; You’ll now implement a simple application that demon-
public ProductRepository() strates how you can retrieve and store application perfor-
{
var options = new DbContextOptionsBuilder mance metadata in the database. You’ll initially build the
<ProductDbContext>() Product module of a simple OrderProcessing application.
.UseInMemoryDatabase("OrderManagementSystem") You’ll capture performance metadata from this application
.Options; while it’s in execution. The source code of this module is
_context = new ProductDbContext(options); comprised of the following classes and interfaces:
_context.Database.EnsureCreated();
} • Product class
public List<Product> GetAll() =>
_context.Products.ToList<Product>(); • IProductRepository interface
public Product GetById(int id) => • ProductRepository class
_context.Products.SingleOrDefault(p => p.Id == id); • ProductController class
public void Create(Product product) =>
_context.Products.Add(product); Create the Model Class
public void Delete(Product product) => Create a new class named Product in a file having the
_context.Products.Remove(product); same name with a .cs extension and write the following
} code in there:

public class Product


tions and validations depending on the provided aspects, {
and saves the updated assembly to the file system. public int Id { get; set; }
public string Name
When using PostSharp, you may create custom aspects { get; set; } = string.Empty;
that encapsulate reusable code and apply these aspects public string Description
to particular methods, classes, or attributes in your code. { get; set; } = string.Empty;
PostSharp incorporates these features into the generated public decimal Price
code, either at build time or at runtime, and integrates { get; set; } = decimal.Zero;
them directly into the assembly. PostSharp supports two }
types of weaving: compile-time and run-time.

The compile-time weaving technique guarantees that Create the Data Context
the aspects are built into the assembly, resulting in re- Next, create the data context class to interact with the
duced runtime cost. This implies that when your applica- database. To do this, create a new class named Product-
tion starts, the aspects are already applied to the code, DbContext that extends the DbContext class of EF Core
eliminating the need for extra processing or overhead. In and write the code from Listing 8 in there.
runtime weaving, PostSharp enables applying aspects in
a more dynamic manner, enabling you to deploy compo- Create the ProductRepository Class
nents like application plug-ins or extensible frameworks Now, create a new class named ProductRepository in a file
at runtime. In other words, although the aspects are inte- having the same name with a .cs extension. Now write the
grated directly into the compiled code during compilation following code in there:
in compile-time weaving, in runtime-weaving, these as-
pects are applied at specified points of the application's public class ProductRepository :
code at runtime. IProductRepository

68 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
Listing 10: The ProductController class
public class ProductController : Controller {
{ return View();
private readonly IProductRepository }
_productRepository;
public ProductController [HttpPost]
(IProductRepository productRepository, [ValidateAntiForgeryToken]
IMemoryCache memoryCache) public ActionResult Edit(int id,
{ IFormCollection collection)
_productRepository = productRepository; {
} try
public ActionResult Index() {
{ return RedirectToAction(nameof(Index));
return View(_productRepository. }
GetAll()); catch
} {
public ActionResult return View();
Details(int id) }
{ }
return View(); public ActionResult Delete(int id)
} {
public ActionResult Create() return View();
{ }
return View();
} [HttpPost]
[ValidateAntiForgeryToken]
[HttpPost] public ActionResult Delete(int id,
[ValidateAntiForgeryToken] IFormCollection collection)
public ActionResult {
Create(IFormCollection collection) try
{ {
try return RedirectToAction(nameof(Index));
{ }
return RedirectToAction(nameof(Index)); catch
} {
catch return View();
{ }
return View(); }
} }
}
public ActionResult Edit(int id)

{ public class ProductController: Controller


{
} private readonly IProductRepository
_productRepository;
The ProductRepository class illustrated in the code snippet
below, implements the methods of the IProductRepository public ProductController
interface. Here is how the IProductRepository interface (IProductRepository productRepository,
should look: IMemoryCache memoryCache)
{
public interface IProductRepository _productRepository = productRepository;
{ }
public List<Product> GetAll();
public Product GetById(int id); public ActionResult Index()
public void Create(Product product); {
public void Delete(Product product); return View(_productRepository.GetAll());
} }

The complete source code of the ProductRepository class //Other action methods
is given in Listing 9. }

Create the ProductController Class


Now, create a new controller named ProductController in Listing 10 shows the complete source of the ProductCon-
the Controllers folder of the project. The following code troller class.
snippet shows how you can take advantage of constructor
injection to create an instance of the ProductRepository Install NuGet Package(s)
class and then use it to retrieve all product records from The next step is to install the necessary NuGet Package(s).
the database in the Index action method. To install the required package into your project, right-

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 69
Listing 11: The ExecutionTimeDbContext class
public class ExecutionTimeDbContext : DbContext {
{ modelBuilder.Entity
public ExecutionTimeDbContext <ExecutionTimeMetadata>
(DbContextOptions (entity =>
<ExecutionTimeDbContext> options) {
: base(options) entity.HasKey(e => e.Id);
{ entity.Property(e =>
} e.MethodName).HasColumnType("TEXT");
protected override void OnConfiguring entity.Property(e =>
(DbContextOptionsBuilder options) e.DeclaringType).HasColumnType("TEXT");
=> options.UseSqlite entity.Property(e =>
($"Data Source=ExecutionTimeMonitor.db;"); e.ExecutionTime).HasColumnType("LONG");
public DbSet<ExecutionTimeMetadata> });
ExecutionTimeMetadatas { get; set; } }
protected override void OnModelCreating }
(ModelBuilder modelBuilder)

Listing 12: The ExecutionTimeAspect class


[PSerializable] in {executionTime} seconds.");
public class ExecutionTimeAspect :
OnMethodBoundaryAspect var options = new DbContextOptionsBuilder
{ <ExecutionTimeDbContext>()
private ExecutionTimeDbContext? _context; .UseSqlite
($"Data Source=ExecutionTimeMonitor.db")
[NonSerialized] .Options;
Stopwatch stopWatch;
public override void _context = new ExecutionTimeDbContext(options);
OnEntry(MethodExecutionArgs args) _context.Database.EnsureCreated();
{
stopWatch = Stopwatch.StartNew(); _context.ExecutionTimeMetadatas.Add
base.OnEntry(args); (new ExecutionTimeMetadata()
} {
public override void OnExit MethodName = methodName,
(MethodExecutionArgs args) DeclaringType = typeName,
{ ExecutionTime = executionTime,
var methodBase = });
new StackTrace().GetFrame(1).GetMethod();
string typeName = _context.SaveChanges();
methodBase.DeclaringType.Name; base.OnExit(args);
string methodName = methodBase.Name; }
long executionTime = }
stopWatch.ElapsedMilliseconds;
Console.WriteLine
($"The method {methodName} executed

click on the solution and then select Manage NuGet Pack- Create the ExecutionTimeMetadata Model
ages for Solution…. Now search for the package named Create a new class named ExecutionTimeMetadata in a file
PostSharp in the search box and install it. Alternatively, named ExecutionTimeMetadata.cs and write the following
you can type the commands shown below at the NuGet code in there.
Package Manager Command Prompt:
public class ExecutionTimeMetadata
PM> Install-Package PostSharp {
[Key]
You can also install this package by executing the follow- [DatabaseGenerated
ing commands at the Windows Shell: (DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
dotnet add package PostSharp public string MethodName { get; set; }
public string DeclaringType { get; set; }
public long ExecutionTime { get; set; }
Store Performance Metadata }
into the Database
In this section, I’ll examine how to capture and store
application performance metadata in a database. You’ll You'll use this class to store method execution metadata
leverage AOP to retrieve and store performance monitor- in memory.
ing data in a database. Note that you’ll store the CPU and
memory usage details in a database as well as the method Create the ExecutionTimeDbContext Class
execution time of an action method in another database. The ExecutionTimeDbContext class is used to connect to
For the sake of simplicity, I’ll use SqlLite databases in a SqlLite database and store the method execution meta-
this example. data in it, as shown in Listing 11.

70 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
Figure 6: Displaying the execution time of the Index action method

Create the ExecutionTimeAspect class [ExecutionTimeAspect]


The ExectionTimeAspect class is attached to a method public ActionResult Index()
call at runtime. It captures and stores execution time of {
a method in a SqlLite database. Listing 12 shows the return View(_productRepository.
complete source code of the ExecutionTimeAspect class. GetAll());
}
Lastly, apply the ExecutionTimeAspect to a method of
your choice to log the method execution time. The code
snippet given below shows how you can apply this aspect Figure 6 shows the execution time (in milliseconds) of
to the Index method of the ProductController class. the Index method of the ProductController class.

Listing 13: The PerformanceDbContext class


public class PerformanceDbContext : DbContext {
{ modelBuilder.Entity
public PerformanceDbContext(DbContextOptions <PerformanceMetadata>(entity =>
<PerformanceDbContext> options) {
: base(options) entity.HasKey(e => e.Id);
{ entity.Property(e => e.CpuUsage).
} HasColumnType("FLOAT");
protected override void OnConfiguring entity.Property(e =>
(DbContextOptionsBuilder options) e.MemoryUsage).
=> options.UseSqlite HasColumnType("FLOAT");
($"Data Source=PerformanceMonitor.db;"); });
public DbSet<PerformanceMetadata> }
PerformanceMetadatas { get; set; } }
protected override void OnModelCreating
(ModelBuilder modelBuilder)

Listing 14: The ApplicationPerformanceUtility class


public class ApplicationPerformanceUtility ManagementObjectSearcher
{ managementObjectSearcher =
public static float GetCpuUsage() new ManagementObjectSearcher
{ ("SELECT * FROM Win32_OperatingSystem");
var managementObjectSearcher = var managementObject = managementObjectSearcher.
new ManagementObjectSearcher Get().Cast<ManagementObject>().
("SELECT * FROM Select(m => new
Win32_PerfFormattedData_PerfOS_Processor"); {
var managementObjectCollection = TotalVisibleMemorySize =
managementObjectSearcher.Get(); m["TotalVisibleMemorySize"],
FreeMemory = m["FreePhysicalMemory"]
float totalUsage = 0; }).FirstOrDefault();
foreach (var managementBaseObject in
managementObjectCollection) var freeMemory =
{ (ulong)managementObject.FreeMemory;
totalUsage += float.Parse var totalMemory =
(managementBaseObject (ulong)managementObject.
["PercentProcessorTime"].ToString()); TotalVisibleMemorySize;
} return (totalMemory - freeMemory) /
(float)totalMemory * 100;
return totalUsage / }
managementObjectCollection.Count; }
}

public static float GetMemoryUsage()


{

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 71
Listing 15: The OnEntry and OnExit methods
public override void OnEntry _context.PerformanceMetadatas.Add
(MethodExecutionArgs args) (new PerformanceMetadata()
{ {
var options = CpuUsage = cpuUsage,
new DbContextOptionsBuilder<PerformanceDbContext>() MemoryUsage = memoryUsage
.UseSqlite($"Data Source=PerformanceMonitor.db") });
.Options;
var ctr = _context.PerformanceMetadatas.Count();
_context = new PerformanceDbContext(options); _context.SaveChanges();
_context.Database.EnsureCreated(); }
public override void OnExit(MethodExecutionArgs args)
var cpuUsage = {
float.Round(ApplicationPerformanceUtility. var typeName = args.Method.DeclaringType.Name;
GetCpuUsage(), 2); var methodName = args.Method.Name;
var memoryUsage = Console.WriteLine
float.Round(ApplicationPerformanceUtility. ($"{methodName} method of {typeName} executed.");
GetMemoryUsage(),2); }

Listing 16: The LoggingAspect class


[PSerializable] float.Round(ApplicationPerformanceUtility.
public class LoggingAspect : OnMethodBoundaryAspect GetMemoryUsage(),2);
{
private PerformanceDbContext? _context; _context.PerformanceMetadatas.Add
public override void OnEntry (new PerformanceMetadata()
(MethodExecutionArgs args) {
{ CpuUsage = cpuUsage,
var options = new MemoryUsage = memoryUsage
DbContextOptionsBuilder });
<PerformanceDbContext>()
.UseSqlite var ctr = _context.PerformanceMetadatas.Count();
($"Data Source=PerformanceMonitor.db") _context.SaveChanges();
.Options; }
public override void OnExit(MethodExecutionArgs args)
_context = new PerformanceDbContext(options); {
_context.Database.EnsureCreated(); var typeName = args.Method.DeclaringType.Name;
var methodName = args.Method.Name;
var cpuUsage = float.Round Console.WriteLine
(ApplicationPerformanceUtility. ($"{methodName} method of {typeName} executed.");
GetCpuUsage(), 2); }
var memoryUsage = }

Create the PerformanceMetadata Model WMI is an acronym for Windows Management Instrumenta-
Create a new class named PerformanceMetadata in a file tion, a COM-based Microsoft technology used to retrieve
having the same name with a .cs extension and write the hardware information. To capture application performance
following code in there. metadata, i.e., the CPU usage and memory usage in this
example, create a new class called ApplicationPerforman-
public class PerformanceMetadata ceUtility in a file named ApplicationPerformanceUtility.cs
{ and write the code given in Listing 14 in there.
[Key]
[DatabaseGenerated Create the LoggingAspect Class
(DatabaseGeneratedOption.Identity)] Create a new class named LoggingAspect in a file named
public int Id { get; set; } LoggingAspect.cs and write the following code in there.
public float CpuUsage { get; set; }
public float MemoryUsage { get; set; } [PSerializable]
} public class LoggingAspect :
OnMethodBoundaryAspect
{
Create the PerformanceDbContext public override void OnEntry
The PerformanceDbContext class connects to a SqlLite (MethodExecutionArgs args)
database named PerformanceMonitor.db to persist per- {
formance metadata. In the OnModelCreating method, you
specify the primary key and the database table columns }
you need. Listing 13 is the complete source code of the
PerformanceDbContext class. public override void OnSuccess
(MethodExecutionArgs args)
Retrieve Performance Metadata {
In this section, I’ll examine how you can take advantage
of WMI to retrieve system information from your computer. }

72 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
Figure 7: Displaying the CPU and Memory usage details

• OnExit: This method is executed after the method


public override void OnException on which the aspect is applied has completed its
(MethodExecutionArgs args) execution with or without an exception.
{
You’ll implement the OnEntry and OnExit methods shortly.
} The OnEntry overriden method is called before execution of
the method on which an aspect is applied. You'll create a
public override void OnExit the SqlLite database in this method and capture and store
(MethodExecutionArgs args) application performance metadata in the SqlLite database
{ using EF Core. Listing 15 shows the OnEntry method.

} The OnExit overriden method captures the type name and


} the method name of the current request and then displays
them at the console window, as shown in the code snip-
pet given below.
The LoggingAspect class extends the OnMethodBoundary-
Aspect class of the PostSharp library. In the preceding code public override void OnExit
example, the following overidden methods have been used. (MethodExecutionArgs args)
{
• OnEntry: This method is executed before the meth- var typeName =
od on which the aspect is applied is executed. args.Method.DeclaringType.Name;
• OnSuccess: This method is executed after the meth- var methodName = args.Method.Name;
od on which the aspect is applied is executed and Console.WriteLine
when it has returned successfully. ($"{methodName}
• OnException: This method is executed after the method of {typeName} executed.");
method on which the aspect is applied has thrown }
an exception.

codemag.com Store Application Performance Metadata in a Database Using AOP in ASP.NET Core 73
CODE COMPILERS

The complete source code of the LoggingAspect class is


SPONSORED SIDEBAR
given in Listing 16.
AI Executive
Briefing When you execute the application and invoke an endpoint Jul/Aug 2024
on which the LoggingAspect attribute has been applied, Volume 25 Issue 4
Experience the game- the performance metadata is captured and stored in the
changing impact of configured SqlLite database, as shown in Figure 7. Group Publisher
AI through CODE Markus Egger
Consulting’s Executive Editor-in-Chief
Briefing service. Uncover Conclusion Rod Paddock
the immense potential and Procedural programming, object-oriented programming Managing Editor
wide-ranging benefits of Ellen Whitney
(OOP), and aspect-oriented programming (AOP) are wide-
AI in every industry. Our ly used programming paradigms with distinctly different Content Editor
briefing provides strategic Melanie Spiller
characteristics. The former emphasizes objects and their
guidance for seamless Writers in This Issue
interactions and the latter paradigm isolates and modu- Ed Charbeneau Markus Egger
implementation, covering
crucial aspects such as
larizes the cross-cutting concerns. Conventional object- Joydip Kanjilal Sahil Malik
oriented methods can pose significant challenges when Paul D. Sheriff
infrastructure, talent
acquisition, and leadership. managing, maintaining, or modifying an application's Technical Reviewers
code because the concerns are entangled and intertwined Markus Egger
Rod Paddock
Discover how to effectively with the core logic.
Production
integrate AI and propel Friedl Raffeiner Grafik Studio
your organization into In this article, I’ve examined how you can capture and www.frigraf.it
future success. store performance metadata in a database. You’ve used Graphic Layout
WMI to capture CPU and memory usage data. The CPU Friedl Raffeiner Grafik Studio in collaboration
Contact us today to and memory usage details have been captured during a with onsight (www.onsightdesign.info)
schedule your executive method invocation. You can leverage a background ser- Printing
briefing and embark vice to capture CPU and Memory usage data and store it Fry Communications, Inc.
on a journey of 800 West Church Rd.
in a database at frequent intervals of time. Mechanicsburg, PA 17055
AI-powered growth.
www.codemag.com/ai Advertising Sales
 Joydip Kanjilal Tammy Ferguson
 832-717-4445 ext. 26
[email protected]
Circulation & Distribution
General Circulation: EPS Software Corp.
Newsstand: Ingram Periodicals, Inc.
International Bonded Couriers (IBC)
Media Solutions
Source Interlink International
Subscriptions
Circulation Manager
Colleen Cade
832-717-4445 ext. 28
[email protected]

US subscriptions are $29.99 USD for one year.


Subscriptions outside the US are $50.99 USD.
Payments should be made in US dollars drawn
on a US bank. American Express, MasterCard,
Visa and Discover credit cards accepted.
Back issues are available. For subscription
information, email [email protected]
or contact customer service at 832-717-4445 ext. 9.
Subscribe online at
www.code-magazine.com

CODE Developer Magazine


EPS Software Corporation / Publishing Division
6605 Cypresswood Drive, Ste 425, Spring, Texas 77379 USA
Phone: 832-717-4445

74 Store Application Performance Metadata in a Database Using AOP in ASP.NET Core codemag.com
CUSTOM SOFTWARE DEVELOPMENT
STAFFING TRAINING/MENTORING SECURITY

MORE THAN JUST


A MAGAZINE!
Does your development team lack skills or time to complete all your business-critical software projects?
CODE Consulting has top-tier developers available with in-depth experience in .NET,
web development, desktop development (WPF), Blazor, Azure, mobile apps, IoT and more.

CONTACT US TODAY FOR A COMPLIMENTARY ONE HOUR TECH CONSULTATION.


NO STRINGS. NO COMMITMENT. JUST CODE.
©shutterstock

codemag.com/code
832-717-4445 ext. 9 • [email protected]
STAFFING

UNLOCK
STAFFING
EXCELLENCE
Top-Notch IT Talent, Contract Flexibility, Happy Teams, and a
Commitment to Customer Success Converge with CODE Staffing

Our IT staffing solutions are engineered to drive your business forward while
saving you time and money. Say goodbye to excessive overhead costs and
lengthy recruitment efforts. With CODE Staffing, you’ll benefit from contract
flexibility that caters to both project-based and permanent placements. We
optimize your workforce strategy, ensuring a perfect fit for every role and
helping you achieve continued operational excellence.

Ready to Discuss Your IT Staffing Needs?

Visit our website to find out more about how we are changing
the staffing industry.

Website: codestaffing.com
Yair Alan Griver (yag)
Chief Executive Officer
Direct: +1 425 301 1590
Email: [email protected]

You might also like