Blazor OceanAutoComplete Component

Introduction

Most line-of-business applications have use cases for an autocomplete control of some sort. For my upcoming Moo2U application, I need an autocomplete control for address (city, state, zip) and for products. I did look around before writing this component but found my business use case didn’t match other Blazor components I looked at.

Features

  • Has a highly customizable auto-complete experience.
  • Search callback to return items.
  • Selected item changed event when an item is selected or when the user leaves the control without selecting an item.
  • Change the appearance of the search results container by creating a class ocean-blazor-auto-complete-container and setting desired values.
  • Change the appearance of the selected search result item by creating these classes ocean-blazor-selected-search-result, ocean-blazor-not-selected-
    search-result, and ocean-blazor-not-selected-search-result:hover and setting desired values.
  • Handles the arrow up and down, page up and down, escape, enter, and tab keys.
    • Arrow up and down moves the selected item 1 item up or down.
    • Page up and down move the selected item 6 items up or down.
    • Escape closes the search results lists.
    • Enter and tab keys raise the selected item changed event and close the search results lists.

Desired User Experience

User experience in line-of-business applications is critical to the success of the application as measured by user productivity and lack of frustration.

Enable the user to enter a few characters and display a list of matching records.  Users must be able to navigate the list using the keyboard and then select an item.  Optionally, the user should be able to use their mouse for record selection and browsing.

Users must be able to dismiss the search results using the keyboard.

Users must be able to select a search result item using the ENTER or TAB keys or by clicking the item with the mouse.

Setup

Install Oceanware.OceanBlazor NuGet package for the client-side and/or the server-side applications.  If using a shared component library for your pages, also install the NuGet package as well.  See NuGet packages below.

For the server-side apps, edit the _Host.cshmtl file as shown below.  The two highlight areas show the required text you need to add.

For the client-side apps, edit the wwwrooot/index.html file and include the same below highlighted edits.

Text Snippets

You can copy these text snippets and add them to your files as required.

<link href="_content/Oceanware.Ocean.Blazor/css/ocean-blazor.css" rel="stylesheet" />

<script src="_content/Oceanware.Ocean.Blazor/ocean-blazor.js"></script>

Usage

Home Address

The below image captures the razor markup for the Home Address City field.

Component Specific Properties

  • @bind-Value is the binding to the model property, in this case, the model object is Person, the property is City.
  • MinimumSearchLength is the minimum number of characters entered before the SearchCallback is invoked. The default value is 1, the above is set to 2.  The best value for this property is dependent on your application, the amount of data, the amount of data returned by the user entering 1, 2, 3, … characters.
  • TItem is the object type that will be returned in the search results.  In this case, it’s the CityStateZip class.
  • ItemStringSelector is the function that will return a string from the selected item. In this case, each time a record is selected the City property will be used to populate the OceanAutoComplete input control.
  • SearchCallback is the function that will be invoked when the minimum number of characters has been entered by the user.  This function will return an IEnumerable<T> where T is a TItem.
  • SelectedItemChanged is a function that will be invoked when the user selects an item.
  • Debounce (not shown) is the time in milliseconds between the last keypress and the invocation of the SearchCallback.  The default value is 300.

SelectedItemChanged Function

The below CitySelectedItemChanged method is invoked by the OceanAutoComplete control when an item is selected.

Note: this method can be passed null for the selectedItem argument, so be sure to check if not null and handle null use cases as required. For the Home Address City, if the user enters a value not in the search results, the application considers this to be valid.  Each application is different.  The below Work Address Zip does not allow entries no in the search results.

The method sets the related property values and sets Focus to the field after the Home Address Zip which if the Work Address, Address Line One.

See the third video for how the Interop.Focus method works.  This method is actually in the Oceanware.Ocean.Blazor assembly and it invokes the JavaScript setFocus method to set focus the control with the id of, “workAddressLineOne.”

Work Address

In this use case, we are using the WorkZip as the lookup property.  Notice the changes from the above example highlighted in green.

SelectedItemChanged Function

This function is similar to the above one for the Home Address City. When the selectedItem is not null, the corresponding properties are set and the focus is moved to the phone.

If selectedItem is null, all the properties are cleared and focus returned to the Work Zip OceanAutoComplete.  This is one example of forcing the user to select an item from the search results before proceeding.

Customizing

The below CSS is taken from the ocean-blazor.css file from the above setup edits to _Host.cshtml file.

You can use the same class names in your applications site.css file to alter the look of the OceanAutoComplete Component search results.

  • ocean-blazor-selected-search-result is used to style the selected item in the search results.  The selected item is one that has been selected by the user using the keyboard.
  • ocean-blazor-not-selected-search-result is used to style search results that are not selected.
  • ocean-blazor-not-selected-search-result:hover is used to style a search result when the mouse is over that result.  Tip:  set the same values for this class as the ocean-blazor-selected-search-result to get the same look for keyboard selected and mouse over search result items.
  • ocean-blazor-auto-complete-not-found is used to style the not found template.
  • ocean-blazor-auto-complete-container is used to style the search results container.  If you change the background, be sure to match the background-color you assign with this class ocean-blazor-not-selected-search-result so that the colors will match.
    • Note:  don’t change the overflow properties as this will break the component.  The others can be changed to suit your application requirements.

Tip: You can copy the below text into your site.css and edit as required.  This is not a requirment if the default styling is compatible with your application.

.ocean-blazor-selected-search-result {
    background-color: gainsboro;
}

.ocean-blazor-not-selected-search-result {
    background-color: white;
}

    .ocean-blazor-not-selected-search-result:hover {
        background-color: gainsboro;
    }

.ocean-blazor-auto-complete-not-found {
    padding: .5em;
    border: 1px solid;
    width: 100%;
}

.ocean-blazor-auto-complete-container {
    cursor: pointer;
    border: 1px solid;
    width: 100%;
    max-height: 300px;
    position: relative;
    overflow-x: hidden;
    overflow-y: auto;
}

References

Before beginning this component, I studied these two components to get an understanding of the business use cases and a general structure for creating my own autocomplete component.

https://chrissainty.com/getting-started-with-blazored-typeahead/

https://github.com/SamProf/MatBlazor

Source

Project Source: https://github.com/Oceanware/BlazorAutoComplete

Ocean Library: https://github.com/OceanLibrary/Ocean

NuGet Packages

Oceanware.Ocean and Oceanware.Ocean.Blazor can be installed using Visual Studio.

All Oceanware NuGet Packages can be downloaded from here:  https://www.nuget.org/packages?q=OCEANWARE

Video

Oceanware OceanAutoComplete Component Demo (video of this source project)

Oceanware OceanAutoComplete Component (video from the Oceanware Ocean Library, OceanAutoComplete component and the demo project in the Ocean Library source project.)

Share Blazor Pages and JavaScript Across Assemblies

Close

I hope you find this demo useful in your Blazor projects.

Just a grain of sand on the world’s beaches.

Blazor OceanNumericInput Component

Introduction

I was checking out a very cool Blazor PWA written by Bradly Wells and noticed that the Blazor InputNumber Component does not support binding to Decimal or Int16 data types and does not support formatting the numeric input as of 10/20/2019.

I’m working on a Blazor Moo2U – A Real-World Application and will need a great user experience when editing numeric values, so I wrote this component.

