20211130のC#に関する記事は8件です。

Blazorプロジェクトのテンプレートについて

Blazorアプリケーションを作り始める時に使えるプロジェクトテンプレートを紹介したいと思います Blazorテンプレート VisualStudioなどを使用してBlazorのプロジェクトを作成するとき、初めから入っているBlazorテンプレートをベースにプロジェクトが作成されます。 Blazorのデフォルトテンプレートではプロジェクト作成の種類に応じて、いくつかの種類に分けることができます。 Blazor WebAssembly アプリ Blazorアプリケーションの実行をWebAssemblyだけで構成します。 Blazor WebAssembly アプリ+ ASP.NET Core Host Blazorアプリケーションの実行をWEbAssemblyで実行します。データを提供する機能として、ASP.Net Coreコントローラーを含んだプロジェクトが作成されます。プロジェクトの種類に「Blazor WebAssembly アプリ」を選択し、追加情報で「ASP.NET Coreでホストされた」を選択することで作成することができます。 Blazor サーバー Blazorアプリケーションの実行をサーバーサイドで実行します。データの提供にASP.Net Core コントローラーは必須ではなく、フロントエンドとバックエンドを一つのプロジェクトに実装することができます。 デフォルトテンプレートに学ぶ デフォルトテンプレートに含まれるBlazorの機能をいくつか見てみましょう。デフォルトテンプレートにはBlazor開発者に向けてのヒントやアイデアが詰まっており非常に参考になります Pages/Index.razor Pagesフォルダに格納されているページ(Counter/FethData/Index)は、デフォルトテンプレートの主な画面が格納されています。 Index.razorコンポーネントは初めの画面に表示されるページです。 これらの画面では、Blazorにおける@pageディレクティブを使用したルーティング定義の実装方法を見ることができます。 Index.razorのルーティング Index.raozr @page "/" Counter.razorのルーティング Counter.raozr @page "/counter" Pages/Counter.razor このページはボタンをクリックすると画面上のカウンターがインクリメントされるページの実装例です。BlazorがJavascriptレスでWebアプリケーションをコーディングできることを証明した非常に分かりやすい例と言えます。 JavaScriptレスなコード Counter.razor @page "/counter" <PageTitle>Counter</PageTitle> <h1>Counter</h1> <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; } } Pages/FetchData.razor FetchData.razorは、日付と気温、天気を表形式で表示するコンポーネントです。このコンポーネントの実装方法はBlazorプロジェクト種類により大きく違ってきます。 Blazor WebAssemblyアプリ Blazor WebAssmeblyアプリでは、表示するデータの取得先として静的に配置されたファイルを読み込みます。読み込むファイルはwwwroot/sample-dataディレクトリに配置されています。Program.csでHttpClientインスタンスを生成しており、ASP.Net CoreのDI(Dependency Injection)の使い方を知ることができます。 Blazor WebAssemblyアプリ + ASP.NET Core Host このプロジェクトは、クライアント側はBlazor WebAssemblyアプリと同じですが、データを提供するサーバー側(ASP.Net Core)のプロジェクトが生成されます。FetchDataの表示データとして、サーバー側プロジェクトにWeatherForecastControllerが生成されています。単に静的なファイルを読み込ませるのではなく認証などの仕組みを作成するプロジェクトでは参考になるでしょう。また、クライアントとサーバーの共通的なインタフェースとして、BlazorApp.Shared/WeatherForecastプロジェクトが作成されており、共通的な定義を集約できるクラスライブラリの作成方法を知ることができます。 Blazor サーバー Blazorサーバーは、バックエンド側の処理をフロントエンドと同一インスタンス内で処理できる為、Blazor WebAssembly アプリと大きく異なります。Blazor サーバーではデータの取得にHttpClientを使用せず、画面側のコードで直接データを提供するクラスを生成することが可能になります。 Shared/SurveyPrompt.razor SurveyPrompt.razorは、Pagesフォルダにあるコンポーネントではなく、画面内で部品のように扱うことができるコンポーネントです。コンポーネントはBlazorを扱う上での基本的な構成要素です。C#でクラスライブラリを作成するように、Blazorではコンポーネントを作ることで部品化することができます。 使いたいところでSurveyPromptコンポーネントを記述する Index.razor <SurveyPrompt Title="How is Blazor working for you?" /> このコンポーネントでは、Title というコンポーネントパラメータを使用する側で指定し、描写時に渡されたパラメータを表示する、という処理をしています。コンポーネントパラメーターの使い方がわかる実装例です。 テンプレートを使う上での注意点 テンプレートやライブラリは.Net Coreのバージョンに大きく依存します。Blazorのデフォルトテンプレートも以前から見た目こそ同じですが、.Net Coreのバージョンアップと共に少しずつ変化してきました。テンプレートやライブラリを使う際は、バージョンによる非互換に注意が必要です。 互換性に影響を与える変更点 サードパーティーのBlazorテンプレート nugetパッケージとして、テンプレートが公開されているもののうち、UIフレームワークのBlazorテンプレートをいくつか紹介します。 MudBlazor.Templates BlazorのUIフレームワークとして人気の高い MudBlazorのテンプレートです。 プロジェクト作成時のオプションに Default を選択すると、デフォルトテンプレートと同じ機能を見ることができます。機能はシンプルですが、初めからライブラリを使用する環境が組み込まれているため、その手間を省けるだけでも大いに活用する意義があります。 プロジェクト作成時のオプションに AdminDashboardを選択すると、多彩なコンポーネントを使用したダッシュボードの作成例を見ることができます。だいたいモックアップではありますが、いくつか動きのある機能もあり、実装の参考になります。 AntDesign.Templates こちらも人気であるAnt Design Blazorを使用したテンプレート。プロジェクトの作成でオプションの fullにチェックを入れないとシンプルなプロジェクトが作成されます。 プロジェクト作成のオプションでfullにチェックを入れると、ダッシュボードアプリケーションが表示されます。Chart部分は実際に動作するので機能が非常に豊富ですね Bootstrap.Blazor.Templates BootstrapBlazorを使ったテンプレート。シンプルですが、BootstrapBlazorも多くのコンポーネントが揃っています BlazorWithIdentity.Template このテンプレートはログイン認証の実装について知ることができます。プロジェクトはWebAssemblyアプリ + ASP.Net Core コントローラーで構成されていて、画面の「Create account」で作成したアカウントで認証する仕組みが実装されています。認証・認可を行うアプリケーションのベースとして、非常に参考になるテンプレートです 他にもテンプレートはいくつかありますが、、、メンテナンスされなかったりして、実用性のあるものはそれほど多くはないですね その他のComponentライブラリ Awesome Blazorは、Blazor開発者が初めに見るべきサイトです。 Blazorに関するありとあらゆる情報が掲載されていて日々進化し続けています。 その中でも、Libraries & ExtensionsにはUIフレームワークをはじめとした様々なライブラリについて知ることができます。 ライブラリによってはテンプレートを提供していませんが、GitHubページからプロジェクトファイルをダウンロードして使うのも良いですね Awesome Blazor 終わりに Blazorのデフォルトテンプレートには、BlazorでC#を使ってこんなことできるよ!というのが詰まっていることがわかりました Blazorアプリケーションを作成する時、サードパーティーのテンプレートをベースにすることで初めから豊富なコンポーネントを使用することができます また、Awesome Blazorを見ると世界中で様々な人がBlazorに注目しており素晴らしいコミュニティを作っています 以上、これからBlazorで開発をする人や、Blazorの知見を深めたい人の参考になれば幸いです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#からSSISパッケージを実行

