Entity Framework Core tools reference – .NET Core CLI

Installing the tools

dotnet ef can be installed as either a global or local tool.

dotnet tool install --global dotnet-ef
dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local dotnet-ef

Before you can use the tools on a specific project, you’ll need to add the Microsoft.EntityFrameworkCore.Design package to it.

dotnet add package Microsoft.EntityFrameworkCore.Design

Update the tools

Use dotnet tool update --global dotnet-ef to update the global tools to the latest available version. If you have the tools installed locally in your project use dotnet tool update dotnet-ef. Install a specific version by appending --version <VERSION> to your command. See the Update section of the dotnet tool documentation for more details.

Usefull Commands

dotnet ef database drop

Deletes the database.

dotnet ef database update

Updates the database to the last migration or to a specified migration.

dotnet ef dbcontext info

Gets information about a DbContext type.

dotnet ef dbcontext list

Lists available DbContext types.

dotnet ef dbcontext optimize

Generates a compiled version of the model used by the DbContext. Added in EF Core 6.

dotnet ef dbcontext scaffold

Generates code for a DbContext and entity types for a database. In order for this command to generate an entity type, the database table must have a primary key.

dotnet ef dbcontext script

Generates a SQL script from the DbContext. Bypasses any migrations.

dotnet ef migrations add

Adds a new migration.

dotnet ef migrations bundle

Creates an executable to update the database.

dotnet ef migrations list

Lists available migrations.

dotnet ef migrations remove

Removes the last migration, rolling back the code changes that were done for the latest migration.

dotnet ef migrations script

Generates a SQL script from migrations.

Reverting a Migration

Suppose you changed your domain class and created the second migration named MySecondMigration using the add-migration command and applied this migration to the database using the Update command. But, for some reason, you want to revert the database to the previous state. In this case, use the update-database <migration name> command to revert the database to the specified previous migration snapshot.

dotnet ef database update MyFirstMigration

The above command will revert the database based on a migration named MyFirstMigration and remove all the changes applied for the second migration named MySecondMigration. This will also remove MySecondMigration entry from the __EFMigrationsHistory table in the database.

Note: This will not remove the migration files related to MySecondMigration. Use the remove commands to remove them from the project.

References
https://docs.microsoft.com/en-us/ef/core/cli/dotnet

Configure PostgreSQL Entity Framework for ASP.NET using Npgsql

Install Required Packages

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

Install dotnet-ef

Install it locally or globally.

Local

dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local dotnet-ef

Global

dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.Design

Defining a DbContext

using Microsoft.EntityFrameworkCore;

namespace BlazorApp1;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseNpgsql("Host=localhost;Database=testdb;Username=postgres;Password=12345");
    }

    public DbSet<Person> People { get; set; }
}

public class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

Create Migration

dotnet ef migrations add InitialCreate

Apply to Database

dotnet ef database update

or

dotnet ef database update InitialCreate
dotnet ef database update 20180904195021_InitialCreate --connection your_connection_string

Program.cs

builder.Services.AddDbContext<AppDbContext>(options => options.UseNpgsql(builder.Configuration.GetConnectionString("AppDbContext")));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

References
https://www.npgsql.org/efcore/index.html
https://docs.microsoft.com/en-us/aspnet/core/data/ef-rp/intro?view=aspnetcore-6.0&tabs=visual-studio
https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/migrations?view=aspnetcore-6.0
https://medium.com/executeautomation/asp-net-core-6-0-minimal-api-with-entity-framework-core-69d0c13ba9ab
https://docs.microsoft.com/en-us/ef/core/cli/dotnet

Handling Form submission with Validation in Blazor

The EditForm component is Blazor’s approach to managing user-input in a way that makes it easy to perform validation against user input. It also provides the ability to check if all validation rules have been satisfied, and present the user with validation errors if they have not.

The EditForm provides the following callbacks for handling form submission:

  • Use OnValidSubmit to assign an event handler to run when a form with valid fields is submitted.
  • Use OnInvalidSubmit to assign an event handler to run when a form with invalid fields is submitted.
  • Use OnSubmit to assign an event handler to run regardless of the form fields’ validation status. The form is validated by calling EditContext.Validate in the event handler method. If Validate returns true, the form is valid.
