使用 Unity 通过 Azure WebJob 从另一个项目注入依赖项
Using Unity to inject dependency from another project with Azure WebJob
我的解决方案中有两个项目 - 一个 Web 项目和一个控制台应用程序。
Web 项目
在我的网络项目中,我有以下工作:
public class TestService : BaseService {
private BrowseService _browseService;
public TestService(BrowseService browseService) {
_browseService = browseService;
}
public ApiResponseDto DoStuff(string username) {
using (var db = new AppContext()) {
var user = db.FindUser(username);
// do stuff with _browseService here
}
}
}
我在这里使用 Unity 进行 DI。
控制台应用程序
现在,我从我的控制台应用程序引用我的 Web 项目并执行以下操作:
public class Functions {
private TestService _testService;
public Functions(TestService testService) {
_testService = testService;
}
public static void ProcessStuff([QueueTrigger("my-queue")] string userId) {
using (var db = new AppContext()) { // works
_testService.DoStuff(userId) // _testService isn't available
}
}
问题
如何让 DI 在我的控制台应用程序中工作?我添加了 Unity,然后执行此操作:
static void Main() {
var container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
var host = new JobHost();
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
但是,上面的构造函数永远不会被命中,并且 _testService
永远不可用。
更新
我尝试了以下操作:
static void Main() {
var container = new UnityContainer();
var host = container.Resolve<JobHost>().
host.RunAndBlock();
}
但是我得到一个例外:
Microsoft.Practices.Unity.ResolutionFailedException was unhandled
_HResult=-2146233088 _message=Resolution of the dependency failed, type = "Microsoft.Azure.WebJobs.JobHost", name = "(none)". Exception
occurred while: while resolving. Exception is:
InvalidOperationException - The type String cannot be constructed. You
must configure the container to supply this value.
----------------------------------------------- At the time of the exception, the container was:
Resolving Microsoft.Azure.WebJobs.JobHost,(none) Resolving
parameter "configuration" of constructor
Microsoft.Azure.WebJobs.JobHost(Microsoft.Azure.WebJobs.JobHostConfiguration
configuration)
Resolving Microsoft.Azure.WebJobs.JobHostConfiguration,(none)
Resolving parameter "dashboardAndStorageConnectionString" of constructor Microsoft.Azure.WebJobs.JobHostConfiguration(System.String
dashboardAndStorageConnectionString)
Resolving System.String,(none)
HResult=-2146233088 IsTransient=false Message=Resolution of the
dependency failed, type = "Microsoft.Azure.WebJobs.JobHost", name =
"(none)". Exception occurred while: while resolving. Exception is:
InvalidOperationException - The type String cannot be constructed. You
must configure the container to supply this value.
更新 2
我现在对这个问题有以下看法:
class Program {
static void Main() {
var container = new UnityContainer();
var config = new JobHostConfiguration {
JobActivator = new MyActivator(container)
};
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
public class MyActivator : IJobActivator {
private readonly IUnityContainer _container;
public MyActivator(IUnityContainer container) {
_container = container;
}
public T CreateInstance<T>() {
return _container.Resolve<T>();
}
}
但是,_testService
仍然是 null,Functions
的注入构造函数永远不会执行。
DependencyResolver 是一个 MVC 结构;它不在控制台应用程序中使用。要完成这项工作,请将您的主要方法更改为:
static void Main() {
var container = new UnityContainer();
var host = container.Resolve<JobHost>().
host.RunAndBlock();
}
然后,只要你使用构造函数注入,一切都应该按预期工作。
根据您的代码,我已经在我这边测试并解决了。请尝试按照以下代码查看是否对您有所帮助:
Web 项目
public class TestService : BaseService
{
private BrowseService _browseService;
public TestService(BrowseService browseService)
{
_browseService = browseService;
}
public string DoStuff(string username)
{
return _browseService.DoStuff(username);
}
}
public class BaseService { }
public abstract class BrowseService
{
public abstract string DoStuff(string username);
}
public class MyBrowseService : BrowseService
{
public override string DoStuff(string username)
{
return string.Format("MyBrowseService.DoStuff is invoked with value={0}", username);
}
}
控制台应用程序
1)Functions.cs
public class Functions
{
private static TestService _testService;
public Functions(TestService testService)
{
_testService = testService;
}
public void ProcessStuff([QueueTrigger("my-queue")] string userId)
{
try
{
Console.WriteLine("ProcessStuff is invoked with value={0}", userId);
string result = _testService.DoStuff(userId);
Console.WriteLine("ProcessStuff return the result:\r\n{0}", result);
}
catch (Exception e)
{
Console.WriteLine("ProcessStuff executed with errors.\r\n{0}\r\n{1}", e.Message, e.StackTrace);
}
}
}
注意:您应该将 WebJob 函数设置为实例函数而不是静态函数。
2)Program.cs
static void Main()
{
UnityContainer container = new UnityContainer();
container.RegisterType<BrowseService, MyBrowseService>();
container.RegisterType<Functions>(); //Need to register WebJob class
var config = new JobHostConfiguration()
{
JobActivator = new UnityJobActivator(container)
};
var host = new JobHost(config);
host.RunAndBlock();
}
结果:
我的解决方案中有两个项目 - 一个 Web 项目和一个控制台应用程序。
Web 项目
在我的网络项目中,我有以下工作:
public class TestService : BaseService {
private BrowseService _browseService;
public TestService(BrowseService browseService) {
_browseService = browseService;
}
public ApiResponseDto DoStuff(string username) {
using (var db = new AppContext()) {
var user = db.FindUser(username);
// do stuff with _browseService here
}
}
}
我在这里使用 Unity 进行 DI。
控制台应用程序
现在,我从我的控制台应用程序引用我的 Web 项目并执行以下操作:
public class Functions {
private TestService _testService;
public Functions(TestService testService) {
_testService = testService;
}
public static void ProcessStuff([QueueTrigger("my-queue")] string userId) {
using (var db = new AppContext()) { // works
_testService.DoStuff(userId) // _testService isn't available
}
}
问题
如何让 DI 在我的控制台应用程序中工作?我添加了 Unity,然后执行此操作:
static void Main() {
var container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
var host = new JobHost();
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
但是,上面的构造函数永远不会被命中,并且 _testService
永远不可用。
更新
我尝试了以下操作:
static void Main() {
var container = new UnityContainer();
var host = container.Resolve<JobHost>().
host.RunAndBlock();
}
但是我得到一个例外:
Microsoft.Practices.Unity.ResolutionFailedException was unhandled
_HResult=-2146233088 _message=Resolution of the dependency failed, type = "Microsoft.Azure.WebJobs.JobHost", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value. ----------------------------------------------- At the time of the exception, the container was:Resolving Microsoft.Azure.WebJobs.JobHost,(none) Resolving parameter "configuration" of constructor Microsoft.Azure.WebJobs.JobHost(Microsoft.Azure.WebJobs.JobHostConfiguration configuration) Resolving Microsoft.Azure.WebJobs.JobHostConfiguration,(none) Resolving parameter "dashboardAndStorageConnectionString" of constructor Microsoft.Azure.WebJobs.JobHostConfiguration(System.String dashboardAndStorageConnectionString) Resolving System.String,(none)
HResult=-2146233088 IsTransient=false Message=Resolution of the dependency failed, type = "Microsoft.Azure.WebJobs.JobHost", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.
更新 2
我现在对这个问题有以下看法
class Program {
static void Main() {
var container = new UnityContainer();
var config = new JobHostConfiguration {
JobActivator = new MyActivator(container)
};
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
public class MyActivator : IJobActivator {
private readonly IUnityContainer _container;
public MyActivator(IUnityContainer container) {
_container = container;
}
public T CreateInstance<T>() {
return _container.Resolve<T>();
}
}
但是,_testService
仍然是 null,Functions
的注入构造函数永远不会执行。
DependencyResolver 是一个 MVC 结构;它不在控制台应用程序中使用。要完成这项工作,请将您的主要方法更改为:
static void Main() {
var container = new UnityContainer();
var host = container.Resolve<JobHost>().
host.RunAndBlock();
}
然后,只要你使用构造函数注入,一切都应该按预期工作。
根据您的代码,我已经在我这边测试并解决了。请尝试按照以下代码查看是否对您有所帮助:
Web 项目
public class TestService : BaseService
{
private BrowseService _browseService;
public TestService(BrowseService browseService)
{
_browseService = browseService;
}
public string DoStuff(string username)
{
return _browseService.DoStuff(username);
}
}
public class BaseService { }
public abstract class BrowseService
{
public abstract string DoStuff(string username);
}
public class MyBrowseService : BrowseService
{
public override string DoStuff(string username)
{
return string.Format("MyBrowseService.DoStuff is invoked with value={0}", username);
}
}
控制台应用程序
1)Functions.cs
public class Functions
{
private static TestService _testService;
public Functions(TestService testService)
{
_testService = testService;
}
public void ProcessStuff([QueueTrigger("my-queue")] string userId)
{
try
{
Console.WriteLine("ProcessStuff is invoked with value={0}", userId);
string result = _testService.DoStuff(userId);
Console.WriteLine("ProcessStuff return the result:\r\n{0}", result);
}
catch (Exception e)
{
Console.WriteLine("ProcessStuff executed with errors.\r\n{0}\r\n{1}", e.Message, e.StackTrace);
}
}
}
注意:您应该将 WebJob 函数设置为实例函数而不是静态函数。
2)Program.cs
static void Main()
{
UnityContainer container = new UnityContainer();
container.RegisterType<BrowseService, MyBrowseService>();
container.RegisterType<Functions>(); //Need to register WebJob class
var config = new JobHostConfiguration()
{
JobActivator = new UnityJobActivator(container)
};
var host = new JobHost(config);
host.RunAndBlock();
}
结果: