2012-05-20 45 views
3

我在使用spring.net 4.0,基于ASP.net的web应用程序的nhibernate 3.0开发web应用程序方面拥有适中的经验。最近我遇到了一个情况,我需要使用spring.net来注入属于WorkerRole类的服务依赖关系。我创建了app.config文件,就像我通常在spring上使用web.config文件一样。这是为了清晰。 (我已经排除根节点)无法使用Spring.NET将依赖项注入Azure WorkerRole对象

<configSections> 
    <sectionGroup name="spring"> 
     <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web" requirePermission="false" /> 
     <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" requirePermission="false" /> 
     <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" /> 
    </sectionGroup> 
    </configSections> 
    <spring> 
    <context> 
     <!-- Application services and data access that has been previously developed and tested--> 
     <resource uri="assembly://DataAccess/data-access-config.xml" /> 
     <resource uri="assembly://Services/service-config.xml" /> 
     <resource uri="AOP.xml" /> 
     <resource uri="DI.xml"/> 
    </context> 
    <parsers> 
     <parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" /> 
     <parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" /> 
     <parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" /> 
    </parsers> 
    </spring> 

同样这里的aop.xml文件

<object id="FilterServiceProxy" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop"> 
    <property name="proxyInterfaces" value="Domain.IFilterService"/> 
    <property name="target" ref="FilterService"/> 
    <property name="interceptorNames"> 
     <list> 
     <value>UnhandledExceptionThrowsAdvice</value> 
     <value>PerformanceLoggingAroundAdvice</value> 
     </list> 
    </property> 
    </object> 
</objects> 

和DI.xml

<object type="FilterMt.WorkerRole, FilterMt" > 
    <property name="FilterMtService1" ref="FilterServiceProxy"/> 
</object> 

然而,我无法注入任何依赖关系成工作者角色。有人能让我知道我在这里做错了吗?有没有不同的方式来配置Windows Azure应用程序的Spring.net DI?

我没有得到任何配置错误,但我看到依赖关系没有被注入,因为我尝试注入的属性对象仍为空。

回答

10

根据我的经验,你不能在你的WorkerRole类(实现RoleEntryPoint的类)中注入任何东西。我到底用Unity(我还为Unity创建了自己的助手来帮助我注入Azure设置),是我拥有自己的基础架构,可以运行并由Unity构建,但是我在工作人员的代码中创建它角色。

例如,我在RoleEntry的OnStart()方法中初始化依赖容器,在那里我解决了我需要的任何东西。然后在我的Run()方法中,我调用了一个解析的依赖关系的方法。

这里是我的RoleEntryPoint的实现的快速,剥下版本:

public class WorkerRole : RoleEntryPoint 
{ 
    private UnityServiceHost _serviceHost; 
    private UnityContainer _container; 

    public override void Run() 
    { 
     // This is a sample worker implementation. Replace with your logic. 
     Trace.WriteLine("FIB.Worker entry point called", "Information"); 
     using (this._container = new UnityContainer()) 
     { 
      this._container.LoadConfiguration(); 
      IWorker someWorker = this._container.Resolve<IWorker>(); 
      someWorker.Start(); 

      IWorker otherWorker = this._container.Resolve<IWorker>("otherWorker"); 
      otherWorker.Start(); 

      while (true) 
      { 
       // sleep 30 minutes. we don't really need to do anything here. 
       Thread.Sleep(1800000); 
       Trace.WriteLine("Working", "Information"); 
      } 
     } 
    } 

    public override bool OnStart() 
    { 
     // Set the maximum number of concurrent connections 
     ServicePointManager.DefaultConnectionLimit = 12; 

     // For information on handling configuration changes 
     // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357. 

     this.CreateServiceHost(); 

     return base.OnStart(); 
    } 

    public override void OnStop() 
    { 
     this._serviceHost.Close(TimeSpan.FromSeconds(30));  
     base.OnStop(); 
    } 

    private void CreateServiceHost() 
    { 
     this._serviceHost = new UnityServiceHost(typeof(MyService)); 

     var binding = new NetTcpBinding(SecurityMode.None); 
     RoleInstanceEndpoint externalEndPoint = 
      RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["ServiceEndpoint"]; 
     string endpoint = String.Format(
      "net.tcp://{0}/MyService", externalEndPoint.IPEndpoint); 
     this._serviceHost.AddServiceEndpoint(typeof(IMyService), binding, endpoint); 
     this._serviceHost.Open(); 
    } 

正如你看到的,我自己的逻辑是IWorker界面,我可以有许多实现我想要的,我instiate他们在我的Run()方法中。我做的更多的是有一个WCF服务,再次完全通过DI与Uni​​ty配置。这是我的IWorker接口:

public interface IWorker : IDisposable 
{ 
    void Start(); 
    void Stop(); 
    void DoWork(); 
} 

就是这样。我的WorkerRole中没有任何“硬”依赖项,只有Unity容器。我的两名工人中有非常复杂的DI,一切都很顺利。

您无法直接干涉WorkerRole.cs类的原因是,它正在由Windows Azure基础结构实例化,而不是由您自己的基础结构实例化。您必须接受这一点,并在WorkerRole适当的方法中构建您的基础架构。不要忘记,您绝对不能退出/中断/返回/退出Run()方法。这样做会标记Windows Azure基础结构,说明代码有问题,并会触发角色回收。

希望这会有所帮助。

+1

所以基本上'WorkerRole'是组合根? – Marijn

+1

我会这么说,是的。 – astaykov

+0

谢谢astaykov。这是解决这个问题的一个很好的方法。 – TWickz

0

我知道这是一个古老的问题,但我正在经历相同的学习曲线,并希望将我的发现分享给努力理解力学的人。

您无法在工作角色类中访问DI的原因是因为这是在IIS之外的操作系统中的单独进程中运行的。将你的WebRole类想象成在Windows服务中运行。

我做了一个小实验与我的MVC的Web站点和WebRole类:

public class WebRole : RoleEntryPoint 
{ 
    public override void Run() 
    { 
     while (true) 
     { 
      Thread.Sleep(10000); 
      WriteToLogFile("Web Role Run: run, Forest, RUN!"); 
     } 
    } 

    private static void WriteToLogFile(string text) 
    { 
     var file = new System.IO.StreamWriter("D:\\tmp\\webRole.txt", true); // might want to change the filename 
     var message = string.Format("{0} | {1}", DateTime.UtcNow, text); 

     file.WriteLine(message); 
     file.Close(); 
    } 
} 

这将写入一个文件一个新的字符串每10秒(左右)。现在以调试模式启动您的Azure站点,确保已部署到Azure模拟器的站点和VS中的调试器已启动。检查网站是否正在运行,并检查WebRole是否正在写入有问题的文件。

现在停止IIS Express(或IIS,如果您正在全面安装中运行它),而不停止VS调试器。您网站上的所有操作现在都会停止。但是,如果您检查临时文件,该过程仍在运行,并且您每10秒钟仍会添加新行。直到你停止调试器。

所以无论你在网络应用程序的内存中加载的是在IIS内部,并且不能在工作者角色中使用。你需要从头开始重新配置你的DI和其他服务。

希望这可以帮助别人更好地理解基本知识。