Skip to content

Latest commit

 

History

History
775 lines (570 loc) · 28.1 KB

dotNET.md

File metadata and controls

775 lines (570 loc) · 28.1 KB

Table of Contents

Contents: .NET Challenge

As Tim Berners-Lee, the creator of the World Wide Web, once said: "The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect."

  1. Write your first C# code
  2. Get started with web development using Visual Studio Code
  3. Learn the basics of web accessibility
  4. Create a web UI with ASP.NET Core
  5. Create a web API with ASP.NET Core controllers
  6. Publish a web app to Azure with Visual Studio
  7. Introduction to .NET
  8. Create a new .NET project and work with dependencies
  9. Interactively debug .NET apps with the Visual Studio Code debugger
  10. Work with files and directories in a .NET app
  11. Introduction to Web Development with Blazor
  12. Build a web app with Blazor
  13. Interact with data in Blazor web apps
  14. Use pages, routing, and layouts to improve Blazor navigation
  15. Improve how forms and validation work in Blazor web apps
  16. Build rich interactive components with Blazor web apps
  17. Build reusable components with Blazor
  18. Build Connect Four game with Blazor
  19. Externalize the configuration of an ASP.NET app by using an Azure key vault
  20. Implement logging in a .NET Framework ASP.NET web application
  21. Improve session scalability in a .NET Framework ASP.NET web application by using Azure Cache for Redis
  22. Build a web API with minimal API, ASP.NET Core, and .NET
  23. Use a database with minimal API, Entity Framework Core, and ASP.NET Core
  24. Create a full stack application by using React and minimal API for ASP.NET Core
  25. Build your first microservice with .NET
  26. Deploy a .NET microservice to Kubernetes
  27. Create and deploy a cloudnative ASP.NET Core microservice
  28. Implement resiliency in a cloudnative ASP.NET Core microservice
  29. Instrument a cloudnative ASP.NET Core microservice
  30. Implement feature flags in a cloudnative ASP.NET Core microservices app
  31. Use managed data stores in a cloudnative ASP.NET Core microservices app
  32. Understand API gateways in a cloudnative ASP.NET Core microservices app
  33. Deploy a cloudnative ASP.NET Core microservice with GitHub Actions

Ensuring accessibility

  1. Contrast checkers

Someone who is color-blind might not be able to differentiate between colors, or might have difficulty working with colors that are similar to one another. The World Wide Web Consortium (W3C), the standards organization for the web, established a rating system for color contrast.

Choosing the right colors to ensure that your page is accessible to all can be tricky to do by hand. You can use the following tools to both generate appropriate colors and test your site to ensure compliance:

  1. ARIA attributes

Someone who's using a screen reader would only hear the words description and order repeated without context.

To support these types of scenarios, HTML supports a set of attributes known as Accessible Rich Internet Applications (ARIA). You can use these attributes to provide more information to screen readers.

For example, you can use aria-label to describe a link when the format of the page doesn't allow you to. The description for widget might be set as:

<a href="#"aria-label="Widget description">description</a>
  1. Web Development for Beginners

Razor

  1. Tutorial

https://github.com/MicrosoftDocs/mslearn-create-razor-pages-aspnet-core

dotnet --list-sdks
cd Contosopizza
dotnet watch

Ctrl + R : Reload

dotnet new page --name PizzaList --namespace ContosoPizza.Pages --output Pages