OceanNumericInput Features

  • Supports binding to Int16, Int16?, Int32, Int32?, Int64, Int64?, Single, Single?, Double, Double?, Decimal, and Decimal? data types.
  • Has a FormatString property.
  • Prevents users from entering invalid numeric values and values with too many digits after the digits separator.
  • String formatting of the entered values uses the culture-specific numeric separator, digits separator, negative sign, and currency symbol.
  • Always uses CurrentCulture when performing string format operations.
  • Allows entering and displaying a number separator.
    • The stock Blazor InputNumber component does not allow comma entry or display as it uses the HTML 5 input with type=”number” that prevents a comma from being entered.
  • Easily enable mobile browser numeric popup keyboard, set the BrowserInputMode property to Decimal or Numeric.

Desired User Experience

User experience in line-of-business applications is critical to the success of the application as measured by user productivity and lack of frustration.

The input component should display numbers formatted to make it easy for the user to read the data.

  • 1,750,4565.99 is much easier to read than 17504565.99
  • 5,555.99 is easier to read than 5555.99

There are several lines of thought around using a masked editor control for numeric inputs.  I’ve never had a good experience with masked edit controls, so I don’t author them.  A non-masked edit control makes it easier to enter data, especially those mask controls that eat keyboard strokes.  When the control eats keyboard strokes and the user has their head down, unexpected results ensue and a frustrated user too.

I think a better UX is to allow the user to make their entry and then show an informative validation message if required.

Give developers the option to easily show popup mobile browser numeric keyboards on field entry. Blazor sites render fantastic on mobile devices, showing the correct keyboard for the various fields adds polish and increases user satisfaction.

Format numbers based on the user’s culture so that the input experience seems normal to them.

Non-Goals

Support hex and exponential numeric input.  This can be added if requested, but for line-of-business applications, I’ve never used these in an input field.

Usage

<OceanNumericInput BrowserInputMode="BrowserInputMode.Decimal" FormatString="N"
                    NumberOfDecimalPlaces="2" placeholder="Revenue" maxlength="10"
                    Class="form-control" id="revenue" @bind-Value="NonNullableNumerics.Revenue" />

Component Specific Properties

  • BrowserInputMode enables easily setting the underlying HTML input control, inputmode property.
  • FormatString takes a standard .NET format string or a custom .NET format string.  I find the N, N1, N2, etc. provides an outstanding UX. When set to “c” the currency symbol is displayed in the field.
  • NumberOfDecimalPlaces takes an integer that represents the number of digits to the right of the digits separator.
    • I added the property to make sure I had the correct number of digits.  I didn’t want to have to write a culture agnostic method to figure out the number of decimals places from a user-entered format string. This was and is simple; at least for now.
  • ParsingErrorMessage has a very good localized default value.  Developers can set this property and when a non-whole number input fails to parse the custom message will be displayed.
  • WholeNumberParsingErrorMessage has a very good localized default value. Developers can set this property and when a whole number input fails to parse the custom message will be displayed.
  • TooManyDigitsErrorMessage has a very good localized default value. Developers can set this property and when a number is entered with too many digits past the digits separator the custom message will be displayed.

Currency Input Options

This image captures two options for currency input using the component.

The corresponding HTML to get the above results. Taken from the below projects NonNullableNumericInputDemo.razor form.

NuGet Packages

Oceanware.Ocean and Oceanware.Ocean.Blazor can be installed using Visual Studio.

All Oceanware NuGet Packages can be downloaded from here:  https://www.nuget.org/packages?q=OCEANWARE

Source

Project Source:  https://github.com/Oceanware/Blazor-Numeric-Input-Component-Demo

Ocean Library: https://github.com/OceanLibrary/Ocean

Video

Close

I hope you find this demo useful in your Blazor projects.

Just a grain of sand on the world’s beaches.

Blazor Security Docs and Blog Posts

Introduction

I’m coming to Blazor with a WPF, Xamarin, and Angular background.  I’ve done a good bit of full .NET Framework Web API and .NET Core Web API.  But, I’ve not done any MVC or Razor page development.

As a result, many concepts in Blazor are new to me, especially the security model, having never used any of it.

An additional twist is that Blazor apps can be either server-side or client-side, each has different requirements.

I put this list of resources for myself, so I can get up to speed and for others who need to master these APIs.

Thoughts

If I was writing a public app, I would use Google, OAuth, Twitter, etc. authentication so that I didn’t have to have any forms or code to create an account, change password, forgot my password, etc.

For blog posts apps with multiple logins, internal authentication is easier so those blog readers don’t have to create multiple 3rd party accounts to use your app.  Moo2U is such an app as I have an admin, drivers 1 – 4, and many pubic e-commerce user logins.

Blazor Authentication and Authorization Resources

Blazor Docs

https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view=aspnetcore-3.0&tabs=visual-studio

Steve Sanderson Authentication and Authorization

https://gist.github.com/SteveSandersonMS/175a08dcdccb384a52ba760122cd2eda

Shaun Walker Oqtane blog post Authentication in Blazor

https://www.oqtane.org/Resources/Blog/PostId/527/exploring-authentication-in-blazor

Shaun Walker Oqtane Framework demonstration of a login form that works server or client-side.

https://github.com/oqtane/oqtane.framework/blob/master/Oqtane.Client/Modules/Admin/Login/Index.razor

Chris Sanity Security Series

https://chrissainty.com/securing-your-blazor-apps-introduction-to-authentication-with-blazor/

Michael Washington server-side cookie authentication

http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4316/A-Demonstration-of-Simple-Server-side-Blazor-Cookie-Authentication.aspx

Michael Washington server-side Google authentication

http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4356/Google-Authentication-in-Server-Side-Blazor.aspx

Ed Charbeneau Authentication and Authorization

https://edcharbeneau.com/blazor-authentication-authorization/

Visual Studio Magazine

https://visualstudiomagazine.com/articles/2019/06/13/aspnet-core-preview-6.aspx

Heather Downing Build an Authenticated Web App in C# with Blazor + ASP.NET Core 3.0 (App uses 3rd party auth with https://www.okta.com/)

https://scotch.io/tutorials/goodbye-javascript-build-an-authenticated-web-app-in-c-with-blazor-aspnet-core-30

Mike Brind Simple Authentication In Razor Pages Without A Database

https://www.mikesdotnetting.com/article/335/simple-authentication-in-razor-pages-without-a-database

Close

If you know of more resources, please post a comment or hit me up on Twitter and I’ll add them.

Thank you and have a great day,

Just a grain of sand on the world’s beaches.

Blazor Simple CQRS with MediatR

Strong Recommendation

I strongly recommend you take the time to watch NDC 2018 session entitled Vertical Slice Architecture – Jimmy Bogard at the bottom of this blog post.

Unless you give yourself a chance to understand MediatR and the motivations for using it, you won’t get much out of the blog post. After this one hour video, come back and read this blog post.

This blog post examines using MediatR in Blazor applications.

Introduction

I’m a pragmatic software architect and developer. I try to write the most straightforward code that can easily be understood and maintained over time. When learning and adopting a new UI stack or platform, I spin up spikes to learn the API’s, figure out cross-cutting concerns, and discover patterns that are a natural fit. Individual spikes allow me to explore and learn concepts and patterns without the noise of an entire application.