@page "/"
@using System.ComponentModel.DataAnnotations

<EditForm Model="@person" OnSubmit="FormSubmit">
    <DataAnnotationsValidator/>
    <ValidationSummary/>
    <div class="mb-3">
        <label for="inputFirstName" class="form-label">First Name</label>
        <InputText @bind-Value="person.FirstName" class="form-control" id="inputFirstName"></InputText>
    </div>
    <div class="mb-3">
        <label for="inputLastName" class="form-label">Last Name</label>
        <InputText @bind-Value="person.LastName" class="form-control" id="inputLastName"></InputText>
    </div>
    <div class="mb-3">
        <label for="inputAge" class="form-label">Age</label>
        <InputNumber @bind-Value="person.Age" class="form-control" id="inputAge"></InputNumber>
    </div>

    <input type="submit" class="btn btn-primary" value="Save"/>
</EditForm>

<div>Form validation : @isFormValid</div>

@code
{

    private Person person = new();
    private bool isFormValid = false;

    public class Person
    {
        public int Id { get; set; }

        [Required(ErrorMessage = "First Name is empty")]
        public string? FirstName { get; set; }

        [Required(ErrorMessage = "Last Name is empty")]
        public string? LastName { get; set; }

        [Required]
        [Range(0, 150, ErrorMessage = "Age is not in range")]
        public int Age { get; set; } = 36;
    }

    private void FormSubmit(EditContext editContext)
    {
        if (editContext.Validate())
        {
            isFormValid = true;
        }
    }
}

You can use ValidationMessage Component instead of ValidationSummary Component to show error message for each field.

<EditForm Model="@person" OnSubmit="FormSubmit">
    <DataAnnotationsValidator/>
    <div class="mb-3">
        <label for="inputFirstName" class="form-label">First Name</label>
        <InputText @bind-Value="person.FirstName" class="form-control" id="inputFirstName"></InputText>
        <ValidationMessage For="() => person.FirstName"></ValidationMessage>
    </div>
    <div class="mb-3">
        <label for="inputLastName" class="form-label">Last Name</label>
        <InputText @bind-Value="person.LastName" class="form-control" id="inputLastName"></InputText>
        <ValidationMessage For="() => person.LastName"></ValidationMessage>
    </div>
    <div class="mb-3">
        <label for="inputAge" class="form-label">Age</label>
        <InputNumber @bind-Value="person.Age" class="form-control" id="inputAge"></InputNumber>
        <ValidationMessage For="() => person.Age"></ValidationMessage>
    </div>

    <input type="submit" class="btn btn-primary" value="Save"/>
</EditForm>

 

References
https://blazor-university.com/forms/handling-form-submission/
https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-6.0

Navigating in Blazor using the NavLink component

Use a NavLink component in place of HTML hyperlink elements (<a>) when creating navigation links. A NavLink component behaves like an <a> element, except it toggles an active CSS class based on whether its href matches the current URL. The active class helps a user understand which page is the active page among the navigation links displayed. Optionally, assign a CSS class name to NavLink.ActiveClass to apply a custom CSS class to the rendered link when the current route matches the href.

<nav class="flex-column">
    <div class="nav-item px-3">
        <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
            <span class="oi oi-home" aria-hidden="true"></span> Home
        </NavLink>
    </div>
    <div class="nav-item px-3">
        <NavLink class="nav-link" href="counter">
            <span class="oi oi-plus" aria-hidden="true"></span> Counter
        </NavLink>
    </div>
    <div class="nav-item px-3">
        <NavLink class="nav-link" href="fetchdata">
            <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
        </NavLink>
    </div>
</nav>

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-6.0#navlink-and-navmenu-components
https://blazor-university.com/routing/navigating-our-app-via-html/

Cascading Values and Parameters in Blazor

MainLayout.razor

@inherits LayoutComponentBase

