Merge pull request #29 from ddieruf/dev

Fixing lost things from merge
This commit is contained in:
David Dieruf 2020-09-18 09:00:20 -04:00 коммит произвёл GitHub
Родитель 16400c0c45 35be02b2f8
Коммит 3eb93b03bc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 75 добавлений и 1436 удалений

Просмотреть файл

@ -1,115 +0,0 @@
@using System.Diagnostics
@inject HttpClient Http
@inject NavigationManager NavigationManager
@inject IJSRuntime JSRuntime
<PageTitle Title="@pageTitle" />
@((MarkupString)Content)
@code {
[Parameter]
public string Component { get; set; }
[Parameter]
public string Area { get; set; }
[Parameter]
public int Version { get; set; }
private string Content { get; set; }
public string pageTitle;
protected override Task OnInitializedAsync() {
NavigationManager.LocationChanged += LocationChanged;
fixNavChar();
return base.OnInitializedAsync();
}
protected override Task OnAfterRenderAsync(bool firstRender) {
if (firstRender) {
ParseUri();
UpdateContent();
ScrollToAnchor(forceScroll: true);
}
return base.OnAfterRenderAsync(firstRender);
}
private void LocationChanged(object sender, LocationChangedEventArgs e) {
//string navigationMethod = e.IsNavigationIntercepted ? "HTML" : "code";
//Debug.WriteLine($"Notified of navigation via {navigationMethod} to {e.Location}");
fixNavChar();
string fragment = NavigationManager.ToAbsoluteUri(e.Location).Fragment;
ParseUri();
if (string.IsNullOrEmpty(fragment)) {
UpdateContent();
StateHasChanged();
}
ScrollToAnchor(fragment);
}
private async void UpdateContent() {
pageTitle = parseTitleFromFileName(Component) + " Documentation";
var filePath = "site-data/docs/" + Version + "/" + Component + "/" + Area + ".html";
try {
Content = await Http.GetStringAsync(filePath);
StateHasChanged();
await JSRuntime.InvokeVoidAsync("highlightCode", true);
StateHasChanged();
} catch (HttpRequestException http) {
if (http.Message.Contains("404")) {
NavigationManager.NavigateTo("/docs/" + Version + "/welcome/overview");
return;
}
}
}
private void ScrollToAnchor(string anchor = "", bool forceScroll = false) {
if (!string.IsNullOrEmpty(anchor) || forceScroll)
JSRuntime.InvokeAsync<string>("scrollToAnchor", anchor);
}
private void Dispose() {
NavigationManager.LocationChanged -= LocationChanged;
}
private void ParseUri() {
var path = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
string[] segments = path.Split(Char.Parse("/"));
if (segments.Length == 0)
return; //nothing to see here
if (segments.Length > 0 && string.IsNullOrEmpty(Component))
Component = segments[0];
if (segments.Length > 1 && string.IsNullOrEmpty(Area))
Area = segments[1];
}
private string parseTitleFromFileName(string fileName)
{
string str = fileName.Replace("-", " ");
string ret = "";
int idx = 0;
foreach (string s in str.Split(char.Parse(" ")))
{
int t;
if (idx == 0 && int.TryParse(s, out t)) //if the item has a position index, don't add to title
continue;
ret += Char.ToUpperInvariant(s[0]) + s.Substring(1).ToLower() + " ";
idx++;
}
return ret.Trim();
}
private void fixNavChar() {
//A fix for the misconfigured docs url
if(!string.IsNullOrEmpty(Component) && Component.IndexOf("-") > 0) {
int t;
if(int.TryParse(Component.Substring(0,Component.IndexOf("-")), out t)){
Component = Component.Substring(Component.IndexOf("-") + 1,Component.Length - Component.IndexOf("-")-1);
}
}
}
}

Просмотреть файл

@ -1,7 +1,5 @@
@using System.IO
@using System
@using System.Diagnostics
@inject NavigationManager NavigationManager
@inject IDocsSite DocsSite
@page "/doc"
@page "/docs"
@ -16,38 +14,7 @@
@page "/docs/{Version:int}/{Component}"
@page "/docs/{Version:int}/{Component}/{Area}"
<div class="width-all">
<div class="width-90 container">
<div class="row docs-row no-gutters">
<div class="docs-nav-col">
<div class="row no-gutters">
<div class="col text-center nav-version @(Version == 2 ? "selected":"")">
@if(Version == 2) {
<span>Steeltoe v2</span>
} else {
<Href href="@("/docs/2/" + Component + "/" + Area)">Steeltoe v2</Href>
}
</div>
<div class="col text-center nav-version @(Version == 3 ? "selected":"")">
@if(Version == 3) {
<span title="Version 3">Steeltoe v3</span>
} else {
<Href href="@("/docs/3/" + Component + "/" + Area)">Steeltoe v3</Href>
}
</div>
</div>
<div class="row no-gutters">
<div class="col bg-white">
<DocsMenu Area="@(Area)" Component="@(Component)" Version="@(Version)" />
</div>
</div>
</div>
<div class="docs-content-col">
<Docs Area="@(Area)" Component="@(Component)" Version="@(Version)" />
</div>
</div>
</div>
</div>
Redirecting to new docs site, please hold.
@code {
private string _area;
@ -76,4 +43,10 @@
_version = (value < 2 || value > 3 || value == 0 ? currentVersion : value);
}
}
protected async override Task OnParametersSetAsync(){
NavigationManager.NavigateTo($"{DocsSite.BaseAddress}/api/v{Version}/{Component}/{Area}.html",true);
await base.OnParametersSetAsync();
return;
}
}

Просмотреть файл

@ -1,55 +0,0 @@
@using System.Diagnostics
@inject IJSRuntime JSRuntime
@inject IParseFromMarkdown ParseMarkdown
@page "/labs/{LabName}"
@page "/labs/{LabName}/{ExerciseName}"
<PageTitle Title="Lab Exercises" />
<div class="width-all">
<div class="width-90 container">
<div class="row no-gutters">
<div class="col mt-5">
@html
</div>
</div>
</div>
</div>
@code {
private MarkupString html;
private string _labName;
private string _exerciseName;
[Parameter]
public string LabName {
get { return _labName; }
set { _labName = value; }
}
[Parameter]
public string ExerciseName {
get { return _exerciseName; }
set { _exerciseName = value; }
}
protected override async Task OnParametersSetAsync() {
//Console.WriteLine($@"labs/{_labName}/{(_exerciseName ?? _labName)}.md");
try{
html = await ParseMarkdown.GetHtmlAsync($@"labs/{_labName}/{(_exerciseName ?? _labName)}.md");
}catch{
html = (MarkupString)$@"<div>No lab could be found at 'labs/{_labName}/{(_exerciseName ?? _labName)}.md'</div>";
}
StateHasChanged();
await JSRuntime.InvokeVoidAsync("highlightCode",true);
StateHasChanged();
await base.OnParametersSetAsync();
return;
}
}

Просмотреть файл

@ -1,4 +1,5 @@

@inject IDocsSite DocsSite
<div class="width-all bg-midnight-blue">
<div class="width-90 container" id="footer">
<div class="row bottom-bar">
@ -76,7 +77,8 @@
<div class="col" id="footer-learn-col">
<div class="pb-2 font-weight-bold">Learn</div>
<div><Href href="/get-started">Guides</Href></div>
<div><Href href="/docs">Documentation</Href></div>
<div><Href href="@(DocsSite.DocsHome)">Documentation</Href></div>
<div><Href href="@(DocsSite.BlogHome)">Blog</Href></div>
</div>
<div class="col" id="footer-projects-col">
<div class="pb-2 font-weight-bold">Projects</div>

Просмотреть файл