Observe the combination of HTML, Razor Syntax, and C# code in the file.

  • Razor Syntax is denoted by @ characters.

  • C# code is enclosed in @{ } blocks. Take note of the directives at the top of the file:

  • The @page directive specifies that this file is a Razor page.

  • The @model directive specifies the model type for the page (in this case, IndexModel, which is defined in Pages/Index.cshtml.cs).

  • The code sets the value of the Title item within the ViewData dictionary to "Home page".

  • The ViewData dictionary is used to pass data between the Razor page and the IndexModel class.

  • At runtime, the Title value is used to set the page's <title> element.

  1. Separation of concerns:

    Razor Pages enforces separation of concerns with a C# PageModel class, encapsulating data properties and logic operations scoped to its Razor page, and defining page handlers for HTTP requests. The PageModel class is a partial class that is automatically generated by the ASP.NET Core project template. The PageModel class is located in the Pages folder and is named after the Razor page. For example, the PageModel class for the Index.cshtml Razor page is named IndexModel.cs.

  2. Use Razor Pages in your ASP.NET Core app when you:

  • Want to generate dynamic web UI.

  • Prefer a page-focused approach.

  • Want to reduce duplication with partial views.

    Razor Pages simplifies ASP.NET Core page organization by keeping related pages and their logic together in their own namespace and directory.

  1. Tag helpers are used to address the inefficiencies of context switching between HTML and C#. Most of ASP.NET Core's built-in Tag helpers extend standard HTML elements. Tag helpers provide extra server-side attributes for HTML elements, making the elements more robust.

There are four tag helpers you should know for this project: Partial, Label, Input, and Validation Summary Message.

Use an asp-for attribute to specify a PageModel property.

<partial name="_ValidationScriptsPartial" />
<label asp-for="Foo.Id" class="control-label"></label>
<input asp-for="Foo.Id" class="form-control" />
<div asp-validation-summary="All"></div>

Rest API

Representational State Transfer (REST) is an architectural style for building web services. REST requests are made over HTTP. They use the same HTTP verbs that web browsers use to retrieve webpages and send data to servers. The verbs are:

  • GET: Retrieve data from the web service.
  • POST: Create a new item of data on the web service.
  • PUT: Update an item of data on the web service.
  • PATCH: Update an item of data on the web service by describing a set of instructions about how the item should be modified. The sample application in this module doesn't use this verb.
  • DELETE: Delete an item of data on the web service.

Build and test the web API

dotnet new webapi -f net6.0

Build and test the web API

dotnet run

Build the web API

dotnet build

.NET HTTP REPL command-line tool that you'll use to make HTTP requests to the web API.

dotnet tool install -g Microsoft.dotnet-httprepl
httprepl https://localhost:{PORT}
connect https://localhost:{PORT}
exit

ASP.Net Core Controller

using Microsoft.AspNetCore.Mvc;

namespace ContosoPizza.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
   private static readonly string[] Summaries = new[]
   {
       "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
   };

   private readonly ILogger<WeatherForecastController> _logger;

   public WeatherForecastController(ILogger<WeatherForecastController> logger)
   {
       _logger = logger;
   }

   [HttpGet(Name = "GetWeatherForecast")]
   public IEnumerable<WeatherForecast> Get()
   {
       return Enumerable.Range(1, 5).Select(index => new WeatherForecast
       {
           Date = DateTime.Now.AddDays(index),
           TemperatureC = Random.Shared.Next(-20, 55),
           Summary = Summaries[Random.Shared.Next(Summaries.Length)]
       })
       .ToArray();
   }
}

Visual Studio

  • Press F5 to build the project and run in debug mode.

  • Press Ctrl+F5 to build the project and run without attaching the debugger.

Razor is an ASP.NET syntax used to create dynamic web pages with C#.

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

The @page directive is telling ASP.NET to process this file as a Razor page.

The @model directive is telling ASP.NET to tie this Razor page with a C# class called PrivacyModel.

.NET

.NET is an ecosystem for application development

App model

App model Framework Notes
Web ASP.NET Core The framework for building server-side logic.
--- --- ---
Web ASP.NET Core MVC The framework for building server-side logic for web pages or web APIs.
Web ASP.NET Core Razor Pages The framework for building server-generated HTML.
Web client Blazor Blazor is a part of ASP.NET Core. Its two modes allow for either Document Object Model (DOM) manipulation via sockets as a communication vehicle for running server-side code, or a WebAssembly implementation for running compiled C# on a browser.
Desktop WinForms A framework for building "battleship gray" Windows-style applications.
Desktop Windows Presentation Foundation (WPF) A framework for building dynamic desktop applications that conform to different form factors. WPF allows form elements to perform movement, fades, glides, and other effects with the help of a rich library of animations.
Mobile Xamarin Allows .NET developers to build apps for iOS and Android devices.

.NET Videos