In 2004-2008, I wrote a good number of ASP.NET Web Forms applications for customers around the United States. These were e-commerce, online bill pay, tax assessment, customer portal, and property tax applications. Many of the forms required dropdowns and other data that was directly related to performing an insert or update. In other words, the shape of the data to load the form was different than the shape of the data to perform the user action. All of my forms hit the database once during load and returned the data for the form (dropdown data was cached). I wrote a two-way data binder control that automatically performed the insert, updates, or deletes. I was doing an elementary form of Command query responsibility segregation (CQRS) without knowing it.

The pattern of querying data and getting a different shape than the shape of the data to update, delete or insert, was as natural, simple, performant, and easy to understand and maintain. I didn’t need a masters degree in software design to write the code this way, it just made sense.

This blog post covers my first spike for the Blazor Moo2U application I’m writing. The goal of this blog post is to discover if the CQRS pattern is a good fit and if the MediatR library can help implement the pattern.

In this blog post, we will be looking into a server-side Blazor app. In server-side Blazor apps, UI logic can be located in either the @code block in the .razor file, in a code-behind C# file, or view model file.

I’ve grown attached to the code-behind file pattern. It fits Blazor very well as the UI binds to properties, events, methods, and cascading parameters quite nicely. I like the tooling for C# files and it feels better than in a @code block. Although, @code blocks do make it easier when presenting since the HTML markup and code can be easily seen together.

Client-side Blazor is scheduled to ship in May 2020. For now, I’ll be sticking to server-side Blazor until Steve Sanderson declares there should be more breaking changes in future client-side releases. I fully expect to easily refactor any applications I’ve written using the server-side model to the client-side model when appropriate.

Source

https://github.com/Oceanware/BlazorMediatr

Goals

  • Author a testable, understandable, and maintainable application.
  • Execute code to get the required data for forms and execute a method to persist changes based on user action in the UI.
  • Enable cross-cutting concerns such as logging, auditing, validation, enabling retries, etc.
  • Use an application structure that supports medium to large size developer teams and embraces change.
  • Use patterns that empower developers to write code quicker with no or fewer defects.

Blazor CQRS with MediatR Library Video

Video walkthrough of the project.

CQS & CQRS Patterns

The command–query separation (CQS) and command-query-responsibility-segregation (CQRS) patterns have been written about for years. There are many books, blog posts, and YouTube videos covering these subjects.

Almost without exception, all of my web, desktop, and mobile applications load their UI with data that is shaped differently than the data used to persist the insert, update, or delete operations.

The CQRS pattern defines a query for getting data, and a command to perform actions such as saving the form data.

We use this pattern at work on a very large Angular – Web API project with great success with developers of all skill levels and experience.

Is CQRS For Me?

If you read the below links, you can see that CQRS is more than queries and commands. Some of the links provide advice to not use CQRS if your app is simple and CRUD patterns would suffice. Obviously, the app presented here is a straightforward app that doesn’t require CQRS.

I would recommend you not base your decision solely on one metric, instead base your decision on how well this or any pattern, framework, or tool enables you to meet your GOALS and fulfill your requirements. Base your decision on the long-term impact and advantages your code and team receive.

CQRS Links
Microsoft Command and Query Responsibility Segregation (CQRS) pattern
Martin Fowler CQRS
Eleven labs CQRS Pattern
Google Search for CQRS

MediatR

What is, and what does MediatR provide?

From the MediatR GitHub ReadMe

Supports request/response, commands, queries, notifications, and events, synchronous and async with intelligent dispatching via C# generic variance.

From the MediatR Wiki

A low-ambition library trying to solve a simple problem – decoupling the in-proc sending of messages from handling messages.

The desire to write decoupled code does not have to come with a big price tag or bloated infrastructure. MediatR has no dependencies, is cross-platform, supporting all of .NET. MediatR is a library that helps implement the CQRS pattern in .NET applications.

The Pattern

MediatR usage is predictable and straightforward. A request is made, the handler handles the request and returns T. You’re an expert now.

The below code is from the SelfContainedExampleBase class. Mediator is injected into the class. To make a request use the Send method and pass the IRequest or IRequest argument. Mediator will invoke the appropriate handler. The handler will return the requested T object.

The below ViewModel is the EditForm Model for the SelfContainedExampleBase.razor page.

The SelectionsDto is returned by the handler and the ViewModel is populated. Roles and Names are the values that are displayed in the two InputSelect controls in the UI. The two InputSelect controls bind their values to the SelectedRole and SelectedName properties respectively. I’m showing only the Roles InputSelect for brevity.

protected override async Task OnInitializedAsync() {
    var selections = await this.Mediator.Send(new GetSelectionsQuery());
    this.Model = new ViewModel(selections.Roles, selections.Names);
}

public class GetSelectionsQuery : IRequest {
}

public class ViewModel {

    public IList Names { get; }
    public IList Roles { get; }
    public String SelectedName { get; set; }
    public String SelectedRole { get; set; }

    public ViewModel(IList roles, IList names) {
        this.Roles = roles;
        this.Names = names;
    }
}

<p>
    <label for="role">Role: </label>
    <InputSelect id="role" @bind-Value="Model.SelectedRole">
        <option value="">Select role ...</option>
        @foreach (var role in Model.Roles) {
            <option value=@role>@role</option>
        }
    </InputSelect>
</p>

The above has a simple implementation and comes at very little cost. The query requests all data required by the form; that data is used to populate a class that acts as the EditForm's Model, in our case a ViewModel instance. Remember, a view model is just a model class that provides data that is shaped specifically for its view.

Below, when the button is clicked the VerifySelections method is invoked. The VerifyAnswerCommand is processed the same as the above query. Like most commands, the VerifyAnswerCommand has a few properties that will be used by the handler. The handler returns a Boolean result and we update the UI accordingly.

<button class="btn btn-primary" @onclick="@VerifySelections">Verify Selections</button>

public async Task VerifySelections() {
    var result = await this.Mediator.Send(new VerifyAnswerCommand { 
        Name = this.Model.SelectedName, Role = this.Model.SelectedRole 
    });
    if (result) {
        this.Result = $"Outstanding, {this.Model.SelectedName}'s role is {this.Model.SelectedRole}";
    } else {
        this.Result = "Sorry give it another try.";
    }
}

The Two MediatR Implementations

I’ve provided two implementations of using MediatR so that you can compare them and if desired, adopt the one that fits your application, team, and requirements.

Self Contained SelfContainedExample
In Jimmy’s video, he showed the Self Contained version in his MVC Razor page app. All the required classes (less repository) are in the one file. Blazor server-side Razor pages can also be authored using this approach. Client-side apps will need to use the below Web API Style approach since the MediatR code will be in the controller route handlers.

This approach isolates the code from the rest of the application, making it almost impossible to introduce a bug in other unrelated code when making changes in the future to this code or any other code in the application.

Web API Style WebApiStyleExample
This approach places the queries, commands, handlers, and models in a familiar separate folder structure. You can see the green highlighted classes and their locations. The above self-contained version, highlighted in orange is a single file.

This is the approach you’ll use in Web API apps like a Blazor API for client-side apps. The Web API controllers will be very thin, each route handler containing the Mediator.Send call.

