20220223のC#に関する記事は10件です。

月末日を取得

ORACLEだとそのものズバリの関数があります。 SELECT LAST_DAY(SYSDATE) AS END_OF_MONTH FROM DUAL; C#だと取り敢えず二通り思い浮かびます。 もっとスマートにコードも少なく記述できる方法がありそうな気もしますが。 DaysInMonthを使う int this_month_days = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month); DateTime endOfMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, this_month_days); 翌月の月初日から1日前を求める DateTime endOfMonth = new DateTime(DateTime.Now.AddMonths(1).Year, DateTime.Now.AddMonths(1).Month, 1).AddDays(-1);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Blazor WebAssemblyでMudBlazorを使ってPie Chartを表示してみた

はじめに この記事では、Blazor WebAssemblyでMudBlazorを使って、Pie Chartを表示するまでの手順を示します。 Blazor WebAssemblyとは .NET を使って対話型のクライアント側 Web アプリを構築するためのWebフレームワークです。 MudBlazorとは 見やすく、直感的に操作できるようなデザインであるマテリアルデザインを導入したコンポーネントフレームワークです。 実行環境 Windows 11 Visual Studio 2022 C# (.NET 6.0) 本文 1. プロジェクトの作成 デスクトップ上に「BlazorApp」というプロジェクトを作成します。 追加情報は特に変更せず、デフォルトで進めます。 以下のようなファイル構成で展開し、プロジェクトの作成は完了です! 2. MudBlazorの導入 まずは、MudBlazorパッケージをインストールします。 ソリューションエクスプローラーにあるBlazorAppプロジェクトを右クリックして、NuGetパッケージの管理を選択してください。そして参照で「MudBlazor」を検索し、MudBlazorパッケージをインストールしましょう。私がインストールしたバージョンは6.0.6でした。 次にMudBlazorを使うために、いくつかコードを追加します。 BlazorAppプロジェクト直下にある「_Imports.razor」ファイルに、以下のように追加します。 _Imports.razor @using System.Net.Http @using System.Net.Http.Json @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.AspNetCore.Components.WebAssembly.Http @using Microsoft.JSInterop @using BlazorApp @using BlazorApp.Shared @using MudBlazor // 追加 wwwrootにある「index.html」ファイルに、以下のように追加します。 headタグ内にlink要素を2つ追加してください。また、bodyタグ内にscript要素を1つ追加してください。 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title>BlazorApp</title> <base href="/" /> <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /> <link href="css/app.css" rel="stylesheet" /> <link href="BlazorApp.styles.css" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" /> <!--追加--> <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" /> <!--追加--> </head> <body> <div id="app">Loading...</div> <div id="blazor-error-ui"> An unhandled error has occurred. <a href="" class="reload">Reload</a> <a class="dismiss">?</a> </div> <script src="_framework/blazor.webassembly.js"></script> <script src="_content/MudBlazor/MudBlazor.min.js"></script> <!--追加--> </body> </html> BlazorAppプロジェクト直下にある「Program.cs」ファイルに、以下のように追加します。 Program.cs using BlazorApp; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor.Services; // 追加 var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.RootComponents.Add<HeadOutlet>("head::after"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddMudServices(); // 追加 await builder.Build().RunAsync(); Sharedフォルダにある「MainLayout.razor」ファイルに、以下のように追加します。 MainLayout.razor @inherits LayoutComponentBase <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"> @Body <MudThemeProvider/> @*追加*@ <MudDialogProvider/> @*追加*@ <MudSnackbarProvider/> @*追加*@ </article> </main> </div> 以上で、MudBlazorの導入は完了です! Pie Chartを表示する それでは、Pie Chartを表示させます。 Pagesフォルダにある「Index.razor」ファイルに、以下のようにコードを追加します。 Index.razor @page "/" <PageTitle>Index</PageTitle> <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> @*ここから下を追加*@ <MudPaper Class="pa-4"> <MudChart ChartType="ChartType.Pie" InputData="@data" @bind-SelectedIndex="bsIndex" InputLabels="@labels" Width="300px" Height="300px" /> </MudPaper> <MudPaper Class="pa-4 mt-2 d-flex justify-center"> <MudButton OnClick="AddDataSize" Variant="Variant.Filled" Color="Color.Primary">Add</MudButton> <MudButton @onclick="RandomizeData" Variant="Variant.Filled" Class="mx-4">Randomize</MudButton> <MudButton OnClick="RemoveDataSize" Variant="Variant.Filled" Color="Color.Secondary">Remove</MudButton> </MudPaper> <MudText Typo="Typo.h6">Selected portion of the chart: @bsIndex</MudText> @code { private int bsIndex = -1; //default value cannot be 0 -> first selectedindex is 0. int dataSize = 4; double[] data = { 77, 25, 20, 5 }; string[] labels = { "Uranium", "Plutonium", "Thorium", "Caesium", "Technetium", "Promethium", "Polonium", "Astatine", "Radon", "Francium", "Radium", "Actinium", "Protactinium", "Neptunium", "Americium", "Curium", "Berkelium", "Californium", "Einsteinium", "Mudblaznium" }; Random random = new Random(); void RandomizeData() { var new_data = new double[dataSize]; for (int i = 0; i < new_data.Length; i++) new_data[i] = random.NextDouble() * 100; data = new_data; StateHasChanged(); } void AddDataSize() { if (dataSize < 20) { dataSize = dataSize + 1; RandomizeData(); } } void RemoveDataSize() { if (dataSize > 0) { dataSize = dataSize - 1; RandomizeData(); } } } 実行すると、以下のように表示できれば成功です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ASP.NET】Web未経験者がASPのMSDNチュートリアルやってみる(モデルの追加)

