我已经开始使用Ninject 2(昨天从Github下载,包括MVC扩展项目)和一个基于以下技术的项目:
这里没有什么神奇之处 - 我有一些存储库接口(命名为IEntityRepository),这些接口是在运行时代码中使用LINQ to SQL实现的(并在单元测试代码中使用哈希表).这些存储库中的每一个都需要一个从LINQ到SQL的DataContext实例才能与数据库通信,因此这是具体存储库类的构造函数参数.绑定设置如下:
Kernel.Bind<MyDataContext>().ToSelf().InRequestScope();
Run Code Online (Sandbox Code Playgroud)
这样做的原因是我希望能够在不同的存储库之间共享实体,如果我碰巧需要更多它们,并且使用LINQ to SQL datacontext工作原理单元,我觉得创建一个HttpRequest的.
我通常使用MyDataContext的无参数构造函数 - 我不认为这是一种风险,因为它用于测试系统上的内部项目,因此datacontext中的"内置"连接字符串是无害的.但是,由于Ninject 2是"贪婪的"并且想要带有MOST参数的构造函数,并且我无法[Inject]以任何有意义的方式将参数粘贴到生成的代码中,每当Ninject尝试创建我的一个控制器时(我需要一个存储库,需要datacontext).
我已经看到了提及IConstructorScorer能够使用带有LEAST参数的构造函数的"反转"的能力,但是再一次,这将改变注入对其他一切的工作方式 - 默认行为可能是我想要的一切但是datacontext.
那么 - 有一个很好的,干净的方式来指定这个绑定(并且只有这个绑定)应该使用特定的构造函数吗?我们可以和Ninject 1中的提供商做同样的事情,也许可以提供我们自己的"工厂"吗?或者我应该放弃并尝试将参数提供给有意义的datacontext?
如果这对任何人都有用,我很乐意把它变成社区维基.
我在MVC3应用程序中有一些慢页面,并且因为我的代码中似乎很少执行时间,所以我想知道是否可以找到更多关于花了这么长时间的内容.并不是说我成功了,但我在这个过程中获得了更多的智慧.
对于拥有一些MVC经验的人来说,这里没有什么是不明显的.基本上,我创建了自己的ActionFilterAttribute,如下所示:
public class ProfilerAttribute : ActionFilterAttribute
{
IDisposable actionStep = null;
IDisposable resultStep = null;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
actionStep = MiniProfiler.Current.Step("OnActionExecuting " + ResultDescriptor(filterContext));
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (actionStep != null)
{
actionStep.Dispose();
actionStep = null;
}
base.OnActionExecuted(filterContext);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
resultStep = MiniProfiler.Current.Step("OnResultExecuting " + ResultDescriptor(filterContext));
base.OnResultExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (resultStep != null)
{
resultStep.Dispose();
resultStep = null;
}
base.OnResultExecuted(filterContext); …Run Code Online (Sandbox Code Playgroud) 我刚刚在一个新项目上做了File - > New Project.啊,绿色田野的气味.
我正在使用刚刚发布的ASP.NET MVC 2(即没有预览或发布候选版本,真实的东西),并且认为我使用Ninject 2(也是已发布的版本)与MVC扩展开始了一个良好的开端.我下载了MVC扩展项目,在VS2008Sp1中打开它,在发布模式下构建它,然后进入mvc2\build\release文件夹并将Ninject.dll和Ninject.Web.Mvc.dll从那里复制到我的Libraries文件夹中项目(这样我就可以在源代码管理中把它们拉到一边,并且每个地方都有正确的版本).我没有包含相应的.xml文件 - 我应该吗?他们只提供智能感知或其他功能吗?我相信没什么大不了的.
Anyhoo,我遵循了我能找到的最新建议; 我在我的MVC2项目中引用了DLL,然后开始使用Global.asax.cs.首先,我让它继承自NinjectHttpApplication.我删除了Application_Start()方法,并改为使用OnApplicationStarted().这是方法:
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
// RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}
Run Code Online (Sandbox Code Playgroud)
我也遵循VS的建议并实现了CreateKernel方法:
protected override Ninject.IKernel CreateKernel()
{
// RegisterAllControllersIn(Assembly.GetExecutingAssembly());
return new StandardKernel();
}
Run Code Online (Sandbox Code Playgroud)
就这些.没有其他修改项目.
您会注意到RegisterAllControllersIn()方法在上面的两个地方被注释掉了.我想我可以用三种不同的组合来运行它,所有这些都带有时髦的副作用;
然后,我将获得标准的"欢迎使用ASP.NET MVC"页面的所有荣耀.但是,在浏览器中正确显示此页面后,VS会向我显示抛出的异常.它抛出NinjectControllerFactory.GetControllerInstance(),它在controllerType参数中使用NULL值调用.请注意,这是在/ Home页面呈现后发生的 - 我不知道为什么再次调用它,并且通过使用断点我已经确定已成功调用了HomeController的GetControllerInstance().为什么这个带有controllerType的新调用为null?我真的不知道.此时按F5将我带回浏览器,没有任何投诉.
这是东西真正开始变得时髦的地方.现在我收到404错误.有时我在RegisterAllControllersIn()行上也得到了一个ArgumentNullException,但这种情况非常罕见,而且我无法重现它.
(并将注释放回CreateKernel()中的注释)
结果似乎与第1点中的行为完全相同.
因此,为了永远不进行 - 是否有关于如何使用Ninject 2(两个非beta版本)设置MVC 2项目以获取Ninject提供的控制器的确切分步指南?当然,我将开始提供一些实际的注入东西(如ISession对象和存储库,记录器等),但我想我会先让它工作.
任何帮助将非常感谢!
(也发布到Ninject Google Group)
我正在编写一个Windows服务(如果一切按计划进行)将一次运行几个月.在服务的整个生命周期中,它将维护几个WCF服务(用于与其他本地应用程序通信的命名管道),它将运行嵌入式数据存储(可能是RavenDB,这或多或少与此问题无关),并且它将使用一些第三方软件维护SIP服务(VoIP功能).我面临的一些挑战意味着必须对事件做出反应并创建一些新的业务对象来处理这些事件所代表的内容.
现在,我已经阅读了Mark Seemann的书(至少是本次讨论的相关部分),我理解为什么服务定位器不好,为什么在组合根(在我的情况下是服务起点)处理这个问题是好的 - 一般情况.
但是,我不明白这是如何适用于所有情况的.我看到在应用程序启动时可以组成完整根目录的情况下,或者像MVC那样,框架中每个请求都使用IoC引擎的情况下,它会如何完美.但是,对于长期运行的服务,我认为在最好的情况下效率很低,而且在某些情况下不可能预先创建所有对象.我无法想象能够编写一个非平凡的服务来获取它可能需要的所有对象,并且永远不需要在生活中创建新的对象.
现在,这还不足以引诱我走向黑暗面并承担隐藏的依赖关系,就像服务定位器会让我做的那样.但在这里做什么是正确的?如果我有一个CallHandlerService需要创建以响应每个传入的调用(因为它使用昂贵的非托管资源),我该如何去做呢?
组合根+只是一点点的服务定位器?
最后一部分并不严肃,但我仍然想知道如何妥善解决这个问题.
有一个应用程序(C#WPF),需要"回家"并从家庭服务器获取更新的东西.理论上,可能有成千上万的客户,需要通过公共互联网进行通信.
每个用户将首先注册用户名和密码.然后,当应用程序运行时,它将不时地调用home,以获取有关新版本,新闻,注释,用户消息以及其他特定于应用程序的内容的信息.这不是"每个人"的应用程序,但如上所述,仍然可能有相当多的用户 - 因此安全性是一个优先事项.我希望它非常非常难以打破,但如果不可能是一个选项,我也会这样做.:)
只需要支持几个基本操作;
服务器端的东西将在带有IIS7的Win2008服务器上.我没有几乎所需的WCF知识来实现这个项目的时间,所以我将来回使用XML文件做一些ASP.NET MVC 2魔术.如果你只有一把锤子..
我正在寻找的是如何在不使用它的情况下尽可能安全地做到这一点的建议.客户端的配置将保留在XML文件中.在服务器端,大多数东西都将存在于SQL服务器中.
我意识到这在某种程度上是一个意见问题,但我也相信它应该有可能达到某种最佳实践,我可以在晚上睡觉而不用担心客户端< - >服务器通信和用户有帐户被劫持等
有什么好主意吗?
谢谢!
我有一个应用程序,它使用一些数据仓库原则,如维度建模,在一个相当简单的数据库上进行报告.
名为Call的示例(简化)实体如下所示:
public virtual long Id { get; set; }
public virtual string OriginatorNumber { get; set; }
public virtual string DestinationNumber { get; set; }
public virtual DateDimension DateDimension { get; set; }
Run Code Online (Sandbox Code Playgroud)
实际模型的一些属性已被删除,因为它们无关紧要.简化的DateDimension如下所示:
public virtual long Id { get; set; }
public virtual DateTime Date { get; set; }
public virtual int DayOfMonth { get; set; }
public virtual int Weekday { get; set; }
Run Code Online (Sandbox Code Playgroud)
还有很多这样的专栏 - 它们通过应用程序设置预先填充了当前十年.因此,整个十年中的每个日期在此表中都有一行,每个调用都有一个指向它发生日期的链接.这全部映射在Fluent NHibernate并且工作正常.
如果我想做一些报告,我可以使用3.0中改进的NHibernate LINQ提供程序轻松完成.我们希望使用LINQ来提高我们提供的可维护性,但如果我们真的必须,我们将考虑HQL,ICriteria甚至纯SQL.
所以说我想建立一个报告,显示来自某个数字的呼叫数量除以它们发生的星期几.我可以这样轻松地做到这一点:
var query = Calls
.Where(c => …Run Code Online (Sandbox Code Playgroud) 我习惯于在Web应用程序中使用IoC/DI - 主要是使用MVC3的Ninject.我的控制器是为我创建的,充满了所有依赖关系,子依赖关系等.
但是,胖客户端应用程序的情况有所不同.我必须创建自己的对象,或者我必须恢复到服务定位器样式方法,我要求内核(可能通过某个接口,允许可测试性)给我一个完整的依赖项对象.
但是,我已经看到Service Locator被描述为反模式的几个地方.
所以我的问题是 - 如果我想在我的胖客户端应用程序中受益于Ninject,是否有更好/更正确的方法来获得所有这些?
请注意我不只是在这里讨论MVVM并将视图模型放入视图中.这特别是需要从内核提供存储库类型对象,然后从该存储库中提取的实体注入了功能(当然数据来自数据库,但它们也需要一些对象作为参数,具体取决于状态世界,Ninject知道如何提供).我可以以某种方式做到这一点,而不会将存储库和实体都作为不可测试的混乱吗?
如果有什么不清楚,请告诉我.谢谢!
编辑7月14日
我确信提供的两个答案可能是正确的.然而,我身体的每一根纤维都在对抗这种变化; 其中一些可能是由于缺乏知识造成的,但也有一个具体原因导致我无法看到这种做事方式的优雅;
我没有在原始问题中解释得这么好,但问题是我正在编写一个库,将被几个(首先是4-5,可能更晚)的WPF客户端应用程序使用.这些应用程序都在相同的域模型等上运行,因此将它们保存在一个库中是保持DRY的唯一方法.但是,该系统的客户也有可能编写自己的客户端 - 我希望他们有一个简单,干净的库来与之交谈.我不想强迫他们在他们的作文根中使用DI(在他的书中使用像Mark Seeman这样的术语) - 因为与他们相比,只需要新建一个MyCrazySystemAdapter()并使用它就可以使事情复杂化.
现在,MyCrazySystemAdapter(因为我知道人们会在这里不同意我选择的名称)需要由子组件组成,并使用DI组合在一起.MyCrazySystemAdapter本身不需要注入.它是客户端与系统通信所需的唯一接口.因此,一个客户应该得到其中一个,DI就像魔术一样在幕后发生,并且该对象由许多不同的对象使用最佳实践和原则组成.
我确实意识到这将成为一种想要做事的有争议的方式.但是,我也知道将成为此API客户的人员.如果他们发现他们需要学习并连接DI系统,并在他们的应用程序入口点(Composition Root)中提前创建他们的整个对象结构,而不是新建一个对象,他们会给我中指和直接搞乱数据库并以你难以想象的方式搞砸了.
TL; DR:为客户端提供结构合理的API太麻烦了.我的API需要提供一个单独的对象 - 使用DI和适当的实践在幕后构建 - 他们可以使用.现实世界有时胜过为了坚持模式和实践而向后建造一切的愿望.
dependency-injection ninject testability thick-client service-locator
我想通过学习更多关于依赖注入/ IoC和其他最佳实践方法来成为一名优秀的编程公民.为此,我有一个项目,我正在努力做出正确的选择,并以"正确"的方式设计一切,无论这意味着什么.Ninject,Moq和ASP.NET MVC帮助实现可测试性并将应用程序"推出门外".
但是,我有一个关于如何为我的应用程序所包含的对象设计实体基类的问题.我有一个简单的类库,Web应用程序是建立在它之上的.该库公开了一个IRepository接口,默认实现(应用程序使用的接口)使用了Linq-to-SQL(DataContext等没有公开给Web应用程序),只是包含获取这些实体的方法.存储库基本上看起来像这样(简化):
public interface IRepository
{
IEnumerable<T> FindAll<T>() where T : Entity
T Get<T>(int id) where T : Entity
}
Run Code Online (Sandbox Code Playgroud)
默认实现使用DataContext上的GetTable()方法来提供正确的数据.
但是,这要求基类"Entity"具有一些功能.通过创建一个与Linq-to-SQL给我的映射对象同名的部分类,很容易让我的对象继承它,但是这样做的"正确"方法是什么?
例如,上面的接口具有通过它的id获取实体的功能 - 从实体派生的所有不同类的类确实具有int类型的"id"字段(从它们各自的表的主键映射),但是我如何以一种允许我像这样实现IRepository的方式来指定它呢?
public class ConcreteRepository : IRepository
{
private SomeDataContext db = new SomeDataContext();
public IEnumerable<T> FindAll<T>() where T : Entity
{
return db.GetTable<T>().ToList();
}
public T Get(int id) where T : Entity
{
return db.GetTable<T>().Where(ent => ent.id == id).FirstOrDefault();
}
}
Run Code Online (Sandbox Code Playgroud)
我在无编译器的PC上从内存中执行此操作,因此原谅任何错误,您希望得到我的意图.
这里的诀窍当然是为了编译它,必须确定Entity承诺从它派生的每个人都有一个id字段.
我可以创建一个抽象字段,或者由Linq-to-SQL粘贴在生成的类中的id字段"隐藏"的普通字段.
但这一切都像是作弊,甚至给编译器警告.
应该"实体"真的是"IEntity"(而不是接口),我应该尝试以Linq-to-SQL将实现的方式定义id字段?这也可以很容易地指定实体实现者需要实现的其他接口.
或者"实体"应该是一个带有抽象id字段的抽象基类,它是否应该以抽象方式实现所需的接口以供其他人覆盖?
我不太清楚C#是否能够找到优雅的解决方案,所以我很乐意听到更有经验的系统设计师的一些基础经验.
谢谢!
编辑4月10日:
我看到我在这里遗漏了一些重要的东西.我的IRepository有两个具体的实现 - 一个是使用LINQ to …
我正在寻找一些关于正确机制的建议,用于在真正的session-pr-request行为中将RavenDB IDocumentSession放入我的存储库.
这是一个绿地MVC3应用程序,我使用NuGet得到了Ninject/Ninject.MVC3.RavenDB正在外部服务器上运行(即非嵌入式).
我已经设置了Ninject模块来返回正确的存储库,并且还为每个请求设置了一个会话.
但是 - MVC3是否会为每个动作方法实例化控制器?在这种情况下,我可以让MVC3/Ninject注入我的存储库和他们需要的会话,没问题.
但是,如果在多个请求之间重用一个控制器,这可能不起作用,因为从先前的请求中闲置的存储库现在可能会使用旧的并丢弃的会话.
我已经看了几种方法 - 上面是基本的.我还尝试过像ActionFilterAttribute这样的东西,它在每个请求开始时从IoC容器中获取一个新会话 - 但在这种情况下,我应该把它放在哪里?
我的存储库是否应该使用Session属性,每次实际从容器中获取当前会话?这将添加存储库实现和IoC容器之间的耦合,但我认为应该工作.
这样做的正确方法是什么?凉爽的孩子们如何做到这一点?任何帮助将非常感谢!
期待在AppHarbor上构建一个在MVC4上运行的Web应用程序.为了响应性和性能,将通过在消息队列上放置消息来处理稍长的运行任务(通常,生成/发送电子邮件,调整图像大小,支付事务处理等).
在那里的某个地方也会有一个或多个工人,将消息出列并处理因此需要处理的任何内容.中央排队机制是RabbitMQ,特别是通过AppHarbor提供的托管CloudAMQP服务.从理论上讲,这种架构可以通过增加更多工作人员来实现"无限"的可扩展性
现在,为了良好的架构,可测试性等,我想将RabbitMQ置于一个或多个易于模拟的接口之后.在定义这些接口时,我需要考虑一些注意事项.
好的,太好了,所以这很多东西.在这个项目之前没有任何RabbitMQ的经验,我被一些额外的要点所困扰.
在构建类似的应用程序时,是否有其他人已经完成了同样的挑战?您对消息队列的接口的体系结构和实际实现有什么建议吗?我只是对此感到神经质,还是我的担忧值得肯定?
如果重要,我的当前消息传递需求由单向消息覆盖,除了在处理完成后确认收到的消息之外,不需要任何响应.
感谢您的任何见解!
ninject ×5
c# ×4
asp.net-mvc ×2
linq-to-sql ×2
.net ×1
appharbor ×1
cloudamqp ×1
encryption ×1
linq ×1
nhibernate ×1
ninject-2 ×1
oop ×1
rabbitmq ×1
ravendb ×1
sql ×1
sql-server ×1
testability ×1
thick-client ×1
xml ×1