I have been considering the Web API Style approach for Blazor Moo2U because while the initial release will be Blazor server-side, I know that I will eventually refactor to the Web API / Blazor client-side app. Of course, refactoring a single file class to separate files is easy too. Got to love choices.

Pro’s and Con’s

Cons

  • More classes, more files.  Yes, we essentially took service methods and make each of them a handler class.

Pros

I’ve written some of the below Pro’s using different wording to hopefully enable the reader to see the valuer from multiple perspectives.

  • Mitigate service layer class bloat as features are added to the app over time since they are all handlers now instead of service methods.
  • Team development has way less merge conflicts when modifying a feature.
  • Team development has no merge conflicts when adding a feature since we are only adding code, no need to modify anything to add a feature.
  • Much easier to add a feature or modify one, since each feature is its own vertical slice of code.
  • MediatR has a built-in pipeline that effortlessly enables decorating handlers, resulting in effortless cross-cutting concern implementation.
  • Query responses provide everything a form requires to function.
  • Using this approach, to add a feature, you’re adding code, not changing existing code.
  • Imagine working on a large open source app like Moo2U, where multiple developers could be adding features simultaneously. This app structure easily supports this scenario without conflicts between developers.

Pipelines & Decorators

The MediatR library enables implementing cross-cutting concerns such as validation, logging, auditing, etc., by configuring the DI container. The developer does not have to deal with any of the code to handle these because MediatR organically supports a pipeline approach to processing messages and returning responses.

Blazor Moo2U will have all cross-cutting concerns handled by the MediatR pipeline.

Note: There is a difference between Blazor server-side application and a Web API application with respect to cross-cutting concerns. This is because Web API has its own pipeline to handle things like validating the model passed to the route handler and for catching exceptions and returning to the client caller the correct HTTP Status Code.

Pipeline Links
Mediatr Pipeline Examples
MediatR Behaviors
Tackling Cross-Cutting Concerns With A Mediator Pipeline
Add Validation To A Mediatr Behavior Pipeline
Defining Cross-Cutting Concerns Using The MediatR Library

MediatR Links

MediatR Wiki Docs
CQRS Using MediatR ASP .NET Core
A Non Trivial Example of MediatR Usage
MediatR YouTube Videos

Vertical Slice Architecture – Jimmy Bogard

Highly recommend you watch this video, you’ll learn a lot that can help you decide if this is for you and your team.

Close

There are no silver bullets in our profession. We look at the available information, compare with our requirements, and make the best decision.

Give, my stated goals, I think the CQRS pattern and MediatR Library will provide significant value to the Blazor Moo2U application.

I hope you find this information helpful. Enjoy authoring your Blazor applications!

Just a grain of sand on the world’s beaches.

Blazor Moo2U – A Real-World Application

Introduction

New frameworks and new UI stacks are the nature of our profession. The web technologies change more often than the desktop. For years, web development was the wild-west as technologies were changing monthly. Now that the big players: Angular, Vue, React, and Aurelia have stabilized, developers can select a web single-page-application (SPA) UI stack that best meets their business requirements. They can do this with confidence that their choice will serve them for many years to come.

Microsoft ASP.NET also has MVC, Razor Pages, and Web Forms to create web applications.  Back in 2003, I used Web Forms 1.0 to develop many websites for our customers.  I’ve not had any production experience with MVC or Razor Pages UI applications. Over the years, I have used .NET Framework Web API and .NET Core 2 Web API in large internal applications for my customers.

I’m explaining this because Blazor is a new ASP.NET Core 3, web UI technology stack.  I have little context or experience with Razor Pages and the whole ASP.NET Core UI technologies. So I’m approaching Blazor differently than other architects or developers that have a lot of real-world, production experience with ASP.NET UI stacks.  Most of the terminology is foreign to me. Configuring the server from scratch, using “app.Use{…….} is new to me.  Obviously, I have much to learn about configuring an ASP.NET Core application, ensuring it is secure and leverages the best practices for CORS, XXS, click-jacking, and more.

I’ve created several Blazor applications and even ported my Ocean validation and character case correction library to support .NET Core 3 and Blazor applications. I like Blazor and see so much potential.  Today, I see internal line-of-business applications as a good fit for Server-Side Blazor.  The Client-Side Blazor applications are in beta as of (Sept 2019) and will RTM in the future. Once both Server-Side and Client-Side Blazor mature, the Blazor sweet-spot will emerge and be well understood by the community.

You can detect I’m cautious about choosing a UI stack for an application.  I strongly believe in selecting a UI stack based on how well it fits the application requirements and nothing else.  Requirements first, then do proper research on current and emerging technologies and make an informed decision.  For line-of-business applications always be cautious of emerging technologies.  For personal projects, go for it, the wild-west is fun, but for costly business application, be careful.  Rember Silverlight and the jumping ship of WPF, I stuck with WPF because it met all our requirements.

When evaluating a new UI stack, I want to do it thoughtfully, with real-world data, and scenarios. Lose the new and shiny mindset and desire to be one of the “in-crowd.” Learn the new stack, push it hard, do your own research, and learn from other early adopters in the community. Also, give the new technology time to stabilize as many new technologies suffer from lots of breaking changes as the product is being developed.

Blazor is in RC1 today (9/22/2019), and the Server-Side Blazor stack will RTM next week.  For me, its time to push the envelope and take it out for a test drive.

Let’s Prove Blazor Scenarios

For my evaluation, I’ve chosen to create a Blazor version of an application I wrote almost 2 years ago, Moo2U (see below Xamarin.Forms Moo2U section). Recreating an application I designed (software design) and know intimately allows me to know my use cases for the application without having to spec out an application from scratch.

Xamarin.Forms Moo2U, is a single delivery driver application that also includes sales and delivery analysis.  The application showcases the Infragistics Xamarin Forms charts and gauges as they display and compare several years of data.

Blazor Moo2U expands the use cases and application scope in the following ways:

  • Internal office desktop application that enables taking orders over the phone, scheduling deliveries for multiple drivers, and analysis of all data utilizing grids, charts, and gauges.
    • The initial application will use community Chart components.
    • When Infragistics releases Blazor components, I’ll add Infragistics version of all analysis pages.
  • Driver delivery application that is accessed by the driver using a mobile phone or Visual Studio mobile device emulator.
  • Online sales application that allows public customers to place an order using their desktop or mobile device.

Application Features

  • ASP.NET Core Security – follow all Microsoft’s and community experts advice for securing a Blazor application and web site.
  • Cross-cutting concerns
    •  Security
      • Office users and drivers will have logins and roles assigned.
      • Public users will have accounts and roles assigned.
    • Exception handling
    • Instrumentation
    •  Validation
      • Rich form and business object validation using Ocean
    • Form Entry Case Correction
      • Rich character case correction for all form fields, allow internal users to modify behavior real-time.
  • All customer address are valid addresses in the Indianapolis, IN area.
  • Will be seeded with two years of data.
  • Will have four delivery drivers.
  • Fully testable.

The above applications will be hosted by the same server and will have different a URL for entering them.

  • /index – Home page, used to navigate to an application and to kickoff the initial loading of historical data and orders.
  • /office – internal office application
  • /order – online ordering application
  • /delivery – driver delivery application

Out of Scope

  • Automatic delivery routing of customer orders would require third-party API’s and potentially not be free. For this release, I’ll preconfigure routes in the correct order.