概要 今回はSSISパッケージを実行するための、コマンドは既にMSから提供されたソースもありますので、そこを参考して作成します。 事前参照資料 ・Visual Studio 2019とSSISインストール 参照サイト:https://qiita.com/neomi/items/0472af43f65be6230490 ・.NET アプリで C# コードを使用して SSIS パッケージを実行する https://docs.microsoft.com/ja-jp/sql/integration-services/ssis-quickstart-run-dotnet?view=sql-server-ver15 ★新しい Visual Studio プロジェクトの作成、参照の追加を参照してください★ ・JP1で実行した場合、30秒で終わってしまう処理を追加するコード参照 http://microsoft-ssis.blogspot.com/2015/05/timeout-after-30-seconds-when-executing.html ・Integrated Logging with the Integration Services Package Log Providers https://www.mssqltips.com/sqlservertip/4070/integrated-logging-with-the-integration-services-package-log-providers/ ・エラーメッセージの出力先および形式 https://software.fujitsu.com/jp/manual/manualfiles/m150000/b1x10203/05z200/b0203-00-05-01-00.html ・SSIS Catalog Logging Tables https://www.timmitchell.net/post/2017/03/31/ssis-catalog-logging-tables/ ソースコード 下記のソースをVSにコピーペーストします。 エラーメッセージを取得する処理がまだ未作成です。 ※正常に実行のため、VSで下記のパッケージをインストールが必要です。 using Microsoft.SqlServer.Management.IntegrationServices; using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SSIS { class Program { static int Main(string[] args) { // Variables string targetServerName = "localhost"; string folderName = "IKOU"; string projectName = "TBL001"; string packageName = "TBL00101.dtsx"; IntegrationServices integrationServices = null; Catalog catalog = null; CatalogFolder folder = null; ProjectInfo project = null; PackageInfo package = null; int returnValue = 1; //0:success, 1:failure long opid = 0; // Create a connection to the server string sqlConnectionString = "Data Source=" + targetServerName + ";Initial Catalog=master;Integrated Security=SSPI;"; using (SqlConnection sqlConnection = new SqlConnection(sqlConnectionString)) { try { // Create the Integration Services object integrationServices = new IntegrationServices(sqlConnection); // Get the Integration Services catalog catalog = integrationServices.Catalogs["SSISDB"]; // Get the folder if (catalog.Folders.Contains(folderName)) { folder = catalog.Folders[folderName]; // Get the project if (folder.Projects.Contains(projectName)) { project = folder.Projects[projectName]; if (project.Packages.Contains(packageName)) { // Get the package package = project.Packages[packageName]; // Run the package opid = package.Execute(false, null); //★★★★★★★★★★★★★★★★★★★★★★★★★ // JP1で実行する際に30秒で終わる処理をこれで解決! //★★★★★★★★★★★★★★★★★★★★★★★★★ // Get execution details with the executionIdentifier from the previous step ExecutionOperation executionOperation = integrationServices.Catalogs["SSISDB"].Executions[opid]; // Workaround for 30 second timeout: // Loop while the execution is not completed while (!(executionOperation.Completed)) { // Refresh execution info executionOperation.Refresh(); // Wait 5 seconds before refreshing (we don't want to stress the server) System.Threading.Thread.Sleep(5000); } //★★★★★★★★★★★★★★★★★★★★★★★★★ // ★★★★★★★★★★★★★★★★★★★★★★★★★ // 実行したopid結果からパッケージのメッセージログを確認 // ★★★★★★★★★★★★★★★★★★★★★★★★★ // TODO:パッケージのエラーログをopidキーで抽出する処理を追加 // return value returnValue = 0; } else { Console.WriteLine("指定したパッケージは存在しません。"); } } else { Console.WriteLine("指定したProject名は存在しません。"); } } else { Console.WriteLine("指定したフォルダ名は存在しません。"); } } catch (Exception ex) { Console.WriteLine("SSIS実行が失敗しました。"); Console.WriteLine("Error=" + ex.Message); } // return value return returnValue; } } } } 実行結果 ローカルPCにはSSIS環境がないため、エラーが表示されています。 下記の実行結果から異常終了の場合、正しく1の異常終了のステータスを返していることが確認できます。正常終了の場合は、0が表示されます。 C:\repos\SSIS\SSIS\bin\Debug>SSIS.exe SSIS実行が失敗しました。 Error=Failed to connect to server localhost. C:\repos\SSIS\SSIS\bin\Debug>echo %errorlevel% 1 終わりに 今回のソースには単純にコンソールにエラーメッセージを表示していますが、 各メッセージをLogファイルに出力すればJP1からエラーの原因を調べる際に良いです。 エラーメッセージをSSIDBのビューから取得処理及びLogファイル作成は未作成ですので、 各自追加してみてください。 ※参照資料 ・catalog.operation_messages (SSISDB データベース) https://docs.microsoft.com/ja-jp/sql/integration-services/system-views/catalog-operation-messages-ssisdb-database?view=sql-server-ver15
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gtk3アプリ RiderとMySqlとDapper