<PageTitle>BlazorApp1</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu/>
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            <CascadingValue Value="@Color">
                @Body
            </CascadingValue>
        </article>
    </main>
</div>

@code
{
    private string Color = "Red";
}

Index.razor

@page "/"

<div style="color: @Color">Hello World</div>

@code
{
    [CascadingParameter]
    public string? Color { get; set; }
}

Cascade multiple values

MainLayout.razor

@inherits LayoutComponentBase

<PageTitle>BlazorApp1</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu/>
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            <CascadingValue Value="@Color" Name="Value">
                <CascadingValue Value="@Size" Name="Size">
                    @Body
                </CascadingValue>
            </CascadingValue>
        </article>
    </main>
</div>

@code
{
    private string Color = "Red";
    private string Size = "12px";
}

Index.razor

@page "/"

<div style="color: @Color;font-size: @Size">Hello World</div>

@code
{
    [CascadingParameter(Name = "Color")]
    public string? Color { get; set; }

    [CascadingParameter(Name = "Size")]
    public string? Size { get; set; }
}

Cascade multiple values using Class

MainLayout.razor

@inherits LayoutComponentBase

<PageTitle>BlazorApp1</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu/>
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            <CascadingValue Value="@appState">
                    @Body
                </CascadingValue>
        </article>
    </main>
</div>

@code
{
    private AppState appState = new AppState();
    
    public class AppState
    {
        public string Color = "Red";
        public string Size = "16px";    
    }
}

Index.razor

@page "/"

<div style="color: @AppState.Color;font-size: @AppState.Size">Hello World</div>

@code
{
    [CascadingParameter]
    public MainLayout.AppState? AppState { get; set; }
}

Pass data across a component hierarchy

MainLayout.razor

@inherits LayoutComponentBase

<PageTitle>BlazorApp1</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu/>
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            <CascadingValue Value="@appState">
                    @Body
                </CascadingValue>
        </article>
    </main>
</div>

@code
{
    private AppState appState = new AppState();
    
    public class AppState
    {
        public string Color = "red";
        public string Size = "16px";    
    }
}

Counter.razor

@page "/counter"

<div class="d-flex align-items-center">
    <label>Color</label>
    <div style="width: 150px;padding-right: 10px;">
        <select @bind="@AppState.Color" class="form-control">
            <option value="red">Red</option>
            <option value="green">Green</option>
            <option value="blue">Blue</option>
        </select>
    </div>
    <label>Size</label>
    <div style="width: 150px;">
        <select @bind="@AppState.Size" class="form-control">
            <option value="16px">16px</option>
            <option value="20px">20px</option>
            <option value="30px">30px</option>
        </select>
    </div>
</div>

@code
{
    [CascadingParameter]
    public MainLayout.AppState AppState { get; set; }
}

Index.razor

@page "/"

<div style="color: @AppState.Color;font-size: @AppState.Size">Hello World</div>

@code
{
    [CascadingParameter]
    public MainLayout.AppState? AppState { get; set; }
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/cascading-values-and-parameters?view=aspnetcore-6.0

CSS isolation in Blazor

To enable CSS isolation, create a razor.css file matching the .razor file for the component in the same folder.
For example, if your component is named “Isolate.razor,” create a file alongside the component named “Isolate.razor.css.” The Isolate.razor.css file is placed in the same folder as the Isolate.razor component.

[Pages/Isolate.razor]

@page "/isolate"
    
<h1>Hello, World</h1>
<p>Welcome   to your new app</p>

[Pages/Isolate.razor.css]

h1 {
       color: blue;
       font-style: italic;
       text-shadow: 2px 2px 2px gray;
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/css-isolation?view=aspnetcore-6.0
https://www.syncfusion.com/faq/blazor/general/what-is-blazor-css-isolation-how-do-you-enable-it-for-your-application

JavaScript isolation in Blazor

wwwroot/scripts.js:

export function showPrompt(message) {
  return prompt(message, 'Type anything here');
}

Pages/CallJsExample6.razor:

@page "/call-js-example-6"
@implements IAsyncDisposable
@inject IJSRuntime JS

<h1>Call JS Example 6</h1>

<p>
    <button @onclick="TriggerPrompt">Trigger browser window prompt</button>
</p>

<p>
    @result
</p>

@code {
    private IJSObjectReference? module;
    private string? result;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", 
                "./scripts.js");
        }
    }

    private async Task TriggerPrompt()
    {
        result = await Prompt("Provide some text");
    }

    public async ValueTask<string?> Prompt(string message) =>
        module is not null ? 
            await module.InvokeAsync<string>("showPrompt", message) : null;

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-6.0#javascript-isolation-in-javascript-modules
https://www.syncfusion.com/faq/blazor/general/what-is-javascript-isolation-in-blazor-components