タイトル通り、Web未経験のエンジニアがASP.NETでMSDNのチュートリアルに沿って慣れてみようという内容です。 筆者のステータスはこんな感じ。 VB.NET経験あり C#独学 Web未経験(何それおいしいの?) 時代はWebだということで、手を出してみます。 手を出すチュートリアルはコチラ。 今回はMSDNのチュートリアル「ASP.NET Core で Razor ページ アプリにモデルを追加する」を進めます。 尚、前回実施したチュートリアルの導入編の続きから始めます。 作成の流れ まずは今回の作成の流れを確認します。MSDNのチュートリアルに沿って次の様に進めます。 データモデルの追加 モデルのスキャフォールディング 初期移行 実行 今回のチュートリアルも簡単そうに見えますね。 1. データモデルの追加 まずはデータモデルの追加を実施します。 しかし、初めてASP.NETを触る人にとっては、「データモデルって何?」ってなります。私もなりました。 MSDNのチュートリアルでは、 アプリのモデル クラスでは、Entity Framework Core (EF Core) を使用して、データベースを操作します。 とあります。いまいちピンときません。ちょっと調べてみました。 寄り道①モデルって何? 気になったので調べてみましたが、MSDN特有の言い回しに辟易してしまったので、MSDN以外のサイトも調べてみました。 その中で、【ASP.NET MVC入門その2】ASP.NET MVCでModelクラスの実装のページにモデルの説明があり、そこには、 ASP.NET MVCのModelとは、データのやりとりをするためのクラスです。 と説明してくれています。 なるほど、データベースを操作するためのクラスということですね。 VB.NETで言うところの「OleDbConnection クラス」みたいなものでしょうか。 ※間違ってたらすみません。 寄り道②MVCって何? モデルを調べていて気になったのがもう一つ。MVCという単語です。「ASP.NET モデル」で検索すると、「MVC」という単語が必ずセットでついてきます。 MVCを調べて見ると、MVCについてマイクロソフトが説明しています。 どうやら、MVCというのは、Model-View-Controllerの略で、アーキテクチャのデザインパターンの一つであり、UI作成のために使われるようです。 Model…データ View…ユーザー インターフェイス Controller…アプリケーション ロジック なるほど。 忘れてしまいそうですが、これはチュートリアルです。 チュートリアルで言ってる「データモデルの追加」というのは、「データをやり取りするためのコーディングをしましょう」ということですね。 気を取り直してデータモデルの追加 というわけでチュートリアルの「データモデルの追加」に戻ります。 MSDNの記載から流れを確認すると、 1-1. 「Models」フォルダを追加 1-2. 「Movie」クラスを追加 1-3. 「Movie」クラスにプロパティを作成 となっています。 1-1.「Models」フォルダを追加 まずは、Visual Studio で前回のチュートリアルで作成したプロジェクト「RazorPagesMovie」を開きます。 RazorPagesMovie プロジェクトを右クリックして、コンテキストメニューから「追加」→「新しいフォルダー」を選択し、プロジェクト内にフォルダを追加します。 すると、「新しいフォルダー」がソリューションエクスプローラー上に作成されます。 このフォルダの名前を、「Models」に変更します。 1-2.「Movie」クラスを追加 「Models」フォルダを追加したら、「Movie」クラスを追加します。 「Models」フォルダを右クリックしてコンテキストメニューを開き、「追加」→「クラス」を選択します。 「新しい項目の追加」画面がポップアップされるので、「クラス」を選んで、名前を「Movie」にして、追加をクリックします。 すると、ソリューションエクスプローラーの「Models」フォルダの中に「Movie.cs」が作成されます。 1-3.「Movie」クラスにプロパティを作成 「Movie」クラスを作成したら、今度は「Movie」クラスにプロパティを作成します。 ひとまず、MSDNのソースコードをそのままコピペ。 using System; using System.ComponentModel.DataAnnotations; namespace RazorPagesMovie.Models { public class Movie { public int ID { get; set; } public string Title { get; set; } [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } public string Genre { get; set; } public decimal Price { get; set; } } } プロパティは、 ID…ID Titel…タイトル ReleaseDate…発売日 Genre…ジャンル Price…価格 と言うところでしょうか。気になるのはこの1行。 [DataType(DataType.Date)] これはプロパティに対して型を指定しているのですが、対象となるプロパティは、 public DateTime ReleaseDate { get; set; } だけです。1行にまとめてもエラーが出ないので、こんな感じに書くと分かりやすいですね。 [DataType(DataType.Date)]public DateTime ReleaseDate { get; set; } 2.モデルのスキャフォールディング データモデルのプロパティを作成したら、モデルのスキャフォールディングを行います。 …スキャフォールディングという、見たことも聞いたこともない単語が登場しました。 スキャフォールディングって何? というわけで調べてみましょうスキャフォールディング。 CodeZineで分かりやすくまとめられています。 Scaffolding(スキャフォールディング)とは、データモデルとなる型を元に、いわゆるCRUD(Create/Read/Upadate/Delete)と呼ばれる追加、読込、変更、削除を行う画面とそのコードを自動で生成する機能のことです。 Scaffoldingを和訳すると「足場」という言葉であり、その名のとおり少ない手間でアプリケーションの「足場」となる大枠の構造を作ることを目的としています。従って、Scaffoldingは完全なアプリケーションを作るための機能ではない、ということは認識しておく必要があります。 なるほど。 作成したモデルを元にして、データ操作に必要な機能を自動で作ってくれるみたいですね。 ただし、大枠の構造を作るだけで、他の機能については自分で実装する必要があるようです。 スキャフォールディングしてみる ではスキャフォールディングを実行してみます。 まず、ソリューションエクスプローラーの「Pages」フォルダを右クリックしてコンテキストメニューを開き、「追加」→「新しいフォルダー」を選択して、「Movies」フォルダを作成します。 こんな感じに「Pages」「Movies」フォルダを作ります。 「Pages」フォルダの中に「Movies」フォルダを作成したら、「Movies」フォルダを右クリックしてコンテキストメニューを開き、「追加」→「新規スキャフォールディングアイテム」をクリックします。 すると、「新規スキャフォールディング アイテムの追加」のポップアップが出て来るので、「Entity Framework を使用する Razor ページ (CRUD)」を選択して追加ボタンをクリック。 またまた少し寄り道を。 CRUDというまたまた新しい単語が出てきていますが、これは、 Create(作成) Read(参照) Update(更新) Delete(削除) の頭文字を取ったもので、データベース操作の基本的な機能です。DBMSにおけるDML(データ操作言語)に相当するものです。 話を戻して、「新規スキャフォールディング アイテムの追加」画面で、「Entity Framework を使用する Razor ページ (CRUD)」を選択して追加ボタンをクリックしたところです。 すると、「Entity Framework を使用する Razor ページ (CRUD)の追加」というポップアップが出てきます。 初期状態だと上図の様に空っぽなので、「モデル クラス」と「データ コンテキスト クラス」を設定します。 「モデル クラス」は、リストからMovie (RazorPagesMovie.Models)を選択します。 「データ コンテキスト クラス」は、右にある「+」ボタンをクリックすると「データコンテキストの追加」のポップアップ画面が出て来るので、「新しいデータコンテキスト型」に「RazorPagesMovie.Data.RazorPagesMovieContext」を設定します。 MSDNのチュートリアルでは、 RazorPagesMovie.Models.RazorPagesMovieContext を RazorPagesMovie.Data.RazorPagesMovieContext に変更します。 とありますが、チュートリアル通りに進めると、「RazorPagesMovie.Data.RazorPagesMovieContext」がデフォルトで入っているはずです(私はそうでした)。 下の画像の様に設定したら追加ボタンをクリックします(チェックボックスは何も触らない)。 すると、「スキャフォールディングしています…」という画面が出て来るので、しばらく待ちます。 スキャフォールディングが完了すると、ファイルとフォルダが作成されます。 まず、「Movies」フォルダ内には次のcshtmlファイルが作成されています。 Create.cshtml Delete.cshtml Details.cshtml Edit.cshtml Index.cshtml ソリューションエクスプローラーで見るとファイルが作成されていることが分かります。 また、RazorPagesMovieプロジェクトの直下に「Data」フォルダが作成され、その中に RazorPagesMovieContext.cs ファイルが作成されます。 これでスキャフォールディングは完了し、DB操作に必要がhtmlファイルが生成されました。 3. 初期移行 スキャフォールディングが完了したら、「パッケージ マネージャー コンソール」から初期移行を実施します。 といっても、MSDNのチュートリアルではコンソール画面にコマンドを入力して実行しているだけなので簡単です。 コマンドの実行 Visual Studio のメニュー画面の「ツール」を開き、「NuGetパッケージマネージャー」→「パッケージ マネージャー コンソール」を選択します。 すると、Visual Studio の画面の下に「パッケージ マネージャー コンソール」が出現します。 上の画像の赤枠で囲った部分が「パッケージ マネージャー コンソール」です。 ここに、コマンドを入力します。 まずは、  Add-Migration InitialCreate と入力して、Enterキーを押下。 「Build succeeded.」と出ていれば完了です。 次に、  Update-Database と入力して、Enterキーを押下。 こちらも「Build succeeded.」と出ていれば完了です。 そして上記のコマンドを実行すると、ソリューションエクスプローラーに「Migrations」フォルダが作成されます。 …何か気が付いたら作成されていたので、MSDNのチュートリアルに書かれていることを忖度しながら解読してみます。 まず、Add-Migration InitialCreate コマンドの実行で、「Migrations」フォルダが作成され、その中に「yyyymmddhhmiss_InitialCreate.cs」と「RazorPagesMovieContextModelSnapshot.cs」の2ファイルが作成されます。 その次の、Update-Database コマンドの実行で、「yyyymmddhhmiss_InitialCreate.cs」のUpメソッドが実行されます。 protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Movie", columns: table => new { ID = table.Column<int>(nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Title = table.Column<string>(nullable: true), ReleaseDate = table.Column<DateTime>(nullable: false), Genre = table.Column<string>(nullable: true), Price = table.Column<decimal>(nullable: false) }, constraints: table => { table.PrimaryKey("PK_Movie", x => x.ID); }); } なるほど、このUpメソッドでテーブルを作成しているんですね。 依存関係挿入に登録されるコンテキスト MSDNのチュートリアルの順番に進めると、唐突に「依存関係挿入に登録されるコンテキストを調べる」が出てきます。 何だこれはという感じですが、 スキャフォールディング ツールによってデータベース コンテキスト context が自動的に作成され、依存関係挿入コンテナーに登録されました。 ということらしい。 長々と書かれていますが、スキャフォールディングではStartup.ConfigureServices メソッドに、モデルとして作成した「Movie」の情報を調整するように追記してくれているみたいです。 そしてもう一つは「Data」フォルダにある RazorPagesMovieContext.cs の話で、RazorPagesMovieContextクラス内で、プロパティが設定されている Movie クラスをデータセットとして扱うことが可能になっているようです。 4.実行 というわけで実行してみます。F5キーでもIIS Expressボタンでもどちらでも大丈夫です。 とりあえず立ち上がりました。 で、ここから、URLの末尾に「/movies」を加えてページ遷移します。 もし、https://localhost:xxxxx/movies (xxxxxはポート番号)にジャンプしない場合は、一度終了して、ビルドしてから再実行してみて下さい。 ※私はジャンプしなかったのでビルドして再実行したら出来ました。 データを登録してみます。 チュートリアルの通りにポチポチと入力。 ※コピペ用にテキスト貼っておきます。 Title:The Good, the bad, and the ugly Genre:Western Price:1.19 Createボタンをクリックし、登録されていることを確認。 大丈夫そうですね。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Splitを使って文字列を文字数で分割できるか?

