キューでメッセージをリッスンし、そのメッセージを処理するアプリケーションがあります。
これまで、顧客ごとにアプリケーションの個別のインスタンスをインストールし、構成ファイルに独自のデータベース接続文字列を設定してきました。これは、アプリケーションの更新に関しては苦痛になりつつあります。
現在、これをリファクタリングしようとしているので、必要なすべての接続文字列を備えた 1 つのインスタンスをインストールでき、ランタイム パラメータ (たとえば message.Client) に応じてデータベースを切り替えることができます。
これは手で配線すれば大丈夫なのですが……。
var data = new MyData(message.Client);
var processor = new MessageProcessor(new Foo(data), new Bar(data));
processor.Process(message);
...しかし、DIコンテナを使用してこれを達成し始める方法を理解するのに苦労しています。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using StructureMap;
namespace M.Test
{
public interface IData
{
IEnumerable<string> Names { get; }
}
public class MyData : IData
{
private readonly string _client;
public MyData(string client)
{
_client = client;
}
public IEnumerable<string> Names
{
get { return _client == "Client A" ? new[] {"One", "Two", "Three"} : new[] {"Uno", "Dos", "Tres"}; }
}
}
public interface IFoo
{
void FooDo();
}
public class Foo : IFoo
{
private readonly IData _dataContext;
public Foo(IData dataContext)
{
_dataContext = dataContext;
}
public void FooDo()
{
Debug.WriteLine(_dataContext.Names.First());
}
}
public interface IBar
{
void BarDo();
}
public class Bar : IBar
{
private readonly IData _data;
public Bar(IData data)
{
_data = data;
}
public void BarDo()
{
Debug.WriteLine(_data.Names.Last());
}
}
public interface IMessageProcessor
{
void Process(Message message);
}
public class MessageProcessor : IMessageProcessor
{
private readonly IFoo _foo;
private readonly IBar _bar;
public MessageProcessor(IFoo foo, IBar bar)
{
_foo = foo;
_bar = bar;
}
public void Process(Message message)
{
_foo.FooDo();
_bar.BarDo();
}
}
public class Message
{
public string Client { get; set; }
}
class Program
{
private static Container _container;
static void Main(string[] args)
{
_container = new Container();
_container.Configure(x =>
{
x.For<IData>().Use<MyData>();
x.For<IMessageProcessor>().Use<MessageProcessor>();
x.For<IBar>().Use<Bar>();
x.For<IFoo>().Use<Foo>();
});
MessageReceived(new Message {Client = "Client A"});
MessageReceived(new Message {Client = "Client B"});
MessageReceived(new Message {Client = "Client A"});
Console.ReadKey();
}
private static void MessageReceived(Message message)
{
// Fine if I do this...
var data = new MyData(message.Client);
var processor = new MessageProcessor(new Foo(data), new Bar(data));
processor.Process(message);
// But would like to do this...
var diProcessor = _container.TryGetInstance<IMessageProcessor>();
diProcessor.Process(message);
}
}
}
私が読んだことから、コンストラクターパラメーターを StructureMap で使用できることがわかります。例えば:
x.For<IData>().Use<MyData>().Ctor<string>("client").Is(someValueAtRunTime);
...しかし、いつ/どのように someValueAtRunTime を設定する必要があるのか\u200b\u200bわかりません。何を試しても、スレッドセーフであるか疑問に思います。
どんな助けでも感謝します。