.NET has the fastest web framework on the planet according to TechEmpower benchmarks, an independent, open-source set of web performance benchmarks that measure dozens of languages and application frameworks.

package

A package dependency is a third-party library. It's a piece of reusable code that accomplishes something and can be added to your application.

package

https://www.nuget.org/packages/<package name>.

dotnet add package <package name>

-| bin/
---| Debug/
------| net3.1
--------| <files included in the dependency>

dotnet list package

dotnet list package --include-transitive

dotnet remove package <name of dependency>

Create a console application

dotnet new console -f net6.0

  • Versioning

Major version: I'm OK with updating to the latest major version as soon as it's out. I accept the fact that I might need to change code on my end.

Minor version: I'm OK with a new feature being added. I'm not OK with code that breaks.

Patch version: The only updates I'm OK with are bug fixes.

  • NuGet version ranges
1.0	x >= 1.0	Minimum version, inclusive
(1.0,)	x > 1.0	Minimum version, exclusive
[1.0]	x == 1.0	Exact version match
(,1.0]	x ≤ 1.0	Maximum version, inclusive
(,1.0)	x < 1.0	Maximum version, exclusive
[1.0,2.0]	1.0 ≤ x ≤ 2.0	Exact range, inclusive
(1.0,2.0)	1.0 < x < 2.0	Exact range, exclusive
[1.0,2.0)	1.0 ≤ x < 2.0	Mixed inclusive minimum and exclusive maximum version
(1.0)	invalid	invalid

dotnet list package

dotnet list package --outdated

  • Logging and tracing
using System.Diagnostics;

Console.WriteLine("This message is readable by the end user.");
Trace.WriteLine("This is a trace message when tracing the app.");
Debug.WriteLine("This is a debug message just for developers.");
Debug.WriteIf(count == 0, "Count should not be 0.");
  • Work with the file system
using System.IO;
using System.Collections.Generic;

// List all content in a directory and all subdirectories
// Find all *.txt files in the stores folder and its subfolders
IEnumerable<string> allFilesInAllFolders = Directory.EnumerateFiles("stores", "*.txt", SearchOption.AllDirectories);

Console.WriteLine(Directory.GetCurrentDirectory());

string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

Console.WriteLine(Path.Combine("stores","201")); // outputs: stores/201

Console.WriteLine(Path.GetExtension("sales.json")); // outputs: .json

Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), "stores","201","newDir"));

bool doesDirectoryExist = Directory.Exists(filePath);

File.WriteAllText(Path.Combine(Directory.GetCurrentDirectory(), "greeting.txt"), "Hello World!");

File.ReadAllText($"stores{Path.DirectorySeparatorChar}201{Path.DirectorySeparatorChar}sales.json");

Web Development with Blazor

Blazor is a user-interface framework built on .NET and Razor. Blazor applications can run on a server as part of an ASP.NET application, or can be deployed to run in the browser on a user's machine similar to a single-page-application.

blazor

  • Blazor Server is an implementation of the Blazor user-interface framework as part of the ASP.NET Core web development framework, deployed to a web server. Developing an application with Blazor Server generates HTML on a web server as it is requested by web site visitors, typically using a web browser. That HTML is then delivered to the visitor's browser, and a two-way communication pipeline is maintained using ASP.NET Core SignalR and preferring a Web Sockets connection.

  • Blazor WebAssembly, sometimes shortened to Blazor WASM, is an implementation of the Blazor user-interface framework that runs on the HTML 5 standard WebAssembly runtime present in all modern browsers. The binary output of your application, the DLL files, are transmitted to the browser and run with a version of .NET that has been optimized to work with the WebAssembly runtime regardless of the underlying operating system of the device browsing to the website.