できません。orz セパレーター(char)が無いと何ともできません。 不便なのでSplitByLengthなる関数を作ったりしましたが、拡張メソッドのほうが格好良くね? ということでネットで調べて作りました。 public static class StringExtensions { /// <summary> /// 指定の文字数で分割 /// </summary> /// <param name="value">分割する文字列</param> /// <param name="count">分割する文字数</param> /// <returns>配列</returns> public static string[] Split(this string value, int count) { var list = new List<string>(); int length = (int)Math.Ceiling((double)value.Length / count); for (int i = 0; i < length; i++) { int start = count * i; if (value.Length <= start) { break; } if (value.Length < start + count) { list.Add(value.Substring(start)); } else { list.Add(value.Substring(start, count)); } } return list.ToArray(); } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# Splitを使って文字列を文字数で分割できるか?

できません。orz セパレーター(char)が無いと何ともできません。 不便なのでSplitByLengthなる関数を作ったりしましたが、拡張メソッドのほうが格好良くね? ということでネットで調べて作りました。 【追記】 最初の投稿にいくつかコメントをいただきまして、勝手に完成度の高いものになってしまいました。 Qiita恐るべしです。 サロゲートペアに対応 @ktz_aliasさんからサロゲートペアがあると文字化けするとコメントとコードをいただきました。 サロゲートペアって何?美味しいの?ってくらいに知らなかったんですが、4バイト文字だったのね。 @ktz_aliasさん、ありがとうございました。 丸写し public static class StringExtensions { /// <summary> /// 指定の文字数で分割 /// </summary> /// <param name="value">分割する文字列</param> /// <param name="maxLength">分割する文字数</param> /// <returns>配列</returns> public static IEnumerable<string> Split(this string value, int maxLength) { var info = new StringInfo(value); var len = info.LengthInTextElements; var p0 = 0; var p1 = maxLength; while (p0 < len) { if (p1 > len) { p1 = len; } yield return info.SubstringByTextElements(p0, p1 - p0); p0 = p1; p1 += maxLength; } } } .NET6版(サロゲートペア非対応) @htsignさんから、.NET 6からChunkメソッドが使えると教えていただきました。 サロゲートペアがなんぼのもんじゃい!という方はぜひ。 とても簡潔に記述できます。 @htsignさん、ありがとうございました。 こちらも丸写し public static class StringExtensions { /// <summary> /// 指定の文字数で分割 /// </summary> /// <param name="value">分割する文字列</param> /// <param name="maxLength">分割する文字数</param> /// <returns>配列</returns> public static string[] Split(this string value, int maxLength) { return value.Chunk(maxLength).Select(cs => new string(cs)).ToArray(); } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Minimal APIのチュートリアルをやってみる

はじめに MicrosoftのMinimal APIのチュートリアルをやってみる。一部、チュートリアルと異なる作業も行う。 最後に、参考をまとめる。 Minimal APIとは 簡略的なASP.NET APIを作成できる機能。 .NET6からサポートされている。 利点 ほんの数行でAPIを実装できる。GET/POST/PUT/DELETEのAPIの一例。 var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "This is a GET"); app.MapPost("/", () => "This is a POST"); app.MapPut("/", () => "This is a PUT"); app.MapDelete("/", () => "This is a DELETE"); app.Run(); 欠点 ASP.NET MVCコントローラの一部機能はサポートされていない。 開発環境 Visual Studio 2022 ASP.NET and Web development .NET6 手順 Web APIプロジェクトを作成する 本記事では、MinimalApiPracticeという名前のソリューションを使用しています。 下記2つの画像はMicrosoft のチュートリアルから引用。 自動生成コードを確認する Program.csに下記コードが記載されていることを確認する。 WeatherForecastというWeb APIと、SwaggerのWeb APIドキュメントが発行される。 自動生成コード var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; app.MapGet("/weatherforecast", () => { var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); return forecast; }) .WithName("GetWeatherForecast"); app.Run(); internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } アプリを実行する デバッカーなしで実行する(Ctrl + F5) ASP.NET Core SSL証明書を承認する 「はい」を選択する。 「はい」を選択する。 ブラウザ上でSwaggerの起動を確認する GETのWeb APIを実行する [Try it out]のあとに、[Execute] を実行する。Web APIの実行結果(Response)が表示される。 Web APIの実行結果を確認する Web APIの実行結果 [ { "date": "2022-02-24T01:09:03.8103012+09:00", "temperatureC": 19, "summary": "Chilly", "temperatureF": 66 }, { "date": "2022-02-25T01:09:03.810409+09:00", "temperatureC": 38, "summary": "Cool", "temperatureF": 100 }, { "date": "2022-02-26T01:09:03.8104115+09:00", "temperatureC": 37, "summary": "Balmy", "temperatureF": 98 }, { "date": "2022-02-27T01:09:03.8104117+09:00", "temperatureC": -14, "summary": "Cool", "temperatureF": 7 }, { "date": "2022-02-28T01:09:03.8104118+09:00", "temperatureC": -20, "summary": "Warm", "temperatureF": -3 } ] Hello WorldのAPIを作成する 自動生成コードを書き換える 下記コードに変更する。 var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run(); 起動時のURLからSwaggerを除く やり方は2通り。 (1)lanchSetting.jsonを直接編集する方法 [Properties]->[launchSettings.json]を選択する。 "launchUrl": "swagger"が2つあるため、消す。 launchSettings.json { "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:54276", "sslPort": 44381 } }, "profiles": { "MinimalApiPractice": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "https://localhost:7247;http://localhost:5247", "dotnetRunMessages": true }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } (2)デバックのプロパティからlanchSetting.jsonを編集する [デバック]->[プロパティ]を開く。 [プロファイルの起動]->[URLの欄]からswaggerを消す。 ソリューション名、IIS Expressのそれぞれから削除する。 ちなみに、起動時のURLからSwaggerの設定を除外し忘れた場合は404になる。 Swaggerを設定する SwaggerからAPIを実行するため、Swaggerの設定を戻す。 コメントの記載がある箇所が追加したコード。 var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapGet("/", () => "Hello World!"); app.Run(); 起動時のURLからSwaggerにSwaggerを追加する。 Swaggerの画面は下記の通り。 GET/PUT/POST/DELETEのAPIを定義する 使用したコードは下記の通り var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // Web API Definition app.MapGet("/testGet", () => "This is a GET"); app.MapPost("/testPost", () => "This is a POST"); app.MapPut("/testPut", () => "This is a PUT"); app.MapDelete("/testDelete", () => "This is a DELETE"); app.Run(); Swaggerの画面は下記の通り。 それぞれのAPI 実行結果は下記の通り。 No Request URL Response body 1 https://localhost:7247/testGet This is a GET 2 https://localhost:7247/testPost This is a POST 3 https://localhost:7247/testPut This is a PUT 4 https://localhost:7247/testDelete This is a DELETE 参考 Minimal API の概要 チュートリアル: ASP.NET Core で Minimal Web API を作成する ASP.NET Core、最小限の API、.NET 6 を使用して Web アプリとサービスを作成する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#/ASP.NET】Minimal APIでWeb APIを定義してみる

