我从未在应用程序中使用依赖注入。我通过几篇关于依赖注入的文章,发现这个概念很有意思但很难在现实生活中实现。现在我想在我的win form apps中实现Dependency Injection。
我们公司目前与UPS,Fedex,Purolator等许多船公司合作,但未来他们计划与许多其他船公司合作。我为UPS,Fedex,Purolator等所有航运公司开发了单独的类库项目,并将这些dll包含在我们的主要表单应用程序中。问题是很多时候我们在代码中硬编码很少的东西,比如国家代码等。
例如我有一个表格,其中有4个按钮。就像那些按钮是“Ship with UPS WorldShip”,另一个按钮叫做“Ship with UPS WebAPI”,另一个按钮名为“Ship with FedEX Desktop Apps”,另一个按钮名为“Ship with Fedex WebAPI”。
当用户点击UPS WorldShip按钮时,会在文件夹中生成一个平面文件。 当用户点击UPS WebAPI按钮,然后请求进入UPS站点。
当用户点击FedEX WinApps按钮时,会在文件夹中生成一个平面文件。 当用户点击FedEX WebAPI按钮,然后请求进入FedEx网站。
所以当用户点击任何按钮时我现在所做的就是我在dll中调用一个特定的函数来完成任务。
我的一切工作正常,但问题是我们公司开始与另一家新的运输公司合作,然后我必须为该公司创建另一个类库。
我说我从未在我的应用程序中使用DI并且没有经验。所以有人指导我如何处理我的情况,因为当一家新的航运公司加入时我不需要编写任何额外的代码。所以指导我如何在我的应用程序中实现DI,并指导我如何使用示例DI代码处理我的情况以获得指导。
1)当我需要调用InitializeKernel()函数时?当应用程序加载或表单加载时
2)我不熟悉ninject所以我只是不明白这行代码的含义是什么
.Configure((b,c)=> b.InTransientScope()命名(c.Name)));
3)c.Name会返回什么?
4)我发现没有配置文件条目。 ninject不需要像Unity DI那样配置文件条目吗?
你给的代码看起来非常专业。如果可能请回答我的所有观点。最后告诉我有没有可用于ninject的pdf用于学习DI和ninject代码的使用。
感谢
非常抱歉,右边的InitializeKernel()声明一次。
你说Ninject支持流畅的配置只有这样才会出现问题,因为当一家新的航运公司加入时我必须在这个区块中更改代码,如
using(var kernel = InitializeKernel())
{
// 4.1 resolve delivery services by names
var upsWorldShip = kernel.Get<IShippingCompanyService>("ShippingUpsWorldShip");
var fedExDesktopApps = kernel.Get<IShippingCompanyService>("ShippingFedExDesktopApps");
var PurolatorExDesktopApps = kernel.Get<IShippingCompanyService>("PurolatorFedExDesktopApps");
// 4.2 delivery processing
upsWorldShip.Delivery();
fedExDesktopApps.Delivery();
// 5 PROFIT!
}
所以我需要添加这一行
var PurolatorExDesktopApps = kernel.Get<IShippingCompanyService> ("PurolatorFedExDesktopApps");
问题是每当一个新的运输相关的dll将被添加,然后我必须在上面的块中添加一行代码....这是不可取的。
如果我可以在配置文件中添加所有dll的相关信息并加载&amp;实例化所有来自那里的所有dll,它会更好。所以我在寻找你的建议。感谢
答案 0 :(得分:2)
似乎你要Configuration by Convention。这意味着您可以识别应该共享公共配置的组件组,然后在read more about it
中在单个语句中指定该组态实际上,这意味着您将所有具有选定功能“交付”的库部署到项目中的“特殊”位置,并从“特殊”界面继承所有实现。最后,让DI容器找到它们并为你配置一切。
以下是如何使用Ninject.Extensions.Conventions
实现此目的的简单示例。
关注评论
// 1 define "delivery" interface
interface IShippingCompanyService
{
void Delivery();
}
// 2.1 — first assembly "Ups.Services.dll"
public class ShippingUpsWorldShip : IShippingCompanyService
{
public void Delivery()
{
"Ship with UPS WorldShip".Dump();
}
}
// 2.2 — first assembly "FedEx.Services.dll"
public class ShippingFedExDesktopApps : IShippingCompanyService
{
public void Delivery()
{
"Ship with FedEX Desktop Apps".Dump();
}
}
使用Ninject内核构建配置(在本例中为StandardKernel
)
// 3 kernel configuration
public static IKernel InitializeKernel()
{
var kernel = new StandardKernel();
kernel.Bind(x => x
// 3.1 search in current assembly
.FromThisAssembly()
.SelectAllClasses() // 3.2 select all classes implement "special" interface
.InheritedFrom<IShippingCompanyService>()
// 3.3 search all assemblies by wildcards
.Join.FromAssembliesMatching("./*Services.dll")
.SelectAllClasses() // 3.2 select all classes implement special interface
.InheritedFrom<IShippingCompanyService>()
// 3.4 bind to "special" interface
.BindAllInterfaces()
// 3.5 configure lifetime management and dependency name
.Configure((b, c) =>
b.InTransientScope().Named(c.Name)));
return kernel;
}
从Composition root of application按名称解析递送服务
// 4 from your Compositon Root ...
using(var kernel = InitializeKernel())
{
// 4.1 resolve delivery services by names
var upsWorldShip = kernel.Get<IShippingCompanyService>("ShippingUpsWorldShip");
var fedExDesktopApps = kernel.Get<IShippingCompanyService>("ShippingFedExDesktopApps");
// 4.2 delivery processing
upsWorldShip.Delivery();
fedExDesktopApps.Delivery();
// 5 PROFIT!
}
所有可用资源here
按惯例进行配置是许多项目中已采用的非常有用的方法。不过,我建议您阅读Mark Seemann book "Dependency Injection in .NET"并观看他的talk about conventions。
.Configure((b, c) => b.InTransientScope().Named(c.Name)))
c.Name
会返回什么?
InitializeKernel()
同名的方法,第二个InitializeKernel()
是什么?
InitializeKernel()
答案 1 :(得分:1)
首先是一本非常好的书"Dependency Injection in .NET" by Seemann
here is许多DI容器的基准。
DI的主要思想是消费者不得创建其消费的服务实例 每个服务都应以最抽象的方式呈现给客户端:接口/基类(在您的情况下是特殊功能)。
然后我必须为该公司创建另一个类库
这是不可避免的。重要的是如何引用这个新的API。客户端代码不应该了解实现细节。