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

C# メモリ上の数値の改ざんを防ぐ

成果物

C#のコンソールテスト用です
https://github.com/Oinary/SecureValue/blob/master/Program.cs

1.やりたいこと

・改ざんされちゃマズい数値を守りたい!(ゲーム内のHPやお金など)
・ファイルだけではなくメモリ上の数値も保護したい。(今回はInt型とFloat型)

2.何を使えば出来るか

XOR(排他的論理和)で解決。
https://qiita.com/kuuso1/items/778acaa7011d98a3ff3a

簡単に言うと2進数で2つの数を演算したとき
片方がTrue(1)ならTrue。      0 xor 1 → 1
両方がTrue又はFalse(0)ならFalse。  0 xor 0 → 0

これって同じ値で演算しなおすと元の値に戻るんです。
1010 xor 0110 → 1100
1100 xor 0110 → 1010

科学の力ってすげぇ(てきとう

3.実装してみた

まずXORを使うのには、元の値とそれを合わせる値が必要。
C#でランダムな整数をもらってきます。(これはちゃんと保存しましょう)

Random.Next()
https://docs.microsoft.com/ja-jp/dotnet/api/system.random.next?view=netframework-4.8

あとは ^ 演算子で保存、復元すれば解決!

SecureInt.cs
private int Seed;
private int Value;
public int _Value
 {
    get
    {
        return Value ^ Seed;
    }
    set
    {
        Seed = new Random().Next()//ランダムなInt
        Value = value ^ Seed;//あとはお好きに
    }
}

3-1.そうは上手くいかなかった

Int型は何も問題なく実装できましたが…。
Float型ってXORを直接は使えない。(馬鹿には分からなかった。

3-2.じゃぁどう回避しようか

ヒントがここにあった…。
https://qiita.com/nia_tn1012/items/d26f0fc993895a09b30b

Floatで後ろ23ビットは仮数部と呼ばれる、我々が目にする数が格納されているところがあります。
例 2.345 → 2345 (小数点を無くした値になります)
その仮数部を隠せば良さげです。
※これはイメージです

Sample
float F = 1.55f;//得たfloat
var I = BitConverter.ToInt32(BitConverter.GetBytes(F),0);//これをbyte[]にして、Int型にさせる
var SignificandPart = I << 9;//左に9ビットシフトすると仮数部だけ残る
var SecureValue = SignificandPart ^ Seed;//あとは煮るなり焼くなり
//戻すときはこの逆で

で出来上がりなのですが、まぁ操作多いんですよ。
なんかこう、もっとサクッとFloatをIntにできないんですかね…。

・・・あったわ

その参照記事の下に別の方法が書かれています。
ポインタを扱うこと がポイント♪ で内部値をInt型で取得できます。

SecureFloat.cs
private int SecValue;
private int Seed;
public unsafe float _Value
{
   get
   {
       var result = SecValue ^ Seed;
       return BitConverter.ToSingle(BitConverter.GetBytes(result), 0);//戻すときは一度byte[]にしてからFloatに変換。
   }
   set
   {
      CalculatingSeed();
      int v = *((int*)&value);//&valueでvalueのポインタを取得、(int*)でInt型のポインタを格納、最初の*でそのポインタの値を指す。
      SecValue = v ^ Seed;//あとはお好きに
   }
}

ポインタの使用は、本来はバグなど意図しない動作を防ぐために制限されています。
それを解除するため、unsafe を明示します。(VisualStudioの設定もお忘れずに)

これで守りたい値の保護方法が実装できそうです。

4.さいごに

不正の種類はいくつもあるので、それ相応の対応をしなければなりません。
が、あの手この手で不正してくるはずです。
実装するコストと見合っているかどうかも検討しないと、クオリティや製作時間に響いちゃいます。

僕みたいな初級の個人ゲームクリエイターならお遊び程度でいいんじゃないでしょうかね。

では初記事をご覧いただきありがとうございました。

※ってか一番大事なメモリエディタの画像なくね?

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

Autodesk Inventor API Hacking (ダークテーマへの対応~アイコン編~)

0. はじめに

Freeradicalの中の人、yamarahです。
Inventor 2021に、プレビュー扱いですがダークテーマが実装されました。
AddInをダークテーマに対応するには、どうすれば良いかという話しです。
ダイアログを表示する場合は、その背景色を変える必要もあるでしょう。とりあえず今回は、リボンに表示されるアイコンを対応させます。

1. Autodesk社の対応を見る

まず、Autodesk社純正のアイコンが、どのような対応をしているのか確認しましょう。
純正LightDark.png
見ての通り、上がライトテーマで、下がダークテーマです。
単に背景の色が違うだけではなく、縁取りの線の色など、細かいデザインが変わっているのが見て取れます。
つまりは、背景色を変えさえすれば良い、という訳ではないということです。

2. 透過アイコンを使う

とはいえ、真面目に2種類のデザインをするのは大変なので、背景色のみを変えて乗り切れないか試してみましょう。
APIを調べた限りでは、テーマ別のアイコンを設定する個所はなさそうです。ですので、背景部を透明にした透過アイコンを試してみます。
テスト用に、以下のアイコン画像を作りました。
TestIcon1.png
アイコン作成にはジェネリック イラレと名高いAffinity Designerを使いました。
Inventorがアルファチャンネルを正しく認識してくれれば、これで大丈夫なはずです。
テスト用のAddInに組み込んで、実際に表示した結果です。
TestIcon1LightDark.png
ダークテーマにおいて、半透明部分のブレンドが正しく行われていないことが見て取れます。
どうやらInventorは、半透明部分には白をブレンドしてアルファー値を二値化処理しているようです。
つまり、この結果から導き出される結論は、アンチエイリアス処理で半透明ピクセルがあるアイコンは、ライトテーマ, ダークテーマ用に作り分けないと見栄えが悪いということです。

3. テーマの切り替えの検出

アイコンの差し替え自体は、ButtonDefinitionStandardIcon, LargeIconを上書きすれば可能です。
問題は、どのタイミングで行うかでして、今回はApplicationEvents.OnApplicationOptionChangeを使います。現在のテーマはApplication.ThemeManager.ActiveThemeで取得可能なので、OnApplicationOptionChangeで値が変化したかどうかを調べるわけです。
抜粋したコードを以下に示します。

private string? CurrentThemeName = null;
private string? GetApplicationThemeName()
{
    return InventorApplication.ThemeManager.ActiveTheme.Name;
}

private void UpdateDefinitionIcon()
{
    if (CurrentThemeName != "DarkTheme")
    {
        ThisDefinition.StandardIcon = Properties.Resources.LightIcon16x16.ToIPictureDisp();
        ThisDefinition.LargeIcon = Properties.Resources.LightIcon32x32.ToIPictureDisp();
    }
    else
    {
        ThisDefinition.StandardIcon = Properties.Resources.DarkIcon16x16.ToIPictureDisp();
        ThisDefinition.LargeIcon = Properties.Resources.DarkIcon32x32.ToIPictureDisp();
    }
}

public void Activate(ApplicationAddInSite addInSiteObject, bool firstTime)
{
    CurrentThemeName = GetApplicationThemeName();
    UpdateDefinitionIcon();
    InventorApplication.ApplicationEvents.OnApplicationOptionChange += ApplicationEvents_OnApplicationOptionChange;
}


private void ApplicationEvents_OnApplicationOptionChange(EventTimingEnum BeforeOrAfter, NameValueMap Context, out HandlingCodeEnum HandlingCode)
{
    if (BeforeOrAfter == EventTimingEnum.kAfter)
    {
        var themeName = GetApplicationThemeName();
        if (CurrentThemeName != themeName)
        {
            // Themeが変わった
            CurrentThemeName = themeName;
            UpdateDefinitionIcon();
        }
    }
    HandlingCode = HandlingCodeEnum.kEventNotHandled;
}

public void Deactivate()
{
    InventorApplication.ApplicationEvents.OnApplicationOptionChange -= ApplicationEvents_OnApplicationOptionChange;
}

これでテーマが変わるタイミングで、アイコンが差し替えられるはずです。

4. 背景焼きこみアイコンの差し替え

背景をライト、ダーク背景色にして、アンチエイリアスを焼き込こんだアイコンを作って、うまく切り替わるか試してみました。
TestIcon2LightDark.png
良い感じに馴染んでいます。これにて解決・・・となるはずだったのですが・・・

5. ハイライト時に背景色が変わらない

ボタンにマウスポインタがフライオーバーした時に、
TestIcon2Bad.png
何やら違和感が。ダークテーマの背景をアイコンに焼き込んだので、うまくハイライトせずに四角い枠が見えてしまっています。
ここまで来れば意地で、アイコン画像をジェネリック フォトショことAffinity Photoに取り込み、背景を透明にします。
Dark切り抜き.png
アンチエイリアス部のみ焼き込みを残して、他の背景は100%透過にしたわけです。
このアイコン画像と差し替えて再チャレンジ。
TestIcon3OK.png
今度はうまく行きました。

6. 旧バージョンへの対応

ThemeオブジェクトはInventor 2021で導入されたものであり、バージョン25以降のInteropを使わないとアクセスできません。しかし、そうすると、作成されたAddInはInventor2020以前では動作しなくなります。
悩ましい問題ですが、ここは泥臭くdynamicを使って逃げましょう。
先のコードのGetApplicationThemeName()を、以下の通り変更します。

private string? GetApplicationThemeName()
{
    try
    {
        return ((dynamic)InventorApplication).ThemeManager.ActiveTheme.Name;
    }
    catch
    {
        return null;
    }
}

例外が発生すればnullを返し、結果としてライトテーマのアイコンが設定されます。
dynamic並びに例外処理は重たい処理なので避けたいということならば、Application.SoftwareVersion.Majorで切り分けでも良いですし、例外検知でフラグを立てて2回目以降は常にnullを返しても良いと思います。

99. 親の記事に戻る

Autodesk Inventor API Hacking (概略)

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

【C#入門】オブジェクト指向の『カプセル化』についてまとめた

この記事では、《オブジェクト指向の『カプセル化』》について、
業務を通して学習した内容を、備忘録としてまとめています。

  • 『カプセル化』とは…?
  • 『カプセル化』すると何がいいのか…?
  • フィールドの設定方法

こういった内容についてまとめています。

※本記事は、自分で学習したことのまとめ用として書いています。
尚、解説で誤った点があれば、スローして頂ければ喜んでキャッチしますのでお願い致します。

【概要】 『カプセル化』 とは…?

capsule_1.jpg

クラス内のフィールド(メンバー変数)をprivateで宣言することで…

外部からの値の参照・変更を制限することができます。

変数を、クラスで包む、囲むイメージ。

『フィールド』とは・・・
クラスのメンバー変数として定義され、クラス内に直接書かれる変数のことで、フィールドと呼ばれます。
『フィールド』は、クラス内のメソッドから参照可能です。

例えば、下記のように記述します。

namespace Sample
{
    public class Program
    {
        private int _num = 0;

        public Program(int num)
        {
            _num = num;
        }
    }
}

上記はコードは・・・

_num変数がprivateのフィールドで宣言されており、カプセル化されている状態です。

この_numを変更するためには…

コンストラクタでint型の値を指定することで、_numの初期値を変更することができます。

【メリット】 『カプセル化』 すると何がいいのか…?

list_2.jpg

  • コードが理解しやすく(読みやすく)なる
    • 値とロジックを1つにまとめることができる
  • 不正な値が設定されることを防げる
  • 保守性が高くなる

『カプセル化』をすると、外部からの値の参照・変更が制限されるため、宣言しているフィールドに設定される値は、必ず自分自身のクラスで設定する必要があります。

そのため・・・

そのフィールドにどういった値が設定されるかは、そのクラスを読むだけで理解できるようになります。

また・・・

外部からフィールドを設定することを許可してしまうと、意図していない(許可したくない)値が設定される可能性があります。

そこで・・・

『カプセル化』をすることで、不正な値が設定されることを、事前に防ぐことが可能です。

『カプセル化』したフィールドの設定方法|外部から変更する

capsule_2.jpg

繰り返しになりますが…

『カプセル化』をすることで、外部からの値の参照・変更を制限することができます。

ですが・・・

外部から値を設定できないので、クラスとしては機能しなくなります。

そのため・・・

何らかの方法で、外部からの値の変更を可能にする必要があります。

『カプセル化』されているフィールドの値を外部から変更する方法は…

  1. コンストラクタ
  2. プロパティ

を使った2つの方法があります。

方法①: コンストラクタ

先ほど少し紹介しましたが…

コンストラクタでフィールドのの初期値を変更することができます。

namespace Sample
{
    public class Program
    {
        private int _num = 0;

        public Program(int num)
        {
            _num = num;
        }
    }
}

上記はコードは・・・

_num変数がprivateのフィールドで宣言されており、カプセル化されている状態です。

この_numを変更するために…

コンストラクタでint型の値を指定することで、_numの初期値を変更しています。

方法②: プロパティ

値を設定するメソッドを公開する。

コンストラクタで設定する方法は、クラスを生成するときにしか動作しないため、初期値しか指定することができません。

生成後に値を変更したくても、コンストラクタだけでは対応できません。

そこで・・・

値を変更することのできるメソッドを公開するやり方があります。

namespace Sample
{
    public class Program
    {
        private int _num = 0;

        public int Num
        {
            set { _num = value; } //値の代入
            get { return _num; } //外部に値を返す
        }
    }
}

set{}の中には…

フィールド(メンバー変数) = value

というように記述します。

valueは、利用者側のクラスで代入された値が格納される『予約語』になります。

また・・・

get{}の中には…

return フィールド(メンバー変数)

というように、戻り値を記述します。

【補足】 C#3.0での書き方

C#3.0では、プロパティのsetgetの中身を省略して記述できるようになりました。

ちなみに・・・

この機能を『自動プロパティ』と言います。

namespace Sample
{
    public class Program
    {
        private int _num = 0;

        public int Num { set; get; }
    }
}

【補足】 C#6.0での書き方

C#6.0では、初期値を指定できるようになりました。

public int Num { get; set; } = 100

ちなみに・・・

上記のコードは、以下と同様になります。

private int _num = 100;

public int Num
{
    set { _num = value; }
    get { return _num; } 
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング初心者用のC#サンプルプログラム

using System;
using System.Text;

namespace Sample
{
    class Program
    {
        const int listSizeMax = 100;
        static void Main(string[] args)
        {
            Prime();
            Console.ReadLine();
        }
        static void Fibonacchi()
        {
            var a = 0; var b = 1;
            for(var i = 0; i < listSizeMax; ++i)
            {
                try
                {
                    checked
                    {
                        var number = a + b;
                        Console.WriteLine($"{i}  {number}");
                        a = b;
                        b = number;

                    }

                }
                catch (Exception)
                {

                    Console.WriteLine($"{i} overflow");
                    break;
                }
            }
        }
        static void Prime()
        {
            var i = 0;
            for (var n = 2; n < int.MaxValue && i < listSizeMax; ++n)
            {
                try
                {
                    checked
                    {
                        var isPrime = IsPrime(n);
                        if (isPrime)
                        {
                            Console.WriteLine($"{i} {n}");
                            i++;

                        }
                    }

                }
                catch (Exception)
                {

                    Console.WriteLine($"{i} overflow");
                    break;
                }
            }
        }
        static void Binary()
        {
            for (var i = 0;  i < listSizeMax; ++i)
            {
                try
                {
                    checked
                    {
                        var buffer = new char[8] { '0', '0', '0', '0', '0', '0', '0', '0' };
                        var n = i;
                        var mask = 0b1;
                        for (var j = buffer.Length - 1; j >= 0; --j)
                        {
                            var bit = n & mask;
                            buffer[j] = (char)(bit + '0');
                            n = n >> 1;
                        }
                        var s = new string(buffer);
                        Console.WriteLine($"{i} {s}");

                    }
                }
                catch (Exception)
                {

                    Console.WriteLine($"{i} overflow");
                    break;
                }
            }
        }
        static void HexDecimal()
        {
            for (var i = 0; i < listSizeMax; ++i)
            {
                try
                {
                    checked
                    {
                        var buffer = new char[2] { '0', '0' };
                        var n = i;
                        var mask = 15;
                        for (var j = buffer.Length - 1; j >= 0; --j)
                        {
                            var unit = n & mask;
                            if(unit < 10)
                            {
                                buffer[j] = (char)(unit + '0');
                            }
                            else
                            {
                                buffer[j] = (char)(unit - 10 + 'a');
                            }
                            n = n >> 4;
                        }
                        var s = new string(buffer);
                        Console.WriteLine($"{i} {s}");

                    }
                }
                catch (Exception)
                {

                    Console.WriteLine($"{i} overflow");
                    break;
                }
            }
        }
        static bool IsPrime(int n)
        {
            var m = Math.Sqrt(n);
            for (var i = 2; i <= m; i++)
            {
                if(n % i == 0)
                {
                    return false;
                }
            }
            return true;
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacでPhotonVoiceを使用したときに他アプリケーションの音量が小さくなる問題

概要

PhotonVoice を使用した Unity 製アプリを起動した途端、別アプリケーションとして起動している Google Chrome 上の YouTube や Spotify 等の音量が極小になる。また、通話中の Discord に至っては音量だけではなくマイク入力も極小になるようだった。本事象は UnityEditor 上でアプリケーションを実行しても発生した。

同じ事象は PhotonVoice を使用していないと思われる LINE や Skype, Zoom の通話中でも発生しているが、Discord や Slack, Google Chrome 上の Facebook Messenger の通話中では発生していないので、何か解決方法があることが分かる。

確定的な原因は分からなかったが、対処方法は分かったので記事として残しておく。

各種バージョン

環境 バージョン
macOS macOS 10.15.4
Unity Unity 2018.2.21f1
Photon Unity Network PUN 1.91

(全体的にバージョンが古くてお恥ずかしい限りです)

対処方法

PhotonVoiceRecorder にある Microphone Type で「Unity」を使用する。
自分のプロジェクトでは「Photon」を使用していたが、これを「Unity」に変更したら解決した。

image.png

ただし、基本的には Unity マイクよりも Photon マイクのほうが何かと優秀なので、Mac で起動したときのみ「Unity」マイクを使用するようにするために下記コードを書いた。 (PhotonマイクのクライアントとUnityマイクのクライアント同士で音声通信が正常に出来ることは検証済み)

private void Start() {
  GetComponent<PhotonVoiceRecorder>().MicrophoneType = IsMacOs() 
    ? PhotonVoiceRecorder.MicAudioSourceType.Unity 
    : PhotonVoiceRecorder.MicAudioSourceType.Photon;

  // 念の為PhotonVoiceSettingも変更しておく
  PhotonVoiceSettings.Instance.MicrophoneType = IsMacOs() 
    ? PhotonVoiceSettings.MicAudioSourceType.Unity 
    : PhotonVoiceSettings.MicAudioSourceType.Photon;
}

// Macで実行されていたらtrue
private bool IsMacOs() {
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
  return true;
#endif
  return false;
}

原因究明 (未解決)

下記のフォーラムで探して回ったが、とにかく同じ事で悩んでいる人が少なかった。
また、投稿があっても回答が無いパターンも多かった。

  • Unity Forum
  • Apple Developer Forums
  • Photon Engine Support Forum
  • Stack Overflow

似たような問題を抱えている人

本事象に一番近いなと思ったのは、Apple Developer Forums に投稿されていた下記の質問。
(もしかしたら全く関係無いかもしれないが)
VoiceProcessingIO lowers the volume of all othe... |Apple Developer Forums

VoIPアプリケーションでVoiceProcessingIO(kAudioUnitSubType_VoiceProcessingIO)オーディオユニットを使用してオーディオを録音および再生しています。ユニットが初期化されている場合を除き、すべてが正常に動作します。他に何かがオーディオを再生している場合、そのオーディオは非常に静かになりますが、出力はすべてフルボリュームで聞こえます。

こちらの投稿には回答が付いていなかったが、macOS のオーディオ API 周りの機能が原因である事が分かる。
(上記記事で紹介されていた kAUVoiceIOProperty_DuckNonVoiceAudio - AudioToolbox | Apple Developer Documentation のプロパティをドキュメントから参照したが、非推奨と書いてあったので対応出来なかった。)

全てのアプリケーションにおいて音声入力時に他のアプリケーションの音量が小さくなるのならここで諦めるが、上述した通り Discord や Slack の通話では音量が変わる事が無かったので、もう少し調べてみることにした。

Photon Voice のマイクタイプについて

公式ドキュメントの「Photon」マイクの説明を見ると、ネイティブのオーディオAPIとやりとりしている事が分かる。

Unityマイクは、ほぼ同じコードベースを使用して複数のプラットフォームをターゲットにすることを容易にするのに最適です。ただし、いくつかの点で、UnityのマイクAPIは制限されているか、あちこちにいくつかの問題があります。そのため、オーディオ入力デバイスと直接やり取りし、UnityのマイクAPIをバイパスする独自の方法を導入しました。これの主な理由の1つは、デバイスのハードウェアに組み込まれているエコーキャンセレーションを利用することです。 ※ Photon Voice For PUN | Photon Engine より引用

macOS の API (特にオーディオ周り)には詳しくないが、オーディオ API が本事象の原因であり、Photon マイクの実装がネイティブのオーディオ API を利用しているのならもしかして?と思ってマイクタイプを「Unity」に変更したら他アプリケーションの音量に影響を与えない事が出来た。

最後に

Unity マイクも内部的にはネイティブのオーディオ API を参照しているのでは?と思ったが、他アプリケーションの音量操作は Unity API 側で無効にされているという認識で良かったのだろうか。

結局、具体的に何のオーディオ API の何のパラメータが原因で、どのような場合に音量操作を行うのかというのは分からなかったので、もし詳しい方がいらっしゃいましたらご教示いただけますと幸いです。

参考リンク

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

Azure Functions Premium プランのリージョン仮想ネットワークの統合を試してみた

Azure Functions Puremium プランでリージョン仮想ネットワークの統合というのが一般提供されたみたいですね。

Azure Functions Premium プランのリージョン仮想ネットワークの統合

仮想ネットワークまわりはめんどくさい印象しかなくて、なるべく遠ざけてきたのですが、この機会に触ってみたいと思います。

確認方法

仮想ネットワークのサービス エンドポイントっていうのを使って Azure Functions Premium から SQL Database にアクセスしてみようと思います。
なんとなく、Database がインターネットにつながっているのを嫌がる人も多いし自分も、なんとなく理解できるので。

ということで Azure ポータルでポチポチリソースを作っていきます。全部同じリージョンに作りましょう。

  • Azure Functions Premium plan
  • SQL Database (安いサーバーレスモデル)
  • 仮想ネットワーク
    • サブネット 2 つ (default: 10.0.0.0/24, functions: 10.0.1.0/24)

サブネットを作るときにサービス エンドポイントを構成できて、そこで Microsoft.SQL を 10.0.1.0/24 のほうに追加します。(作ったあとからでも設定できます)

image.png

SQL Database の方を完全にふさいでしまう前に DB 作ってしまいます。自分の IP アドレスを SQL Database のファイアウォールに追加して、SQL Database のクエリエディター(プレビュー)から以下の SQL を実行してテーブルとデータを作っておきました。

CREATE TABLE MESSAGES (
  ID INTEGER PRIMARY KEY,
  MESSAGE NVARCHAR(256)
);

INSERT INTO MESSAGES(ID, MESSAGE) VALUES(1, 'Hello from SQL Database');

Azure Functions の構成

とりあえず Azure Functions で VNet 統合をします。Azure Functions のネットワークの設定を開いて NNet 統合の「構成するにはここをクリック」を選択しましょう。

image.png

そして「VNet の追加」を選択して、先ほど作っておいた functions という名前のサブネットを選びます。

image.png

適当に Azure Functions のコードを作成します。とりあえず SQL Database につながればいいので手抜きな感じで、こんなコードを書きました。

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Data.SqlClient;
using Microsoft.Extensions.Configuration;

namespace PrivateNetFunc
{
    public class Function1
    {
        public Function1(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        private IConfiguration Configuration { get; }

        [FunctionName("Function1")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            string result = null;
            using (var conn = new SqlConnection(Configuration.GetConnectionString("DB_CON")))
            {
                await conn.OpenAsync();
                log.LogInformation("Opened");
                using (var command = conn.CreateCommand())
                {
                    command.CommandText = "SELECT TOP 1 MESSAGE FROM MESSAGES";
                    log.LogInformation($"Execugint Query: {command.CommandText}");
                    using (var r = await command.ExecuteReaderAsync())
                    {
                        log.LogInformation($"Executed ExecuteReaderAsync");
                        await r.ReadAsync();
                        log.LogInformation($"Executed ReadAsync");
                        result = r.GetString(0);
                        log.LogInformation($"Get data: {result}");
                    }
                }

                await conn.CloseAsync();
            }

            return new OkObjectResult($"{DateTime.UtcNow}: {result}");
        }
    }
}

SQL Database の接続文字列をポータルからゲットして Azure Functions の接続文字列に DB_CON という名前でついかしましょう。

image.png

そして、Azure Functions にコードをデプロイします。

動作確認(動かないことを確認)

まだ、ちゃんと設定が終わっていないのでエラーになるはずです。試してみましょう。
叩くとこんな感じのエラーが出ました。

image.png

SQL Server の仮想ネットワークからの接続受け入れ設定

仮想ネットワークのサービスエンドポイントで Microsoft.Sql を追加しましたが、まだ SQL Server 側で仮想ネットワークからの通信を行け入れるようにしていなかったので SQL Server のファイアウォールと仮想ネットワークで、既存の仮想ネットワークを追加を選択して、 functions の仮想ネットワークを追加します。

image.png

再度動作確認(動くことを確認)

この設定まで完了すると、関数のエンドポイントを叩くことで、ちゃんと動くようになります。

image.png

余談

Azure Functions は、仮想ネットワーク上にあるわけじゃないので、その点は注意です。
あと、Azure Functions の全ての送信側の通信を仮想ネットワーク側に回して、ネットワークセキュリティグループとかで制御したい場合には、アプリケーション設定に以下の項目を追加することで、RFC 1918 以外の通信も仮想ネットワークにルーティングするようになります。

  • WEBSITE_VNET_ROUTE_ALL という名前で値に 1 を設定

まとめ

こんだけ、簡単に仮想ネットワークに統合できて、仮想ネットワークからのアクセスのみに SQL Db やらなんやら対応サービスを構成するだけで接続元を絞れるなら仮想ネットワーク使うのもいいですね。

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

【Unity】初心者が覚えるべきDebug.Logの使い方

環境

Unity 2019.3.7f1

Debug.Logって?

Unity側で用意された標準機能 
Debug.Log()
は定型文です。呪文として覚えましょう!
開発中めちゃくちゃ使うので勝手に覚えちゃうと思います笑

どんな時に使う?

・変数の中身を知りたいとき
・何の処理が行われたかをわかるようにしたいとき(テキストを表示)
・処理が実行されたか確認したいとき

前準備 コンソールウインドウを開く

図1.png

このような画面が出ます。
ここにDebug.Logの中身が表示されます。
image.png

使ってみる

・変数の中身を知りたいとき

スクリプトを用意
 名前はTEST_scriptにしました。

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

public class TEST_script : MonoBehaviour{

    int a;//aというint型の変数を宣言

    void Start()
    {
        a = 10;//変数aの中身を10に設定
        Debug.Log(a);//コンソールウインドウに変数aの持っている数値を表示
    }
}

空のゲームオブジェクトを用意
ヒエラルキー上で右クリック→空のオブジェクト作成
image.png
空のオブジェクトが作成された!
image.png

先程作ったスクリプトを空のオブジェクトへドラッグ&ドロップ
インスペクターにスクリプトが割り当てられたことを確認
image.png

実行ボタン押す
image.png

変数aの中身が表示されました!
image.png

・何の処理が行われたかをわかるようにしたいとき

スクリプトのDebug.Log()のかっこ内を"ダブルクォーテーションで囲んで文字を入力

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

public class TEST_script : MonoBehaviour
{
    int a;//aというint型の変数を宣言

    // Start is called before the first frame update
    void Start()
    {
        a = 10;//変数aの中身を10に設定
        Debug.Log("aに10を代入");//コンソールウインドウにテキストを表示
    }
}

テキストが表示されました!
image.png

・処理が実行されたか確認したいとき

if分の中身が実行されたか見てみましょう。

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

public class TEST_script : MonoBehaviour
{
    int a;//aというint型の変数を宣言

    // Start is called before the first frame update
    void Start()
    {
        a = 10;//変数aの中身を10に設定

        if(a == 10)//aが10だったらif分の中身の処理実行
        {
            Debug.Log("if文の中身が処理された");//コンソールウインドウにテキストを表示
        }

    }
}

if分の中身が処理されたことがわかります
image.png

少し応用

"a="+a といれるとテキストと変数の中身を同時表示できます。

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

public class TEST_script : MonoBehaviour
{
    int a;//aというint型の変数を宣言

    // Start is called before the first frame update
    void Start()
    {
        a = 10;//変数aの中身を10に設定

        Debug.Log("a="+a);  

    }
}

image.png
表示された変数の内容がわかりやすくなります。

楽しいUnityライフを!

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

Moq で ref を持つメソッドの参照渡しの値をモック化する

概要

C# のモックライブラリ Moq を用いて ref を持つメソッドの参照渡しの値をモック化する方法になります。

参考情報

丁寧に解説されていたため、参考になりました。
https://dontcodetired.com/blog/post/Setting-Up-Mock-ref-Return-Values-in-Moq

解説

Moq の バージョン 4.8 以降にて、refパラメータに対する対応が実施されています。
その際、作成したモックにて参照渡しの値を設定するコードサンプルをメモとして残します。

    /// <summary>
    /// テスト対象となるインターフェースです
    /// </summary>
    public interface ITestTarget
    {
        void DoSomething(string value1, ref string value2);
    }

    /// <summary>
    /// コールバック用のデリデートを定義します
    /// </summary>
    /// <param name="value1"></param>
    /// <param name="value2"></param>
    delegate void DoSomethingCallback(string value1, ref string value2);

    [TestClass]
    public class UnitTest
    {
        [TestMethod]
        public void TestMethod()
        {
            // Arrange
            var mock = new Mock<ITestTarget>();
            // モックの振る舞いを登録します
            // ref参照の変数で値を変更します
            mock.Setup(_ => _.DoSomething(It.IsAny<string>(), ref It.Ref<string>.IsAny))
                .Callback(new DoSomethingCallback((string value1, ref string value2) => value2 = "This is output value."));
            var target = mock.Object;

            // Act
            var input = "This is input value.";
            target.DoSomething("", ref input);

            // Assert
            Assert.AreEqual("This is output value.", input);
        }
    }

まず、テスト対象メソッドが呼ばれた際のコールバック用のデリゲートを定義しておきます。
そして、Callbackにて ref に設定する変数を変更するように記載すれば OK です。

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