はじめに MicrosoftのMinimal APIのチュートリアルをベースに、GET/PUT/POST/DELETEのWeb APIを定義して、動かしてみる。最後に、参考をまとめる。 Minimal APIとは 簡略的なASP.NET APIを作成できる機能。 .NET6からサポートされている。 利点 ほんの数行でAPIを実装できる。GET/POST/PUT/DELETEのAPIの一例。 var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "This is a GET"); app.MapPost("/", () => "This is a POST"); app.MapPut("/", () => "This is a PUT"); app.MapDelete("/", () => "This is a DELETE"); app.Run(); 欠点 ASP.NET MVCコントローラの一部機能はサポートされていない。 開発環境 Visual Studio 2022 ASP.NET and Web development .NET6 手順 Web APIプロジェクトを作成する 本記事では、MinimalApiPracticeという名前のソリューションを使用しています。 下記2つの画像はMicrosoft のチュートリアルから引用。 自動生成コードを確認する Program.csに下記コードが記載されていることを確認する。 WeatherForecastというWeb APIと、SwaggerのWeb APIドキュメントが発行される。 自動生成コード var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; app.MapGet("/weatherforecast", () => { var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast ( DateTime.Now.AddDays(index), Random.Shared.Next(-20, 55), summaries[Random.Shared.Next(summaries.Length)] )) .ToArray(); return forecast; }) .WithName("GetWeatherForecast"); app.Run(); internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary) { public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } アプリを実行する デバッカーなしで実行する(Ctrl + F5) ASP.NET Core SSL証明書を承認する 「はい」を選択する。 「はい」を選択する。 ブラウザ上でSwaggerの起動を確認する GETのWeb APIを実行する [Try it out]のあとに、[Execute] を実行する。Web APIの実行結果(Response)が表示される。 Web APIの実行結果を確認する Web APIの実行結果 [ { "date": "2022-02-24T01:09:03.8103012+09:00", "temperatureC": 19, "summary": "Chilly", "temperatureF": 66 }, { "date": "2022-02-25T01:09:03.810409+09:00", "temperatureC": 38, "summary": "Cool", "temperatureF": 100 }, { "date": "2022-02-26T01:09:03.8104115+09:00", "temperatureC": 37, "summary": "Balmy", "temperatureF": 98 }, { "date": "2022-02-27T01:09:03.8104117+09:00", "temperatureC": -14, "summary": "Cool", "temperatureF": 7 }, { "date": "2022-02-28T01:09:03.8104118+09:00", "temperatureC": -20, "summary": "Warm", "temperatureF": -3 } ] Hello WorldのAPIを作成する 自動生成コードを書き換える 下記コードに変更する。 var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run(); 起動時のURLからSwaggerを除く やり方は2通り。 (1)lanchSetting.jsonを直接編集する方法 [Properties]->[launchSettings.json]を選択する。 "launchUrl": "swagger"が2つあるため、消す。 launchSettings.json { "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:54276", "sslPort": 44381 } }, "profiles": { "MinimalApiPractice": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "https://localhost:7247;http://localhost:5247", "dotnetRunMessages": true }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } (2)デバックのプロパティからlanchSetting.jsonを編集する [デバック]->[プロパティ]を開く。 [プロファイルの起動]->[URLの欄]からswaggerを消す。 ソリューション名、IIS Expressのそれぞれから削除する。 アプリを実行する 成功時 ブラウザ画面に下記文字列が出力される。 Hello World! 失敗時 例) 起動時のURLからSwaggerの設定を除外し忘れた場合、404になる。 Swaggerを設定する SwaggerからAPIを実行するため、Swaggerの設定を戻す。 コメントの記載がある箇所が追加したコード。 var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapGet("/", () => "Hello World!"); app.Run(); 起動時のURLからSwaggerにSwaggerを追加する。 Swaggerの画面は下記の通り。 GET/PUT/POST/DELETEのAPIを定義する 使用したコードは下記の通り var builder = WebApplication.CreateBuilder(args); // Add services to the container. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // Web API Definition app.MapGet("/testGet", () => "This is a GET"); app.MapPost("/testPost", () => "This is a POST"); app.MapPut("/testPut", () => "This is a PUT"); app.MapDelete("/testDelete", () => "This is a DELETE"); app.Run(); Swaggerの画面は下記の通り。 それぞれのAPI 実行結果は下記の通り。 No Request URL Response body 1 https://localhost:7247/testGet This is a GET 2 https://localhost:7247/testPost This is a POST 3 https://localhost:7247/testPut This is a PUT 4 https://localhost:7247/testDelete This is a DELETE 参考 Minimal API の概要 チュートリアル: ASP.NET Core で Minimal Web API を作成する ASP.NET Core、最小限の API、.NET 6 を使用して Web アプリとサービスを作成する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

