20190830のC#に関する記事は7件です。

Azure Functions (C#) で ASP.NET Core っぽく DI を利用する

概要

Azure Functions にて .NET Core で開発する際において、DIを用いた実装方法について纏めます。
ASP.NET Core にて利用したように、Serviceインスタンスの依存関係注入がやり易い形になっています。

公式のドキュメントは、下記になります。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-dotnet-dependency-injection

以下、記事を参考にさせていただきました。
https://blog.shibayan.jp/entry/20190520/1558340113
https://qiita.com/HiroyukiSakoh/items/e9e472a92a53da4d7568

環境

  • Azure Functions
  • Windows10
  • Visual Studio 2019
  • .NET Core 2.2

コードサンプル

サンプルコードを Github にアップしています。
https://github.com/tYoshiyuki/azure-functions-di-sample

解説

公式の記事の通り、Microsoft.Azure.Functions.Extensions を Nuget より取得し、プロジェクトに加えます。
https://www.nuget.org/packages/Microsoft.Azure.Functions.Extensions/

Startup.cs にて DI の設定を行います。
実装例として、設定ファイルの読み込みとサービスのDI設定を行っています。

Startup.cs
[assembly: FunctionsStartup(typeof(Startup))]
namespace AzureFunctionsDiSample
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var services = builder.Services;
            var provider = services.BuildServiceProvider();
            var configuration = provider.GetRequiredService<IConfiguration>();

            // 設定ファイルの内容をバインドする
            services.Configure<AppSettings>(configuration.GetSection("AppSettings"));

            // サービスのDI設定を行う
            services.AddTransient<IHelloService, HelloService>();
            services.AddTransient<IApplication, Application>();
        }
    }
}

コードサンプルは、以下のようにクラスのレイヤー分けを行っています。

クラス名 説明
EntryPoint Azure Functions のエントリーポイント
Application メインとなるアプリケーション
HelloService ビジネスロジックサービス

Azure Functions のエントリーポイントとなるクラス (EntryPoint.cs) から、
実際のアプリケーション処理を行うクラス、サービス処理を行うクラスを別レイヤーに切り出しています。
これにより、エントリーポイントとアプリケーションの依存関係を分離し、ユニットテストを実施し易い形にしています。

DIで設定したインスタンスは、コンストラクタインジェクションで受け取ります。
ASP.NET Core で利用する形と同じようなイメージになります。

EntryPoint.cs
public EntryPoint(IApplication application)
{
    _application = application;
}

