- 投稿日:2021-02-26T17:54:22+09:00
Prism コードサンプル学習:07-Modules
Prism コードサンプル学習:07-Modules
はじめに
以下の記事の続きです。
https://qiita.com/mngreen/items/41d3bd3159be3b279a5f07-Modules
本サンプルではModuleの読み込みを、以下の5パターンの方法で行うやり方です。
- App.configを用いた読み込み07-Modules - AppConfig
- プロジェクトを参照し、IModuleCatalogを用いて読み込み07-Modules - Code
- Moduleが格納されているフォルダを指定して読み込み07-Modules - Directory
- ModuleInfoのインスタンスを生成してIModuleCatalogに追加07-Modules - LoadManual
- ModuleInfoをXamlで定義し、そのXaml構造からModuleCatalogを生成07-Modules - Xaml
App.configを用いた読み込み
App.configで読み込まれるようにどこで設定されているか
- App.xaml.csでCreateModuleCatalogをオーバーライドして
return new ConfigurationModuleCatalog();としているが、この内部の呼び先をたどっていくとConfigurationStore.Desktopに到達する。App.configが参照されるのは、ここでConfigurationManagerを利用しているから。
プロジェクトを参照し、IModuleCatalogを用いて読み込み
Moduleが格納されているフォルダを指定して読み込み
- フォルダパスを指定すると、それ以下のModuleをかき集めてくれる。実際に読み込み処理が発生するのはここ
- 内部で使用されているイベントは遅延ローディングする仕組みで見たのと同じように見える。
- ビルド時にModuleフォルダに格納するように設定の変更が必要
ModuleInfoのインスタンスを生成してIModuleCatalogに追加
- プロジェクトを参照し、IModuleCatalogを用いて読み込みが隠蔽しているところを自前でもできることを示しているだけ。
ModuleInfoをXamlで定義し、そのXamlからModuleCatalogを生成
Uriでxamlを指定し、dllを読み込む。処理はここ
- 以下のように読み込み対象のモジュールを指定する。
<m:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:m="clr-namespace:Prism.Modularity;assembly=Prism.Wpf"> <m:ModuleInfo ModuleName="ModuleAModule" ModuleType="ModuleA.ModuleAModule, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </m:ModuleCatalog>個人的所感
- プロジェクト参照が必要な方法は以下。
- プロジェクトを参照し、IModuleCatalogを用いて読み込み
- ModuleInfoのインスタンスを生成してIModuleCatalogに追加
- プロジェクト参照がなくても動的に読み込める方法は以下。
- App.configを用いた読み込み
- Moduleが格納されているフォルダを指定して読み込み
- ModuleInfoをXamlで定義し、そのXamlからModuleCatalogを生成
プロジェクト参照をなくせて、変更が少なく済みそうなModuleが格納されているフォルダを指定して読み込みが良さそうに見える。
他の動的に読み込める方法はバージョンや名前空間が変わるごとにメンテが必要となり大変そう。おわりに
今回はModuleの読み込む方法について確認しました。
個人的には動的に読み込める恩恵を受けられる方法が良いかと思いますが、Prismが使われているオープンソースでの主流についても把握したほうがよいと思いました。
次回、08-ViewModelLocatorについて見ていこうと思います。
- 投稿日:2021-02-26T14:26:45+09:00
.NETでDockerを利用したローカル開発時にもAWS Profileを使ってシークレットを安全に引き渡す
はじめに
ローカル開発時に.NETのプログラムからAWSの各サービスを利用するには、認証情報としてAWSのプロファイル情報を利用するか、アクセスキーとシークレットキーを設定する必要があります。プログラムの設定ファイルなどにアクセスキーやシークレットキーを記載すると、誤ってソース管理リポジトリに公開してしまう危険があるため、可能であればAWSプロファイルを利用してAWSに接続することが推奨されます。
この記事では、Dockerを利用したローカル開発時に、AWS Profileを利用してシークレットを安全に取り扱う方法について解説します。プロファイルを利用した.NET CoreでのAWSサービスの利用
.NET CoreでAWSの各サービスを利用する場合は下記のドキュメントに記載されている通り、設定ファイル(
appsettings.json
)に利用するAWSのプロファイル情報を定義し、Startup時にAddDefaultAWSOptions
拡張メソッドで前述の設定内容を有効にすることが推奨されています。
https://docs.aws.amazon.com/ja_jp/sdk-for-net/v3/developer-guide/net-dg-config-netcore.html具体的には、下記のようになります。
appsettings.json{ "AWS": { "Profile": "DevProfile", "Region": "ap-northeast-1" } }Startup.cs(AWSサービスのDI設定)public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddDefaultAWSOptions(Configuration.GetAWSOptions()); services.AddAWSService<IAmazonSecretsManager>(); /// ... 略 ... } /// ... 略 ... }サービスの利用public class HomeController : ControllerBase { private readonly IAmazonSecretsManager _amazonSecretsManager; public HomeController (IAmazonSecretsManager amazonSecretsManager) { _amazonSecretsManager = amazonSecretsManager; } public async Task<string> Get() { var secret = await _amazonSecretsManager.GetSecretValueAsync(new GetSecretValueRequest { SecretId = "MySecret" }); return secret.SecretString; } }Visual StudioでIISにホストしたり、
dotnet run
でWebサイトをセルフホストした場合はこれで問題ありませんが、Dockerにホストした場合はDocker内に設定ファイル(appsettings.jsonで指定した)AWSプロファイルが存在しないため、下記のような例外が発生します。AWSプロファイルからAWSの接続情報が取得できないために発生する例外Amazon.Runtime.AmazonServiceException: Unable to get IAM security credentials from EC2 Instance Metadata Service. at Amazon.Runtime.DefaultInstanceProfileAWSCredentials.FetchCredentials() at Amazon.Runtime.DefaultInstanceProfileAWSCredentials.GetCredentials() at Amazon.Runtime.DefaultInstanceProfileAWSCredentials.GetCredentialsAsync() at Amazon.Runtime.Internal.CredentialsRetriever.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.ErrorCallbackHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.MetricsHandler.InvokeAsync[T](IExecutionContext executionContext)Docker利用のAWSプロファイルの利用
アクセスキーとシークレットキーを設定してもよいのですが、せっかく機密情報を記載しなくてもよい仕組みがあるのでプロファイルを利用したいですよね。AWSプロファイルは、各ユーザーのホームディレクトリ直下の.awsディレクトリに保存されています。このディレクトリ配下の設定情報はどのOSでも共通になっているので、このフォルダーをボリュームマウントしてあげればよさそうです。
Visual Studioを利用している場合は、コンテナーオーケストレーターのサポートから
Docker Composeを追加して、
docker-compose.override.ymlにホームディレクトリ/.awsディレクトリを各コンテナのホームディレクトリにマウントする設定を追加してあげましょう。AWSプロファイル名は各開発者で異なる可能性があるので、AWSプロファイル名もこちらに書いておくと良いかもしれませんね。docker-compose.override.ymlversion: '3.4' services: app: environment: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=https://+:443;http://+:80 - AWS__Profile=DevProfile # 追加 ports: - "80" - "443" volumes: - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro - ${USERPROFILE}/.aws:/root/.aws/:ro # 追加プロファイルからアクセスキーとシークレットキーが取得できていますね。
まとめ
- AWSに接続する場合はできるだけAWSプロファイルを利用する。
- ローカルでDockerコンテナの中からAWSに接続する場合はホストの.awsディレクトリをマウントしてAWSプロファイルを利用する。
- 投稿日:2021-02-26T10:32:38+09:00
埋め込んだファイルをStreamとして取り出す
はじめに
.NETで一時的なHTTPサーバーを立ち上げて、index.htmlだけを返す必要がありました。
単一のexeで完結させたいので、下記2点を実現したいと考えています。
- index.htmlをexeに埋め込む
- 埋め込んだリソースをStreamとして取り出すindex.htmlをexeに埋め込む
index.htmlのプロパティを開き、ビルドアクションを埋め込みリソースとして設定します。
埋め込んだリソースをStreamとして取り出す
GetManifestResourceStream
を使うことで、Streamとして埋め込みリソースを取り出せます。
GetManifestResourceStream
の引数には、プロジェクト名.[フォルダ階層.]ファイル名
を指定します。Program.csvar context = await http.GetContextAsync(); context.Response.ContentType = "text/html"; var assembly = Assembly.GetExecutingAssembly(); using (var file = assembly.GetManifestResourceStream("WindowsFormsApp1.index.html")) { file.CopyTo(context.Response.OutputStream); }
- 投稿日:2021-02-26T08:26:34+09:00
移動する方向にオブジェクトを傾けさせたい【Unity】
タイトルの通り。
UFOとかドローン、ゴーストみたいな浮遊してる敵とかに使えるかも?
Transform.InverseTransformDirectionという存在を初めて知った。Simple_Tilt.csusing UnityEngine; public class Simple_Tilt : MonoBehaviour { [SerializeField] private float xMultiple; private Vector3 latestPos; private Vector3 tiltVector; private Vector3 localDiff; void Update() { //ワールドでの移動量 Vector3 diff = transform.position - latestPos; latestPos = transform.position; //ローカル用に変換する localDiff = transform.InverseTransformDirection(diff.normalized); tiltVector = new Vector3( localDiff.z * xMultiple, transform.eulerAngles.y, localDiff.x * -xMultiple); transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(tiltVector), 0.1f); } }
- 投稿日:2021-02-26T01:49:37+09:00
【Unity】Packageのインポートで同一のファイル名のシーンやスクリプトがあると上書きされるので注意
Packageをインポートしたらデータが上書きされてびっくり
タイトルの通りなので注意したい。
なんとなく別プロジェクトのUIとかスクリプトを使い回そうとしてインポートしたら起きました。
一旦上書きされてしまうと、バックアップ以外に戻す方法がないっぽい。
テストしてみると、とりあえずsceneとscriptは上書きされてしまいました。
一応警告は出るが、、
パッと情報がなかったので、何かの間違いかもと思ってテストしてみた。
同じファイル名のシーンとスクリプトとがあるプロジェクトを二つ用意
スクリプトはこんな感じのやつの表示テキスト部分だけが違を変えたものに。
Hello.cs// Start is called before the first frame update void Start() { Debug.Log("上書きされた"); }エクスポート側
あ、ちっさく警告でてる!。
ここで気づけてチェックを外せばOKだけど、
このままimportを押してしまうと上書きされてしまう。もうちょっとババーンと警告出して欲しいな。
ちなみに昔は警告も出なかったそうな。コワイ。
https://answers.unity.com/questions/1006498/accidentally-overwritten-scripts-with-imported-pac.html
https://answers.unity.com/questions/594502/help-scene-file-overwritten-after-import-package.html
https://www.reddit.com/r/Unity3D/comments/adlhzg/does_unity_just_overwrite_your_scene_if_you/ちなみにプロジェクトウィンドウの中に同一ファイル名のファイルをコピーしても上書きされない。
Finderなどでコピペすると上書き、というか新しいファイルに置き換えられるらしい。
https://amagamina.jp/overwriter/
- 投稿日:2021-02-26T01:49:37+09:00
【Unity】Packageのインポートは同一のファイル名のシーンやスクリプトを上書きするっぽいので注意
Packageをインポートしたらデータが上書きされてびっくり
タイトルの通りなので注意したい。
なんとなく別プロジェクトのUIとかスクリプトを使い回そうとしてインポートしたら起きました。
GameManagerとかOpenURLとか一部使い回してるけど中身が違うスクリプトが上書きしてしまって焦った。とりあえずsceneとscriptは丸々上書きされてしまいました。
一旦上書きされてしまうと、バックアップ以外に戻す方法がないっぽい。
今回はDropBoxから復元しました。ファイル操作のミスとかでも間違って上書きしちゃうことはあるけど、
気をつけたい。一応警告は出るが、、
パッと情報がなかったので、何かの間違いかもと思ってテストしてみた。
同じファイル名のシーンとスクリプトとがあるプロジェクトを二つ用意
スクリプトはこんな感じのやつの表示テキスト部分だけを変えたものに。
Hello.cs// Start is called before the first frame update void Start() { Debug.Log("上書きされた"); }エクスポート側
あ、ちっさく警告でてる!。
ここで気づけてチェックを外せばOKだけど、
このままimportを押してしまうと上書きされてしまう。もうちょっとババーンと警告出して欲しいな。
ちなみに昔は警告も出なかったそうな。コワイ。
https://answers.unity.com/questions/1006498/accidentally-overwritten-scripts-with-imported-pac.html
https://answers.unity.com/questions/594502/help-scene-file-overwritten-after-import-package.html
https://www.reddit.com/r/Unity3D/comments/adlhzg/does_unity_just_overwrite_your_scene_if_you/その他メモ
あとプロジェクトウィンドウの中に同一ファイル名のファイルをコピーしても上書きされない。
別のファイルとして召喚される。
Finder上からの操作であれば上書きできる。
https://amagamina.jp/overwriter/
- 投稿日:2021-02-26T01:49:37+09:00
【Unity】Packageのインポートで同一ファイル名のシーンやスクリプトが上書きされる
Packageをインポートしたらデータが上書きされてびっくり
タイトルの通りなので注意したい。
なんとなく別プロジェクトのUIとかスクリプトを使い回そうとしてインポートしたら起きました。
GameManagerとかOpenURLとか一部使い回してるけど中身が違うスクリプトが上書きしてしまって焦った。とりあえずsceneとscriptは丸々上書きされてしまいました。
一旦上書きされてしまうと、バックアップ以外に戻す方法がないっぽい。
今回はDropBoxから復元しました。ファイル操作のミスとかでも間違って上書きしちゃうことはあるけど、
気をつけたい。Unityのバージョンは2019.4.1f
一応警告は出るが、、
パッと情報がなかったので、何かの間違いかもと思ってテストしてみた。
同じファイル名のシーンとスクリプトとがあるプロジェクトを二つ用意
スクリプトはこんな感じのやつの表示テキスト部分だけを変えたものに。
Hello.cs// Start is called before the first frame update void Start() { Debug.Log("上書きされた"); }エクスポート側
あ、ちっさく警告でてる!。
ここで気づけてチェックを外せばOKだけど、
このままimportを押してしまうと上書きされてしまう。もうちょっとババーンと警告出して欲しいな。
ちなみに昔は警告も出なかったそうな。コワイ。
https://answers.unity.com/questions/1006498/accidentally-overwritten-scripts-with-imported-pac.html
https://answers.unity.com/questions/594502/help-scene-file-overwritten-after-import-package.html
https://www.reddit.com/r/Unity3D/comments/adlhzg/does_unity_just_overwrite_your_scene_if_you/その他メモ
あとプロジェクトウィンドウの中に同一ファイル名のファイルをコピーしても上書きされない。
別のファイルとして召喚される。
Finder上からの操作であれば上書きできる。
https://amagamina.jp/overwriter/
- 投稿日:2021-02-26T00:12:16+09:00
[C#]コンストラクタを呼ばずにインスタンスを作る
以下のようなクラスがあるとき、インスタンスの作成にとても時間がかかってしまいます。
public class Hoge { private int v; public int Value => v; public Hoge() { // Application.isPlayingはメインスレッドで呼ばなければ例外が発生する Debug.Log($"Application.isPlaying:{Application.isPlaying}"); // コンストラクタで重い処理をしている v = HeavyFunc(); } private int HeavyFunc() { // 重い初期化処理 Thread.Sleep(5000); // 計算結果 return 42; } }インスタンスを作成するときにメインスレッドで行ってしまうとUIが止まってしまうのでできれば別スレッドで作成したいところです。
しかし、コンストラクタ内部でApplication.isPlaying
にアクセスしてしまっているため通常はメインスレッドでしか作成することができません。Task.Run(() => { try { var h = new Hoge(); Debug.Log(h.Value); } catch (Exception e) { // UnityException: get_isPlaying can only be called from the main thread. // Constructors and field initializers will be executed from the loading thread when loading a scene. // Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function. Debug.LogException(e); } });このクラスを書いたのが自分であれば修正すればいいですがソースコードを修正できない場合もあります。
そのような場合、最終手段として
System.Runtime.Serialization.FormatterServices.GetUninitializedObject
を使うことでコンストラクタを呼ばずにインスタンスを作成することができます。
インスタンスさえ作成できれば後はリフレクションで何とかなります。// privateなフィールド、メソッドにアクセスするためにリフレクションを使用する var vInfo = typeof(Hoge).GetField("v", BindingFlags.NonPublic | BindingFlags.Instance); var heavyFuncInfo = typeof(Hoge).GetMethod("HeavyFunc", BindingFlags.NonPublic | BindingFlags.Instance); _ = Task.Run(() => { try { // コンストラクタを呼ばずにインスタンスを作成 var hoge = FormatterServices.GetUninitializedObject(typeof(Hoge)) as Hoge; // HeavyFuncを実行する var result = heavyFuncInfo.Invoke(hoge, null); // フィールドに値をセット vInfo.SetValue(hoge, result); // 正しくインスタンスが作成されている Debug.Log(hoge.Value); } catch (Exception e) { Debug.LogException(e); } });