.NET nanoFrameworkでマイコンプログラミング(WiFiとMQTT)

.NET nanoFrameworkのサンプルプログラム3つ目です。 今回はWifi接続とMQTTです。 使用したデバイスは M5 ATOM Matrix ですが、ESP32ボードならどれでも動作すると思います。 ハードウェア ・M5 ATOM Matrix ・ESP32 DevkitC ソフトウェア ・VisualStudio2019 ・ファームウェア ESP32_PICO 1.7.4-preview.54 ・ファームウェア ESP32_REV0 1.7.4-preview.54 追加するNuGetパッケージ ・nanoFramework.System.Device.WiFi 1.4.0-preview.36 ・nanoFramework.M2Mqtt 5.0.2-preview.80 プログラム Program.cs using System; using System.Diagnostics; using System.Threading; //追加 using nanoFramework.Networking; using System.Text; using nanoFramework.M2Mqtt; using nanoFramework.M2Mqtt.Messages; namespace NF_WiFi_MQTT { public class Program { const string ssid = "YOUR SSID"; const string password = "PASSWORD"; public static void Main() { //Wifi接続 ConnectWifi(); //mqttクライアント var client = new MqttClient("BROKER ADDRESS"); var clientId = Guid.NewGuid().ToString(); client.Connect(clientId); //Subscribe client.Subscribe(new[] { "NF-mqtt/demo" }, new[] { MqttQoSLevel.AtLeastOnce }); //イベント登録 client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived; //Publish for (int i = 0; i < 5; i++) { client.Publish("NF-mqtt/demo", Encoding.UTF8.GetBytes("=== Hello MQTT! ==="), MqttQoSLevel.AtLeastOnce, false); Thread.Sleep(5000); } //接続の解除 client.Disconnect(); Thread.Sleep(Timeout.Infinite); } private static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e) { Debug.WriteLine($"Message received: {Encoding.UTF8.GetString(e.Message, 0, e.Message.Length)}"); } private static void ConnectWifi() { CancellationTokenSource cs = new(60000); //WifiでDHCP接続 var success = WiFiNetworkHelper.ConnectDhcp(ssid, password, requiresDateTime: true, token: cs.Token); if (!success) { Debug.WriteLine($"Can't connect to the network, error: {WiFiNetworkHelper.Status}"); if (WiFiNetworkHelper.HelperException != null) { Debug.WriteLine($"ex: {WiFiNetworkHelper.HelperException}"); } } else { Debug.WriteLine("Wifi Connected!"); } } } } ・"YOUR SSID","PASSWORD","BROKER ADDRESS"は自分の環境に合わせて変更してください。 ・Brokerは色々ありますが、shiftr.io Desktopがローカル環境で試せるのでお勧めです。 ・少し前までWifi接続のためにはnanoFramework.Windows.Devices.Wifiを使っていたのですが、最新のファームウェアではnanoFramework.System.Device.WiFiを使う必要があります。他にもGPIOなどのパッケージが変更になっています。 ソースコードはこちらからダウンロードできます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WPF/C# コントロールの要素をキャプチャする

