0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ASP.NET MVC で DI したくて SimpleInjector でサービス一括登録した

Posted at

やったこと

ASP.NET MVCでロジックや共通部品をサービスとしてDIするときに、基本的にはサービスと実装が同名で1対1対応するので、それらをいちいちRegisterしなくていいようにした。ドキュメントに載ってはいるが一応メモ。

バージョン

.NET Framework 4.8
Microsoft.AspNet.Mvc 5.2.7
NuGet Gallery | SimpleInjector.Integration.Web.Mvc 5.0.0 とその依存関係

コード

Global.asax
using DiAndAop.Services;
using SimpleInjector;
using SimpleInjector.Integration.Web;
using SimpleInjector.Integration.Web.Mvc;
using System;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace DiAndAop
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            RegisterDiContainer();

            // ...
        }

        /// <summary>
        /// DIコンテナを設定する。
        /// </summary>
        private static void RegisterDiContainer()
        {
            // Create the container as usual.
            Container container = new Container();
            // デフォルトの生存期間を設定
            WebRequestLifestyle webRequestLifestyle = new WebRequestLifestyle();
            container.Options.DefaultScopedLifestyle = webRequestLifestyle;
            // 一括登録しない実装を指定
            Type[] batchRegExcludeType = { typeof(Hello) };
            BatchReg(container, batchRegExcludeType, webRequestLifestyle);

            // 一括登録以外のサービスを登録
            container.Register<IHello, Hello>(Lifestyle.Scoped);

            // This is an extension method from the integration package.
            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

            container.Verify();

            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
        }


        /// <summary>
        /// DIコンテナにサービスを一括登録する。実装とサービスが(頭の"I"を除いて)同名のクラスを対象とする。
        /// サービスと同名のもの以外に実装が存在する場合も、同名の実装が対象となる。
        /// </summary>
        /// <param name="container">DIコンテナ</param>
        /// <param name="batchRegExcludeType">除外する型</param>
        /// <param name="lifestyle">生成・破棄のオプション</param>

        private static void BatchReg(Container container, Type[] batchRegExcludeType, Lifestyle lifestyle)
        {
            Lifestyle _lifestyle = lifestyle is null ? Lifestyle.Transient : lifestyle;

            // MvcApplication の部分は、サービスとクライアントがいるアセンブリを指定できればなんでもよい
            Assembly assembly = typeof(MvcApplication).Assembly;
            // 一括登録対象を抽出
            var registrations = assembly.GetExportedTypes()
                .AsParallel()
                .Where(type => type.Namespace.StartsWith("DiAndAop.Services"))
                .Where(impl => !batchRegExcludeType.Contains(impl))
                .Select(impl => impl.GetInterfaces()
                    .Where(service => service.Name == "I" + impl.Name)
                    .Select(service => (impl, service))
                    .SingleOrDefault())
                .Where(pair => !pair.Equals(default));
            // 一括登録実施
            foreach (var reg in registrations)
            {
                container.Register(reg.service, reg.impl, _lifestyle);
            }
        }
    }
}

  • 例では DiAndAop.Services 名前空間にサービスがある想定となっている(Whereの中)ので、実態に合わせて書き換えること。
  • 気分で AsParallel を使っており、対象が少ないとかえって遅いかもしれない。
  • サービスと同名だが他の実装を使いたい場合や、他とは異なる生存期間を設定したい場合など、一括登録の対象から除外したい場合は batchRegExcludeType に型を羅列すればいい。

リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?