2012-05-20 80 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和其他服務。

希望這可以幫助別人更好地理解基本知識。