Settings(ApplicationSettingsBase)とDependency Injectionを使用して、すべての構成ファイルコードをロジックコードから除外するにはどうすればよいですか?
構成とは、お客様固有の構成ファイルを意味します。
本当に必要なときに毎回構成クラスを注入する必要がありますか、それとも別のパターンがありますか?
サンプルコードを入手していただければ幸いです。
サンプル:
静的構成:
public static class StaticConfiguration
{
public static bool ShouldApplySpecialLogic { get; set; }
public static string SupportedFileMask { get; set; }
}
public class ConsumerOfStaticConfiguration
{
public void Process()
{
if (StaticConfiguration.ShouldApplySpecialLogic)
{
var strings = StaticConfiguration.SupportedFileMask.Split(',');
foreach (var @string in strings)
{
}
}
}
}
非静的構成:
public interface IConfiguration
{
bool ShouldApplySpecialLogic { get; set; }
string SupportedFileMask { get; set; }
}
public class Configuration : IConfiguration
{
public bool ShouldApplySpecialLogic { get; set; }
public string SupportedFileMask { get; set; }
}
public class Consumer
{
private readonly IConfiguration _configuration;
public Consumer(IConfiguration configuration)
{
_configuration = configuration;
}
public void Process()
{
if (_configuration.ShouldApplySpecialLogic)
{
var strings = _configuration.SupportedFileMask.Split(',');
foreach (var @string in strings)
{
}
}
}
}
非静的構成の静的コンテキスト:
public static class Context
{
public static IConfiguration Configuration { get; set; }
}
public class ConsumerOfStaticContext
{
public void Process()
{
if (Context.Configuration.ShouldApplySpecialLogic)
{
var strings = Context.Configuration.SupportedFileMask.Split(',');
foreach (var @string in strings)
{
}
}
}
}
認識すべき重要な部分は、構成は、アプリケーションの動作を駆動するいくつかの値のソースのうちの1つにすぎないということです。
2番目のオプション(非静的構成)は、完全にコンシューマーを構成値のソースから切り離すを可能にするため、最適です。ただし、構成設定は通常Value Objectsとしてモデル化するのが最も良いため、インターフェースは必要ありません。
それでも設定ファイルから値を読みたい場合は、アプリケーションの Composition Root から行うことができます。 StructureMapでは、次のようになります。
var config = (MyConfigurationSection)ConfigurationManager.GetSection("myConfig");
container.Configure(r => r
.For<Consumer>()
.Ctor<MyConfigurationSection>()
.Is(config));
構成クラスは理解を減らし、コンシューマの結合を増やします。これは、クラスに必要な1つまたは2つに関連しない設定が多数ある可能性があるためです。ただし、依存関係を満たすために、IConfiguration
の実装は、すべてのアクセサーに値を提供する必要があります。無関係なもの。
また、クラスとインフラストラクチャの知識を結び付けます。「これらの値は一緒に構成されます」などの詳細がアプリケーション構成からクラスに流出し、無関係なシステムへの変更によって影響を受ける表面領域が増加します。
構成値を共有する最も複雑で最も柔軟な方法は、値自体のコンストラクター注入を使用して、インフラストラクチャの懸念を外部化することです。ただし、別の回答のコメントでは、コンストラクターパラメーターがたくさんあるのが怖いことを示していますが、これは妥当な懸念事項です。
認識すべき重要な点は、プリミティブと複雑な依存関係に違いがないということです。整数に依存するかインターフェイスに依存するかに関係なく、それらは両方ともあなたが知っていることですわからないので教えてください。この観点から、IConfiguration
はIDependencies
と同じくらい意味があります。大きなコンストラクターは、パラメーターがプリミティブであるか複雑であるかに関係なく、クラスの責任が大きすぎることを示しています。
int
、string
およびbool
を他の依存関係と同様に扱うことを検討してください。これにより、クラスがより明確になり、焦点が絞られ、変更に対する耐性が高まり、単体テストが容易になります。
1つの方法は、投稿するように構成インターフェースを挿入することです。他にいくつかの方法があります。
セッターの公開
class Consumer
{
public bool ShouldApplySpecialLogic { get; set; }
...
}
構成ルートでは、構成ファイルを読み取るか、ハードコードすることができます。 Autofacの例:
builder.RegisterType<Consumer>().AsSelf()
.OnActivated(e => e.Instance.ShouldApplySpecialLogic = true);
これはおそらく、適切なデフォルトがある場合にのみお勧めします
コンストラクター注入
public class Server
{
public Server(int portToListenOn) { ... }
}
構成ルート:
builder.Register(c => new Server(12345)).AsSelf();
私のアプリケーションでは、IoCを使用して上記で行ったことを行います。つまり、IoCコンテナー(StructureMapも)を使用してIApplicationSettings
をクラスに挿入します。
たとえば、ASP.NET MVC3プロジェクトでは、次のようになります。
Public Class MyController
Inherits Controller
...
Private ReadOnly mApplicationSettings As IApplicationSettings
Public Sub New(..., applicationSettings As IApplicationSettings)
...
Me.mApplicationSettings = applicationSettings
End Sub
Public Function SomeAction(custId As Guid) As ActionResult
...
' Look up setting for custId
' If not found fall back on default like
viewModel.SomeProperty = Me.mApplicationSettings.SomeDefaultValue
Return View("...", viewModel)
End Function
End Class
私のIApplicationSettings
の実装は、アプリの.config
ファイルからほとんどのものを引き出し、ハードコーディングされた値もいくつかあります。
私の例は、ロジックフロー制御ではありませんでしたが(例のように)、実際の場合と同じように機能しました。
これを行うもう1つの方法は、サービスロケータタイプのパターンを実行することです。このパターンでは、依存性注入コンテナに構成クラスのインスタンスを即座に取得するように要求します。 Service-Location 一般にアンチパターンと見なされます ですが、まだ使用されている可能性があります。