Criteria You could choose Blazor Server because... You could choose Blazor WebAssembly because...
Developers are familiar with .NET Building applications will feel like a familiar ASP.NET Core application Building applications will use your existing skills to run natively in the browser
--- --- ---
Need to integrate with existing .NET investments There is an existing model for integrating with ASP.NET Core applications Allowing those resources to run natively in the browser gives better interaction and perceived performance than connecting to a web server
Existing web servers Your existing web servers are running ASP.NET Core You need to deploy your application to any server without need for server-side rendering
Complexity of the application Your application has heavy processing requirements that benefit from distributed applications running in a data center Your application can benefit from running with native processor speeds on the client
Network requirements Your application will always be connected to a server Your application can run in 'occasionally connected' mode without requiring constant interaction with a server
Code security requirements Your application is validated or required to run in specific geographic locations that can be enforced with a server Your application code can run anywhere on any device without this requirement

Create a new Blazor app

dotnet new blazorserver -f net6.0
-| bin
-| Data
-| obj
-| Pages
  -| _Host.cshtml
  -| Counter.razor
  -| Error.cshtml
  -| Error.cshtml.cs
  -| FetchData.razor
  -| Index.razor
-| Properties
-| Shared
  -| MainLayout.razor
  -| MainLayout.razor.css
  -| NavMenu.razor
  -| NavMenu.razor.css
  -| SurveyPrompt.razor
-| wwwroot
-| _Imports.razor
-| App.razor
-| appsettings.Development.json
-| appsettings.json
-| BlazorApp.csproj
-| Program.cs

Run the app

dotnet watch run

Razor

@page "/counter"

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

In this hierarchy of parent and child components, you can share information between them by using component parameters. You start by defining the component parameter in the child component. It's defined as a C# public property and decorated with the [Parameter] attribute:

<h2>New Pizza: @PizzaName</h2>

<p>@PizzaDescription</p>

@code {
    [Parameter]
    public string PizzaName { get; set; }
    
    [Parameter]
    public string PizzaDescription { get; set; } = "The best pizza you've ever tasted."
}

Data binding

Use data binding to connect an HTML element to a field, property, or expression. This way, when the value changes, the HTML element is automatically updated.

@page "/"

<h1>My favorite pizza is: @favPizza</h1>

<p>
    Enter your favorite pizza:
    <input @bind="favPizza" />
</p>

@code {
    private string favPizza { get; set; } = "Margherita"
}
git clone https://github.com/MicrosoftDocs/mslearn-interact-with-data-blazor-web-apps.git BlazingPizza

Navigation

git clone https://github.com/MicrosoftDocs/mslearn-blazor-navigation.git BlazingPizza

Route parameters

@page "/FavoritePizzas/{favorite}"

<h1>Choose a Pizza</h1>

<p>Your favorite pizza is: @Favorite</p>

@code {
	[Parameter]
	public string Favorite { get; set; }
}
@inject NavigationManager NavigationManager

Layout

Layout components don't include a @page directive because they don't handle requests directly and shouldn't have a route created for them. Instead, the referencing components use the @page directive.

@inherits LayoutComponentBase

<header>
	<h1>Blazing Pizza</h1>
</header>

<nav>
	<a href="Pizzas">Browse Pizzas</a>
	<a href="Toppings">Browse Extra Toppings</a>
	<a href="FavoritePizzas">Tell us your favorite</a>
	<a href="Orders">Track Your Order</a>
</nav>

@Body

<footer>
	@new MarkdownString(TrademarkMessage)
</footer>

@code {
	public string TrademarkMessage { get; set; } = "All content is &copy; Blazing Pizzas 2021";
}
@page "/FavoritePizzas/{favorite}"
@layout BlazingPizzasMainLayout

<h1>Choose a Pizza</h1>

<p>Your favorite pizza is: @Favorite</p>

@code {
	[Parameter]
	public string Favorite { get; set; }
}

Event Handling

git clone https://github.com/MicrosoftDocs/mslearn-use-forms-in-blazor-web-apps.git BlazingPizza

EditForm

<EditForm Model=@currentForecast>
    <InputNumber @bind-Value=currentForecast.TemperatureC width="5" min="-100" step="5"></InputNumber>
</EditForm>
<EditForm Model=Order.DeliveryAddress OnValidSubmit=PlaceOrder OnInvalidSubmit=ShowError>

Blazor component lifecycle

bl-life

git clone https://github.com/MicrosoftDocs/mslearn-build-interactive-components-blazor.git BlazingPizza

Razor class libraries