[FunctionName("FunctionsDiSample")]
public IActionResult Run(
    [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
    ILogger log)
{
    log.LogInformation("Function Run");

    _application.Run();

    return new OkObjectResult("Hello Functions DI Sample");
}

EntryPointでは Application を受け取り、また同様に Application では HelloService を受け取ります。
設定ファイルについては、IOptionsで受け取れます。

Application.cs
private readonly AppSettings _appSettings;
private readonly IHelloService _service;

public Application(ILogger<IApplication> logger, IOptions<AppSettings> optionsAccessor, IHelloService service) : base(logger)
{
    _appSettings = optionsAccessor.Value;
    _service = service;
}

ASP.NET Core で開発する際に意識するような クラスのレイヤー分け のノウハウが、
Azure Functionsでも生かせるようになり、今後の開発の幅が広がると思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ラムダ式とは

ラムダ式とは

関数型言語由来の概念。
関数型言語とは「関数を値と同じ様に扱える」言語。

"値"というのは数値とか文字列とかリストとか。
値と同じ様に扱えるとは、

  • 変数に代入できて
  • 関数の引数に渡せて
  • 関数の戻り値にできる

ということ。

例えば、引数に値をとり、それに10を足して返す関数

F(x) = x + 10

のような関数。
関数型言語ではこの関数を値として取り回せる。

では、上記の関数を変数に代入するにはどうすればよいか。
この「値として取り回せる関数の書き方」がラムダ式。

例えば、関数型言語のHaskellでは上記の関数は

 f = x -> x + 10

というふうに記述できる。

「【数値xを受け取り、それに10を足した値を返す関数】を、fという変数に代入した」と思って下さい。

この書き方は言語により異なるが、どれもラムダ式である。
どれも「値として取り回せる関数の書き方」を定義したものだから。
-> とか => とか細かな書き方の違いは関係ありません。

と、ここまでがラムダ式の話なのだがJavaやC#では少々事情が異なる。

これらはクラスあっての言語なので関数はクラスの中、つまりメソッドという形でしか存在できないからです。

なので、function(C#だとFunc)インターフェイスを作り、擬似的に関数として取り回せる様にしている。

例えばJavaで

Function<Integer, Integer>f = new Funciton<>(){
    public Integer apply(Integer x){
        return x + 10;
    }
}

の省略記法に過ぎないわけです。

単なるインスタンスなので、変数に代入できるし、引数にも戻り地にも出来る、というわけです。

以上がラムダ式の説明になります。

  • 「そもそもラムダ式とはなんなのか」
  • 「(関数型言語由来の概念である)ラムダ式を、オブジェクト志向言語に落とし込むには?」

がごっちゃになると一気にわけがわからなくなるので、この2つは分けて考えたほうが良いですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity Addressable Asset Systemを試してみた (その1)

前提

  • unity 2018.4.7f1
  • Addressables 1.1.10
  • 導入から簡単に使ってみるところまで
    • アセットに含まれるプレハブとスプライトを使って、スライドショウを実行します。

公式ドキュメント

導入

  • パッケージマネージャーを使ってAddressablesを導入します。
  • Window (Menu) > Package Manager > Pakkages (Window) > Addressables > Install (Button) SS-13.png

Addressablesの初期化

  • Addressablesウィンドウで初期化を実施します。
  • Window (Menu) > Asset Management > Addressables > Addressables (Winodow) > Create Addressables Settings (Button) SS-1.png

設定

  • Addressablesウィンドウから設定を選び、インスペクターで設定します。 SS-2.png
  • Addressables (Winodow) > Profiles Default > Inspect Profile Settings
    SS-3.png

カタログ

  • Player Version Overrideを記入し、Build Remote Catalogをチェックして、Remote Catalog Build/Load PathをRemote Pathに設定します。
    SS-4.png
    これで、指定したバージョンを含む名前で、Build Pathにカタログが生成されます。
  • バージョンが指定されないと、代わりにビルド日時が使われます。
    古いカタログは自動的に削除されないので、ファイルが増えていきます。
  • カタログは、実行時にリモートから読み込まれ、更新の有無が判定されます。
    カタログが作られていなかったり、正しいカタログが読み込めないと、アセットファイルが新しくなっていても更新は行われません。
  • アプリとアセットが必ず同時に更新されるプロジェクトであれば、カタログは不要だと思われます。
    対して、アセットだけ更新される場合は、カタログが必要です。

リモートパス

  • RemoteBuildPathRemoteLoadPathを記入します。
    SS-7.png
  • これらは、それぞれ、「アップロードするアセットファイルを作るフォルダ」と「アップロード先(=実行時に取得する)のURL」です。
    • [BuildTarget]が、ビルドターゲットを表す文字列に置き換えられることで、ターゲット毎に異なるアセットに切り替わります。

ラベル

  • 新しいラベル(タグ)を作ります。
    SS-5.png
    SS-6.png
    これによって、アセットを一括ロードできるようになります。

アセットの構築

グループの作成

  • Addressablesウィンドウにグループを作ります。
  • Addressables (Window) > Create New Group (Context Menu) > Packed Assets SS-8.png
  • デフォルトグループは、コンテキストメニューから切り替え可能です。

グループの設定

  • Addressablesウィンドウで作成したグループPacked Assetsを選択して、インスペクターで設定します。
  • Build PathLoad Pathをリモートに設定します。
    SS-9.png

アセットの追加

  • グループにプロジェクトウインドウからアセット(ファイルまたはフォルダ)を追加します。
  • フォルダを追加すると階層ができます。
    SS-10.png
  • Addressablesに追加されたアセットには、マークが付きます。
    SS-13.png
    • このチェックを外すと、Addressablesウィンドウからも消えます。
  • 逆に、Projectウィンドウで選んだアセットに対して、インスペクターでマークすることで、デフォルトグループに加えることも可能です。
  • アセットや階層には、ラベル(タグ)を付けられます。
    SS-11.png
  • アセットや階層の名前(Asset Address)は元のパス名から自動で付けられます。
  • これらのアドレスは任意に変更できます。アセットや階層を選んで、コンテキストメニューからSimplify Entry Namesを実行すると自動的に短くできます。
    SS-12.png
  • アセットや階層の名前は、Addressablesウィンドウでも、インスペクターでも変更可能です。
  • アセットや階層は、ドラッグ&ドロップで、あるいは、コンテキストメニューからグループ間を移動できます。

アセット(だけ)のビルド

  • Addressables (Window) > Build > Build Player Content

アセットを使う

アセットの参照

  • アセットは、string(名前、ラベル)、または、AssetReference(インスペクター経由)で特定します。
// インスペクターでアセットを指定する
[SerializeField] private AssetReference SpriteAsset = default;
  • 以降の例では、AssetReferenceは使用せず、名前とラベルを使います。

サンプルの流れ

SampleMain.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;

public class SampleMain : MonoBehaviour {

    private void Start () {
        StartCoroutine (loader ());
    }

    private IEnumerator loader () {
        // ロードの開始
        var textHandle = Addressables.LoadAssetAsync<GameObject> ("Prefabs/BottomText.prefab");
        var imageHandle = Addressables.LoadAssetAsync<GameObject> ("Prefabs/FullScreenImage.prefab");
        var spriteHandle = Addressables.LoadAssetsAsync<Sprite> ("Sprites", null); // ラベルを指定して一括ロード
        // 完了の待機
        yield return new WaitUntil (() => textHandle.IsDone && imageHandle.IsDone && spriteHandle.IsDone);
        // エラーがないことを確認
        if (textHandle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded
            && imageHandle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded
            && spriteHandle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded) {
            // プレファブからオブジェクトを生成
            var image = Instantiate (imageHandle.Result, transform).GetComponent<Image> ();
            var text = Instantiate (textHandle.Result, transform).GetComponent<Text> ();
            // スプライトを順に切り替え
            for (var i = 0; i < spriteHandle.Result.Count; i = (i + 1) % spriteHandle.Result.Count) {
                image.sprite = spriteHandle.Result [i];
                text.text = $"{spriteHandle.Result [i].name}  <size=20>© UTJ/UCL</size>";
                yield return new WaitForSeconds (3f);
            }
        }

    }
}

  • 非同期に処理する必要があるので、コルーチンを使います。
  • プレハブは個別の名前を、スプライトは一括してラベルを指定してロードを開始します。
  • 非同期ロードハンドルをチェックしてロードの完了を待ちます。
  • ロードが成功したかチェックします。
  • プレハブからオブジェクトを生成します。
  • スプライトを順に表示します。

プロジェクトの入手 (GitHub)

ダウンロード ⇒ AddressableAssetsTest.unitypackage
ソースはこちらです。

あとがき

気になったこと

  • まだ、公式ドキュメントが英語しかないようです。
  • 短期間に色々変わっているようで、ネットで調べた情報が実際と異なったりしました。
  • 設定をいじっていたら、Addressablesウインドウからアセットの一部が消えてしまって復旧できなくなる…ということが2度ありました。

今後の予定

  • 次回は「Addressablesを製品で使うとどうなるだろう」というテーマになると思います。
  • 具体的な製品プロジェクトの予定が立ったら進展すると思います。

参考にさせていただいた記事 (Qiita)

どうもありがとうございました。


UNITY-CHAN! © Unity Technologies Japan/UCL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【.NetCore】[Remote]属性でクライアント側で自作バリデーションを行う。

クライアント側で自作の検証がしたい。

MVCの検証属性は便利だが、たまに足りないものがある。
サーバーサイドでの検証で良いなら検証処理を作って、POST後に検証すればいいので簡単にできる。

しかし、クライアント側でもJavaScriptで一応チェックしておきたいときがある。
そんなときに[Remote]アノテーションを使用する。

Controller

        [AcceptVerbs("Get", "Post")]
        public IActionResult VerifyHttps(string detail)
        {
            if (detail.IndexOf("http") != -1)
            {
                return Json($"これURLですよ。");
            }

            return Json(true);
        }

AcceptVerbs属性をつけて、戻りとはJsonで返す。

Model

        [Remote(action: "VerifyHttps", controller: "Test")]
        public string Detail { get; set; }

Remoteの引数にアクションとコントローラーを入れる。

View

      <div class="form-group">
          <label asp-for="Detail" class="control-label"></label>
          <input asp-for="Detail" class="form-control" />
          <span asp-validation-for="Detail" class="text-danger"></span>
      </div>

    ~~~~

   @section Scripts {
       @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
   }

これでクライアント側で検証が走る。
意外と簡単にできる、さすが.Net

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

時を操るアセット「Chronos」の基本的な使い方

この記事について

この記事はUnityアセット真夏のアドベントカレンダー 2019 Summer!31日目の記事です。

Chronos」とは?

LIDIQ氏がAssetStoreにて製作、販売をしている、
あらゆるオブジェクトの時間を操れるアセットです。

Chronos Time Control

どのように操れるか

698F7890-57F3-4626-90AF-2676F33008DE.jpeg
時間を遅くしたり止めたり、加速させたり戻したり…
時間の調整が細かく出来ます。

時間操作の影響を受ける対象

B486C5DC-5918-4CA7-8BB3-4ECF2E8652A8.jpeg
一括で管理したり、いくつかのグループに分けて管理したり、1つずつ管理したり、範囲(エリア)内のオブジェクトのみを管理したり…
カスタマイズ性が高いのも特徴です。

どのような挙動をするかはこちらの動画をご覧下さい。

基本的な使い方

それでは、使い方に移っていきます。
まず、Chronosの時間操作を扱うためにはシーン上に「Timekeeper」というコンポーネントを持つオブジェクトが必要です。
なのでまずはそれを追加してみましょう!
(既にプロジェクトを作成し、Chronosを購入、インポートしている前提で進めていきますので、まだの方は先にインポートまで終わらせておいてください)
6CF49CC4-0323-47B6-AF2F-4FC76929BB67.png
Hierarchyビュー上で右クリックします。
A1EE4BD2-C79D-4CA0-97BA-2FB885C418E2.png
下にある「Timekeeper」をクリック
2D88F7A5-FDEE-40AA-8591-59F58B172B57.png

これで、Chronosを使う準備が出来ました。

時間操作

それでは時間を操作していきます。
時間を操作したいオブジェクトに、「Localclock」と、「Timeline」というコンポーネントを追加します。
7D91931F-7DA6-4B00-8729-C99D78BB41CA.png
Addcomponentをクリックして(今回は物理演算を適用するためRigidbodyも追加しています)
9DD3590A-DDA6-4BA4-B93E-D905180B3787.png
Localclock」を追加。
81406F63-399D-4991-8FAC-C088CDB3C07A.png
続いて「Timeline」も追加します。
これで時間操作を適用させる準備が出来ました。
時間を操作するためにスクリプトを書いていきます。
2881E4D8-1600-429B-AB6E-E5FB36B9CDB5.png
Projectビュー上で右クリックし、createからC#Scriptを押します
スクリプト名を適当に決め(私はTimeControlsしました)そのスクリプトファイルを開きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Chronos;

public class TimeControl : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GetComponent<LocalClock>().localTimeScale = 0.01f;
    }

    // Update is called once per frame
    void Update()
    {

    }
}

