如何用autofac实现多依赖注入装饰器
How to implement multi dependency injection decorator with autofac
我想用 IOC 容器 autofac 调用 MessageStore
class。
如何使用最新版本的 autofac 注册这个装饰器和复合模式?
这段代码结合了合成器和装饰器模式,注意 SOLID Principal。
我对此感到困惑。我的问题是,这段代码如何用 autofac
定义
var fileStore = new FileStore(new DirectoryInfo(HostingEnvironment.MapPath("~/file"))); var cacheStore = new CacheStore(fileStore, fileStore); var logStore = new LogStore(cacheStore, cacheStore); var messageStore = new MessageStore(logStore, logStore); messageStore.Save(12, "Hello");
public class FileStore : IFileLocator, IStoreWriter,IStoreReader
{
private readonly DirectoryInfo _workingDirectory;
public FileStore(DirectoryInfo workDirectory)
{
if (workDirectory == null)
throw new ArgumentNullException("workDirectory");
if (!workDirectory.Exists)
throw new ArgumentException("Directory not found", "workDirectory");
_workingDirectory = workDirectory;
}
public virtual void Save(int id, string message)
{
var path = GetFileInfo(id).FullName;
File.WriteAllText(path, message);
}
public virtual Maybe<string> Read(int id)
{
var file = GetFileInfo(id);
if (!file.Exists)
return new Maybe<string>();
var path = file.FullName;
return new Maybe<string>(File.ReadAllText(path));
}
public virtual FileInfo GetFileInfo(int id)
{
return new FileInfo(
Path.Combine(_workingDirectory.FullName, id + ".txt"));
}
}
public class CacheStore : IStoreWriter, IStoreReader
{
private readonly ConcurrentDictionary<int, Maybe<string>> _cache;
private readonly IStoreWriter _writer;
private readonly IStoreReader _reader;
public CacheStore(IStoreWriter writer, IStoreReader reader)
{
_cache = new ConcurrentDictionary<int, Maybe<string>>();
_writer = writer;
_reader = reader;
}
public virtual void Save(int id, string message)
{
_writer.Save(id, message);
var m = new Maybe<string>(message);
_cache.AddOrUpdate(id, m, (i, s) => m);
}
public virtual Maybe<string> Read(int id)
{
Maybe<string> retVal;
if (_cache.TryGetValue(id, out retVal))
return retVal;
retVal = _reader.Read(id);
if (retVal.Any())
_cache.AddOrUpdate(id, retVal, (i, s) => retVal);
return retVal;
}
}
public class LogStore : IStoreWriter, IStoreReader
{
private readonly IStoreWriter _writer;
private readonly IStoreReader _reader;
public LogStore(IStoreWriter writer, IStoreReader reader)
{
_writer = writer;
_reader = reader;
}
public void Save(int id, string message)
{
Log.Information("Saving message {id}.", id);
_writer.Save(id, message);
Log.Information("Saved message {id}.", id);
}
public Maybe<string> Read(int id)
{
Log.Debug("Reading message {id}.", id);
var retVal = _reader.Read(id);
if (retVal.Any())
Log.Debug("Returning message {id}.", id);
else
Log.Debug("No message {id} found.", id);
return retVal;
}
}
public class MessageStore
{
private readonly IStoreWriter _writer;
private readonly IStoreReader _reader;
public MessageStore(IStoreWriter writer, IStoreReader reader)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (reader == null)
throw new ArgumentNullException("reader");
_writer = writer;
_reader = reader;
}
public void Save(int id, string message)
{
_writer.Save(id, message);
}
public Maybe<string> Read(int id)
{
return _reader.Read(id);
}
}
鉴于您的所有商店都实施并使用 IStoreReader
和 IStoreWriter
,您可以通过将它们组合到一个 IStore
界面中来简化事情。这可以是定义 Save
和 Read
方法的单个接口,或者如果需要,它可以继承现有的 IStoreReader
和 IStoreWriter
接口。
然后您可以将您的 FileStore
- 这似乎是主要实现 - 注册为键控服务。然后使用 RegisterDecorator
注册缓存和日志装饰器。最后注册MessageStore
,解析没有key的服务,会做最外层的装饰器
builder.Register(f => new FileStore(new DirectoryInfo(HostingEnvironment.MapPath("~/file"))))
.Keyed<IStore>("file");
builder.RegisterDecorator<IStore>(
(c, inner) => new CacheStore(inner), fromKey: "file", toKey: "cache");
builder.RegisterDecorator<IStore>(
(c, inner) => new LogStore(inner), fromKey: "cache", toKey: null);
builder.Register(c => new MessageStore(c.Resolve<IStore>()));
我确信 API 周围的装饰器可以得到改进,这绝对是我打算尽快做的事情。
谢谢亚历克斯。但是我用下面的代码解决了,因为我不想创建 IStore
。你考虑一下我的讨论吗?
builder.Register(f => new FileStore(new DirectoryInfo(HostingEnvironment.MapPath("~/file"))))
.Named<IStoreWriter>("F-writer").Named<IStoreReader>("F-reader");
builder.Register(
c => new CacheStore(c.ResolveNamed<IStoreWriter>("F-writer"), c.ResolveNamed<IStoreReader>("F-reader")))
.Named<IStoreWriter>("C-writer").Named<IStoreReader>("C-reader");
builder.Register(
c => new LogStore(c.ResolveNamed<IStoreWriter>("C-writer"), c.ResolveNamed<IStoreReader>("C-reader")))
.Named<IStoreWriter>("L-writer").Named<IStoreReader>("L-reader");
builder.Register(
c =>
new MessageStore(c.ResolveNamed<IStoreWriter>("L-writer"), c.ResolveNamed<IStoreReader>("L-reader")));
我想用 IOC 容器 autofac 调用 MessageStore
class。
如何使用最新版本的 autofac 注册这个装饰器和复合模式?
这段代码结合了合成器和装饰器模式,注意 SOLID Principal。
我对此感到困惑。我的问题是,这段代码如何用 autofac
定义var fileStore = new FileStore(new DirectoryInfo(HostingEnvironment.MapPath("~/file"))); var cacheStore = new CacheStore(fileStore, fileStore); var logStore = new LogStore(cacheStore, cacheStore); var messageStore = new MessageStore(logStore, logStore); messageStore.Save(12, "Hello");
public class FileStore : IFileLocator, IStoreWriter,IStoreReader
{
private readonly DirectoryInfo _workingDirectory;
public FileStore(DirectoryInfo workDirectory)
{
if (workDirectory == null)
throw new ArgumentNullException("workDirectory");
if (!workDirectory.Exists)
throw new ArgumentException("Directory not found", "workDirectory");
_workingDirectory = workDirectory;
}
public virtual void Save(int id, string message)
{
var path = GetFileInfo(id).FullName;
File.WriteAllText(path, message);
}
public virtual Maybe<string> Read(int id)
{
var file = GetFileInfo(id);
if (!file.Exists)
return new Maybe<string>();
var path = file.FullName;
return new Maybe<string>(File.ReadAllText(path));
}
public virtual FileInfo GetFileInfo(int id)
{
return new FileInfo(
Path.Combine(_workingDirectory.FullName, id + ".txt"));
}
}
public class CacheStore : IStoreWriter, IStoreReader
{
private readonly ConcurrentDictionary<int, Maybe<string>> _cache;
private readonly IStoreWriter _writer;
private readonly IStoreReader _reader;
public CacheStore(IStoreWriter writer, IStoreReader reader)
{
_cache = new ConcurrentDictionary<int, Maybe<string>>();
_writer = writer;
_reader = reader;
}
public virtual void Save(int id, string message)
{
_writer.Save(id, message);
var m = new Maybe<string>(message);
_cache.AddOrUpdate(id, m, (i, s) => m);
}
public virtual Maybe<string> Read(int id)
{
Maybe<string> retVal;
if (_cache.TryGetValue(id, out retVal))
return retVal;
retVal = _reader.Read(id);
if (retVal.Any())
_cache.AddOrUpdate(id, retVal, (i, s) => retVal);
return retVal;
}
}
public class LogStore : IStoreWriter, IStoreReader
{
private readonly IStoreWriter _writer;
private readonly IStoreReader _reader;
public LogStore(IStoreWriter writer, IStoreReader reader)
{
_writer = writer;
_reader = reader;
}
public void Save(int id, string message)
{
Log.Information("Saving message {id}.", id);
_writer.Save(id, message);
Log.Information("Saved message {id}.", id);
}
public Maybe<string> Read(int id)
{
Log.Debug("Reading message {id}.", id);
var retVal = _reader.Read(id);
if (retVal.Any())
Log.Debug("Returning message {id}.", id);
else
Log.Debug("No message {id} found.", id);
return retVal;
}
}
public class MessageStore
{
private readonly IStoreWriter _writer;
private readonly IStoreReader _reader;
public MessageStore(IStoreWriter writer, IStoreReader reader)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (reader == null)
throw new ArgumentNullException("reader");
_writer = writer;
_reader = reader;
}
public void Save(int id, string message)
{
_writer.Save(id, message);
}
public Maybe<string> Read(int id)
{
return _reader.Read(id);
}
}
鉴于您的所有商店都实施并使用 IStoreReader
和 IStoreWriter
,您可以通过将它们组合到一个 IStore
界面中来简化事情。这可以是定义 Save
和 Read
方法的单个接口,或者如果需要,它可以继承现有的 IStoreReader
和 IStoreWriter
接口。
然后您可以将您的 FileStore
- 这似乎是主要实现 - 注册为键控服务。然后使用 RegisterDecorator
注册缓存和日志装饰器。最后注册MessageStore
,解析没有key的服务,会做最外层的装饰器
builder.Register(f => new FileStore(new DirectoryInfo(HostingEnvironment.MapPath("~/file"))))
.Keyed<IStore>("file");
builder.RegisterDecorator<IStore>(
(c, inner) => new CacheStore(inner), fromKey: "file", toKey: "cache");
builder.RegisterDecorator<IStore>(
(c, inner) => new LogStore(inner), fromKey: "cache", toKey: null);
builder.Register(c => new MessageStore(c.Resolve<IStore>()));
我确信 API 周围的装饰器可以得到改进,这绝对是我打算尽快做的事情。
谢谢亚历克斯。但是我用下面的代码解决了,因为我不想创建 IStore
。你考虑一下我的讨论吗?
builder.Register(f => new FileStore(new DirectoryInfo(HostingEnvironment.MapPath("~/file"))))
.Named<IStoreWriter>("F-writer").Named<IStoreReader>("F-reader");
builder.Register(
c => new CacheStore(c.ResolveNamed<IStoreWriter>("F-writer"), c.ResolveNamed<IStoreReader>("F-reader")))
.Named<IStoreWriter>("C-writer").Named<IStoreReader>("C-reader");
builder.Register(
c => new LogStore(c.ResolveNamed<IStoreWriter>("C-writer"), c.ResolveNamed<IStoreReader>("C-reader")))
.Named<IStoreWriter>("L-writer").Named<IStoreReader>("L-reader");
builder.Register(
c =>
new MessageStore(c.ResolveNamed<IStoreWriter>("L-writer"), c.ResolveNamed<IStoreReader>("L-reader")));