前提条件 MySqlのインストール MySql WorkBenchのインストール DapeprをNuGetからインストール DapperExtensionをNuGetからインストール MySQL WorkBenchでDBを作成する RiderにMySqlに接続するツールがあり、スキーマ、テーブル、カラムが作成できます。 DBの作成の仕方がわからなかったため、MySql WorkBenchからDbだけを作成します WorkBenchでDbだけ作成します。 DBへ接続 DBを作成したらRiderから接続します。 DataBaseにスキーマ名を記入します。 Rider上のテーブルの作成 DBち(スキーマ)を作成するとテーブルを作成できるようになります。 Rider上でのDBの操作 カラムを追加したり、外部キーを追加したりできます。 NuGetからMySql.Dataをダウンロード NugetからMySqlクライアントMySql.Dataをインストールします スキーマからモデルを生成する ここからソースをダウンロードし、Riderのフォルダの中に格納しすぐモデルファイルを作成できるようにします。 MySql用にカスタマイズしていきます。 右クリックから実行しモデルファイルを生成します。 テストソース using System; using System.Linq; using MySql.Data.MySqlClient; using Dapper; using DapperExtensions; namespace mySql { class Program { public class test { public Int64 id { get; set; } = 0; public string code { get; set; } = null; public string name { get; set; } = null; } static void Main(string[] args) { MySqlConnectionStringBuilder b = new MySqlConnectionStringBuilder(); b.Server = "localhost"; b.Port = 3306; b.Database = ""; b.UserID = ""; b.Password = ""; MySqlConnection con = new MySqlConnection(b.ConnectionString); //MySQL形式でSQLを書き出す DapperExtensions.DapperExtensions.SqlDialect = new DapperExtensions.Sql.MySqlDialect(); //Dapperの_の入ったカラム名を有効にする。 Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; con.Open(); string sql = "select * from test;"; var result = con.Query<test>(sql); foreach(var p in result) { Console.WriteLine("ID:" + p.id + " 名:" + p.name); } test test1 = new test(); test1.name = "test2"; test1.code = "java"; con.Insert<test>(test1); string sql3 = "select * from test Where code = 'java';"; var test_result2 = con.QueryAsync<test>(sql3); Console.WriteLine(test_result2.Result); foreach (test test_t in test_result2.Result) { con.Delete<test>(test_t); } var result5= con.QueryAsync<test>(sql); Console.WriteLine(" count " + result5.Result.Count()); con.Close(); } } } 課題 DapperExtensionのInsertAsyncなどAsync系が実行できなかった。 続く
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

人工知能はひまつぶしにひつまぶしを食べるか(検証編・準備)

コーディングが完了したので、簡単に動作確認(機能を検証)してみた。とりあえず、仕様は満たしているようである。 いきなり、結合テストをしてしまったが、単体テストをいくつか作成する。単体テストのフレームワークは、NUnitを使う。 単体テスト対象クラス BalanceBaseクラス Prodauctクラス Colaクラス インターフェースの作成 NSubstituteを使うので、上記クラスを継承するインターフェースが必要になる。Public修飾子のメソッドやプロパティしかテストできない。 IProductインターフェース テストの対象となるプロパティが3個とメソッドが2個。 IProduct.cs using System; using System.Collections.Generic; using System.Text; namespace VendingMachine { public interface IProduct { #region プロパティ /// <summary> /// 商品名 /// </summary> string ProductName { get; set; } /// <summary> /// 在庫 /// </summary> int Stock { get; set; } /// <summary> /// 商品価格 /// </summary> int Price { get; set; } #endregion /// <summary> /// /// </summary> /// <returns></returns> bool HasStock(); /// <summary> /// /// </summary> void SubtractStock(); } } IBalanceインターフェース テストの対象となるメソッドが3個。 IBalance.cs using System; using System.Collections.Generic; using System.Text; namespace VendingMachine { public interface IBalance { /// <summary> /// /// </summary> /// <param name="amount"></param> /// <returns></returns> bool Credit(int amount); /// <summary> /// /// </summary> /// <param name="amount"></param> /// <returns></returns> bool Debit(int amount); /// <summary> /// /// </summary> /// <param name="amount"></param> /// <returns></returns> int GetBalance(); } } インターフェースの継承 Productクラスは、IProductを継承するようソースコードを修正する。 Product.cs public abstract class Product : IProduct 同様に、BindableBaseクラスは、IBalanceを継承するようソースコードを修正する。 BindableBase.cs public class BalanceBase : IBalance 以上でテストケースを作成する準備は、整った。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

人工知能はひまつぶしにひつまぶしを食べるか(検証編・単体テスト)

抽象クラスのテスト Productクラスは抽象クラスなので、Mockでしかテストできない。したがって、NSubstituteを使う。でも、これって本当にテストになっているのかな、と思ってしまう。 Productクラス ProductTests.cs using NUnit.Framework; using NSubstitute; using VendingMachine; using System; using System.Collections.Generic; using System.Text; namespace VendingMachine.Tests { [TestFixture()] public class ProductTests { [Test()] public void StockTest() { // Arrange var sut = Substitute.For<IProduct>(); // Act sut.Stock.Returns(1); // Assert Assert.That(sut.Stock,Is.EqualTo(1)); } [Test()] public void ProductNameTest() { // Arrange var sut = Substitute.For<IProduct>(); // Act sut.ProductName.Returns("コーラ"); // Assert Assert.That(sut.ProductName, Is.EqualTo("コーラ")); } [Test()] public void PriceTest() { // Arrange var sut = Substitute.For<IProduct>(); // Act sut.Price.Returns(100); // Assert Assert.That(sut.Price, Is.EqualTo(100)); } [Test()] public void HasStockTest001() { // Arrange var sut = Substitute.For<IProduct>(); // Act sut.HasStock().Returns(true); // Assert Assert.That(sut.HasStock(), Is.EqualTo(true)); sut.Received().HasStock(); } [Test()] public void HasStockTest002() { // Arraange var sut = Substitute.For<IProduct>(); // Act sut.HasStock().Returns(false); // Assert Assert.That(sut.HasStock(), Is.EqualTo(false)); sut.Received().HasStock(); } [Test()] public void SubtractStockTest() { // Arrange var sut = Substitute.For<IProduct>(); // Act sut.SubtractStock(); // Assert sut.Received().SubtractStock(); } } } 具象クラスのテスト BalanceBaseクラスは具象クラスである。Mockする箇所がないので、NSubstituteは使わずにテストする。こちらのほうが、しっくりする。 BalanceBaseクラス BalanceBaseTests.cs using NUnit.Framework; using VendingMachine; using System; using System.Collections.Generic; using System.Text; namespace VendingMachine.Tests { [TestFixture()] public class BalanceBaseTests { #region Setup /// <summary> /// テストクラス初期処理 /// </summary> [OneTimeSetUp()] public void TestClassInit() { } /// <summary> /// テストクラス終了処理 /// </summary> [OneTimeTearDown()] public void TestClassTerm() { } /// <summary> /// テスト単位初期処理 /// </summary> [SetUp()] public void TestMethodInit() { } /// <summary> /// テスト単位終了処理 /// </summary> [TearDown()] public void TestMethodTerm() { } #endregion [Test()] public void BalanceBaseTest() { // Arrange var sut = new BalanceBase(); // Act // Assert Assert.IsNotNull(sut); Assert.IsInstanceOf<BalanceBase>(sut); } [Test()] public void CreditTest001() { // Arrange var sut = new BalanceBase(); // Act var result = sut.Credit(10000); // Assert Assert.AreEqual(true, result); } [Test()] public void CreditTest002() { // Arrange var sut = new BalanceBase(); // Act var result = sut.Credit(10001); // Assert Assert.AreEqual(false, result); } [Test()] public void DebitTest001() { // Arrange var sut = new BalanceBase(); // Act var temp = sut.Credit(10000); // var result = sut.Debit(100); // Assert Assert.AreEqual(true, result); } [Test()] public void DebitTest002() { // Arrange var sut = new BalanceBase(); // Act var result = sut.Debit(100); // Assert Assert.AreEqual(false, result); } [Test()] public void GetBalanceTest001() { // Arrange var sut = new BalanceBase(); // Act var result = sut.GetBalance(); // Assert Assert.AreEqual(0, result); } [Test()] public void GetBalanceTest002() { // Arrange var sut = new BalanceBase(); // Act var temp = sut.Credit(10000); // var result = sut.GetBalance(); // Assert Assert.AreEqual(10000, result); } [Test()] public void GetBalanceTest003() { // Arrange var sut = new BalanceBase(); // Act var temp = sut.Credit(10000); // var temp2 = sut.Debit(100); // var result = sut.GetBalance(); // Assert Assert.AreEqual(9900, result); } } } Colaクラス Productクラスを継承するColaクラスの単体テスト ColaTests.cs using NUnit.Framework; using VendingMachine; using System; using System.Collections.Generic; using System.Text; namespace VendingMachine.Tests { [TestFixture()] public class ColaTests { [Test()] public void ColaTest() { // Arrange var sut = new Cola(); // Act // Assert Assert.IsNotNull(sut); Assert.IsInstanceOf<Cola>(sut); // Assert.That(sut.ProductName, Is.EqualTo("コーラ")); Assert.That(sut.Stock, Is.EqualTo(5)); Assert.That(sut.Price, Is.EqualTo(100)); } [Test()] public void HasStockTest001() { // Arrange var sut = new Cola(); // Act var result = sut.HasStock(); // Assert Assert.That(result, Is.EqualTo(true)); } [Test()] public void HasStockTest002() { // Arrange var sut = new Cola(); for (int i = 1; i <= 5; ++i) { sut.SubtractStock(); } // Act var result = sut.HasStock(); // Assert Assert.That(result, Is.EqualTo(false)); Assert.That(sut.Stock, Is.EqualTo(0)); } [Test()] public void SubtractStockTest() { // Arrange var sut = new Cola(); // Act sut.SubtractStock(); // Assert Assert.That(sut.Stock, Is.EqualTo(4)); } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCode + .NET Interactive で PowerFx を体験してみよう

はじめに PowerFx がオープンソースとして公開され、独自のアプリに PowerFx を組み込むことができるようになりました。 この記事では、PowerrFx で実際にどのようなことができるかを VSCode の拡張機能である .NET Interactive を使って確認して行きます。 プログラムからの PowerFx の利用 たとえば C# であれば、アプリに次の 2 つのパッケージを追加するだけで、PowerFx の実行エンジンを実体化させプログラム中で PowerFx の式を評価することができます。 この機能を使った PowerFx の対話型アプリのサンプルは power-fx-host-samples として GitHub に公開されています。 ❯ dotnet new console ❯ dotnet add package Microsoft.PowerFx.Core --prerelease ❯ dotnet add package Microsoft.PowerFx.Interpreter --prerelease Program.cs using Microsoft.PowerFx; var engine = new RecalcEngine(); var result = engine.Eval("Sum(1, 2, 3)"); Console.WriteLine(result.ToObject()); 実行結果 ❯ dotnet run 6 VSCode + .NET Interactive + PowerFx VSCode の .NET Interactive 上で動作する PowerFx の拡張機能は PowerFx.NET.Interactive という NuGet ライブラリとして公開されています。動作させるには、README 従い VSCode の.NET Interactive 拡張と、DataTable 拡張を有効にします。 .NET Interactiveで作業をするためにノートを作成しましょう。 新しい .NET Interactive のノートを作成する場合は、Ctrl+Shift+Alt+N でノートを作成します。もしくはコマンドパレットから .NET Interactive: Create new blank notebook を実行してもよいです。 作成するノートの拡張子は .dib でも .ipynb でもどちらでも大丈夫です。言語は C# を選択してください。 ノートが作成されたら、まずは PowerFx のカーネルを NuGet から取得してインストールします。 #r "nuget: PowerFx.NET.Interactive, 0.0.9.7" 現時点のバージョンではこれらの組み込みの数式に対応しているようです。 詳細については、PowerApps の Formula reference を参照してください。 Abs, AddColumns, And, Average, Average, Blank, Concat, Coalesce, Char, Concatenate, CountIf, CountRows, Date, DateAdd, DateDiff, DateValue, DateTimeValue, Day, EndsWith, Exp, IsBlank, IsError, IsToday, If, IfError, Int, Filter, First, FirstN, ForAll, Hour, Last, LastN, Left, Len, Ln, Log, Lower, Max, Max, Mid, Min, Min, Minute, Mod, Month, Not, Now, Or, Power, Replace, Right, Round, RoundUp, RoundDown, Second, Sequence, Sort, StartsWith, Sum, Sum, Split, Sqrt, Substitute, Switch, Table, Text, Time, TimeValue, Today, Trim, TrimEnds, Trunc, Upper, Value, With, Year PowerFx の式を実行する場合は、#!powerfx でカーネルを指定して実行します。例えば、records という変数にテーブルを読み込み、Value が 40 より大きいものを昇順でソートした 1 件目を表示するとしたら次のような式になります。 #!powerfx ClearCollect(records, Table( { Id: 1, Name: "Hoge1", Value: 1 }, { Id: 2, Name: "Hoge2", Value: 13 }, { Id: 3, Name: "Hoge3", Value: 44 }, { Id: 4, Name: "Hoge4", Value: 43 } )); Upper(First(Sort(Filter(records, Value > 40), Value)).Name) また、変数に式を設定するとその値は追跡されそれを参照している変数は自動的に再計算されていることも確認できます。 #!powerfx Set(val1, 1); Set(val2, val1 + 2); val3 = val1 + 2; Set(val1, 2); val2; val3; おわりに PowerFx 自体は Power プラットフォーム上ではすでに利用可能で、今後 PowerAutomate などに移植されるとさらに利用用途が広がり面白くなりそうな機能です。 .NET Interactive の拡張機能はプレリリース版なので、動作が若干怪しい部分もありますが簡単に試してみるには面白と思うので気になる人は触ってみると良いと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#を使用してWord文書にワードアートを挿入する方法

C#を使用してWord文書にワードアートを挿入する方法 背景 Word文書にワードアート効果を追加すると、文書のレイアウトをより美しくなります。 特定な内容を強調するか、強い印象を残したいするか、ワードアートを選択なら人に閃いた感じを与えることができます。この記事では、主にC#およびSpire.Docコンポーネントを使用してWord文書にワードアートを挿入する方法を紹介します。 Spire.Docは、ワードアートを含むさまざまな形状タイプをサポートしています。これらのタイプは、ShapeType列挙型で探すことができます。次の例では、2つのワードアートをWord文書に追加することを展示します。 ワードアートを挿入する詳細な手順 1 Word文書を新しく作成します  Document doc = new Document(); 2 文書にセクションと段落を追加します Section section = doc.AddSection(); Paragraph paragraph = section.AddParagraph(); 3 図形を段落に挿入し、図形の種類をワードアートとして指定します。ワードアートのテキスト、位置、塗りつぶしの色、ストロークの色を設定します ShapeObject shape = paragraph.AppendShape(120,30,ShapeType.TextWave); shape.WordArt.Text = "ハーロウ"; shape.VerticalPosition = 80; shape.HorizontalPosition = 170; shape.FillColor = Color.Yellow; shape.StrokeColor = Color.SeaGreen; shape = paragraph.AppendShape(120,30,ShapeType.TextSlantUp); shape.WordArt.Text = "ワールド"; shape.VerticalPosition = 150; shape.FillColor = Color.Yellow; shape.StrokeColor = Color.Red; 4 文書を保存します doc.SaveToFile("ワードアート.docx", FileFormat.Docx2013); 効果は以下の通りです: コード一覧 using System.Drawing; using Spire.Doc; using Spire.Doc.Documents; using Spire.Doc.Fields; namespace WordArt { class Program { static void Main(string[] args) { //Word文書を新しく作成する Document doc = new Document(); //文書にセクションと段落を追加する Section section = doc.AddSection(); Paragraph paragraph = section.AddParagraph(); //図形を段落に挿入し、図形の種類をワードアートとして指定する //ワードアートのテキスト、位置、塗りつぶしの色、ストロークの色を設定する ShapeObject shape = paragraph.AppendShape(120,30,ShapeType.TextWave); shape.WordArt.Text = "ハーロウ"; shape.VerticalPosition = 80; shape.HorizontalPosition = 170; shape.FillColor = Color.Yellow; shape.StrokeColor = Color.SeaGreen; shape = paragraph.AppendShape(120,30,ShapeType.TextSlantUp); shape.WordArt.Text = "ワールド"; shape.VerticalPosition = 150; shape.FillColor = Color.Yellow; shape.StrokeColor = Color.Red; //文書を保存する doc.SaveToFile("ワードアート.docx", FileFormat.Docx2013); } } } 以上です、けっこう簡単でしょうね、最後まで読んでいただきありがとうございます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Slack の Incoming Webhookで簡易なフィードバック管理機能を作る(Azure Functionsを利用)

はじめに 本稿は、Slack の Incoming Webhook を用いて、アプリに対するユーザーからの要望や不具合報告などのフィードバック管理を簡易的に実現する方法の紹介です。 ユーザーからのフィードバックを管理したい Webサービスであっても、Android/iOSアプリであっても、ユーザーからの要望や不具合報告など、ユーザーからのフィードバックを管理したいことは多いです。 アクティブユーザー数の少ない個人開発のアプリやサービスなら、なおさらユーザーからのフィードバックを元に改善することが重要です。 しかし、DB(データベース)にデータを登録するのは、ちょっとだけ面倒です。 ユーザーからの要望や不具合報告登録をDBに登録する場合、登録したデータを検索したり表示したりするための管理機能が必要ですし、DBに登録されたことを通知する機能も欲しいです。 アプリの本質的でない部分に、あまり労力を使いたくないというのが心情です。 そこで Slack の Incoming Webhook DBの代わりに、Slack の Incoming Webhook を使えば、指定したチャンネルに要望や不具合報告を投稿可能です。 Slackなので、検索もしやすいし、通知にもなります。 フリープランでも、直近10,000件まで投稿が記録できるので、アプリのユーザー数が多くなるまでは、簡易的な管理として十分活用できます。 実現手順の概要 Slack の Incoming Webhook を用いてフィードバック管理機能を作る手順は以下の通りです。 フィードバック管理用のSlackのワークスペースを作成する(こちらのリンク先参照) Incoming Webhook URLを取得する(こちらのリンク先参照) Incoming Webhook URL を用いて Slack に投稿する Web API を作成する 上記の Web API を Webサービスやアプリから実行する この手順の中で、1, 2, 4 は簡単ですが、3 のWeb API を作成する部分は技術的要素があるので、その部分の詳細を以降で説明します。 Microsoft Azure を用いた Web API の作成手順 ここからは、Web API を作成する1つの方法として、Visual Studio で Microsoft Azure の Azure Functions を用いる方法を説明します。 Azure Functions のプロジェクトを作成する まず最初は、以下の公式ページの通りに、Web APIの雛形を作ります。 クイック スタート:Visual Studio を使用して Azure で初めての関数を作成する 上記の手順でプロジェクトを作成すれば、以下のように Function1 というクラスが自動で作成されます。 Function1 の中身は、Web API を実現するための雛形が、下図のように最初から書いてあります。 そのため、やることは、このメソッドの中身を変更するだけです。 このメソッドの中身を変更して、上記公式ページにある Azure に発行する処理を行えば、Web APIの作成完了です。 Slackに投稿するメソッドを作成する C# で Slack の Incoming Webhook を用いて投稿する実装はとても簡単です。 以下のようなメソッドを作れば、指定したSlackのワークスペースに投稿できます。 このメソッドを持つクラス(SlackNotificationServiceクラス)のソースコードはこちらを参照ください。 /// <summary> /// Slackにメッセージを通知する /// </summary> /// <param name="message">メッセージ</param> /// <param name="webhookUrl">webhookUrl</param> /// <param name="userName">ユーザー名</param> /// <param name="channelName">チャンネル名</param> /// <param name="mention">メンションを付けるか/param> /// <returns>通知に成功したか</returns> public async Task<bool> Notify(string message, string webhookUrl, string userName, string channelName, bool mention = true) { // 先頭にChannelメンションを付ける if (mention) { message = $"{ChannelMention}{Environment.NewLine}{message}"; } // 送信パラメータを作成 var slackPayload = new SlackPayload() { // メッセージと投稿者名とチャンネル名を設定 text = message, username = userName, channel = channelName, }; // 送信パラメータオブジェクトをJSONに変換 var jsonSlackPayload = JsonConvert.SerializeObject(slackPayload); // Jsonの送信パラメータ情報をHttpContentに変換 var slackPayloadDictionary = new Dictionary<string, string>() { {PayloadKeyValue, jsonSlackPayload} }; var urlParameter = new FormUrlEncodedContent(slackPayloadDictionary); try { // Skackに投稿 var response = await _HttpClient.PostAsync(webhookUrl, urlParameter) .ConfigureAwait(false); return (response.StatusCode == HttpStatusCode.OK); } catch { return false; } } 上記の実装は2021年11月時点でも正常に動作しますが、これは2020年以前に行ったものであり、2021年時点では Incoming WebHook URL の取得方法について、推奨する方法が変わっています。詳しくは以下の記事を参照ください。 上記の推奨する方法で Incoming WebHook URL を取得した場合、username というパラメータを用いて投稿者名を変更することはできません。 利用できるパラメータの詳細は、以下の公式ページを参照ください。 Azure Functionsから上記メソッドを呼び出す あとは、上記のSlackに投稿するメソッド(SlackNotificationService.Notifyメソッド)を、Azure Functions のメソッドから呼び出すだけです。 もともとメソッドの雛形があるので、そのメソッドの中身を以下のような感じに書き換えればOKです。 ここでは、投稿する本文(message)、チャンネル名(channelName)、メンションするか(mention)をWeb APIのリクエストボティのパラメータとして受け取っています。 以下のクラス全体のソースコードはこちらを参照ください。 public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); // リクエストボディからパラメータを取得 string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject(requestBody); string message = data?.message; string channelName = data?.channelName; bool mention = data?.mention; // Slackの指定のチャンネルに投稿する var service = new SlackNotificationService(); var success = await service.Notify(message, "https://hooks.slack.com/services/XXXXXXX", "BotName", channelName, mention); // Slackへの投稿が成功か失敗か返す string responseMessage = success ? "success" : "failed"; return new OkObjectResult(responseMessage); } 動作確認する 上記のWeb APIを呼び出す際に、リクエストボディに3つのパラメータを渡す必要があります。 そのパラメータをjson形式で記載する例は以下を参照ください。 { "message": "ユーザーからの要望や不具合報告のメッセージ。", "channelName": "error_report", "mention": true } 上記のリクエストボディのパラメータでWeb APIを実行すると、#error_reportチャンネルに下図のように投稿されます。 活用例 ユーザーからのフィードバックの他にも、ユーザーがアプリでどんな操作をしたのかのログを取得する用途にも活用できます。 例えば、以下のように、用途ごとにチャンネルを分けることもできます。 ユーザーからの不具合報告(#error_reportチャンネル) ユーザーからの要望報告(#user_reportチャンネル) アプリでの特定操作時のログ(#info_log) リワード広告の表示ログ(#reward_log) 不具合報告チャンネルには、下図のように、アプリで例外が発生した原因を特定するための情報を投稿すると便利です。 まとめ Slack の Incoming Webhook と Azure Functions を用いることで、フィードバックの管理を簡単に実現できます。本稿で紹介したソースコードは以下のリポジトリで公開しています。 ちなみに私は、普段はエンジニアリングマネージャーとして、チームの皆で楽しく開発する施策を色々実施しています。詳しくは以下を参照ください。 Twitterでも開発に役立つ情報を発信しています → @kojimadev
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む