このコードを書き、時間操作をしたいオブジェクトに適用することで時間を遅くする(100分の1)にすることができます。
コードの解説をしますと

GetComponent<LocalClock>()

まずオブジェクトが持つ「Localclock」を取得し

localTimeScale = 0.01f;

その時間を0.01倍速にしています。
この0.01の部分を変えれば任意の速度に変更できます。

次にこれをオブジェクト単位ではなく、一括で変更できるようにしていきましょう。
まず親にしたいオブジェクトに「GlobalClock」を追加しますが、Timekeeperに既についているので、Timekeeper以外を親にしたい場合以外は追加する必要はありません。
それでは「GlobalClock」と「LocalClock」を関連付けしていきます。
3F0CB524-D82F-4B92-B5F0-B616BAA8AB5F.png
GlobalClock」のKeyの部分の名前を覚えておきます。
3C5750D7-019C-4E89-8DCE-714CD0A5AB1E.png
そして「Timeline」のModeをLocalからGlobalに変えます。
CF0E3349-419A-45EE-BEFE-758ECDBCB20A.png
最後に「Timeline」のGlobalClockを先程のKeyの名前を選択して、完了です。
これをまとめて動かしたいオブジェクトの数だけ行ってください。

それでは先程のコードを改変して、Tキーを押した時に全体の時間を止め、もう一度Tキーを押すと時間が元に戻るコードを書いていきます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Chronos;