By using Razor class libraries, you can share and reuse user-interface components between Blazor applications. In this module, you'll focus on building and sharing components for Blazor applications.

ASP.NET

Configuration builders for ASP.NET

Implement logging in an ASP.NET web app

Store session state information in an ASP.NET web app

git clone https://github.com/dotnet-architecture/eShopModernizing.git

log4net

<log4net>
  <root>
    <level value="ALL" />
    <appender-ref ref="file" />
  </root>
  <appender name="file" type="log4net.Appender.RollingFileAppender">
    <file value="logFiles\myapp.log" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="5" />
    <maximumFileSize value="10MB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %property{activity} %level %logger - %property{requestinfo}%newline%message%newline%newline" />
    </layout>
  </appender>
</log4net>

Swagger

using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
     c.SwaggerDoc("v1", new OpenApiInfo {
         Title = "PizzaStore API",
         Description = "Making the Pizzas you love",
         Version = "v1" });
});

var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
   c.SwaggerEndpoint("/swagger/v1/swagger.json", "PizzaStore API V1");
});

app.MapGet("/", () => "Hello World!");

app.Run();
git clone https://github.com/microsoftdocs/mslearn-dotnet-kubernetes
  • Cloud Native Microservice: eShopOnContainers Solution architecture

bl-life

Solution diagram

bl-life

https://github.com/dotnet-architecture/eshoponcontainers

Free e-book: .NET Microservices: Architecture for Containerized .NET Applications

To implement code-based resiliency, this module uses Polly, which is a .NET library for resilience and transient failure handling.

Some popular service mesh options for Kubernetes clusters include Linkerd, Istio, and Consul.

Video: Implement microservices patterns with .NET and Docker containers

  • Enable Azure Monitor for Containers
az aks enable-addons \
    --addons monitoring \
    --name eshop-learn-aks \
    --resource-group eshop-learn-rg \
    --query provisioningState

Tips

  • Blazor Web Server

    @Link

    using BlazorAppChatGPTPluginTEST.Data;
    using Microsoft.Extensions.FileProviders;
    using Microsoft.OpenApi.Models;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    builder.Services.AddSingleton<WeatherForecastService>();
    
    // ** Create CORS policy called OpenAI
    // to allow OpenAI to access the API
    builder.Services.AddCors(options =>
    {
        options.AddPolicy("OpenAI", policy =>
        {
            policy.WithOrigins(
                "https://chat.openai.com",
                "http://localhost:5200")
            .AllowAnyHeader()
            .AllowAnyMethod();
        });
    });
    // ** Add controllers to the application
    builder.Services.AddControllers();
    // ** Add Swagger/OpenAPI to the application
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    
    builder.Services.AddSwaggerGen(options =>
    {                   
        options.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["controller"]}_{e.HttpMethod}");
        options.SwaggerDoc("v1", new OpenApiInfo
        {
            Title = "Blazor Azure Cognitive Search Plugin",
            Version = "v1",
            Description = "Blazorで動作するAzure Cognitive Search接続用のプラグインです。"
        });
    });
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    
    // Disable this so that OpenAI can access the API
    // without using https  (which is not supported by OpenAI)
    //app.UseHttpsRedirection();
    
    app.UseStaticFiles();
    app.UseRouting();
    app.MapBlazorHub();
    app.MapControllers();
    app.MapFallbackToPage("/_Host");
    
    // ** CORS to allow OpenAI to access the API
    app.UseCors("OpenAI");
    
    // ** Serve the .well-known folder for OpenAI
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), ".well-known")),
        RequestPath = "/.well-known"
    });
    
    // ** UseSwagger
    app.UseSwagger(c =>
    {
        c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
        {
            swaggerDoc.Servers = new List<OpenApiServer> {
                            new OpenApiServer {
                                Url = $"{httpReq.Scheme}://{httpReq.Host.Value}"
                            }
                        };
        });
    });
    
    // ** UseSwaggerUI
    app.UseSwaggerUI(x =>
    {
        x.SwaggerEndpoint(
            "/swagger/v1/swagger.yaml",
            "Blazor TODO Plugin (no auth)"
            );
    });
    
    app.Run();