shuhelohelo’s blog

Xamarin.Forms多めです.

Xamarin.FormsでASP.NET CoreなDI(Dependency Injection) (3)

これまで,Xamarin.FormsでAsp.Net CoreのDIの仕組みを利用する方法を書いてきました.

shuhelohelo.hatenablog.com

shuhelohelo.hatenablog.com

最後にまだDIできる余地が残されています.

それがApp.xaml.csのAppクラスです.

現時点でAppクラスのコンストラクタは以下のようになっています.

        public App()
        {
            InitializeComponent();

            //ServiceProviderからMainPageのインスタンスを取得
            MainPage = Startup.ServiceProvider.GetService<MainPage>();//Xamarin.Forms.Xamlに定義されてる拡張メソッドGetService<T>
        }

やっていいのかどうかは置いておいて,ここでGetServiceメソッドで取得しているMainPageのインスタンスもDIしてみたいです.

        public App(Page mainPage)
        {
            InitializeComponent();

            MainPage = mainPage;
        }

このためにはAppクラス自体がServiceProviderによって生成される必要があるので,以下のようにAppクラスを登録します.

        static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
        {
            //開発と本番で登録するクラスを切り替える
            if (ctx.HostingEnvironment.IsDevelopment())
            {
                services.AddSingleton<IDataService, MockDataService>();
            }
            else
            {
                services.AddSingleton<IDataService, DataService>();
            }

            services.AddTransient<MainPageViewModel>();
            services.AddTransient<MainPage>();
            services.AddSingleton<App>();//これ
        }

Startup.Init()メソッドを以下のようにAppクラスを返すようにして,

        public static App Init(Action<HostBuilderContext, IServiceCollection> nativeConfigureServices)
        {
            var a = Assembly.GetExecutingAssembly();
            using var stream = a.GetManifestResourceStream("XFUseAspNetCoreDI.appsettings.json");

            var host = new HostBuilder()
                .ConfigureHostConfiguration(c =>
                {
                    //これは?
                    c.AddCommandLine(new string[] { $"ContentRoot={FileSystem.AppDataDirectory}" });

                    //設定ファイルを読む
                    c.AddJsonStream(stream);
                })
                .ConfigureServices((c, x) =>
                {
                    //プラットフォーム固有機能のDIを行うためのコールバックを実行
                    nativeConfigureServices(c, x);
                    ConfigureServices(c, x);
                })
                .Build();

            ServiceProvider = host.Services;

            return ServiceProvider.GetService<App>();
        }

ネイティブ側のLoadApplicationメソッドを以下のようにすると,DIの設定とAppクラスのインスタンス取得をまとめることができてスッキリします.

````cs protected override void OnCreate(Bundle savedInstanceState) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);

        Xamarin.Essentials.Platform.Init(this, savedInstanceState);
        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

        LoadApplication(Startup.Init(ConfigureServices));
    }

これで実行すると,以下のようにAppコンストラクタにMainPageのインスタンスが渡されていることが確認できました.

[f:id:shuhelohelo:20200608134024p:plain]


# 思ったこと

ページ遷移のときはどうするんだろうか.


# ソースコード

[https://github.com/shuheydev/XFUseAspNetCoreDI:embed:cite]