public class TimeControl : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            if (GetComponent<GlobalClock>().localTimeScale == 0)
                GetComponent<GlobalClock>().localTimeScale = 1;
            else
                GetComponent<GlobalClock>().localTimeScale = 0;
        }
    }
}

このコードを「GlobalClock」を持つオブジェクトに適用します。
そしてゲームを初めTキーを押してみると…?
一度押すと止まり、もう一度押すと動いたと思います。
最後にコードの解説をしますと

if (Input.GetKeyDown(KeyCode.T))
{
の部分で「もし、Tキーが押されたなら〜」という条件式を作り

if (GetComponent<GlobalClock>().localTimeScale == 0)
GetComponent<GlobalClock>().localTimeScale = 1
の部分で「既に時間が止まっているなら〜」という条件式をさらに作り
その下の文で時間を等倍にする処理をしています。
つまり「時間が既に止まっているな時間を等倍にする」という処理をここで行っています。

else
GetComponent<GlobalClock>().localTimeScale = 0;

この文で「時間が止まっていないなら」という先程の条件式の反対の状況になっていれば処理し時間を止めます。
ここで「時間が止まっていないなら時間を止める」という処理です。

最後に

Chronosではここで紹介した以外にもまだまだ使い方があります!
是非Chronosをマスターして時間を自在に操って見てください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[C#/UWP] WriteableBitmapで点を打って、テレビの放送終了後の砂嵐をつくる(UWP版)

もくじ
https://qiita.com/tera1707/items/4fda73d86eded283ec4f

やりたいこと

以前、WPFで同じことを試したが、そのままのコードをWPFにもっていっても動かなった。
WriteableBitmapクラスはUWPにもあるが、仕様が異なっているからと思われる。
また、別スレッド中に、UIスレッドで処理をしてもらうための書き方(Dispatcher.Invoke())も、WPFとUWPで異なっている。

UWPでも画面に点を打つことがあるので、やり方を知りたい。

サンプル

下記のようにすると動いた。

MainPage.xaml.cs
using System;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;

namespace SandStormUWP
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            Task.Run(() =>
            {
                while (true)
                {
                    const int width = 256;
                    const int height = 256;

                    byte[] data = new byte[width * height * 4];

                    Random rnd = new System.Random();    // インスタンスを生成
                    int rndMax = 256;                    // 0~256の乱数を取得

                    // バイト列に色情報を入れる
                    for (int i = 0; i < width; i++)
                    {
                        for (int j = 0; j < height; j++)
                        {
                            data[4 * (i + j * width)] = (byte)rnd.Next(rndMax);
                            data[4 * (i + j * width) + 1] = (byte)rnd.Next(rndMax);
                            data[4 * (i + j * width) + 2] = (byte)rnd.Next(rndMax);
                            data[4 * (i + j * width) + 3] = (byte)rnd.Next(rndMax);
                        }
                    }

                    var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
                    {
                        WriteableBitmap bitmap = new WriteableBitmap(width, height);

                        InMemoryRandomAccessStream inMRAS = new InMemoryRandomAccessStream();
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, inMRAS);
                        encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Ignore, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, data);
                        await encoder.FlushAsync();
                        BitmapImage bitmapImage = new BitmapImage();
                        bitmapImage.SetSource(inMRAS);
                        MyImage.Source = bitmapImage;   // 「MyImage」は、xamlの<Image Name="MyImage"/>より。砂嵐を張り付けるImageの名前。
                    });
                }
            });
        }
    }
}