Xamarin.Forms Moo2U

I originally wrote Moo2U while working at Infragistics in January 2018. I was working on the Control Configurators for Xamarin Forms and WPF and needed a showcase application for the Configurators and our new Xamain.Forms controls.  At that time I was in Bulgaria working with our team there.

I got the idea of a delivery truck application because, in Sofia, they have milk delivery trucks.  I got to work with two awesome UI/UX designers Spasimir Dinev and Stefan Ivanov and we created Moo2U!

The Moo2U application loads years of delivery data and purchasing history to show off the Infragistics charts and gauges and stellar UI/UX.

Moo2U for Xamarin.Forms is available here.

After downloading, recommend you do NOT update any NuGet packages.  Just compile, run, and have fun.  If you update the NuGet packages, you’ll have breaking changes cause by updates to Prism.  The Prism updates are good, but not needed to run the Xamarin Forms Moo2U application. If you need the application updated, contact Infragistics support and request they update their showcase application.

Moo2U Deliveries

Application Design

These are my initial thoughts as I dive into creating this application:

  • Try and use the platform as provided by Microsoft.  If I go off and write a lot of customized code, that could impact my analysis of the Blazor product.
  • This application will be built over time, just like real-world applications.  Features added feedback received, features added or modified. As such, I’ll be using Jimmy Bogard’s Mediatr so that I can work on vertical slices of the application over time. At my work, we are using Mediatr and I’ve come to greatly respect it.  It’s the first time I’ve used it and see great value and results that it brings to our large Angular / ASP.NET Core Web API application.
    • Mediatr enables a simple CQRS design to applicaitons.
    • Mediatr is simple to use and author your applications.
    • The end result is an application that is easy to extend or modify and has a clean separation of data reading and writing.
  • Use SQL Server LocalDb.
  • Use Entity Framework (EF) Core Code-First and AutoMapper.
    • Entity types in the Data.dll will be internal classes so that they do not leak out to other assemblies.
    • EF or any ORM, and its classes should NEVER leak into your application. Use AutoMapper to return types defined in your application’s shared assembly that contains all front-end types for editing, DTO’s, enums, constants, et al.
    • I’ve never been a fan of EF and have always used my own data stack that I wrote. I think the complete rewrite of EF Core from the ground up has resolved most of my concerns.  We use it at work and have not had any problems.  Congrats to the EF team on a stable product.
  • A stretch goal is to add the ability to swap out the Data.dll for another that uses Azure or AWS cloud services without requiring any additional code changes.

Source Code

When I made my initial push to GitHub, I’ll blog about.  At the moment, I’m waiting for Blazor to RTM, and Visual Studio .NET Core 3 support to get out of Preview.

Close

But, I’m not sitting around!  I’ve started Blazor Power Toys extension for Visual Studio 2019 so that we can easily create Blazor edit forms based on types in our applications.  XAML Power Toys is a similar extension for creating XAML edit forms.

Thanks for joining me in this journey to see what Blazor can do in a real-world application,

Enjoy!

Just a grain of sand on the world’s beaches.

 

 

 

 

 

 

 

 

Easily Collapse – Expand All Swagger Groups

Swagger is an excellent tool for running your Web API endpoints. One feature it needs is the ability to quickly collapse or expand all groups.

With a button to do this, we need to get creative, and Google Chrome Snippets is an easy solution for us.

Step One: Read about Google Chrome Snippets

Step Two: Create the required snippet in Chome Developer Tools

  • Open Chrome
  • Open Chrome Developer Tools (F12)
  • Open Snippets by clicking Sources, “>>” and selecting Snippets
  • Create a new snippet, name it whatever you want, I named mine, “Collapse-Expand-Swagger” and paste in this code:
var all = document.getElementsByClassName('expand-operation');
for (var i = 0; i < all.length; i++) {
  all[i].click();
}

Step Three: Run your snippet

  • Open Chrome
  • Navigate to your Swagger page
  • Open Chrome Developer Tools
  • Use on of the methods described here to run your snippet: Google Chrome Snippets
  • Depending on the number of groups, it can take 2 -3 seconds to collapse them all.
  • Close Chome Developer Tools

Close

Other browsers may also have snippets, check the docs on your browsers developer tools.

Enjoy!

Just a grain of sand on the world’s beaches.

Angular 7 Azure Functions SignalR Custom Authentication

Introduction

I’ve been working on an Angular 7 game that has a multi-player over the Internet feature, so I was time to learn Microsoft Azure!

I chose Azure to host the game, store users in Azure Table Storage, and provide real-time communication features using Azure SignalR.

I wrote this reference implementation that combines Angular 7, Azure Functions, Azure SignalR, and Custom Authentication for the Azure Functions endpoints so that I could learn all the pieces and how they fit together.

Additionally, this application uses a custom IBinder imperative output binding for creating the SignalRConnectionInfo.  The SignalRConnectionInfo contains the JWT token that the client SignalR Hub uses when communicating with the Azure SignalR Service. This application demonstrates injecting an authenticated users UserId into the token, this is required by the SignalR Service to send messages to specific users.

Refactoring 6/24/2019

I refactored the code to simplify and make it cleaner. Of note is the Client signal-r.service.ts; it now uses async await to make the startSignalR method much easier to read and understand, since it now has top -> bottom flow.

The app.component.ts now uses the SubSink package to unsubscribe from Subjects properly.

I also removed all the magic strings from the Server app.

What Can You Learn From This Application and Videos?

  • How to configure a Visual Studio 2019 Azure Functions project to communicate with SignalR
  • How to authenticate a user against a database and then return a JWT authorization token
  • How to implement custom authentication for Azure Function endpoints
  • How to include an Authorization Bearer token with an HTTP call to the Azure Functions endpoints
  • How to validate and read JWT tokens
  • How to request and return JWT tokens for SignalR
  • How to start a client SignalR Hub
  • How to send a SignalR message to one or more users
  • How to create a custom IBinder imperative output binding for an Azure Functions
  • How to use a GateKeeper to simplify authenticating Azure Functions endpoints

Source Code

Download or clone this GitHub repo:  https://github.com/Oceanware/Angular-Azure-SignalR-CustomAuth

Prerequisites

Server Application: Visual Studio 2019 with the Azure Development Workload installed. Visual Studio 2019 for the Mac will probably work, I’ve just not tested it.

Client Application: Standard Angular 7 tooling setup, editor of your choice.

Videos

Full Video Series Playlist

https://www.youtube.com/playlist?list=PLFZfBw9eNzgzojmcvLlO0a0gw-n6sdInd

Individual Videos

0. Refactored Code – Cleaner Better – WATCH Me First

Since publishing the other 7 videos and the code, I’ve refactored the code and made it cleaner.

Of note is the Client signal-r.service.ts which got a nice async await upgrade.

I also removed all the magic strings from the Server app.

1. Azure SignalR, Source Code Installing, Configuring, and Running The Applications

This is the first of seven videos in this series explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how to get the source code, configure it, then run the application.

2. Seeding The Database

This is the second in a series of seven videos explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how an Angular 7 Client application calls an Azure Function endpoint that will seed an Azure Table Storage table with users for the app.

3. Logging Into Azure Application Using Custom Authentication