概要 WPFとC#でウィンドウの中に配置したコントロールを画像として保存する必要があったので書いていく 書いた環境 この記事を書いた環境なので他の環境でも多分動く 項目 値 OS Windows 11 Pro (21H2) IDE Microsoft Visual Studio Community 2022 (64bit) .NETバージョン .NET 6 手っ取り早く答えが欲しい人向けのコード キャプチャしたい要素(一番親の要素)を引数に渡すとBitmapSourceで返すメソッド //以下のusingを追加する //using System.Windows; //using System.Windows.Media; //using System.Windows.Media.Imaging; public static BitmapSource FrameworkElementToBitmapSource(FrameworkElement element) { element.UpdateLayout(); var width = element.ActualWidth; var height = element.ActualHeight; var dv = new DrawingVisual(); using (var dc = dv.RenderOpen()) { dc.DrawRectangle(new BitmapCacheBrush(element), null, new Rect(0, 0, width, height)); } var rtb = new RenderTargetBitmap((int)width, (int)height, 96d, 96d, PixelFormats.Pbgra32); rtb.Render(dv); return rtb; } (おまけ) 上のメソッドで帰ってきたBitmapSourceをPNGファイルとして保存するメソッド。 //以下のusingを追加する //using System.IO; public static void BitmapSourceToPngFile(BitmapSource bitmapSource, string pngFilePath) { using (var stream = new FileStream(pngFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) { var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); encoder.Save(stream); } } どうしてこのような処理が必要なのか 実は以下のようなコードでも一応コンパイルは通る public static BitmapSource FrameworkElementToBitmapSource(FrameworkElement element) { element.UpdateLayout(); var rtb = new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight, 96d, 96d, PixelFormats.Pbgra32); rtb.Render(element); return rtb; } なぜならFrameworkElementはRenderTargetBitmapのRenderメソッドの引数として渡すVisualクラスを継承しているため。 しかし、出力したい要素がStackPanelのChildrenプロパティから取得した要素だったり、ウィンドウの外に飛び出した要素だったりすると正しく動かない 第一の問題の解決法: DrawingVisualクラスを使う! DrawingVisualクラスを使うと以下のようなコードになる var dv = new DrawingVisual(); using (var dc = dv.RenderOpen()) { //ここで「dc」に描画 } var rtb = new RenderTargetBitmap((int)width, (int)height, 96d, 96d, PixelFormats.Pbgra32); rtb.Render(dv); 「dc」の持つDrawRectangleメソッドはBrushの派生クラスを使って要素を描画し、追加する項目はVisualクラスの派生クラスなので以下のようなコードが考えられる 実際ほとんどのブログでは以下のようなVisualBrushを使ったコードが掲載されている var dv = new DrawingVisual(); using (var dc = dv.RenderOpen()) { dc.DrawRectangle(new VisualBrush(element), null, new Rect(0, 0, element.ActualWidth, element.ActualHeight)); } var rtb = new RenderTargetBitmap((int)width, (int)height, 96d, 96d, PixelFormats.Pbgra32); rtb.Render(dv); しかしこのVisualBrushクラスには問題があり、大きいサイズの画像を作成しようとした場合サイズに比例して品質が悪くなる 実際にキャプチャした元のウィンドウとキャプチャした結果の画像を比較した画像が以下の通り 折角出力した画像がこんなガビガビなのだったらガッカリなのでこれはなんとかしなければならない 第二の問題の解決法: VisualBrushクラスではなくBitmapCacheBrushを使う! var dv = new DrawingVisual(); using (var dc = dv.RenderOpen()) { dc.DrawRectangle(new BitmapCacheBrush(element), null, new Rect(0, 0, element.ActualWidth, element.ActualHeight)); //VisualBrush → BitmapCacheBrushに変更 } 変更した結果の出力した比較が以下の通り 綺麗に出力できました! 結論 コントロールをキャプチャする時はDrawingVisualとBitmapCacheBrushを使おう!! サンプルソースコード 今回作成したサンプルを以下のGitHubへアップロードしておきますね Sakurai-Shinya/WPF_Element_Capture_Sample
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