image.png

参考

UWPでバイト配列を画像として表示する
https://jprogramer.com/uwp/3926

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】文字列→数値変換の色々

文字列を数値に変換することは
割と良くあるけど微妙に忘れがちなので備忘の意味も込めて。
#16進数文字列の変換とか使うたびに調べているような…

2進数/8進数/16進数の変換

個人的にはこれを良く使っている。

var binary = Convert.ToInt32("11", 2); // 2進数
var octal = Convert.ToInt32("11", 8); // 8進数
var hex = Convert.ToInt32("1a", 16); // 16進数

// 上から3, 9, 26になる

他にもNumberStylesを使う方法もあるのでそちらも記載。

var hex = int.Parse("1a", NumberStyles.HexNumber);

NumberStyles.HexNumberの部分は
AllowHexSpecifierを指定すれば16進数として扱ってくれるけど
前後に余分な空白があるとNGなので素直にHexNumberとしておくのが無難。

どちらの方法を使っても良いと思うけど
TryParseしたい時はNumberStylesを使う。

int hex;

if(false == int.TryParse( "xyz", System.Globalization.NumberStyles.HexNumber, null, out hex )
{
    MessageBox.Show( "16進数に変換できないよ" );
}

その他の変換

NumberStylesは指数とか3桁区切りになっている場合に変換出来るので知っておくと便利。

vat str = "123,456,789";
var num = int.Parse(str, System.Globalization.NumberStyles.AllowThousands);
// 123456789に変換される

str = "123e4";
num = int.Parse(str, System.Globalization.NumberStyles.AllowExponent);
// 1230000に変換される

但し桁区切り文字に関しては実行環境の設定に依存するので注意。
setting.png
※[コントロールパネル]-[地域と言語]から『追加の設定』ボタンを押下すると表示される

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む