This is the third in a series of seven videos explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how an Angular 7 Client application logs into an Azure Functions application. The users are validated against users in an Azure Table Storage table, and if authenticated, the caller is issued a JWT authorization token.

The caller will then use the token for future calls to Azure Function endpoints that require an authorization token.

4. Getting A SignalR JWT and Start Client SignalR Hub

This is the fourth in a series of seven videos explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how an Angular 7 Client calls an Azure Function to get an Azure SignalR JWT and then start the client SignalR Hub.

5. Sending SignalR Messages To One Or More Client Applications

This is the fifth in a series of seven videos explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how an Angular 7 application can send a request to an Azure Function that publishes a SignalR message to one or more client applications.

6. Deep Dive – SignalRConnectionInfo & IBinder Output Binding

This is the sixth in a series of seven videos explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how to use a custom Azure Function Output Binding to create the SignalRConnectionInfo JWT token and embed the authenticated users UserId in the token.

The custom solution is more secure than the default Input Binding SignalRConnectionInfo provided by the SDK. Microsoft will be offering a solution of this type in a future release.

7. Deep Dive – Custom Authentication – Gatekeeper – Token Tools

This is the seventh in a series of seven videos explaining an application that uses Angular 7, Azure Functions, SignalR, and Custom Authentication for Azure Function endpoints.

In this video, you’ll learn how to implement custom authorization and custom authentication for the Azure Function endpoints.

A GateKeeper class simplifies authenticating endpoints.

Getting Started

Create Azure SignalR Service

What is Azure SignalR Service?

Create an Azure SignalR Service Instance

Create an Azure SignalR Service instance in the Azure Portal. Go to Keys and note the connection string, you’ll need this later.

Azure Functions (SignalRServer) App

  1. Clone or download the source repo.
  2. Open the SignalRServer solution in Visual Studio.
  3. Add a local.settings.json file to the SignalRServer project.
  4. Open the local.settings.json file and paste the below json into the file.
  5. Replace the below AzureSignalRConnectionString with the connection string you copied from the Azure Portal Keys blade.
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "AzureWebJobsDashboard": "UseDevelopmentStorage=true",
    "AzureSignalRConnectionString": "Endpoint=INSERT_YOUR_SIGNALRSERVICE_ENDPOINT_HERE;"
  },
  "Host": {
    "LocalHttpPort": 7071,
    "CORS": "*"
  }
}
  1. Start Debugging

Angular Client (Client) App

From the Client folder, run npm install, this will install all dependencies.

Run ng serve, this will start a local test server and open your default browser open http://localhost:4200.

Open a second or more browser window and navigate to http://localhost:4200.

Using the UI:

  1. Seed The Database
  2. Login
  3. Start SignalR Client
  4. Start sending messages to all user or to an individual user.

Helpful Links

I learned a lot from these posts:

GrillPhil ServerlessRealtimeDemo

SibeeshVenu Realtime IoT Device Data using Azure SignalR and Azure Function in Angular

Erik Andreas Azure Functions SignalR Authentication Using Imperative Binding

Dynamic Binding in Azure Functions with Imperative Bindings

Ben Morris Custom Token Authentication In Azure Functions

Some of the above posts were authored before the latest SignalR client NuGet packages came out. This app reflects Angular 7 and the newer Microsoft.Azure.WebJobs.Extensions.SignalRService packages published by Microsoft in Feb 2019.

Close

I hope you find this reference implementation helpful. I learned a lot by writing it and consulting with Microsoft’s Cloud Developer Advocate Anthony Chu Twitter and https://anthonychu.ca/ blog.

Just a grain of sand on the world’s beaches.

 

Angular, Angular Material, Reactive Forms Validation

Introduction

I’ve been working on a game for several weeks that uses Angular, Angular Material, and Reactive Forms. I spent a few days spiking on various techniques for validating forms and came up with my own solution, which I’m sharing here.

My Requirements

  • Validation messages in component (not in HTML)
  • Validation logic in the component
  • Clean and simple HTML
  • Enable cross-field validation scenarios
  • Integration with Angular Material
  • An easy repeatable pattern for all my forms

References I Looked At

Assumptions

I assume you know what Reactive Forms are and how to implement one. If not, please have a look at the above references.

My Coding Style

I use TypeScript compile option strict. I do this because it yields better code by removing assumptions. It makes it easier to maintain over time and for others to read and debug. Yes, you have to type more code and once in a while, jump through a hoop to get rid of an error. IMHO – totally worth the extra work up front.

In tsconfig.json, I set strict, noUnusedLocals, noImplicitReturns, and noImplicitAny, as seen below.

Note: There are times during development, such as adding a new feature, that you’ll need to turn off strict and noUnusedLocals because you’ll get errors each time you save a file because the browser reloads feature is recompiling and rendering your app. This happens because you’re in development and some files may not ready to meet these standards just because you saved the file. So temporarily disabling these will adding new features to your app will help you.

