End of Support is Coming

End of support for Windows Server 2008 and 2008 R2 is rapidly approaching. On January 14th, 2020 support for Windows Server 2008 and 2008 R2 will end; support for SQL Server 2008 and 2008 R2 already completed on July 9th, 2019.

Window Server Risks

What does this mean for my organization?

End of support means the end of monthly security updates and support from Microsoft. Without Microsoft’s regular security updates and patches to protect your environment, you expose your applications and data running on the platform to several risks. These risks may include the potential for security breaches, attacks, and compliance failure for important regulations such as GDPR, HIPAA, PCI, Sarbanes-Oxley, FedRAMP, and others. Read this datasheet for more details.

The requirements for maintaining compliant IT workloads vary depending on the regulation, but almost all of them forbid the use of unsupported software. Even if unsupported software is not officially prohibited, most compliance initiatives require the prompt performance of security patching. With this in mind, it’s particularly difficult for an organization to justify using software for which patches are no longer being created. Perhaps the most critical reason for IT professionals to migrate away from Windows Server 2008 and SQL Server 2008 before their end of life date, is that doing so is a matter of self-preservation.

The risks of not upgrading

Neglecting an end of life scenario can save a bit of money upfront; however, the risks associated with ignoring the end of support are far costlier. These issues vary in severity and can be anything – a security breach, an unfamiliar error message, or perhaps a compatibility problem. IT professionals don’t want to be in a situation where they need to explain to management that an issue has occurred, and can’t be addressed, because the workload impacted runs on unsupported software.

We understand that upgrading to a newer version of Windows Server and SQL server can be challenging and requires validation work. However, if your organization isn’t already acting on a plan to migrate and modernize your infrastructure before the end of support, you’re already behind.

Time to modernize

End of support is an ideal time to transform your IT platform and move your infrastructure and applications to the cloud. Nevertheless, it can be difficult to upgrade everything before the end of support deadlines. You cannot wait months and years or dedicate your IT organization to spend time upgrading your critical end of support IT infrastructure.

So how do you quickly ensure you can avoid potential critical security and compliance interruptions? What are my choices from here?

Move your servers to Azure as-is

The good news is Microsoft announced that Extended Security Updates would be available, for FREE, in Azure for 2008 and 2008 R2 versions of Windows Server and SQL Server. This support will be available for three more years after the end of support deadline. Despite this, organizations with the end of support technologies need a quick solution for migrating their IT infrastructure to Azure. Organizations must remain secure and compliant without taking months or years to create a strategic cloud transformation plan.

We often see the struggle to balance these two competing needs with large enterprise organizations who are faced with a myriad of legacy technologies and the pressure to modernize. The options are plentiful, the current infrastructure is complex, and decisions aren’t easy. This common scenario made us rethink how we can approach modernization, both quickly and strategically. Instead, address the immediate need to move out of a data center or end of support technology while working towards a well-thought-out cloud transformation roadmap. AIS CTO Vishwas Lele details this Two-Step approach to Cloud Transformation Journey using a Tactical “Lift-n-Shift” approach to rehost infrastructure on Azure.

Step 1: Move your end of support infrastructure into Azure as-is

Migrate your Windows Server and SQL Server applications to Microsoft Azure and breathe new life into your server infrastructure. The first step of this two-step approach perfectly aligns with the needs of migrating end of support workloads to Azure with minimal to no changes to your existing footprint (and near-zero downtime).

This positions you to:

  • Immediately meet deadlines for the end of support
  • Remain secure and compliant with critical business & industry regulations
  • Quickly leverage Azure capabilities (giving you tangible benefits)
  • Generate lasting cost-savings with Microsoft’s financially attractive ability to port your existing licenses to Azure

Some organizations shy away from a Lift-n-Shift approach. On the surface, it may seem wasteful, as we are duplicating your current footprint in Azure. However, by completing this effort in weeks, not months or years, duplication is minimized. Pair this with AIS’s FinOps methodology for cloud financial management best practices and significant savings can be achieved by moving your servers to an Azure-optimized infrastructure. By comparison, running your Windows Servers in AWS could be as much as 5 times more expensive to run Windows Server.

Step 2: Application innovation and modernization

Once you’ve started moving your on-premises infrastructure to the cloud, the modernization efforts begin, and a whole new world of opportunities to transform is realized. Even the modernization of your legacy applications can be accelerated by embracing the services of Azure cloud.