@ -1,151 +1,66 @@
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@inject IDocsSite DocsSite
@*<div class="width-all" style="background-color:"#d8d8d8">
<div class="width-70 container">
<div class="row no-gutters p-1">
<div class="col text-center">This is some text</div>
</div>
<nav class="bg-white navbar navbar-expand-xl container py-xl-2">
<Href class="navbar-brand" href="/">
<img id="logo" class="svg" src="/images/logo.svg" alt="Steeltoe" >
</Href>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar">
<ul class=" navbar-nav text-center">
<li class="nav-item dropdown ml-xl-5 mr-xl-2">
<a class="nav-link dropdown-toggle open" href="# id="why" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Why Steeltoe
</a>
<div class="dropdown-menu" aria-labelledby="why">
<Href class="dropdown-item" href="/why-steeltoe">Overview</Href>
<Href class="dropdown-item" href="/microservices">Microservices</Href>
<Href class="dropdown-item" href="/cloud">Cloud</Href>
<Href class="dropdown-item" href="/web-application">Web Applications</Href>
<Href class="dropdown-item" href="/event-driven">Event Driven</Href>
</div>
</li>
<li class="nav-item dropdown mx-xl-2">
<a class="nav-link dropdown-toggle" href="#" id="learn" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Learn
</a>
<div class="dropdown-menu" aria-labelledby="learn">
<Href class="dropdown-item" href="/get-started">Get Started</Href>
<Href class="dropdown-item" href="@(DocsSite.DocsHome)">Documentation</Href>
<Href class="dropdown-item" href="@(DocsSite.BlogHome)">Blog</Href>
</div>
</li>
<li class="nav-item dropdown mx-xl-2">
<a class="nav-link dropdown-toggle" href="#" id="projects" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Projects
</a>
<div class="dropdown-menu" aria-labelledby="projects">
<Href class="dropdown-item" href="/app-configuration">Steeltoe Application Configuration</Href>
<Href class="dropdown-item" href="/circuit-breakers">Steeltoe Circuit Breakers</Href>
<Href class="dropdown-item" href="/cloud-management">Steeltoe Distributed Tracing</Href>
<Href class="dropdown-item" href="/docs/logging">Steeltoe Dynamic Logging</Href>
<Href class="dropdown-item" href="/cloud-management">Steeltoe Management</Href>
<Href class="dropdown-item" href="/file-sharing">Steeltoe Network File Sharing</Href>
<Href class="dropdown-item" href="/security-providers">Steeltoe Security</Href>
<Href class="dropdown-item" href="/service-connectors">Steeltoe Service Connectors</Href>
<Href class="dropdown-item" href="/service-discovery">Steeltoe Service Discovery</Href>
<Href class="dropdown-item" href="/messaging">Steeltoe Messaging</Href>
<div class="small pl-4 pt-3">Developer Tools</div>
<Href class="dropdown-item pl-5" href="/initializr">Steeltoe Initializr</Href>
</div>
</li>
<li class="nav-item mx-xl-2">
<Href class="nav-link" href="/training">Training</Href>
</li>
<li class="nav-item mx-xl-2">
<Href class="nav-link" href="/support">Support</Href>
</li>
<li class="nav-item mx-xl-2">
<Href class="nav-link" href="/community">Community</Href>
</li>
</ul>
</div>
</div>*@
<div class="width-all">
<div class="width-90 container">
<div class="row top-bar">
<div class="col-sm-3"><Href href="index"><?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="75px" preserveAspectRatio="xMidYMid meet"
viewBox="0 0 812.7 288.5" xml:space="preserve">
<style type="text/css">
.st0{fill:#00376E;}
.st1{fill:#0066CC;}
.st2{opacity:0.2;fill:#00376E;enable-background:new ;}
.st3{fill:#8A8C8E;}
</style>
<title>PVLG-Steeltoe-2019</title>
<polygon class="st0" points="0,216.3 124.9,288.5 62.4,180.3 "/>
<polygon class="st1" points="124.9,0 87.5,21.6 0,72.1 62.4,180.3 124.9,288.5 249.8,216.3 "/>
<polyline class="st2" points="219.3,163.4 0,72.1 0,72.1 124.9,0 "/>
<polygon class="st0" points="124.9,0 0,72.1 124.9,144.3 124.9,144.3 249.8,72.1 "/>
<path class="st0" d="M310,136.7c3.7,1.6,7.6,2.8,11.6,3.6c4.3,1.1,8.6,2.4,12.8,4c3.3,1.3,6.2,3.4,8.5,6.1c2.4,2.8,3.5,6.4,3.5,11
c0.1,5.5-2.4,10.7-6.7,14.1c-4.5,3.7-10.8,5.6-19,5.6c-8.5,0.1-16.8-2-24.2-6c-1.5-1-2.3-2.6-2.2-4.4c0-1.4,0.5-2.7,1.5-3.7
c0.9-1.1,2.3-1.6,3.7-1.6c0.8,0,1.7,0.2,2.4,0.5c2.8,1.2,5.6,2.2,8.5,2.9c3.1,0.8,6.4,1.1,9.6,1.1c9.9,0,14.8-3.2,14.8-9.5
c0-2-1.1-3.6-3.4-4.7c-3.6-1.5-7.3-2.7-11.1-3.6c-4.4-1-8.8-2.3-13-3.9c-3.4-1.3-6.4-3.4-8.8-6.1c-2.5-3-3.8-6.8-3.7-10.7
c-0.2-5.8,2.3-11.4,6.7-15.2c4.5-3.9,10.9-5.9,19.3-5.9c6.6,0,13.1,1.1,19.3,3.3c1.2,0.3,2.2,1,2.9,2c1.5,2.1,1.3,4.9-0.5,6.8
c-1,1-2.4,1.6-3.8,1.6c-0.6,0-1.2-0.1-1.7-0.3c-4.9-1.6-10.1-2.4-15.2-2.4c-4.8,0-8.6,0.9-11.3,2.6s-4,4-4,6.7
C306.2,133.2,307.7,135.6,310,136.7z"/>
<path class="st0" d="M398.3,170.6c0.9,0.9,1.5,2.1,1.5,3.4c0,2-1.2,3.9-3,4.7c-3.5,1.6-7.2,2.4-11,2.4c-13,0-19.4-5.9-19.4-17.6
v-41.3h-9.6c-1.4,0-2.5-1.1-2.5-2.4c0,0,0-0.1,0-0.1c0-0.9,0.4-1.7,1.2-2.2l18.2-17.8c0.6-0.7,1.4-1.1,2.2-1.2
c0.7,0,1.3,0.3,1.8,0.8c0.5,0.5,0.7,1.2,0.7,1.9v10.6h15c2.8-0.1,5.1,2,5.2,4.8c0,0.1,0,0.3,0,0.4c0,1.4-0.5,2.7-1.5,3.7
c-1,1-2.3,1.6-3.7,1.5h-15v40.2c0,3.4,0.8,5.7,2.5,6.6c1.9,1,4,1.5,6.2,1.4c1.8,0,3.6-0.3,5.3-0.8c0.3-0.1,0.7-0.2,1.1-0.3
c0.5-0.1,1-0.1,1.5-0.1C396.2,169.2,397.4,169.7,398.3,170.6z"/>
<path class="st0" d="M468.7,166.5c1.1,0.9,1.6,2.3,1.6,3.7c0,2-1.2,3.6-3.5,5c-3.2,1.9-6.7,3.3-10.3,4.4c-4.3,1.1-8.7,1.6-13.1,1.5
c-10.8,0-19.3-3.1-25.4-9.2s-9.1-14.9-9.1-26c-0.1-6,1.1-12,3.5-17.6c2.2-5.2,5.9-9.7,10.6-12.9c4.8-3.3,10.7-5,17.8-5
c6-0.2,12,1.4,17.1,4.6c4.7,3,8.5,7.3,10.9,12.3c2.5,5.2,3.8,10.9,3.7,16.7c0,1.6-0.6,3.1-1.7,4.3c-1.2,1.2-2.8,1.8-4.5,1.7h-45.2
c0.7,6.2,3,11,6.9,14.5c3.9,3.5,9.4,5.2,16.4,5.2c3.3,0.1,6.6-0.3,9.8-1.1c2.8-0.7,5.6-1.7,8.2-3c0.8-0.3,1.6-0.5,2.4-0.5
C466.3,165,467.7,165.5,468.7,166.5z M431.9,122.7c-3,1.4-5.5,3.7-7.3,6.5c-2.1,3.3-3.2,7.1-3.3,10.9h39.3
c-0.1-3.9-1.3-7.7-3.4-10.9c-1.8-2.8-4.4-5-7.4-6.5c-2.8-1.3-5.8-2.1-8.9-2.1C437.8,120.6,434.7,121.4,431.9,122.7z"/>
<path class="st0" d="M544.6,166.5c1.1,1,1.6,2.3,1.6,3.8c0,2-1.2,3.6-3.5,5c-3.2,1.9-6.7,3.3-10.3,4.4c-4.3,1.1-8.7,1.6-13.1,1.5
c-10.8,0-19.3-3.1-25.4-9.2s-9.1-14.9-9.1-26c-0.1-6.1,1.1-12.1,3.5-17.6c2.2-5.2,5.9-9.7,10.7-12.9c4.8-3.3,10.7-5,17.8-5
c6-0.2,12,1.4,17.1,4.6c4.7,3,8.5,7.3,10.9,12.3c2.5,5.2,3.8,10.9,3.7,16.7c0,1.6-0.6,3.1-1.7,4.3c-1.2,1.2-2.8,1.8-4.5,1.7h-45.2
c0.7,6.2,3,11,6.9,14.5c3.9,3.5,9.4,5.2,16.4,5.2c3.3,0.1,6.6-0.3,9.8-1.1c2.8-0.7,5.6-1.7,8.2-3c0.8-0.3,1.6-0.5,2.4-0.5
C542.2,165,543.6,165.5,544.6,166.5z M507.8,122.7c-3,1.4-5.5,3.7-7.3,6.5c-2.1,3.3-3.2,7.1-3.3,10.9h39.3
c-0.1-3.9-1.3-7.7-3.4-10.9c-1.8-2.8-4.4-5-7.4-6.5c-2.8-1.3-5.8-2.1-8.9-2.1C513.7,120.6,510.7,121.4,507.8,122.7z"/>
<path class="st0" d="M576.3,83.5c1.1,1.2,1.8,2.8,1.8,4.4v86.5c0,1.6-0.6,3.2-1.8,4.3c-1.2,1.1-2.7,1.8-4.3,1.8c-3.3,0-6-2.7-6-6
V87.9c0-1.6,0.6-3.2,1.8-4.3c1.1-1.2,2.7-1.8,4.3-1.8C573.6,81.7,575.2,82.3,576.3,83.5z"/>
<path class="st0" d="M636.7,170.6c0.9,0.9,1.5,2.1,1.5,3.4c0,2-1.2,3.9-3,4.7c-3.5,1.6-7.2,2.4-11,2.4c-13,0-19.4-5.9-19.4-17.6
v-41.3h-9.5c-1.4,0-2.5-1.1-2.5-2.5c0,0,0,0,0-0.1c0-0.9,0.5-1.7,1.2-2.2L612,99.6c0.6-0.7,1.4-1.1,2.3-1.2c0.7,0,1.3,0.3,1.8,0.8
c0.5,0.5,0.7,1.2,0.7,1.9v10.6h15c2.8-0.1,5.1,2,5.2,4.8c0,0.1,0,0.3,0,0.4c0,1.4-0.5,2.7-1.5,3.7c-1,1-2.3,1.6-3.7,1.5h-15v40.2
c0,3.4,0.8,5.7,2.5,6.6c1.9,1,4,1.5,6.2,1.4c1.8,0,3.6-0.3,5.3-0.8c0.3-0.1,0.7-0.2,1.1-0.3c0.5-0.1,1-0.1,1.5-0.1
C634.7,169.2,635.9,169.7,636.7,170.6z"/>
<path class="st0" d="M699.2,114.8c5.1,2.9,9.3,7.2,12,12.5c5.7,11.7,5.7,25.3,0,37c-2.7,5.2-6.9,9.6-12,12.5
c-11.2,5.9-24.6,5.9-35.8,0c-5.1-2.9-9.3-7.2-11.9-12.5c-5.6-11.7-5.6-25.3,0-37c2.7-5.2,6.8-9.6,12-12.5
C674.6,108.9,688,108.9,699.2,114.8L699.2,114.8z M691.8,167.4c3.5-1.8,6.3-4.6,8.3-8c2.2-3.7,3.3-8.3,3.3-13.9s-1.1-10.1-3.3-13.8
c-1.9-3.4-4.8-6.2-8.3-7.9c-3.3-1.6-6.8-2.5-10.5-2.5c-3.7,0-7.3,0.8-10.6,2.5c-3.5,1.8-6.3,4.5-8.2,7.9c-2.1,3.7-3.2,8.2-3.2,13.8
s1.1,10.2,3.2,13.9c1.9,3.4,4.7,6.2,8.2,8c3.3,1.7,6.9,2.5,10.6,2.5C685,170,688.6,169.1,691.8,167.4z"/>
<path class="st0" d="M788.1,166.5c1.1,0.9,1.6,2.3,1.6,3.7c0,2-1.2,3.6-3.5,5c-3.2,1.9-6.7,3.3-10.3,4.4c-4.3,1.1-8.7,1.6-13.1,1.5
c-10.8,0-19.3-3.1-25.4-9.2s-9.1-14.9-9.1-26c-0.1-6,1.1-12,3.5-17.5c2.2-5.2,5.9-9.7,10.7-12.9c4.8-3.3,10.7-5,17.8-5
c6-0.2,12,1.4,17.1,4.6c4.7,3,8.5,7.3,10.9,12.3c2.5,5.2,3.8,10.9,3.7,16.7c0,1.6-0.6,3.1-1.7,4.3c-1.2,1.2-2.8,1.8-4.5,1.7h-45.2
c0.7,6.2,3,11,6.9,14.5c3.9,3.5,9.3,5.2,16.4,5.2c3.3,0.1,6.6-0.3,9.8-1.1c2.8-0.7,5.6-1.7,8.2-3c0.8-0.3,1.6-0.5,2.4-0.5
C785.7,165.1,787.1,165.5,788.1,166.5z M751.3,122.7c-3,1.4-5.5,3.7-7.3,6.5c-2.1,3.3-3.2,7.1-3.3,10.9H780
c-0.1-3.9-1.3-7.7-3.4-10.9c-1.8-2.8-4.4-5-7.4-6.5c-2.8-1.3-5.8-2.1-8.9-2.1C757.2,120.6,754.1,121.4,751.3,122.7z"/>
<path class="st0" d="M804.5,126.9c-4.5,0-8.2-3.7-8.2-8.2s3.7-8.2,8.2-8.2c4.5,0,8.2,3.7,8.2,8.2c0,0,0,0,0,0
C812.7,123.2,809,126.9,804.5,126.9z M804.5,111.7c-3.9,0-7,3.1-7,7s3.1,7,7,7s7-3.1,7-7c0-3.8-3-7-6.9-7
C804.6,111.7,804.6,111.7,804.5,111.7L804.5,111.7z M806.8,123.4l-2.4-3.7h-1.6v3.7h-1.3V114h3.8c1.6-0.1,3,1.2,3.1,2.8
c0,0,0,0,0,0.1c0,1.4-1,2.6-2.4,2.8l2.5,3.8H806.8z M805.2,115.2h-2.5v3.3h2.5c0.9,0.1,1.7-0.6,1.8-1.5c0.1-0.9-0.6-1.7-1.5-1.8
C805.4,115.2,805.3,115.2,805.2,115.2L805.2,115.2z"/>
</svg>
</Href></div>
<div class="col text-center offset-sm-2 mt-4 @(labHeader?"hide":"")">
<div class="has-menu"><span>Why Steeltoe</span><span class="nav-arrow"></span></div>
</div>
<div class="col text-center mt-4 @(labHeader?"hide":"")">
<div class="has-menu"><span>Learn</span><div class="nav-arrow"></div></div>
</div>
<div class="col text-center mt-4 @(labHeader?"hide":"")">
<div class="has-menu"><span>Projects</span><div class="nav-arrow"></div></div>
</div>
<div class="col text-center mt-4 @(labHeader?"hide":"")"><Href href="/training">Training</Href></div>
<div class="col text-center mt-4 @(labHeader?"hide":"")"><Href href="/support">Support</Href></div>
<div class="col text-center mt-4 @(labHeader?"hide":"")"><Href href="/community">Community</Href></div>
<div class="rel @(labHeader?"hide":"")" id="dropdown-menus">
<div class="abs" id="scope"></div>
<div class="drop-menu" id="why-items" onmouseleave="unhovAll()">
<div class="drop-target" id="why-target" @onmouseover="@(() => showHover("why"))"></div>
<ul onmouseleave="unhovAll()">
<li><Href href="/why-steeltoe" @onclick="hideHover">Overview</Href></li>
<li><Href href="/microservices" @onclick="hideHover">Microservices</Href></li>
<li><Href href="/cloud" @onclick="hideHover">Cloud</Href></li>
<li><Href href="/web-applications" @onclick="hideHover">Web Applications</Href></li>
<li><Href href="/event-driven" @onclick="hideHover">Event Driven</Href></li>
</ul>
</div>
<div class="drop-menu" id="learn-items" onmouseleave="unhovAll()">
<div class="drop-target" id="learn-target" @onmouseover="@(() => showHover("learn"))"></div>
<ul onmouseleave="unhovAll()">
@*<li><Href href="/quickstart" @onclick="hideHover">Quickstart</Href></li>*@
<li><Href href="/get-started" @onclick="hideHover">Get Started</Href></li>
<li><Href href="/docs" @onclick="hideHover">Documentation</Href></li>
</ul>
</div>
<div class="drop-menu" id="project-items" onmouseleave="unhovAll()">
<div class="drop-target" id="project-target" @onmouseover="@(() => showHover("project"))"></div>
<ul onmouseleave="unhovAll()">
<li class=""><Href href="/app-configuration" @onclick="hideHover">Steeltoe Application Configuration</Href></li>
<li class=""><Href href="/circuit-breakers" @onclick="hideHover">Steeltoe Circuit Breakers</Href></li>
<li class=""><Href href="/cloud-management" @onclick="hideHover">Steeltoe Distributed Tracing</Href></li>
<li class=""><Href href="/docs/logging" @onclick="hideHover">Steeltoe Dynamic Logging</Href></li>
<li class=""><Href href="/cloud-management" @onclick="hideHover">Steeltoe Management</Href></li>
<li class=""><Href href="/file-sharing" @onclick="hideHover">Steeltoe Network File Sharing</Href></li>
<li class=""><Href href="/security-providers" @onclick="hideHover">Steeltoe Security</Href></li>
<li class=""><Href href="/service-connectors" @onclick="hideHover">Steeltoe Service Connectors</Href></li>
<li class=""><Href href="/service-discovery" @onclick="hideHover">Steeltoe Service Discovery</Href></li>
<li class=""><Href href="/messaging" @onclick="hideHover">Steeltoe Messaging</Href></li>
<li class="small pt-4">Developer Tools</li>
<li class="pl-2"><Href href="/initializr">Steeltoe Initializr</Href></li>
</ul>
</div>
</div>
<div class="col text-center offset-sm-2 mt-4 @(labHeader?"":"hide")">
<div><h2>Lab Exercises</h2></div>
</div>
</div>
</div>
</div>
</nav>
@code {
private bool labHeader { get; set; } = false;
protected override async Task OnInitializedAsync() {
if (NavigationManager.Uri.Contains("labs"))
labHeader = true;
await base.OnInitializedAsync();
}
private async void showHover(string a) {
await JSRuntime.InvokeVoidAsync("hov", a);
}
private async void hideHover() {
await JSRuntime.InvokeVoidAsync("unhovAll");
}
}

Просмотреть файл

@ -1,179 +0,0 @@
.top-bar {
padding: 5px 0 5px 0;
}
.top-bar .col .nav-link {
color: #00376e
}
.has-menu {
color: #00376e;
display: inline-block;
padding: 0;
white-space: nowrap;
}
#nav-items a:focus, .has-menu span:focus {
outline: none !important;
color: #0066cc;
}
.drop-menu li a {
transition: color .2s
}
.drop-menu li a:focus, .drop-menu li a:hover {
color: #001f3f;
outline: none
}
#nav-items > li > a, #nav-items > li > div {
font-weight: 700;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: color .2s;
font-size: .9375rem
}
#nav-items > li > a:hover, #nav-items > li > div:hover {
color: #001f3f;
}
.has-menu:focus .drop-menu, .has-menu:hover .drop-menu {
display: block
}
.drop-menu {
position: absolute;
white-space: nowrap;
transition: all 0s linear;
top: -24px;
/*margin: 10px;*/
opacity: 0
}
.drop-menu ul {
box-sizing: border-box;
width: 230px;
margin: 0
}
.drop-menu li {
display: none
}
.drop-target {
display: block;
height: 80px;
/*padding-bottom: 8px*/
}
#scope {
background: #fff;
width: 289px;
box-shadow: 0 5px 30px 0 rgba(108,135,135,.5);
top: 71px;
opacity: 0
}
#scope, #scope.why-scope {
transition: all .2s ease-out
}
#why-target {
}
#why-items {
right: 591px;
width: 135px
}
#scope.why-scope {
right: 431px;
height: 200px;
opacity: 1
}
#learn-target, #why-target {
transform: translateX(-10px)
}
#learn-target {
}
#learn-items {
right: 469px;
width: 95px
}
#scope.learn-scope {
right: 272px;
height: 99px;
opacity: 1
}
#project-target {
}
#project-items {
right: 355px;
width: 100px;
}
#scope.project-scope {
right: 157px;
height: 457px;
opacity: 1
}
#community-target {
width: 110px;
transform: translateX(87px)
}
#community-items {
right: -80px
}
#scope.community-scope {
right: -80px;
height: 196px;
opacity: 1
}
.drop-menu.active {
opacity: 1;
transition: all .3s ease-in
}
.drop-menu.active ul {
padding: 37px 30px;
height: auto
}
.drop-menu.active li {
display: block;
margin-bottom: 10px;
transition: opacity 0s
}
.drop-menu li:last-child {
margin-bottom: 0
}
.has-menu.active {
color: #6db33f
}
.nav-arrow {
transform: rotate(45deg) translateY(-6px);
-webkit-transform: rotate(45deg) translateY(-6px);
border: solid #191e1e;
border-width: 0 1px 1px 0;
display: inline-block;
padding: 3px;
margin-left: 5px
}
.relative {
height: 100%;
width: 100%
}
.rel, .relative {
position: relative
}
.abs {
position: absolute
}