{
  "compileOnSave": false,
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,    
    "removeComments": true,
    "noImplicitReturns": true,
    "noImplicitAny": true,
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

The above settings will be inconsistent with the out-of-the-box tslint settings so you’ll need to make one change.

In the /src folder you’ll see tslint.json, I added the last rule, “no-inferrable-types” and set to false. If you don’t, when you run “ng lint” you’ll get lint errors because you specified the type for each of your variables.

{
    "extends": "../tslint.json",
    "rules": {
        "directive-selector": [
            true,
            "attribute",
            "app",
            "camelCase"
        ],
        "component-selector": [
            true,
            "element",
            "app",
            "kebab-case"
        ],
        "no-inferrable-types": [
            false,
            "ignore-params"
          ]
    }
}

Component Base Class

I have a base class for most of my Components in all my Angular apps. Not sure if the Angular community is a fan of this, but I am. Using a base class can remove boilermaker code and fields from similar Components. For example, all my Components that have a data entry form have the same set of fields and validation wiring up, so I moved this to a base class. This partially fulfills one of my requirements, “Easy, repeatable pattern for all my forms.” Additionally, it keeps my code DRY.

I try to be pragmatic and reason about my code with an object-oriented mindset, have a base class is just one of the ways I do this.

Source Code

The source code can be cloned or downloaded from https://github.com/Oceanware/Angular-Material-ReactiveForms-Validation

Reactive Forms Validation

Cross-field validation scenarios are common. For example, validating two email input controls to ensure they are equal, or two password input controls. Cross-field validation requires you author a validator for your scenario.

These are the repeatable steps I follow when creating a data entry form that requires validation, this include cross-field validation:

In the Componenet.ts

  • Set up the validationMessages object.
    • For each control with validation rules, add an object with the required validation messages.
    • For each nested group with group-level validation errors, add an object with the required validation messages. See “passwordsGroup” below.
  • Set up the formErrors object.
    • For each control with validation rules, add the control name to this object.
    • For each nested group validation rules, add the group name to this object
  • Define the form in ngOnInit
  • Start control monitoring in ngAfterViewInit
  • If I have cross-field validation in the form
    • Import the CrossFieldErrorMatcher
    • Add this field and instantiate an instance of the class: errorMatcher = new CrossFieldErrorMatcher();

In the Componenet.html

  • For each control that has validation
    • add a mat-error component
      • insert a binding to the the control’s formErrors object, example: {{ formErrors[’email’] }}
  • For each control with cross-field validation that is nested in a group (See Registration Component)
    • add a mat-error component
      • insert a binding containing the following:
      • {{ formErrors[‘confirmPassword’] ? formErrors[‘confirmPassword’] : formErrors[‘passwordsGroup’] }}
  • For each control with cross-field validation that is NOT nested in a group (See Change Password Component)
    • add a mat-error component
      • insert a binding containing the following:
      • {{ formErrors[‘newPassword’] ? formErrors[‘newPassword’] : validationMessages[‘newPassword’][‘passwordsMatch’] }}

In the component constructor, add the required validation messages for each control that has a validator to the validationMessages object. Putting the messages here instead of the HTML, makes them very easy to unit test or load from a file or database especially in applications that are localized.

You’ll also add the required control and group names with a validator to the formErrors object.

constructor(private formBuilder: FormBuilder) {
  super();

  this.validationMessages = {
    userName: {
      required: 'User name is required.',
      minlength: 'User name minimum length is 6.',
      maxlength: 'User name maximum length is 15.',
      pattern: 'User name minimum length 6, allowed characters letters, numbers only. No spaces.'
    },
    password: {
      required: 'Password is required.',
      minlength: 'Password minimum length is 6.',
      maxlength: 'Password maximum length is 15.',
      pattern: 'Password minimum length 6, requires one letter, one number, one special character !@#$%^&* no spaces.'
    },
    confirmPassword: {
      required: 'Confirm password is required.',
      minlength: 'Confirm password minimum length is 6.',
      maxlength: 'Confirm password maximum length is 15.',
      pattern: 'Confirm password minimum length 6, requires one letter, one number, one special character !@#$%^&* no spaces.',
      passwordsDoNotMatch: 'Passwords must match.'
    },
    email: {
      required: 'Email is required.',
      email: 'Email is not properly formatted.',
    },
    passwordsGroup: {
      passwordsDoNotMatch: 'Passwords must match.'
    }
  };

  this.formErrors = {
    userName: '',
    email: '',
    password: '',
    confirmPassword: '',
    passwordsGroup: ''
  };
}

Create your Reactive Forms form, adding any required validators.

Notice the passwordsGroup, it has two controls and has a group validator, “passwordsDoNotMatch.”

ngOnInit() {
  this.form = this.formBuilder.group({
    userName: ['', [
      Validators.required,
      Validators.minLength(6),
      Validators.maxLength(15),
      Validators.pattern('^[a-zA-Z0-9]*$')]],
    email: ['', [
      Validators.required,
      Validators.email]],
    passwordsGroup: this.formBuilder.group({
      password: ['', [
        Validators.required,
        Validators.maxLength(15),
        Validators.pattern('^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,}$')]],
      confirmPassword: ['', [
        Validators.required,
        Validators.maxLength(15),
        Validators.pattern('^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,}$')]],
    }, { validators: passwordsDoNotMatch })
  });
}

Invoke startControlMonitoring for the form. This method monitors each control value change, control blur event, and then invokes a method to check the controls and set their validation error messages.

ngAfterViewInit(): void {
  setTimeout(() => {
    this.firstItem.nativeElement.focus();
  }, 250);
  this.startControlMonitoring(this.form);
}

For the controls that have any validation rules add a mat-error component and bind to the formErrors object, as shown below, any validation rules that fail will be displayed to the user.

<mat-error>
  {{ formErrors['email'] }}
</mat-error&gt;

Cross-Field validation for controls nested in a group (see Registration Component)

For the controls that are part of cross-field validation, add a mat-error component, and add the bindings to the formErrors object as shown below.

If there any validation rules on the control fail, they will be displayed to the user. If there are no failed control validation rules, we show the validation rule for the group this control is nested in. I normally only display group validation messages for one control. No need to bother the user with multiple group validation error messages.

<mat-error>
  {{ formErrors['confirmPassword'] ? formErrors['confirmPassword'] : formErrors['passwordsGroup'] }}
</mat-error&gt;

Cross-Field validation for controls NOT nested in a group (see Change Password Component)

Note: in practice, you would probably not define your cross-fields without nesting them. I’m showing this example for completeness of the possible scenarios. I recommend nesting controls that have cross-field validation in their own group.

For the controls that are part of cross-field validation, add a mat-error component, and add the bindings to the formErrors object as shown below.

If there any validation rules on the control fail, they will be displayed to the user. If there are no failed control validation rules, we show the validation rule defined in validationMessages for the control and validation rule. No need to bother the user with multiple group validation error messages.

The difference between this example and the above one is that the controls are not nested in the defined form, so we have to get the error message from a different source because the error will not be added to the formErrors object.

<mat-error>
  {{ formErrors['newPassword'] ? formErrors['newPassword'] : validationMessages['newPassword']['passwordsMatch'] }}
</mat-error&gt;

CrossFieldErrorMatcher

When performing cross-field validation, and the validation fails, the group the controls belong to will be INVALID and not the individual controls. Angular Material provides an ErrorStateMatcher to set an individual control to an INVALID state so that the validation pipeline can consider the control INVALID and render it accordingly. When a control is INVALID, Angular Material not only enables displaying the error message but makes the control display itself in an error state, as shown below.

We can see the New Password control not only has an error message, but the control label is red, and the input has a red line.

The control ErrorStateManager property is bound to the instance of the CrossFieldErrorMatcher in the component.

You’ll need to create a class that derives from ErrorStateMatcher and then implement your own logic.

The key takeaway from my class is the control.parent.invalid check. Notice that I’m checking the state of the control’s parent, in our scenario that will be the form object this control is a member of.

When the newPassword control is checked below, and the group validation rule has failed, the newPassword control will have an INVALID state set on it.

import { ErrorStateMatcher } from '@angular/material';
import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';

export class CrossFieldErrorMatcher implements ErrorStateMatcher {
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
        if (control) {
            return (control.dirty || control.touched) && control.parent.invalid;
        }
        return false;
    }
}

Data Entry Form Component Base Class

In keeping with my goal of, “Easy, repeatable pattern for all my forms,” and to keep my code DRY, I’ve created a base class to put the common code in that data entry form components require.

The startControlMonitoring method sets up an observable for the form fields so that the logic required to set the formErrrors object validation rule failures can execute.

The logValidationErrors recursively iterates over the controls in the form and checks if the control is valid or not. Since I’m using AbstractControl, this logic checks both FormGroups and FormControls in one pass and without a need for the code to branch based on the type of control.

If a control is found to be invalid, the validation error message is looked up and set on the formErrors object.

import { ViewChildren, ElementRef } from '@angular/core';
import { FormControlName, FormGroup } from '@angular/forms';
import { Observable, fromEvent, merge } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

export class FormComponentBase {
    // @ts-ignore
    @ViewChildren(FormControlName, { read: ElementRef }) formInputElements: ElementRef[];

    public validationMessages: { [key: string]: { [key: string]: string } } = {};
    public formErrors: { [key: string]: string } = {};

    protected startControlMonitoring(form: FormGroup): void {
        const controlBlurs: Observable[] = this.formInputElements
            .map((formControl: ElementRef) => fromEvent(formControl.nativeElement, 'blur'));

        merge(form.valueChanges, ...controlBlurs).pipe(
            debounceTime(300)
        ).subscribe(value => {
            this.logValidationErrors(form);
        });
    }