CHECK OUT OUR WHITEPAPER & LEARN ABOUT CLOUD-BASED APP MODERNIZATION APPROACHES

AIS has you covered with the migration of your infrastructure to Azure

With just a few months left for the Windows Server End of Support deadline (with the SQL deadline already passed), updating your IT infrastructure must be a priority to avoid business disruption. Even with standardized processes and years of experience, deploying new versions of Windows and SQL Server is no small task in the enterprise.

Our experts have Azure covered so you can focus on doing business. AIS can help you jumpstart this process with a comprehensive cloud migration assessment. Our program gives you flexibility in gauging readiness to leverage cloud technology for your servers. By using machine learning and data collection, we can provide you a portfolio inventory, data-driven insights, and recommendations to aid in defining your migration strategy. Also, we’ll provide detailed economic costs to run your servers in the cloud. You’ll have a clear line of sight into the cost of running your servers in the cloud, as well as a clear roadmap for migration.

With this assessment, we can quickly prepare your cloud infrastructure and to begin migrating servers to an environment that’s scalable and secure. We can get you migrated soon with our extensive experience and expertise.

Start you Azure migration planning today!

The time to act is now! While most coverage surrounding the end of support appears to emphasize the negative aspects, organizations that approach the situation through the right lens stand to reap the benefits of modernization.

Part of this approach requires organizations to choose a trusted and capable partner with the experience and skillsets to ensure a successful migration. With the impending deadlines quickly approaching, it’s time to take action.

Let AIS accelerate your end of support migration to Azure, starting with a cloud migration assessment, followed up a roadmap and the execution of an expert migration strategy.

GET AN ASSESSMENT OF YOUR WINDOWS SERVER 2008 WORKLOADS

Blazor is coming! In fact, it’s coming sooner than later. Check out ASP.NET’s blog post from April 18, 2019 announcing the official preview.

What is Blazor?

by Vivek Gunnala 

Blazor is a new interactive .Net Web framework, which is part of the open-source .Net platform. Blazor uses C#, HTML, CSS and Razor components instead of JavaScript. It’s built on open web standards without the need for any plugins or code transpilation, and it works on all modern web browsers, hence called “.Net in the browser”, the C# code is directly run on the browser using WebAssembly. Both client-side code and server-side code is developed in C#, which allows you to reuse code and libraries between both sides, such as validations, models, etc.

Apps built in Blazor can use existing .Net libraries by leveraging .Net Standard, allowing the same code to be used across platforms. Since it is an experimental project, Blazor is evolving rapidly with over 60,000 contributors.

About WebAssembly

At a high-level, WebAssembly is explained on the official site as, “a binary instruction format a stack-based virtual machine. It is designed as a portable target for compilation of high-level languages, enabling deployment on the web for client and server applications.”

Should I Use Blazor For My Next Project?

by Ash Tewari 

Blazor’s development status has been promoted from an “Experimental” project to a committed product. This is great news. Blazor is available now as an official preview. Let’s review the factors you should consider when making decisions about adopting Client-Side Blazor for your next production project.

