ASMX 依赖注入和 IoC
我在尝试让我的 asmx
Web 服务使用依赖项注入并使用 IoC 来执行此操作时遇到了困难。我希望我的网络服务能够使用我的内部业务层服务。该 Web 服务将由来自不同域的外部客户端使用,主要用于发送和接收有关订单和客户等实体的信息。
一个例子是:
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return new MyBusinessService().MyMethod();
}
}
public class MyBusinessService : IMyBusinessService
{
public string MyMethod()
{
return "hello";
}
}
我想使用依赖注入来消除“更新”我的服务的需要,但我无法找到一种方法来做到这一点。我可以使用穷人 DI 让它工作。
像这样:
public class MyService : System.Web.Services.WebService
{
private IMyBusinessService _myService;
public MyService(IMyBusinessService myService)
{
_myService = myService;
}
public MyService() : this(new MyBusinessServie()) { }
[WebMethod]
public string HelloWorld()
{
return _myService.MyMethod();
}
}
但我无法弄清楚如何使用 IoC 容器来注入我的依赖项,因为如果没有无参数构造函数,我无法让服务运行。 我刚刚开始测试依赖注入,并让它在带有 StructureMap 的 Windows 窗体应用程序上正常工作,但陷入了困境。
I have gotten stuck while trying to get my asmx
web service to use dependency injection and using an IoC to do it. I want my webservice to be able to use my internal business layer services. The webservice is to be used by an external client from a different domain and will mainly be used to send and receive information about entities such as Orders and Customers.
An example would be:
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return new MyBusinessService().MyMethod();
}
}
public class MyBusinessService : IMyBusinessService
{
public string MyMethod()
{
return "hello";
}
}
I want to use dependency injection to eliminate the need for "newing" up my service but I can't figure out a way to do this. I can get it to work using poor mans DI.
Like this:
public class MyService : System.Web.Services.WebService
{
private IMyBusinessService _myService;
public MyService(IMyBusinessService myService)
{
_myService = myService;
}
public MyService() : this(new MyBusinessServie()) { }
[WebMethod]
public string HelloWorld()
{
return _myService.MyMethod();
}
}
But I can't work out how to use a IoC container to inject my dependencies because I can't get the service to run without a parameterless constructor.
I have just started to test dependency injection and got it to work fine on my windows forms application with StructureMap but got stuck on this one.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不幸的是,没有任何方法可以在 ASP.NET 中使用 Web 服务执行构造函数注入。 ASP.NET 要求您提供默认构造函数。 MyService 的构造函数与您可以使用此类 Web 服务获得的组合根非常接近,无需使用 DI 容器。
对于 ASP.NET,具有多个组合根并不罕见。它可以是各个网络服务和网页的构造者。如果您使用 ASP.NET MVC,则它是 ControllerFactory,它对 DI 更友好。
在您的实现中,重要的部分不是从 Web 服务中移动对象图的构造,因为这是您的组合根。主要要做的事情是使 Web 服务尽可能精简,将大部分逻辑保留在依赖项中,以便可以对其进行测试或重用。从 HTTP 标头中提取信息是 Web 服务可以将该信息传递给依赖项的任务示例。
关于 DI 模式和技术,一本值得参考的好书是 .NET 中的依赖注入作者:马克·西曼。
如果您的 Web 服务实现了 System.Web.IHttpHandler 而不是从 System.Web.Services.WebService 派生,您可以像这样实现您的 DI:
Global.ashx.cs
MyService。 ashx.cs
INeedMyBusinessService.cs
然而,此实现的问题是,它不能与实现
System.Web.Services.WebService
的 Web 服务一起工作,因为 Web 服务对象是不是初始化直到调用PreRequestHandlerExecute
事件之后,这是调用ProcessRequest
之前的最后一个事件。如果您希望每个 Web 服务都有一个唯一的实例,则上面的示例适用。如果您希望每个 Web 服务请求都有相同的
MyBusinessService
实例(单例生命周期),您可以像这样实现 Global.ashx.cs 文件:Unfortunately there isn't any way for one to perform constructor injection with web services in ASP.NET. It is a requirement of ASP.NET that you provide a default constructor. The constructor of MyService is about as close to the composition root that you can get with this type of web service, without using a DI container.
With ASP.NET it is not unusual to have multiple composition roots. Which can be the constructors of the individual web services and web pages. If you are using ASP.NET MVC it is the ControllerFactory, which is more DI friendly.
With your implementation the important part isn't to move the construction of the object graph from the web service, as this is your composition root. The main thing to do, is to keep the web service as thin as possible, keep most of the logic in the dependency so it can be tested, or reused. Pulling information out of the HTTP headers is an example of a task that the web service could to then pass off that information to the dependency.
A good book to refer to for DI patterns and techniques is Dependency Injection in .NET by Mark Seemann.
If your web service implemented
System.Web.IHttpHandler
instead of deriving fromSystem.Web.Services.WebService
you could implement your DI like so:Global.ashx.cs
MyService.ashx.cs
INeedMyBusinessService.cs
However the catch with this implementation is that is does not work with web services that implement
System.Web.Services.WebService
as the web service object is not initialized until after thePreRequestHandlerExecute
event is call, which is the last event beforeProcessRequest
is called.The above example works if you want to have a unique instance for each web service. If you wanted to have the same instance (Singleton lifecycle) of
MyBusinessService
for each web service request you could implement the Global.ashx.cs file like so:WebService 上只能有无参数构造函数。但是,您可以做的是在 WebService 类上拥有一个属性,并在无参数构造函数内部调用类似 _myDependency = container.resolve(); 的内容。
You can only have a parameter-less constructor on a WebService. However, what you could do, is have a property on the WebService class, and inside of the parameter-less constructor call something like _myDependency = container.resolve();
这是一个老问题,不太可能帮助很多人,但是当 ServiceProvider::GetService() 无法返回 a 的实例时,您基本上需要
IDependencyResolver
和IDependencyScope
实现。请求的类型,该类型是显式实例化(理想情况下使用容器来解析构造函数参数。)该类型可以使用反射“显式实例化”,或者使用现代的东西,例如
ActivatorUtilities.GetServiceOrCreateInstance(...)
默认情况下,当依赖解析器没有为控制器、页面、模块(Web 服务)等提供请求类型的实例时,运行时将尝试使用事实上的 Activator 类来创建实例,而 Activator 只能创建具有公共无参数构造函数的类型的实例。
因此,如果您无法/不愿意创建
IDependencyResolver
/IDependencyScope
实现,那么说您的类型需要一个公共的无参数构造函数只是部分正确。实现自定义依赖解析器 impl 是一件微不足道的事情,MSDN 有基本实现的文章和示例。您唯一需要的其他东西是具有类型注册的明显 DI 容器,以及向 ASP.NET 注册并利用您的 DI 容器的
IDependencyResolver
。今天,这可能类似于 Microsoft.Extensions.DependencyInjection,但就问题的日期和内容而言,它也可能是 Unity(依赖注入框架,而不是游戏)引擎。)配置和集成 DI 容器有点超出了问答的范围,并且可能已经有其他问答涵盖了这样做。我要指出的是,如果您正在构建自己的 IDependencyResolver,您还可以选择使用更现代的 DI 框架(例如 ASP.NET Core 脚手架中使用的框架),即使您可能使用的是以下版本的 ASP.NET 版本: 2000年代。底层 DI 框架无关紧要,依赖解析器才是关键。另请参阅:
HTH!
This is an old question and unlikely to help very many people, but you basically need
IDependencyResolver
andIDependencyScope
implementations that when ServiceProvider::GetService() fails to return an instance of a requested type, the type is explicitly instanced (ideally using the container to resolve ctor parameters.)The type can be "explicitly instanced" using reflection, or, using something modern like
ActivatorUtilities.GetServiceOrCreateInstance(...)
By default, when the dependency resolver does not provide an instance of a requested type for a controller, page, module (webservice), etc the runtime will attempt to use the de facto
Activator
class to create an instance, andActivator
can only create instances of types which have a public, parameterless constructor.So to say that your type requires a public, parameterless ctor is only partially true.. if you are unable/unwilling to create
IDependencyResolver
/IDependencyScope
implementations. A custom dependency resolver impl is a trivial thing to implement, and MSDN has articles and examples of basic implementations.The only other thing you require is the obvious DI container with type registrations, and an
IDependencyResolver
registered with ASP.NET that leverages your DI container. Today that would likely be something likeMicrosoft.Extensions.DependencyInjection
but for the date and content of the question it could also have beenUnity
(the dependency injection framework, not the game engine.) Configuring and integrating a DI container is a bit beyond the scope of a Q&A, and there may be other Q&As already which cover doing that. I will note that if you're building your own IDependencyResolver, you also have the options of using a more modern DI framework (such as the one used within ASP.NET Core scaffolds) even though you may be using an ASP.NET version from the 2000s. The underlying DI framework is irrelevant, the Dependency Resolver is what is key here.See Also:
HTH!