    private logValidationErrors(group: FormGroup): void {

        Object.keys(group.controls).forEach((key: string) => {
            const abstractControl = group.get(key);

            this.formErrors[key] = '';

            if (abstractControl && !abstractControl.valid && (abstractControl.touched || abstractControl.dirty)) {
                const messages = this.validationMessages[key];
                for (const errorKey in abstractControl.errors) {
                    if (errorKey) {
                        this.formErrors[key] += messages[errorKey] + ' ';
                    }
                }
            }
            if (abstractControl instanceof FormGroup) {
                this.logValidationErrors(abstractControl);
            }
        });
    }
}

Walk Through Video

Close

I hope you find this information and example project helpful in your Angular, Angular Material, Reactive Forms projects.

Just a grain of sand on the world’s beaches.

 

WPF XamDataGrid Configurator Released!

Introduction

Since joining Infragistics, I’ve spent the bulk of my time working on Visual Studio tooling (extensions) for Xamarin.Forms and WPF.  We have shipped an Xamarin.Forms Toolbox, Xamarin.Forms AppMap, and Control Configurators for these Xamarin.Forms and WPF Infragistics controls:

  • XamBulletGraph
  • XamCategoryChart
  • XamDataGrid
  • XamLinearGauge
  • XamPieChart
  • XamRadialGauge

The Infragistics Controls Configurators are a giant leap forward in Visual Studio design-time tooling, providing the developer with an unparalleled experience and feature set.  If you have not tried these or at least watched some of the below videos, I recommend you do so. 

An example of the unparalleled experience is the dynamic, design-time sample data created from your user types. Seeing a data grid or chart filled with live sample data from your users types is an awesome design-time experience.  Unlike the WPF XAML Designer feature that allows for injecting user specified sample data into the designer (I was the Microsoft PM on that feature), the Configurator sample data does not required the developer to do anything except create their types, build the solution, and set up a data binding.  Configurators are the gold standard of excellence for a design-time development experience.

The Infragistics documentation for the Configurators is here:

The Infragistics YouTube videos for the Xamarin.Forms and WPF Configurators are in this list:

The Infragistics YouTube videos for the Xamarin.Forms are in this list

WPF XamDataGrid Control Configurator

configurators

The Infragistics WPF XamDataGrid is a feature rich, performant data grid that meets the needs of demanding enterprise line-of-business applications. I have a lot of real-world experience using this data grid in my WPF enterprise applications before joining Infragistics.

The above image shows the Configurator extension dynamic sample data being rendered.  The Orders collection has 5 Order instances, each Order has 5 OrderDetail instances, and each OrderDetail has 5 Feature instances.  All dynamically created from the DataSource property binding to underlying user data types.

Notice the Customer.Status field, this is an Enum, this is type generated as well.

Configurators enable Infragistics customers to more easily learn and discover the control API’s because as properties or collections are changed at design-time, these changes are immediately reflected in the Configurator UI. The Configurators also have customized property window categories that group properties by feature.

Links to related online Help Topics are also provided in the Help ribbon group.

If you are a WPF line-of-business developer, I strongly encourage you to investigate Ultimate UI for WPF. Feature rich controls, outstanding support, and design-time Control Configurators for visually configuring your controls.

Have a great day,

Just a grain of sand on the worlds beaches.

Infragistics AppMap for Xamarin.Forms

Introduction

Today, Infragistics has made the popular AppMap for Xamarin.Forms available to all developers at no charge.

AppMap enables developers to visually map out and then generate their Xamarin.Forms application.

The code generation includes selected projects (iOS and Android, UWP coming soon), Pages (Views), ViewModels, and navigation code that follows best-practice Prism MVVM architecture.

For example, last month I created a 17 page application in three minutes. Easily saved myself an hour or two with project creation..

Videos

Please watch these short AppMap training videos to ensure you get the most from the AppMap tool and Prism for Xamarin.Forms.

Download and Installation

AppMap is included with the Infragistics Platform Installer and can also be download from the Visual Studio Marketplace.

Additionally, you can install from within Visual Studio using the Extensions and updates dialog.

AppMap works in all versions of Visual Studio 2015 and 2017.

Launching AppMap

AppMap is launched from the Visual Studio New Project Dialog or New Item Dialog.

NewProject

When using the New Item dialog, the name has no impact and is not used by the tool.  You can leave the default name and click the Add button.

Note: The New Item dialog only works with Xamarin.Forms project that were created by AppMap.

NewItem

Sign In

The first time you open AppMap you’ll need to sign in.  If you don’t have an Infragistics account yet, click the link and set one up.

The Customer Experience Improvement Program really does help us plan, allocate resources, is zero impact, and anonymous. As you can imagine, creating and maintaining Visual Studio Tooling is expensive and time consuming. This data helps us provide the best tooling for our customers and provide free tools to the community.

SignIn

Project Selection

This Create New Project dialog allows the developer to select the platforms for project creation. 

UWP will be supported in the coming soon release of AppMap

AppMap uses Prism for Xamarin.Forms. Prism provides a modern framework and developer guidance that embraces separation of concerns, dependency injection (DI), MVVM, and provides an incredibly rich, simple, and easy to use navigation API. The docs can be read here.

This dialog prompts you to select the DI Container you would like to use. When the project is created by AppMap, or when an AppMap Item is added to a project, AppMap automatically registers the added pages with the DI Container for you.

The Show AppMap checkbox allows you to show the AppMap dialog and then create the projects, or when unchecked, just create the projects.

The purpose of this dialog option is to enable a real-world application development workflow. Most developers have their own ViewModel base class.  AppMap allows developers to select the ViewModel base class to use for code generation. You can use one of two provided bases classes, or selected your own. So, by first creating  empty projects (projects without pages), developers can then bring in their own libraries and frameworks to the solution.  Then, launch the add New Item dialog, and in the AppMap select your ViewModel base class.

If your not familiar with the provided AppMap ViewModel base classed, please review them.  They both implement Prism navigation interfaces and have several commands that AppMap expects a ViewModel to have.  When AppMap generates your views, it wires up buttons and toolbar buttons to commands on the ViewModel. Optionally, you can derive your own ViewModel base class from one of the provided ones, but this is not a requirement.

ProjectDialog

AppMap

AppMap provides a diagram tool for laying out pages and creating relationships between them. These relationships provide the tool metadata for generating navigation code.

A feature of AppMap is to parse the entered Name, and set the Title property. You can edit the Name by double clicking the name in the diagram page or use the Properties panel.

The Code Generations Options panel is where you decide where your ViewModels will be placed, which folder names you would like to use, and the ViewModel base class to use.

Again, please watch the series of videos on AppMap to get a full understanding of it’s capabilities and features.

AppMap

This is the solution that was created by the above AppMap selections.  It took me 30 seconds to lay my application out and create it.

Notice that I like my ViewModels nested under my views.  This is not a requirement, but a personal preference.

Solution

Road Map

In the near future, we’ll release a new version of AppMap with these features:

  • .NET Standard 2.0 Xamarin.Forms Project Creation
  • Option to create UWP Project

Close

I always use AppMap for creating my projects as it saves so much time and saves me from having to create the pages and ViewModels one by one.

Have a great day,

Just a grain of sand on the worlds beaches.