本当の継承シングルトンを見せてやんよ【C#】

今回は,継承可能なシングルトン,つまり,この抽象クラスを継承すればなんでもシングルトンになれるぜ〜ってクラスを紹介します。 継承ツリーという概念と、みんな大好きジェネリックが出てきます。 誰しも一回は通る道 public abstract class BaseSingleton<T> { public static T Instance; public BaseSingleton() { Instance = (T)this; } } public class Singleton : BaseSingleton<Singleton> { } これじゃコンパイラーは通しちゃくれません。なぜでしょうか。 Cannot convert type 'BaseSingleton<T>' to 'T'. Instance = (T)this;のところでひっかっています。これはObject => BaseSingleton<T>とObject => Tという二つの継承ツリーが存在しており、言語仕様として別ツリーにはキャストできないからです。つまり、TとBaseSingleton<T>の関係を教えてやればいいのです。 結論 正解は、これ。 public abstract class BaseSingleton<T> where T : BaseSingleton<T> { public static T Instance; public BaseSingleton() { Instance = (T)this; } } public class Singleton : BaseSingleton<Singleton> { } where節により、継承関係が明示されました。 継承ツリーはObject => BaseSingleton<T> => Tとなっており、これならキャスト可能です。 余談: UnityのMonoBehaviourをシングルトンにしてみる 同じように。 public abstract class SingletonBehaviour<T> : MonoBehaviour where T : SingletonBehaviour<T> { public static T instance; public SingletonBehaviour() { instance = (T)this; } private protected virtual void OnDestroy() { instance = null; } } まとめ ジェネリックってほんとにムズカシイ!けどめっちゃ楽しい!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む