Call Class instance methods from JavaScript functions in Blazor

The component should keep a reference to the DotNetObjectReference we create.
The component should implement IDisposable and dispose our DotNetObjectReference.

@page "/"
@inject IJSRuntime JSRuntime
@implements IDisposable

<h1>Text received</h1>
<ul>
  @foreach (string text in TextHistory)
  {
    <li>@text</li>
  }
</ul>

@code
{
  List<string> TextHistory = new List<string>();
  DotNetObjectReference<Index> ObjectReference;

  protected override async Task OnAfterRenderAsync(bool firstRender)
  {
    await base.OnAfterRenderAsync(firstRender);
    if (firstRender)
    {
      ObjectReference = DotNetObjectReference.Create(this);
      await JSRuntime.InvokeVoidAsync("BlazorUniversity.startRandomGenerator", ObjectReference);
    }
  }

  [JSInvokable("AddText")]
  public void AddTextToTextHistory(string text)
  {
    TextHistory.Add(text.ToString());
    while (TextHistory.Count > 10)
      TextHistory.RemoveAt(0);
    StateHasChanged();
    System.Diagnostics.Debug.WriteLine("DotNet: Received " + text);
  }

  public void Dispose()
  {
    GC.SuppressFinalize(this);

    if (ObjectReference != null)
    {
      //Now dispose our object reference so our component can be garbage collected
      ObjectReference.Dispose();
    }
  }
}
var BlazorUniversity = BlazorUniversity || {};
BlazorUniversity.startRandomGenerator = function (dotNetObject) {
  return setInterval(function () {
    let text = Math.random() * 1000;
    console.log("JS: Generated " + text);
    dotNetObject.invokeMethodAsync('AddText', text.toString());
  }, 1000);
};
BlazorUniversity.stopRandomGenerator = function (handle) {
  clearInterval(handle);
};

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-6.0#class-instance-examples
https://blazor-university.com/javascript-interop/calling-dotnet-from-javascript/
https://blazor-university.com/javascript-interop/calling-dotnet-from-javascript/lifetimes-and-memory-leaks/

Call static .NET methods from JavaScript functions in Blazor

DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});
  • The {ASSEMBLY NAME} placeholder is the app’s assembly name.
  • The {.NET METHOD ID} placeholder is the .NET method identifier.
  • The {ARGUMENTS} placeholder are optional, comma-separated arguments to pass to the method, each of which must be JSON-serializable.
@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

@code {
    [JSInvokable]
    public static Task<int[]> ReturnArrayAsync()
    {
        return Task.FromResult(new int[] { 1, 2, 3 });
    }
}
<script>
  window.returnArrayAsync = () => {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
      .then(data => {
        console.log(data);
      });
    };
</script>

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-6.0#invoke-a-static-net-method
https://blazor-university.com/javascript-interop/calling-dotnet-from-javascript/calling-static-dotnet-methods/

Split HTML And C# Code In Blazor Using Partial Class

Partial Class is a feature of implementing a single class into multiple files. So now we will maintain the Html code in Counter.razor file and C# code in Counter.razor.cs file. Counter.razor.cs file acts as a code-behind file for Counter.razor file.

Counter.razor

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

Counter.razor.cs

namespace BlazorApp1.Pages;

public partial class Counter
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

References
https://www.learmoreseekmore.com/2020/06/blazor-paratial-class-or-componentbase-class.html