Просмотреть файл

@ -53,8 +53,7 @@
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.2/styles/a11y-dark.min.css">
<link rel="stylesheet" href="css/site.css" />
<!--<link rel="stylesheet" href="css/nav.css" />-->
<!--<link rel="stylesheet" href="css/mobile.css" />-->
<link rel="stylesheet" href="css/mobile.css" />
</head>
<body>
<!-- Google Tag Manager (noscript) -->

Просмотреть файл

@ -1,289 +0,0 @@
# Steeltoe 3.0 packs a mighty punch with many new features
As you make your way through cloud computing and (inevitably) microservices, there will be a never ending list of configuration choices and technical debt. Containerizing legacy code, best practices in new code, developing locally, debugging production apps. That's just a hint of the kinds of questions to be answered.
Fortunately, youre not the first to embark on this journey. Others have gone ahead and discovered realistic ways to do things. And dont worry youre also not the last, so dont feel like you're playing catch up.
Running in the cloud means different things to different folks but at its heart, its containerization. You may run a container on your desktop, on an enterprise network, or on a public cloud. For Steeltoe, they are all the same.
If youre not familiar with the Steeltoe project, it is here to help your legacy .NET framework and new .NET Core run extremely well in the cloud. Steeltoe was started in 2015 as a means for .NET Framework applications to enjoy all that Spring Cloud has to offer. Service discovery, external configuration sources, message brokers, service connectors, management endpoints, and more. Over the years Steeltoe has followed Microsoft to .NET Core, but has arranged the project in a way that Framework apps can still be supported.
How does Steeltoe make your .NET microservices better? It takes away the burden of managing all the "stuff" that makes up your service. And seasoned developers will tell you, most of the code in their applications has nothing to do with what the application was meant to do. Most of the code is supporting connections to other services, enhancing logs, abstracting 3rd party package lock-in, and generally conforming to the environment it will run within. Its a necessary evil - without it the app is buggy and useless, but creating it doubles the time to production.
Steeltoe makes things like production ready database connections a single line of code and some configuration values. It uses all the powerful abstractions like IConfiguration, ILogging, IHealthProvider, and others to deliver libraries that developers use to spend more time writing business logic and less time with boilerplate-type stuff. Just getting started with ASP.NET? Steeltoe will help you ease into all those possible configuration values. Looking to get in-depth and extend libraries to your needs? Steeltoe is based on common libraries that all .NET uses.
Steeltoe 3.0 is a product of years of learning. Small businesses and large enterprises have all been benefiting and contributing to this new release. Its a fresh take on cloud opinions that seemingly never get answered. Its the next evolution for your microservices to go to cloud ninja status.
---
##### If youre moving from Steeltoe 2.x and would like a quick comparision with version 3.0, refer to [this page](https://steeltoe.io/docs/3/welcome/whats-new).
---
Let's take a look at the new things included in Steeltoe 3.0. If youre still wondering how the project fits in your new or existing .NET applications, [learn how here](https://steeltoe.io).
## RabbitMQ messaging in less than 5 lines of code
You might know it as a few different things - eventing, event architecture, event message bus, pub/sub, etc. All of these patterns have one thing in common. They have a heavy dependency on a message broker and queue. That dependency adds extra emphasis on how your app handles its connection & communication to the queue. It needs to be resilient to change and not fail if the queue isnt there, and it needs to conform to how the message container will be built - but still keep the intended data in-tact.
To help developers use message based systems but not have to manage all the debt that typically comes along with such a thing, Steeltoe 3 introduces the new Messaging component. This component does all the work of resiliency, portability, and fault-tolerance. To implement it you provide the location of the message server and start reading & writing messages. Want to include a custom object in the message? Steeltoe Messaging will take care of converting the bytes. Should the queue be "ensured" when the application is starting up? Configure Steeltoe Messaging to create it, if nothing is present. Do you have potentially many instances of an application that all share the same queue? Steeltoe Messaging will handle everything appropriately for you.
To get started using Messaging ([here is a full example](https://github.com/SteeltoeOSS/Samples/tree/master/Messaging)), provide the server address in `appsettings.json`:
```json
"Spring": {
"RabbitMq": {
"Host": "localhost",
"Port": 5672,
"Username": "admin",
"Password": "secret"
}
}
```
And implement the Rabbit message container in `Startup.cs`:
```csharp
public void ConfigureServices(IServiceCollection services) {
services.AddRabbitServices(); // Add core services
services.AddRabbitAdmin(); // Add Rabbit admin
services.AddRabbitTemplate(); // Add Rabbit template
services.AddRabbitQueue(new Queue("myqueue")); // Add queue to be declared
// Add the rabbit listener which receives from "myqueue"
services.AddSingleton<MyListener>();
services.AddRabbitListeners<MyListener>();
// Start a hosted service that sends a message to "myqueue"
services.AddSingleton<IHostedService, MySender>();
...
}
```
Then using dependency injection, obtain a RabbitTemplate and send a message to the queue:
```csharp
public class MySender : IHostedService {
...
public MySender(RabbitTemplate amqpTemplate, MyCustomObject myObj) {
amqpTemplate.ConvertAndSend("myqueue", myObj);
}
}
```
Receive messages from the queue named "myqueue":
```csharp
public class MyListener {
...
[RabbitListener("myqueue")]
public void Listen(MyCustomObject myObj){
logger.LogInformation($"Received something: {myObj.MyThing}");
}
}
```
Once youve got the basics down, its time to extend and make the design better with things like custom factories. Steeltoe Messaging will take care of the conversion of a message into a structured type but sometimes you want to intercept that conversion and make decisions. You can create your own `DirectRabbitListenerContainer` and customize to your heart's content. Learn more about custom listener container factories [in the docs](https://dev.steeltoe.io/docs/3/messaging/rabbitmq-intro#basics).
## Legacy and Modern together in the cloud
While all the latest headlines may be around .NET Core, the reality is there is still quite a bit of .NET Framework in production. And the developers of those applications are probably getting pressure to "get that app in a container". Or at least "reduce the apps infrastructure". Steeltoes roots are with .NET Framework and every feature in version 2.x fully supports Framework apps.
Going forward the team may not bring every feature added in 3.x back to 2.x but they are actively maintaining the branch. Making sure things stay secure and have up to date patches. If the community shows a need for a certain feature to be back-ported, the Steeltoe team is ready and willing to listen.
## Kubernetes is the future
The current developer landscape is almost demanding that everyone learn something about Kubernetes. Granted you may only be learning why you dont want it, its still a very popular topic and a platform that many are embracing.
As a developer working with Kubernetes, the platform leaves quite a bit to be desired. The experience is raw and changing rapidly. We are seeing tools emerge that are aimed at helping the developers be more productive in a cluster, but theres still a ways to go.
The Steeltoe team has begun the journey of supporting K8s specific things with the introduction of a new service discovery client and new configuration providers.
Adding to the list of supported service registries, Steeltoe now offers developers the option of using native Kubernetes. The really amazing design of this is, there are no additional dependencies to be deployed. Registration and discovery can happen with the resources already provided in every cluster.
In Kubernetes, when you want an application registered as discoverable, no work is required. To discover services, simply include the `Steeltoe.Discovery.ClientCore` and `Steeltoe.Discovery.Kubernetes` packages along with implementing the discovery client in the `HostBuilder` ([here is a full example](https://github.com/SteeltoeOSS/Samples/tree/master/Discovery/src)).
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
.AddDiscoveryClient();
```
Let's say the registered service was named "fortuneService". To discover it in another application, add a new http client factory to the services collection.
```csharp
public void ConfigureServices(IServiceCollection services) {
services.AddHttpClient("fortunes", c =>
{
c.BaseAddress = new Uri("http://fortuneService/api/fortunes/");
})
.AddServiceDiscovery()
.AddTypedClient<IFortuneService, FortuneService>();
...
}
```
Now when an new request is created using the http client `var result = await _httpClient.GetStringAsync("random");` the full url of http://fortuneService/api/fortunes/random will be used and Kubernetes will resolve it for you.
Kubernetes also has powerful built in features when it comes to getting configuration settings into an application. Combine that with the power of .NET Cores configuration provider hierarchy and you have one heck of a cloud-native application.
Let's say we have the following ConfigMap ([here is a full example](https://github.com/SteeltoeOSS/Samples/tree/master/Configuration/src/Kubernetes)):
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: kubernetes
namespace: default
data:
someKey: someValue
```
We want to get the value of `someKey` into the application but dont want to add anything platform specific. First add Kubernetes as a configuration provider in the HostBuilder:
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
.AddKubernetesConfiguration();
```
And then retrieve the configuration value through IConfiguration dependency injection:
```csharp
public HomeController(IConfiguration config) {
string myKey = config["someKey"];
}
```
If you'd like to see more visit the [samples repo](https://github.com/SteeltoeOSS/Samples), or have a look in the [docs](https://steeltoe.io/docs).
## Generate production ready projects and get going fast
Our friends in the Java world using Spring have been enjoying a project called Spring Initializr ([https://start.spring.io](https://start.spring.io)) for years. Its a brilliant mix of creating ready to go microservices with all the best practices and boilerplate taken care of. The Steeltoe team thought the .NET community should have the same kind of tool. So they created the Steeltoe Initializr ([https://start.steeltoe.io](https://start.steeltoe.io)).
The Initializr project aims to solve a very common challenge in every organization, of any size. When new projects are started, dont use a copy of an old one and dont spend the time writing everything from scratch. Instead do a little planning ahead and know what dependencies the new application will be taking on. Then build a call to Initializr or visit its web UI and generate the project.
Not only does this save the developer from writing code to manage config server connections or health endpoints or any other essential of microservices, it also keeps their projects on the latest patched libraries.
---
##### Learn more about Initializr [now](https://steeltoe.io/initializr)
---
When you review the available dependencies in Steeltoes hosted version of Initializr you are probably going to have the need to add your own custom dependencies or want to bring the whole tool in-house. That is one of Initializrs super powers!
Initializr is not an application that needs a managed installation and long term tender loving care. Its a Nuget distributed package that can be added to a very simple .NET Core application - hosted anywhere. When an update is published, just open the project in your IDE and update the package. If youd like to add the Steeltoe UI on top of the Initializr service, clone a copy of the public site. Then you can customize and run internally.
## Container observability
One of the most shocking things to a developer that is new to working with containerized applications is the loss of "visibility" into what the application is doing. Traditionally you had things like IIS logs and the event store, but in a containerized world those things are locked away in private container networks. So, the traditional way needs to become modern and Steeltoe is here to get you there.
Observability is typically a sum of logs, traces, and metrics. Sometimes you have them all and sometimes not. Sometimes the data is all on one dashboard and (most of the time) its distributed between 2 or more dashboards. Regardless of where the data is being observed, a developer should not have to bring in all kinds of custom dependencies to conform to each dashboard used. They should offer the information in a simple, neutral way with little time spent getting it all wired up.
Steeltoe 3.0 continues the management endpoints found in 2.x but takes things to a deeper place. Along with the following examples, you can also get started using Tanzu Observability with Wavefront or create a Grafana dashboard in our [observability guides](https://dev.steeltoe.io/observability).
* Originally OpenCensus was used for creating standard trace data and metrics. That has been superseded by the OpenTelemetry telemetric standard.
* Creating tracing spans has been simplified to a single line in `startup.cs` ([here is a full example](https://github.com/SteeltoeOSS/Samples/tree/master/Management/src/Tracing))
```csharp
public void ConfigureServices(IServiceCollection services) {
services.AddDistributedTracing(Configuration, builder => builder.UseZipkinWithTraceOptions(services));
...
}
```
* In addition to the [metrics endpoint](https://dev.steeltoe.io/docs/3/management/metrics-observers), there is a new prometheus endpoint that offers a simple way for metrics to be scraped. Below is an example prometheus.yml configuration ([here is a full example](https://github.com/SteeltoeOSS/Samples/tree/master/Management/src)):
```yaml
scrape_configs:
- job_name: 'steeltoe-prometheus'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
```
* [Dynamic logging](https://dev.steeltoe.io/docs/3/logging) can be implemented with a single statement in the `HostBuilder`
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
.AddDynamicLogging();
```
* To use Spring Boot Admin as your management dashboard add the following to `appsettings.json` ([here is a full example](https://github.com/SteeltoeOSS/Samples/tree/master/Management/src/SpringBootAdmin)):
```json
"spring": {
"boot": {
"admin": {
"client": {
"url": "http://<MY_BOOT_ADMIN_SERVER>:8080"
}
}
}
}
```
And implement the client in Startup.cs
```csharp
public void Configure(IApplicationBuilder app) {
...
app.RegisterWithSpringBootAdmin(Configuration);
}
```
## Not just for Cloud Foundry
If youve been using Steeltoe for any amount of time youll notice a strong hint in the documentation and samples, for Cloud Foundry. That's the application platform Steeltoe grew up on. But as things go the baby bird must leave the nest to discover bigger pastures, and Steeltoe is ready to fly.
In this new version, Steeltoe is spreading its cloud wings and showing strong support for all cloud platforms. In fact it doesnt even need a cloud platform. You could run a .NET app with Steeltoe in IIS, or Visual Studio debugger, or as a container. The point is Steeltoe is a framework to help developers do what they love - coding. Not managing log messages or some database connection.
Steeltoe still has much love for Cloud Foundry but youre going to see a lot more local and "get it in a container" kind of examples from the team. A statement like UseCloudFoundryActuators is going to have a complementing UseAllActuators, for those not on CF. And while VCAP is a huge help in Cloud Foundry, you may want to provide your own connection information through `appsettings.json`. Youll see a lot more flexibility in that direction with this new version.
Here are a few examples of new ways to implement things in the `HostBuilder`:
* Initialize only the health and dynamic logging
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
.AddHealthActuator();
}
```
* Initialize all actuators and optionally secure them behind an authorization policy
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
.AddAllActuators(/*endpoints => endpoints.RequireAuthorization("actuators.read")*/);
}
```
* To instantly enable the enhanced features of app manager in Tanzu Application Services
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
.UseCloudHosting(5000)
.AddCloudFoundryActuators();
}
```
## Learn more and get started today
To get started with any Steeltoe projects, head over to the [getting started guides](https://steeltoe.io/get-started). Combine this with the samples in the [Steeltoe GitHub repo](https://github.com/SteeltoeOSS/Samples), and youll have .NET microservices up and running before you know it!
Want a complete runtime? Try [Pivotal Web Services](https://run.pivotal.io/) for free! This will give you access to a complete modern app runtime.
Want to get deeper into creating cloud-native .NET apps? Attend the VMware Pivotal Labss [4 -day .NET developer course](https://pivotal.io/platform-acceleration-lab/pal-for-developers-net). Youll get hands-on cloud-native .NET training learn best practices when creating microservices and become a Steeltoe ninja!
We are also offering a hands-on "getting started" workshop this year at the [SpringOne](https://springone.io) conference. [Read more about the workshop and get signed up, space is limited!](https://springone.io/2020/workshops/steeltoe)

Просмотреть файл

@ -1,153 +0,0 @@
[vs-new-proj]: /site-data/labs/spring-one/images/vs-new-proj.png "New visual studio web project"
[vs-name-proj]: /site-data/labs/spring-one/images/vs-configure-project.png "Name project"
[vs-create-proj]: /site-data/labs/spring-one/images/vs-create-project.png "Create an api project"
[vs-add-endpointcore]: /site-data/labs/spring-one/images/vs-add-endpointcore.png "Endpointcode nuget dependency"
[vs-add-dynamiclogger]: /site-data/labs/spring-one/images/vs-add-dynamiclogger.png "Dynamiclogger nuget dependency"
[vs-add-tracingcore]: /site-data/labs/spring-one/images/vs-add-tracingcore.png "TracingCode nuget dependency"
[vs-run-application]: /site-data/labs/spring-one/images/vs-run-application.png "Run the project"
[run-weatherforecast]: /site-data/labs/spring-one/images/weatherforecast-endpoint.png "Weatherforecast endpoint"
[health-endpoint]: /site-data/labs/spring-one/images/health-endpoint.png "Health endpoint"
[info-endpoint]: /site-data/labs/spring-one/images/info-endpoint.png "Info endpoint"
[trace-log]: /site-data/labs/spring-one/images/trace-log.png "Trace logs"
[home-page-link]: /labs/spring-one
[exercise-1-link]: /labs/spring-one/exercise1
[exercise-2-link]: /labs/spring-one/exercise2
[exercise-3-link]: /labs/spring-one/exercise3
[exercise-4-link]: /labs/spring-one/exercise4
[exercise-5-link]: /labs/spring-one/exercise5
## Getting to know Steeltoe
### Goal
Understand how Steeltoe is distributed (Nuget) and how one adds components into an existing application.
### Expected Results
Begin building an API that will be enhanced with more components in the next exercise(s).
### Get Started
Let's start by creating a brand new .NET Core webapi project. If you're using Visual Studio, choose `File > New > Project`
|![vs-new-proj] Choose ASP.NET Core Web Application from the default templates. |![vs-name-proj] The default project name WebApplication1 will be used throughout, but you can rename.|![vs-create-proj] Choose an application type of API, everything else can keep its default value.|
|:--|
Or if you prefer the dotnet cli:
```powershell
dotnet new webapi -n WebApplication1
cd WebApplication1
```
Once created, open the new project in your IDE of choice (we will be using Visual Studio throughout this lab). The first action is to bring in the Steeltoe packages to the app. You can do this by right clicking on the project name in the solution explorer and choose `Manage NuGet packages...`. In the package manger window choose `Browse`, search for `Steeltoe.Management.Endpointcore`, and install.
![vs-add-endpointcore]
Then search for the `Steeltoe.Extensions.Logging.DynamicLogger` package and install.
![vs-add-dynamiclogger]
Finally the `Steeltoe.Management.TracingCore` package and install.
![vs-add-tracingcore]
You could have done all this in the cli:
```powershell
dotnet add package Steeltoe.Management.Endpointcore
dotnet add package Steeltoe.Extensions.Logging.DynamicLogger
dotnet add package Steeltoe.Management.TracingCore
```
Steeltoe features are broken up into packages, giving you the option to only bring in and extend the dependencies needed. As we implement each package within the application we'll discuss why these packages were chosen.
Open `Program.cs` and append the adding statements to the host builder. Visual Studio should prompt to add the `using Steeltoe.Management.Endpoint` direction.
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
//Steeltoe actuator packages
.AddHealthActuator()
.AddInfoActuator()
.AddLoggersActuator()
;
```
We've implemented 3 features within the application by adding these actuators.
- The health actuator will add a new endpoint at `/actuators/health`. Internally this function uses .NET's IHealthContributor to "decide" if everything is reporting good health and responds with HTTP 200 status. Also within the response body there is a json formatted message to accomodate a deeper check that specfic platforms like Cloud Foundry and Kubernetes do.
- The info actuator adds a new endpoint at `/actuators/info`. This function gathers all kinds of information like versioing information, select package information, and DLL info. Everything is formatted as json and included in the response.
- The loggers actuator enables enhanced log message details via ILogger.
Now open `Startup.cs` and add distributed tracing features, Visual Studio should prompt you to add the `using Steeltoe.Management.Tracing` direction.
```csharp
public void ConfigureServices(IServiceCollection services) {
services.AddControllers();
//Steeltoe distributed tracing
services.AddDistributedTracing(Configuration);
}
```
With the addition of distributed tracing option, under the covers Steeltoe uses the OpenTelemetry specification to generate spans and traces throughout the application, as requests are recieved. No additional configuration is needed.
Also having the combination of the logging actuator and distributed tracing implemented, Steeltoe will automatically append the application name, span Id, and trace Id on log messages when possible. This can be very handy when debugging a specific happening and error in production.
To see the trace logging in action, lets add a log message in `Controllers\WeatherForecastController.cs` controller. Append the below message as the first line with the 'Get' function.
```csharp
[HttpGet]
public IEnumerable<WeatherForecast> Get() {
//Testing Steeltoe logging with distributed tracing
_logger.LogInformation("Hi there");
//...
}
```
With the packages implemented in host builder, distributed tracing activated, and a sample log message being written to console, we are ready to see everything in action. Start the application by clicking the `Debug > Start Debugging` top menu item.
![vs-run-application]
Or use the dotnet cli:
```powershell
dotnet run
```
Once started your default browser should open and automatically load the weather forecast endpoint.
![run-weatherforecast]
Let's look at the health endpoint. Replace `WeatherForecast` with `/actuators/health` in the browser address bar. The health page will load with json formatted info.
![health-endpoint]
As we discussed above, the page loaded with a status of 200 and output information to help application platforms gain a deeper "knowledge" of app health.
Now navigate to the info endpint by replacing `health` with `info` in the address bar.
![info-endpoint]
Relevant app info is output, with json formatting.
Finally lets look at the log message that was written by going back to Visual Studio (keep the app running) and locate the Output window. Choose `Webapplication1 - ASP.NET Core Web Server` in the "from" dropdown and scroll to the bottom of the log. (If you're using the dotnet cli, the logs should be output in the same window you ran the app.)
![trace-log]
Locate the "Hi there" log message. Notice the additional information prepended to the messsage.
- The first item is the application's name
- Second is the OpenTelemetry generated span id
- Third is the OpenTelemetry generated trace id
### Summary
These are the basics of any cloud ready microservice. Logging and debugging are significantly different than a traditional IIS environment. But! A developer shouldn't be spending tons of time coding these buildplate-type things. Heeelllo Steeltoe!
|[<< Back to Introduction][home-page-link]|[Next Exercise >>][exercise-2-link]|
|:--|--:|

Просмотреть файл

@ -1,92 +0,0 @@
[vs-run-application]: /site-data/labs/spring-one/images/vs-run-application.png "Run the project"
[run-weatherforecast]: /site-data/labs/spring-one/images/weatherforecast-endpoint.png "Weatherforecast endpoint"
[home-page-link]: /labs/spring-one
[exercise-1-link]: /labs/spring-one/exercise1
[exercise-2-link]: /labs/spring-one/exercise2
[exercise-3-link]: /labs/spring-one/exercise3
[exercise-4-link]: /labs/spring-one/exercise4
[exercise-5-link]: /labs/spring-one/exercise5
## Exploring all actuators
### Goal
See all actuators running and learn what options are available.
### Expected Results
Enhance the app created in the previous exercise to enable all actuator endpoints.
### Get Started
Open `Program.cs` and replace the 3 Steltoe "Add" statements with the single "all actuators" statement.
```csharp
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
})
//Steeltoe actuators
.AddAllActuators()
;
```
Expose all the actuator endpoints for debugging and demonstration purpose in `appsettings.json`.
```json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Steeltoe": "Information"
}
},
"AllowedHosts": "*",
"management": {
"endpoints": {
"actuator": {
"exposure": {
"include": [ "*" ]
}
}
}
}
}
```
With all actuators implemented in host builder, start the application by clicking the `Debug > Start Debugging` top menu item.
![vs-run-application]
Or use the dotnet cli:
```powershell
dotnet run
```
Once started your default browser should open and automatically load the weather forecast endpoint.
![run-weatherforecast]
What exactly has happened? In the previous exercise 3 of the endpoints where implemented and we visited each in the browser to see their output. There was no need to expose those select endpoints because by default Steeltoe doesn't secure them (you can [if you want](https://steeltoe.io/docs/3/management/using-endpoints#exposing-endpoints)). With the addition of all endpoints, there are some that are secured by default. Here's a list of each endpoint that is available and it's purpose. While the application is running visit each one to learn more.
- `/actuators`: A json structured list of all actuator endpoints that have been exposed.
- `/actuators/env`: A listing of all environment variables that are available to the app.
- `/actuators/health`: The current health status of the app as reported in IHealthContributor, customized for different platforms.
- `/actuators/info`: Various app information collected from the IInfoContributor.
- `/actuators/loggers`: View and configure the logging levels of your application at runtime. This endpoints supports POST requests to adjust logging levels.
- `/actuator/mappings`: Details about utomatically discovered MVC and WebAPI project routes and route templates.
- `/actuators/metrics`: App CLR and HTTP metrics collected using OpenTelemetry library.
- `/actuators/prometheus`: A copy of the metrics endpoint, in a Prometheus friendly format.
- `/actuators/refresh`: Trigger the apps IConfigurationRoot to automatically refresh all configuration values.
- `/actuators/tracing`: Details about the last few request traces made by the app.
### Summary
Similar to the previous exercise, there is a minimum expectation of any microserivce running in the cloud. These things are meant to help the developer debug, trace, and observe the application within its container. But these things have the potential to consume the developer's time creating everything, adding the right options, and making it distributable. Steeltoe aims to use the best in .NET to get the developer back to coding business logic and not deal with the boilerplate stuff.
|[<< Previous Exercise][exercise-1-link]|[Next Exercise >>][exercise-3-link]|
|:--|--:|

Просмотреть файл

@ -1,261 +0,0 @@
[vs-add-efcore]: /site-data/labs/spring-one/images/vs-add-efcore.png "SqlServer EFCore nuget dependency"
[home-page-link]: /labs/spring-one
[exercise-1-link]: /labs/spring-one/exercise1
[exercise-2-link]: /labs/spring-one/exercise2
[exercise-3-link]: /labs/spring-one/exercise3
[exercise-4-link]: /labs/spring-one/exercise4
[exercise-5-link]: /labs/spring-one/exercise5
## Adding a cloud connector with SQL
### Goal
Add a ToDo list data context and item model to the app to see how Steeltoe manages the connection.
### Expected Results
App initializes the database and serves new endpoint for interacting with Todo list items.
### Get Started
We're going to add a database connection and context using entity framework code, in the previously created application. To get started add the Steeltoe package `Steeltoe.Connector.SqlServer.EFCore`.
![vs-add-efcore]
Or use the dotnet cli:
```powershell
dotnet add package Steeltoe.Connector.SqlServer.EFCore
```
Now create a new folder named `Models` and within create a new class named `TodoContext.cs`. This class will server as our context for interacting with the database. Paste the following in the class.
```csharp
using Microsoft.EntityFrameworkCore;
namespace WebApplication1.Models {
public class TodoContext : DbContext {
public TodoContext(): base(){ }
public TodoContext(DbContextOptions<TodoContext> options)
: base(options) {
}
public DbSet<TodoItem> TodoItems { get; set; }
}
}
```
Also in the `Models` folder, create a class named `TodoItem.cs` and paste the following within. This will serve a definition of the things that make up a ToDo list item.
```csharp
using System;
namespace WebApplication1.Models {
public class TodoItem {
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
}
```
Now head over to `Startup.cs` and add the 'DBContext'. Visual Studio should prompt you to add `using Steeltoe.Connector.SqlServer.EFCore` package. Note - there is not need to add any other packages like a SqlClient. The Steeltoe package takes care of everything.
```csharp
public void ConfigureServices(IServiceCollection services) {
services.AddDbContext<TodoContext>(options => options.UseSqlServer(Configuration));
//...
}
```
Because we are going to interacting with a brand new database server we'll need to make sure the database has been initialized before the application can fully start up. In `Startup.cs` adjust the input parmaeters of the `Configure` function to include the TodoContext and add the `EnsureCreated` command as the last line in the function.
```csharp
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, TodoContext context) {
//...
context.Database.EnsureCreated();
}
```
Create a new class in the `Controllers` folder named `TodoItemsController.cs` and paste the following within.
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems1
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
return await _context.TodoItems.ToListAsync();
}
// GET: api/TodoItems1/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
// PUT: api/TodoItems1/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/TodoItems1
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
}
// DELETE: api/TodoItems1/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return todoItem;
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
}
}
```
Finally overwrite default values in `appsettings.json` that the Steeltoe package will use when connecting to the database.
```json
{
"$schema": "https://steeltoe.io/schema/latest/schema.json",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
},
"AllowedHosts": "*",
"sqlserver": {
"credentials": {
//"server": null,
//"port": null,
"username": "<PROVIDE_VALUE>",
"password": "<PROVIDE_VALUE>"
}
},
"management": {
"endpoints": {
"actuator": {
"exposure": {
"include": [ "*" ]
}
}
}
}
}
```
Before we see everything in action lets review what has been done. With the Steeltoe EFCore package added, we create a definition of a database context and list item, and then used them in startup to be a part of dependency injection. But instead of bringing in the typical SqlClient packages to help define things, we used `Steeltoe.Connector.SqlServer.EFCore`. This package not only has all needed sub-packages included but also introduces easily configurable settings with default values. To learn more about what values can be customised, [have a look at the docs](https://steeltoe.io/docs/3/connectors/microsoft-sql-server). In our example we're using the default port of '1433' and a server name of 'localhost'. If you wanted the app to connect to a SQL database hosted elsewhere you could privde different values in appsettings.json. We've provided the required credentials and server name in appsettings. The database name will be derived from our ToDo context. They key is to give Steeltoe connector a valid healthy connection to SQL, it will do the rest.
To get everything going you're going to need a runing instance of SQL. Depending on how that instance is made available, you'll want to adjust the values in `appsettings.json`.
- [Running SQL locally](https://www.sqlservertutorial.net/install-sql-server/): Mostly likely the instance is running on `localhost` through port `1433`. If so then continue on, thats the default.
- [Running in docker (desktop)](https://hub.docker.com/_/microsoft-mssql-server): If it's available on 'localhost' port '1433' then continue on. Otherwise you'll need to uncomment the `server` and `port` parameters in appsettings and provide valid values.
- Running outside your local desktop: If SQL is running somewhere else you'll need its URI and port number. Uncomment the `server` and `port` parameters in appsettings and provide valid values.
As for the `username` and `password` values in `appsettings.json`, replace the placeholder with valid values. The account will need enough permission to create a new database and add tabels within. An example docker command you could run locally to get everything going is:
```powershell
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=IheartSteeltoe1" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
```
Assuming all the SQL requirements are taken care of, start up the application by clicking the `Debug > Start Debugging` top menu item.
![vs-run-application]
Or use the dotnet cli:
```powershell
dotnet run
```
Once started your default browser should open and automatically load the weather forecast endpoint.
![run-weatherforecast]
First lets make sure t
|[<< Previous Exercise][exercise-2-link]|[Next Exercise >>][exercise-4-link]|
|:--|--:|

Просмотреть файл

@ -1,41 +0,0 @@
[xxxxx]: /site-data/labs/spring-one/images/XXXXX.png "xxxxx"
[home-page-link]: /labs/spring-one
[exercise-1-link]: /labs/spring-one/exercise1
[exercise-2-link]: /labs/spring-one/exercise2
[exercise-3-link]: /labs/spring-one/exercise3
[exercise-4-link]: /labs/spring-one/exercise4
[exercise-5-link]: /labs/spring-one/exercise5
## Using an external configuration provider
### Goal
sssss
### Expected Results
ssssssssss
### Get Started
1. Replace Actuator calls with AddAllActuators
<br/><br/>
1. Expose actuators for testing purposes
<br/><br/>
1. Run the application `Start Debugging`
![vs-run-application]
```powershell
dotnet run
```
<br/><br/>
1. Explore endpoints and their values
<br/><br/>
|[<< Previous Exercise][exercise-3-link]|[Next Exercise >>][exercise-5-link]|
|:--|--:|

Просмотреть файл

@ -1,42 +0,0 @@

[xxxxx]: /site-data/labs/spring-one/images/XXXXX.png "xxxxx"
[home-page-link]: /labs/spring-one
[exercise-1-link]: /labs/spring-one/exercise1
[exercise-2-link]: /labs/spring-one/exercise2
[exercise-3-link]: /labs/spring-one/exercise3
[exercise-4-link]: /labs/spring-one/exercise4
[exercise-5-link]: /labs/spring-one/exercise5
## XXXXXX
### Goal
sssss
### Expected Results
ssssssssss
### Get Started
1. Replace Actuator calls with AddAllActuators
<br/><br/>
1. Expose actuators for testing purposes
<br/><br/>
1. Run the application `Start Debugging`
![vs-run-application]
```powershell
dotnet run
```
<br/><br/>
1. Explore endpoints and their values
<br/><br/>
|[<< Previous Exercise][exercise-4-link]|[Back to home >>][home-page-link]|
|:--|--:|

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 27 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 96 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 41 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 25 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 28 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 27 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 26 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 41 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 53 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 17 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 53 KiB

Просмотреть файл

@ -1,23 +0,0 @@
[home-page-link]: /labs/spring-one
[exercise-1-link]: /labs/spring-one/exercise1
[exercise-2-link]: /labs/spring-one/exercise2
[exercise-3-link]: /labs/spring-one/exercise3
[exercise-4-link]: /labs/spring-one/exercise4
[exercise-5-link]: /labs/spring-one/exercise5
## Spring One Workshops - Getting started with .NET microserivces and Steeltoe
This lab has X exercises to get you familiar with adding Steeltoe in an application and using some of its components.
Exercise in this lab:
|||
|:--:|:--|
|1.|Getting to know Steeltoe|
|2.|Exploring all actuators|
|3.|Adding a cloud connector with SQL|
|4.|Using an external configuration provider|
|5.|Exercise 5|
|[Get Started][exercise-1-link]|
|:--:|