我开始在 Windows 应用程序项目上使用 StructureMap。在学习基础知识的过程中,我发现了两种方法来安排我的解决方案来实现相同的目标,我想知道是否有人可以评论这两种方法中的一种是否是更好的选择,以及为什么。
这里的目标是使用 IOC,以便我可以使用 2 个服务而不需要依赖它们。因此,我在业务层中创建了接口,然后在基础设施项目中实现了这些接口,并在那时包装了实际的服务。
在我的第一次尝试中,我创建了一个项目 DependencyResolver,其中包含使用流畅接口初始化结构图的代码(当有人想要 IServiceA 时,给他们一个 ServiceX 的实例)。因为 DependencyResolver 的初始化需要从我的应用程序启动,所以我有一个从应用程序到 DependencyResolver 的引用,如下所示:

然后我发现我可以删除对 DependencyResolver 的引用,并依靠 StructureMap 扫描器和命名约定在运行时获取该引用,所以我的设置如下所示:

因此,我进一步采用了命名约定,深入到我正在使用的服务中,并且能够完全取消 DependencyResolver。此时,我完全依赖结构图扫描仪和命名约定来正确设置:

所以。我在这里,不太确定我应该如何看待这三个选项。选项 1 似乎不错,但由于使用了 StructureMap,我的 UI 间接引用了它不应该(直接)引用的所有内容。但是,我不确定这是否真的重要。
选项 2 消除了从应用程序到 DependencyResolver 的引用的需要,并依赖命名约定来访问该项目中的类,并且我仍然对所有剩余的设置具有高级别的控制权(但我现在依赖于 StructureMap)直接来自我的应用程序)。
选项 3 似乎是最简单的(只需以某种方式命名所有内容,然后扫描程序集),但这似乎更容易出错且脆弱。特别是如果我想做一些比 IServiceAbc => ServiceAbc 更复杂的事情。
那么,有谁对我在这方面有更多经验的人可以给我一些建议吗?
我是否应该避免从我的应用程序间接引用我的服务?如果是,这样做的真正好处是什么?我认为尝试用命名约定做所有事情只在简单的项目中才是明智的,对吗?
是否有一个标准模式来完成我在这里想做的事情?
抱歉发了这么长的帖子..
我有一个像这样的界面
public interface IAddressProvider
{
string GetAddress(double lat, double long);
}
Run Code Online (Sandbox Code Playgroud)
在我的消费类中,我想循环遍历具体的提供者,直到得到结果,例如(简化的):
string address;
address = _cachedAddressProvider.GetAddress(lat, long);
if(address == null)
address = _localDbAddressProvider.GetAddress(lat, long);
if(address = null)
address = _externalAddressProvider.GetAddress(lat, long);
return address ?? "no address found";
Run Code Online (Sandbox Code Playgroud)
然后,我可以模拟每个提供程序进行单元测试,将 null 设置为返回值以适当测试所有代码路径。
我如何将接口注入到我的消费类中(最好使用 StructureMap)以便正确解析每个具体实现?
我正在尝试解决 IoC 问题,一开始看起来很简单,但结果却很痛苦:-P
我有一个重量级主类,它必须只初始化一次,因此它被标记为单例。然而,该类使用一个必须为每个请求创建一次的子类,因此它被标记为 Transient:
public class MyRegistry : Registry
{
public MyRegistry()
{
For<IMainClass>()
.Singleton()
.Use(ctx => new MainClass(() => ctx.GetInstance<ISubClass>()));
For<ISubClass>()
.Transient()
.Use(ctx => CreateNewInstanceOfSubClass());
}
private ISubClass CreateNewInstanceOfSubClass()
{
return new SubClass();
}
}
public interface ISubClass
{ }
public class SubClass : ISubClass
{ }
public interface IMainClass
{ }
public class MainClass : IMainClass
{
private readonly Func<ISubClass> _subClassProvider;
public MainClass(Func<ISubClass> subClassProvider)
{
_subClassProvider = subClassProvider;
}
public void DoStuff()
{
var requestSpecificInstanceOfSubClass = _subClassProvider(); …Run Code Online (Sandbox Code Playgroud) 我正在将代码转换为使用带有 StructureMap 的 IoC 容器。试图让我的头脑理解这些事情,我觉得它开始“点击”,我可以看到它对后端有如此大的意义。
然而,我在努力的过程中发现了一些我不确定如何使其发挥作用的情况。具体来说,我的原始构造函数使用并非真正依赖项的参数执行了一些重要操作,或者执行了一些在运行时会发生更改的操作。
假设我从这个(IoC 容器之前)开始,我使用构造函数传递我的依赖项,但也向它发送一个ImportantObject运行时依赖项:
IMyPageViewModel myPageViewModel = new MyPageViewModel(importantObject, dialogManager, pageDisplay, viewModelProvider)
Run Code Online (Sandbox Code Playgroud)
在这里它正在构建:
public MyPageViewModel(ImportantObject importantObject, IDialogManager dialogManager,IPageDisplay pageDisplay, IViewModelProvider viewModelProvider)
{
this.dialogManager = dialogManager;
this.pageDisplay = pageDisplay;
this.viewModelProvider = viewModelProvider;
importantObject.DoThatImportantThing();
}
Run Code Online (Sandbox Code Playgroud)
现在,我正在迁移到使用 IoC 容器,首先我认为我应该这样做:
//I need to create an instance to use, so I use my IoC container:
IMyPageViewModel myPageViewModel = container.GetInstance<IMyPageViewModel>();
Run Code Online (Sandbox Code Playgroud)
然后让它解决它的依赖关系,但是 importantObject 是在运行时设置的。我无法将其注册为依赖项:
public MyPageViewModel(IDialogManager dialogManager,IPageDisplay pageDisplay, IViewModelProvider viewModelProvider, IContainer container)
{
this.dialogManager = dialogManager;
this.pageDisplay = pageDisplay;
this.viewModelProvider = …Run Code Online (Sandbox Code Playgroud) 我准备通过这个滑动玻璃门.我无法弄清楚如何在VB.NET中执行以下代码来挽救我的生命.
private static void InitStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.AddRegistry(new DataAccessRegistry());
x.AddRegistry(new CoreRegistry());
x.AddRegistry(new WebUIRegistry());
x.Scan(scanner =>
{
scanner.Assembly("RPMWare.Core");
scanner.Assembly("RPMWare.Core.DataAccess");
scanner.WithDefaultConventions();
});
});
}
Run Code Online (Sandbox Code Playgroud) 在我在网上看到的大多数样本中,MVC控制器中的DI都是这样完成的
public ProductController(IProductRepository Rep)
{
this._rep = Rep;
}
Run Code Online (Sandbox Code Playgroud)
使用自定义ControllerFactory,它使用选择的DI框架并注入存储库.
为什么以上认为比上述更好
public ProuctController()
{
this._rep = ObjectFactory.GetInstance<IProductRepository>();
}
Run Code Online (Sandbox Code Playgroud)
这将得到相同的结果,但不需要自定义控制器工厂.
就测试而言,测试应用程序可以有一个单独的BootStrapper.这样,当控制器被测试时,他们可以获得假的存储库,当它们被用于实际时,它们将获得真实存储库.
我正在尝试为Ravendb实现IoC(Ninject)并遇到了一些障碍.我正在使用http://www.dotnetguy.co.uk/post/2010/06/12/raven-db-ndash-part-1-ndash-documentsession-per-request-with-structuremap中的代码来提供帮助.
public interface IRavenSessionFactoryBuilder
{
IRavenSessionFactory GetSessionFactory();
}
public class RavenSessionFactoryBuilder : IRavenSessionFactoryBuilder
{
private IRavenSessionFactory _ravenSessionFactory;
public IRavenSessionFactory GetSessionFactory()
{
return _ravenSessionFactory ?? (_ravenSessionFactory = CreateSessionFactory());
}
private static IRavenSessionFactory CreateSessionFactory()
{
Debug.Write("IRavenSessionFactory Created");
return new RavenSessionFactory(new DocumentStore
{
Url =
System.Web.Configuration.WebConfigurationManager.AppSettings[
"Raven.DocumentStore"]
});
}
}
public interface IRavenSessionFactory
{
IDocumentSession CreateSession();
}
public class RavenSessionFactory : IRavenSessionFactory
{
private readonly IDocumentStore _documentStore;
public RavenSessionFactory(IDocumentStore documentStore)
{
if (_documentStore != null) return;
_documentStore = documentStore;
_documentStore.Initialize();
} …Run Code Online (Sandbox Code Playgroud) 在我的应用程序中有些情况我的存储库需要将不同的参数传递给具体类型的构造函数.我希望能够做到这样的事情:
var arg = (x == y) ? z : a;
ObjectFactory.GetInstance<IRepository>(arg);
Run Code Online (Sandbox Code Playgroud)
参数只能在创建Repository实例时根据某些条件构造.
如何才能做到这一点?
我在运行测试时遇到一些问题,这会产生一个非常大的字节数组(~4GB).
当我在发布/调试模式下运行它时,一切都很好,但是当我运行初始化这个数组的测试时,我得到OutOfMemory异常
for (int i = 0; i < 56000; i++)
{
m_BlocksFree.Enqueue(new byte[65536]);
}
Run Code Online (Sandbox Code Playgroud)
起初我认为,因为我有很多测试初始化这个大数组然后我得到一个内存不足异常,但即使运行单个测试我得到相同的异常.
我正在用C#编写并使用MSTest,Rhinomocks和structureMap,win7 64bit.
谢谢你们的帮手:)
我正在使用NUnit,Moq和StructureMap.
我有一个以下的NUnit测试:
[Test]
public void ShouldCallCustomMethod_ForAllICustomInterfaceMocks()
{
var customInterfaceMock1 = new Mock<ICustomInterface>();
var customInterfaceMock2 = new Mock<ICustomInterface>();
ObjectFactory.Inject(customInterfaceMock1.Object);
ObjectFactory.Inject(customInterfaceMock2.Object);
var sut = new SUT();
sut.MethodThatShouldCallCustomMethodOnMocks();
customInterfaceMock1.Verify(m => m.CustomMethod());
customInterfaceMock2.Verify(m => m.CustomMethod());
}
Run Code Online (Sandbox Code Playgroud)
ICustomInterface:
public interface ICustomInterface
{
IEnumerable<Type> CustomMethod();
}
Run Code Online (Sandbox Code Playgroud)
现在,如果SUT类的实现如下所示:
public class SUT
{
public IEnumerable<Type> MethodThatShouldCallCustomMethodOnMocks()
{
var result = ObjectFactory.GetAllInstances<ICustomInterface>()
.SelectMany(i => i.CustomMethod());
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
由于没有在模拟上调用CustomMethod方法,因此上面的测试失败.但是,如果我将SUT类的实现更改为:
public class SUT
{
public IEnumerable<Type> MethodThatShouldCallCustomMethodOnMocks()
{
var customInterfaceInstances = ObjectFactory.GetAllInstances<ICustomInterface>();
foreach (var instance in customInterfaceInstances)
instance.CustomMethod();
return …Run Code Online (Sandbox Code Playgroud) structuremap ×10
c# ×6
unit-testing ×3
.net ×1
asp.net-mvc ×1
c#-4.0 ×1
linq ×1
moq ×1
mstest ×1
ninject ×1
ravendb ×1
rhino-mocks ×1
vb.net ×1