Mono.wasm (The .NET runtime compiled into WebAssembly executing your .NET assemblies in the browser) does not interact with the DOM directly. It goes through JS Interop, which is expensive. The areas where .NET Code will get the most net benefit is in the Model and Business Logic, not the DOM manipulation. If your application is very chatty with the DOM, you might need to carefully assess whether you are getting the expected performance boost from WebAssembly execution of your .NET assemblies. [https://webassemblycode.com/webassembly-cant-access-dom/]

Currently, only the mono runtime is compiled to WebAssembly. Your .NET code is executed as-is. This means that your .NET code is essentially going through two interpreters and it has a noticeable performance impact. There is work being done to compile .NET assemblies to wasm. That and other related improvements in linking and compiling) is expected to improve the performance. The fact that Microsoft has decided to commit Blazor as a product indicates that there is confidence that these performance improvements are likely to become a reality.
[https://www.mono-project.com/news/2018/01/16/mono-static-webassembly-compilation/, https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md]

In the client-side hosting model, your code is still running in the browser sandbox. So, you don’t have any access to FileSystem and other OS libraries. This limitation applies to javascript as well. In fact, WebAssembly is executed by the Javascript runtime. Yes, the same runtime which is executing the javascript in your web application.
[https://medium.com/coinmonks/webassembly-whats-the-big-deal-662396ff1cd6]

Well, if WebAssembly is executed by the same Javascript runtime, then where are the performance gains everyone is touting about coming from? The answer is that the performance gains come from skipping the parsing steps and/or optimizing compilation steps. The WebAssembly is decoded and JITed instead of parsed and compiled before the JIT step. However, there is work still ongoing to make .NET IL interpretation reach the performance levels required to fulfill the promises
[https://hacks.mozilla.org/2017/02/what-makes-webassembly-fast/]

Remember that your Blazor code executes in the UI thread of the browser, which can create a bottleneck if your application is CPU bound. Ironically, the CPU/computationally intensive applications are also one of the most compelling use-cases for Blazor. You may need to look into running Blazor components in the Web Worker. We will cover this in a separate blog post dedicated to this technique.

Server-Side Blazor

by Sean McGettrick 

Server-side Blazor, previously referred to as Razor Components, allows developers the same freedom to create UI components using C# instead of Javascript that client-side Blazor does. The primary difference being that the code is hosted on the server instead of the browser. Blazor components and application logic written to run client-side can also be used server-side.

Razor Components support all the functionality a front-end developer would expect in a modern library including:

  • Parameterization
  • Event handling
  • 2-way data binding
  • Routing
  • Dependency injection
  • Layouts
  • Templating
  • CSS cascading

Razor Components can be nested and reused, similar to React.

Differences from Client-Side

With server-side Blazor, all components are hosted and served from an ASP.NET Core server instead of being run in the browser via WASM. Communication between client and server are handled via SignalR.

Further differences between client and server-side Blazor will be outlined in the next two sections.

Advantages

Server-side Blazor offers a number of advantages over its client-side counterpart. These include:

  • No WASM dependencies. Older desktop browsers and some current mobile browsers lack support for WASM. Since server-side Blazor only requires the browser to be able to support Javascript it can run on more platforms.
  • Building on the last point, since the components and application logic sit server-side, the application is not restricted to the capabilities of the browser.
  • Developing the application on an entirely server-based platform allows you access to more mature .NET runtime and tooling support.
  • Razor components have access to any .NET Core compatible API.
  • Application load times in the browser are faster due to a smaller footprint. Only the SignalR Javascript code required to run the application is downloaded to the client.

Disadvantages

There are, however, some disadvantages to using server-side Blazor:

  • There is higher application latency due to user interactions requiring a network round-trip between the browser and the server.
  • Since the application is entirely hosted on the server, there is no offline support. If the server goes down, the application will not function which breaks one of the core tenets of building a Progressive Web Application (“Connectivity independent: Service workers allow work offline, or on low-quality networks”).
  • With the server being responsible for maintaining client state and connections, this can create difficulty in scaling the application since the server is doing all the work.
  • The application must be hosted on an ASP.NET Core server.

Server-Side Blazor Code Re-Use, Razor Pages to Blazor using an MVVM approach

by Adam Vincent 

What is MVVM?

In a nutshell, MVVM is a design pattern derived from the Model-View-Presenter (MVP) pattern. The Model-View-Controller (MVC) pattern is also derived from MVP, but where MVC is suited to sit on top of a stateless HTTP protocol, MVVM is suited for user interface (UI) platforms with state and two-way data binding. MVVM is commonly implemented in Desktop (WPF / UWP), Web (Silverlight), and Mobile (Xamarin.Forms) applications. Like the other frameworks, Blazor acts much like a Single Page Application (SPA) that has two-way data binding and can benefit from the MVVM pattern. So whether you have existing MVVM code in the form of a WPF or mobile application, or are starting green with new code, you can leverage MVVM to re-use your existing code in Blazor, or share your code with other platforms.

You can find more information on MVVM on Wikipedia.

Example Presentation Layer

BindableBase 

At the heart of MVVM is the INotifyPropertyChanged interface which notifies clients that a property has changed. It is through this interface that converts a user interaction into your code being called. Usually, all ViewModels, and some Models will implement INotifyPropertyChanged therefore, it is common to either use a library (Prism, MVVM Light, Caliburn) or to create your own base class. What follows is a minimal implementation of INotifyPropertyChanged.

public abstract class BindableBase : INotifyPropertyChanged
{
    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

In this simplified model class, which derives from BindableBase, we have a CustomerModel with a single property FirstName. In this context we would probably have a customer filling out an input within a form on a website where they must fill in their first name. This input would be bound to an instance of CustomerModel on the ViewModel. While the customer is filling out the form, since we are in a two-way data binding scenario, each time the customer enters or removes a character from the form’s input box, SetField() is called and will cause the PropertyChanged event to fire.

public class NewCustomerModel : BindableBase
{
    private string firstName;
    
    public string FirstName
    {
        get => firstName;
        set
        {
            SetField(ref firstName, value);
        }
    }
}

Learn More: If you need to know more about INotifyPropertyChanged the Microsoft Docs cover this topic very well.

Model

With INotifyPropertyChanged out of the way, here is the entire presentation model.

public class NewCustomerModel : BindableBase
{
    [Display(Name = "Customer Number")]
    public string CustomerNumber { get; set; }
 
    [Display(Name = "Full Name")]
    public string FullName => $"{FirstName} {LastName}";
 
    private string firstName;
    [Required]
    [Display(Name = "First Name")]
    public string FirstName
    {
        get => firstName;
        set
        {
            SetField(ref firstName, value);
            OnPropertyChanged(nameof(FullName));
        }
    }
 
    private string lastName;
    [Required]
    [Display(Name = "Last Name")]
    public string LastName
    {
        get => lastName;
        set
        {
            SetField(ref lastName, value);
            OnPropertyChanged(nameof(FullName));
        }
    }
 
    [Display(Name = "Address")]
    public string Address => $"{Street}, {City}, {State} {PostalCode}";
 
    private string street;
 
    [Required]
    [Display(Name = "Street Address")]
    public string Street
    {
        get => street;
        set
        {
            SetField(ref street, value);
            OnPropertyChanged(nameof(Address));
        }
    }
    private string city;
 
    [Required]
    [Display(Name = "City")]
    public string City
    {
        get => city;
        set
        {
            SetField(ref city, value);
            OnPropertyChanged(nameof(Address));
        }
    }
    private string state;
 
    [Required]
    [Display(Name = "State")]
    public string State
    {
        get => state;
        set
        {
            SetField(ref state, value);
            OnPropertyChanged(nameof(Address));
        }
    }
    private string postalCode;
 
    [Required]
    [Display(Name = "Zip Code")]
    public string PostalCode
    {
        get => postalCode;
        set
        {
            SetField(ref postalCode, value);
            OnPropertyChanged(nameof(Address));
        }
    }
}

There are a few things to point out in this presentation model. First, please note the use of the Data Annotation attributes such as [Required]. You can decorate your properties to provide rich form validation feedback to your users. When the customer is filling out a form and misses a required field it will not pass the model validation. This will prevent the form from being submitted as well as provide an error message if one is configured. We will cover this more in the View section

The next thing I wanted to point out is I’ve covered SetField() in the INotifyPropertyChanged section, but there is an additional bit of complexity.

[Display(Name = "Full Name")]
public string FullName => $"{FirstName} {LastName}";

Note that the FullName property is a { get; }-only concatenation of the customer’s first and last name. Since we are forcing the customer to fill out first and last name in a separate form field, changing either the first or last name causes the FullName to change. We want the ViewModel to be informed of any changes to FullName.

private string firstName;
[Required]
[Display(Name = "First Name")]
public string FirstName
{
    get => firstName;
    set
    {
        SetField(ref firstName, value);
        OnPropertyChanged(nameof(FullName));
    }
}

After the SetField() is invoked in the base class, there is an additional call to OnPropertyChanged(), which lets the ViewModel know that in addition to FirstName changing, FullName has also changed.

Example ViewModel Interface

The example ViewModel below will expand on the model above. We’ll be using a simplified user story of “Creating a New Customer.”

Blazor supports .NET Core’s dependency injection out of the box, which makes injecting a ViewModel very simple. In the following ViewModel interface, we’ll need our concrete class to have an instance of NewCustomer as well as a method which knows how to create a new customer.

public interface ICustomerCreateViewModel
{
    NewCustomerModel NewCustomer { get; set; }
    void Create();
}

And the concrete implementation of ICustomerCreateViewModel:

public class CustomerCreateViewModel : ICustomerCreateViewModel
{
    private readonly ICustomerService _customerService;
 
    public CustomerCreateViewModel(ICustomerService customerService)
    {
        _customerService = customerService;
    }
 
    public NewCustomerModel NewCustomer { get; set; } = new NewCustomerModel();
 
    public void Create()
    {
        //map presentation model to the data layer entity
        var customer = new NewCustomer()
        {
            CustomerNumber = Guid.NewGuid().ToString().Split('-')[0],
            FullName = $"{newCustomer.FirstName} {NewCustomer.LastName}",
            Address = $"{newCustomer.Address}, {NewCustomer.City}, {newCustomer.State} {NewCustomer.PostalCode}"
        };
 
        //create
        _customerService.AddNewCustomer(customer);
    }
}

ViewModel Deep-Dive

In the constructor, we’re getting an instance of our ICustomerService which knows how to create new customers when provided the data layer entity called NewCustomer.

I need to point out that NewCustomer and NewCustomerModel serve two different purposes. NewCustomer, a simple class object, is the data entity used to persist the item. NewCustomerModel is the presentation model. In this example, we save the customer’s full name as a single column in a database (and is a single property in NewCustomer), but on the form backed by the NewCustomerModel presentation model, we want the customer to fill out multiple properties, ‘First Name’ and ‘Last Name’.

In the ViewModel, the Create() method shows how a NewCustomerModel is mapped to a NewCustomer. There are some tools that are very good at doing this type of mapping (like AutoMapper), but for this example the amount of code to map between the types is trivial. For reference, what follows is the data entity.

public class NewCustomer
{
        public string CustomerNumber { get; set; }
        public string FullName { get; set; }
        public string Address { get; set; }
}

Opinionated Note: Presentation models and data entities should be separated into their respective layers. It is possible to create a single CustomerModel and use it for both presentation and data layers to reduce code duplication, but I highly discourage this practice.

View

The last and final piece to the MVVM pattern is the View. The View in the context of Blazor is either a Page or Component, which is either a .razor file, or a .cshtml file and contains Razor code. Razor code is a mix of C# and HTML markup. In the context of this article, our view will be a customer form that can be filled out. There is also a button that calls the ViewModel’s Create() method when the form has been filled out properly according to the validation rules.

@page "/customer/create"
@using HappyStorage.Common.Ui.Customers
@using HappyStorage.BlazorWeb.Components
@inject Microsoft.AspNetCore.Components.IUriHelper UriHelper
@inject HappyStorage.Common.Ui.Customers.ICustomerCreateViewModel viewModel
 
<h1>Create Customer</h1>
 
<EditForm Model="@viewModel.NewCustomer" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div class="form-group">
        <h3>Name</h3>
        <LabelComponent labelFor="@(() => viewModel.NewCustomer.FirstName)" />
        <InputText class="form-control" bind-Value="@viewModel.NewCustomer.FirstName" />
 
        <LabelComponent labelFor="(() => viewModel.NewCustomer.LastName)" />
        <InputText class="form-control" bind-Value="@viewModel.NewCustomer.LastName" />
    </div>
    <div class="form-group">
        <h3>Address</h3>
 
        <LabelComponent labelFor="@(() => viewModel.NewCustomer.Street)" />
        <InputText class="form-control" bind-Value="@viewModel.NewCustomer.Street" />
 
        <LabelComponent labelFor="@(() => viewModel.NewCustomer.City)" />
        <InputText class="form-control" bind-Value="@viewModel.NewCustomer.City" />
 
        <LabelComponent labelFor="@(() => viewModel.NewCustomer.State)" />
        <InputText class="form-control" bind-Value="@viewModel.NewCustomer.State" />
 
        <LabelComponent labelFor="@(() => viewModel.NewCustomer.PostalCode)" />
        <InputText class="form-control" bind-Value="@viewModel.NewCustomer.PostalCode" />
    </div>
    <br />
    <button class="btn btn-primary" type="submit">Submit</button>
    <button class="btn" type="button" onclick="@ReturnToList">Cancel</button>
</EditForm>

The first thing to note is at the top of the code. This is how we use dependency injection to get an instance of our ViewModel.

@inject HappyStorage.Common.Ui.Customers.ICustomerCreateViewModel viewModel

Easy! Next, we need to create the form. The  needs an instance of a model to bind to, our NewCustomer ViewModel, and a method to call when the user submits a valid form.

<EditForm Model="@viewModel.NewCustomer" OnValidSubmit="@HandleValidSubmit">
...
</EditForm>

Next, we bind each property to their respective input fields. Blazor has some built-in   helpers which help you accomplish the binding. They are still under development and you may find some features are lacking at the time of writing. Please refer to the docs in the note below for more up-to-date info.

Note: The  is something I’ve created as a replacement for the asp-for  tag-helper that retrieves the DisplayAttribute from the presentation model classes. That code is available in the GitHub repository listed at the top.

<LabelComponent labelFor="@(() => viewModel.NewCustomer.FirstName)" />
<InputText class="form-control" bind-Value="@viewModel.NewCustomer.FirstName" />
 
<LabelComponent labelFor="(() => viewModel.NewCustomer.LastName)" />
<InputText class="form-control" bind-Value="@viewModel.NewCustomer.LastName" />

The magic here is bind-Value which binds our  text box to the value of the ViewModel’s instance of the NewCustomerModel presentation model.

Note: You can view full documentation on Blazor Forms and Validation here.

Last but not least, we’ll need some code to call our ViewModel’s Create() method when the form is submitted and valid. We’ll also need the onclick=ReturnToList I’ve defined for the Cancel button.

@functions {
    private void HandleValidSubmit()
    {
        viewModel.Create();
        ReturnToList();
    }
 
    private void ReturnToList()
    {
        UriHelper.NavigateTo("/customers");
    }
}

Conclusion

That’s it! In summary, I’ve covered what MVVM is, how Blazor can benefit from it, as well as an in-depth look at a simple example of how we can create a form with validation and rich feedback to the user. It is also important to reiterate that this example works not only in Blazor but can also be used in Windows Presentation Foundation (WPF) desktop applications as well as on other platforms. Please check out the GitHub repository as I continue to develop and expand on this concept.

Developer Gotchas

by Morgan Baker 

Working with a new framework like Blazor always has its learning experiences. The goal of this section is to help alleviate headaches by providing common problems and solutions we encountered with Blazor.

  • My localization isn’t working!
    For this problem, check your route parameters. Depending on the type of parameter, the invariant culture is used by the route by default, allowing for no localization for URLs. This can be solved by allowing the parameter to be passed in as any type, and then validating the type in C# code before using it.
  • I can’t debug my C# code!
    Server-side debugging for Blazor doesn’t exist yet, but you’ll still be able to debug the whole application (assuming your server-side is using ASP.NET Core).
  • I can’t see my C# in the browser!
    C# code in Blazor is compiled through WebAssembly before being delivered to the browser. When this happens, the C# can’t be displayed in the browser. However, you can still see the code in Chrome through remote debugging. Follow these steps.
  • Why isn’t my new route working?
    Most of the time you’ll need to rebuild the application to get new routes on development applications. Other causes might be naming problems or a problem with the route parameter types.
  • Everything seems to be loading slow
    This can be multiple issues, some of which are not Blazor-specific. However, for the Blazor-specific issues, it varies between server and client. Any page using server-side Blazor must make an HTTP call to the server, which deals a hit to performance. Any site using client-side Blazor will have a long initial load time, then be more relaxed later.
  • I’m seeing a blank page and I set everything up correctly!
    This is a specific one that I ran into when first using the templates in Visual Studio 2019. The solution was making sure I had the right .NET Core SDK installed. You can have the wrong version and still create a Blazor website with no errors, at least until the app starts running. You can install the latest version of the .NET Core SDK here.

Online Resources

by JP Roberts III 

As of the writing of this blog post, Blazor is still a new framework, and as such, is still changing rapidly. Pluralsight doesn’t have any courses covering Blazor, Udemy only has a couple of short videos, and Microsoft’s Learning site has no specific courses dedicated to Blazor.

However, there are several websites that have a good deal of information and samples for developers:

YouTube also has several informative videos on Blazor, such as a two-part series on the Microsoft Visual Studio channel: Blazor – Part 1 , Blazor – Part 2.

Some Updates for Global Azure Virtual Network (VNet) Peering in Azure

Last year, I wrote a blog post discussing Global VNet Peering in Azure to highlight the capabilities and limitations. The use of global peering at that time was significantly different in capability from local peering and required careful consideration before including in the design. Microsoft is continually adding and updating capabilities of the Azure platform, and the information from my original post requires updates to describe the current state of VNet peering.

The virtual networks can exist in any Azure public cloud region, but not in Azure national clouds.

Update – Global VNet peering is now available in all Azure regions, including Azure national clouds. You can create peering between VNets in any region in Azure Government, and peering can exist between US DoD and US Gov regions. The peering can span both regions and subscriptions.

Azure's Global Footprint
The above image shows Azure regions and the global footprint.

In Azure commercial, a peering can also be created between VNets in different Azure Active Directory tenants using PowerShell or command-line interface (CLI). This requires configuring an account with access in both tenants with at least the minimum required permissions on the VNets (network contributor role). In Azure Government, this is not currently possible and peered VNets must exist under the same Azure Active Directory tenant.

Resources in one virtual network cannot communicate with the IP address of an Azure internal load balancer in the peered virtual network.

Update – This limitation existed with the available load balancer at that time. Load balancers are now available in “Basic” and “Standard” tiers. The Basic load balancer is not accessible from a globally peered VNet. The “Standard” load balancer is accessible across global peering and has other additional features. A design can generally be adapted to replace Basic load balancers with Standard load balancers in high availability deployments where implementing global peering. Basic load balancers are a free resource. Standard load balancers are charged based on the number of rules and data processed.

Several Azure services also utilize a Basic load balancer and are subject to the same constraints. Please verify that the resources you are using for your specific design are supported.

You cannot use remote gateways or allow gateway transit. To use remote gateways or allow gateway transit, both virtual networks in the peering must exist in the same region.

Update – This is no longer accurate. A globally peered VNet can now use a remote gateway.

Transferring data between peered VNets does incur some cost. The cost is nominal within the same region. Cost may become significant when moving between regions and through gateways.

In summary, there have been significant updates to Global VNet Peering since my original post. The current capability now more closely aligns with local peering. These changes simplify network connectivity between regions, and the inclusion of multi-region redundancy makes disaster recovery more feasible.

Improve Networking and Connectivity in Your Environment. Contact AIS Today to Discuss Your Options.

Recently, I have been using the new windows terminal to run CMD and PowerShell commands while supporting clients. I wanted to write this blog to help answer some of the questions and issues I had while installing and customizing it.

Note: The New Windows Terminal is in PREVIEW. That means you may experience crashes or features may appear/disappear without warning.

The new terminal has an impressive set of features that I will detail below. These include:

  • Tabbed interface for Command Prompt and Multiple PowerShell versions
  • Support for Unicode characters so you can now use emoji in your scripts!
  • Rich customization options that can be modified to suit your preferences

Install Notes

Prerequisites

The first settings to check is your current version of Windows 10. You can find this by right-clicking Start and selecting System. Scroll down and look at the version you are currently running. You need to be running 1903 or later:

Windows 10 System Setting

Windows 10 System Settings

If you need to update to version 1903 (also called the Windows 10 May 2019 Update) you can open Windows Update by clicking Start, then Typing “Update”. Then click “Check for Update” in the Start menu. This will bring up Windows Update. From there you can click the “Check for Updates” button and apply the latest version. If no version appears you can manually download/install version 1903 here.

Install the New Terminal

Install the Windows Terminal (Preview) from the Microsoft Store. Fire that app up and search for Windows Terminal. Once you find it, click “Get” in the upper right. Ensure you are on a device in which you have logged in to with a Microsoft/Outlook.com/LiveID account. I had an issue with device authorization I had to work through before the store would allow me to download and install the terminal.

Once the install completes, you can start the terminal by clicking Start then typing Terminal. If you are a taskbar die hard (like me) you may also wish to pin the app:

Windows Terminal

The Interface

Once you fire up the terminal, you will immediately notice it looks different from a standard PowerShell or CMD shell. The tabs along the top allow you to run multiple shells in the same session. You can also link to multiple versions of PowerShell by adding additional profiles to the settings JSON file. We will cover the customization of settings in the next section.

Multiple Versions of Powershell

Customization

One of the most exciting features of the new terminal is the ability to customize it. You can set custom background images (yes, even GIFs!). You can also change text color schemes, cursor shape and color, and background opacity.

To access the configuration settings, you need to click the down arrow at the upper right of the terminal. From there click “Settings”:

Terminal Configuration Settings

That will open the profiles.json in your favorite editor. On my system that’s VSCode.

Scroll down to the Profiles section:

Terminal Profile Section

To create your own profile copy and paste the following JSON above an existing profile:

{
"startingDirectory": "%USERPROFILE%",
"guid": "{565ed1db-1474-455e-9d62-cb9fc7eb3f59}",
"name": "PowerShell",
"background": "#012456",
"colorscheme": "Campbell",
"historySize": 9001,
"snapOnInput": true,
"cursorColor": "#FFFFFF",
"cursorShape": "bar",
"commandline": "powershell.exe",
"fontFace": "Courier New",
"fontSize": 12,
"acrylicOpacity": 0.5,
"useAcrylic": false,
"closeOnExit": true,
"padding": "0, 0, 0, 0",
"icon": "ms-appdata:///roaming/pwsh-32.png"
},

From there, we can use this structure to begin our custom profile.

Important: The GUID above must be unique for each profile. You can change one character or use PowerShell Cmdlet New-GUID to generate a completely new GUID. If there are overlapping profile GUIDS, unexpected behavior will result.

Next, let’s look at the implementation details of each customization:

Acrylic Settings

The acrylic setting allows you to set the opacity to the background of the terminal. When the terminal window is in focus, there is a cool translucent effect allowing you to see the windows behind the terminal. When the window is out of focus, the opacity is cranked back up, and the terminal becomes fully opaque once more.

CMD in Focus:

CMD in Focus

CMD Out of Focus:

CMD Out of Focus

Note: If you use a background image, Acrylic needs to be disabled (set to false). As of this writing, acrylic does not support the overlay of a background image.

Background Images

You can add a background image to a specific profile. The image can be static or a GIF. You can add a background image with the addition of the following key/value pair in the profile:

"backgroundImage" : "/aisbackground.jpg",

This will change the default background to the image you have added:

CMD Background Image

Or you can get creative and add a GIF:

"backgroundImage" : "/nyan.gif",

Fun GIF

Note: If you set a GIF as a background, you should also add the following key to the profile containing the GIF:

"backgroundImageStretchMode" : "uniformToFill",

Color Schemes

There are default color schemes included if you scroll down to the Schemes area in the profile JSON. The default names you can use are (Pay attention to the case below, it matters):

  • Campbell (The new default color scheme for Windows Console)
  • One Half Dark
  • One Half Light
  • Solarized Dark
  • Solarized Light

You can modify the Hex values for the existing schemes or copy/paste one of the above and rename/edit it how you see fit.

These color schemes can also be applied to standard CMD console through the Microsoft ColorTool.

Cursor Share and Color

In addition to overall color schemes, you can modify the shape and color of the cursor in your custom profile.

Here are the other options and their settings for cursor shape:

Important: Note the camelCase, once again, these properties are case sensitive.

bar

"cursorShape" : “bar",
Cursor Shape Bar

emptyBox

"cursorShape" : "filledBox",

Cursor Shape emptyBox

filledBox

"cursorShape" : "filledBox",

Cursor Shape filledBox

underscore

"cursorShape" : "underscore",

Cursor Shape Underscore

vintage

"cursorShape" : "vintage",

Cursor Shape Vintage

I also changed the cursor color to the blue from our company style guide:

"cursorColor" : "#0F5995",

Cursor Color AIS

Icon Setting

When you click the down arrow in the new terminal, you will notice a small blank space next to the CMD/Command Prompt shell.

Terminal Icon Setting

This can also be customized. I changed mine to the AIS logo in my custom profiles:

Terminal Custom Icon

To accomplish this, edit the Icon key in the profile as follows:

"icon" : "C:/Users/Clint.Richardson/aisfavicon.png",

Command Line (Target shell):

You may have noticed in the previous section that my choices of PowerShell version also changed. This allows me to run PowerShell 5 which ships with Windows 10. Or the new PowerShell Core 6. I also wanted to add a visual queue to the background image, so I knew when I was using version 6.

PowerShell Version 5

PowerShell Version 5

PowerShell Version 6

PowerShell Version 6

To enable version 6 in a custom profile, you first need to download and install PowerShell Core 6. After that you can make the following change to the command like key:

"commandline" : "pwsh.exe",

I also added the PowerShell Core 6 Avatar to my background image. If you would like the add the image it can be found here. I also had to convert the SVG to a PNG. You can do that here.

Emoji in Scripts

Finally, there is the concept the VSCode and PowerShell Core 6/The New Windows Terminal understand Unicode characters. What does that mean to us? EMOJIS IN SCRIPTS 😁😂😜!!!!

A straightforward example of this is to show the write-host Cmdlet in VSCode. First, we form our write-host then wherever we want to insert an emoji, we press “WIN-.” On the keyboard. That’s the Windows key and the period. From that menu, we can insert our emoji into our PowerShell script.

Emojis in Script

Once we save and run the script in the New Terminal, this is what we see:

New Terminal Script

In Closing

I hope this post has helped you to understand the customization options available in the new Windows Terminal. In the future, I’m sure the customization options will receive better documentation or maybe a UI configure them.

Now get to downloading, and I hope you have as much fun making the new terminal your own!