2011-10-21 15 views
16

Così mi sono bloccato mentre cercavo di far sì che il mio webservice asmx usasse l'iniezione delle dipendenze e usasse un IoC per farlo. Voglio che il mio servizio web sia in grado di utilizzare i miei servizi di livello aziendale interno. Il servizio web deve essere utilizzato da un client esterno da un dominio diverso e verrà principalmente utilizzato per inviare e ricevere informazioni su entità quali Ordini e Clienti.Iniezione delle dipendenze ASMX e IoC

Un esempio potrebbe essere:

public class MyService : System.Web.Services.WebService 
{ 
    [WebMethod] 
    public string HelloWorld() 
    { 
     return new MyBusinessService().MyMethod(); 
    } 
} 

public class MyBusinessService : IMyBusinessService 
{ 
    public string MyMethod() 
    { 
     return "hello"; 
    } 
} 

Voglio usare l'iniezione di dipendenza per eliminare la necessità di "Newing" il mio servizio, ma i cant capire un modo per fare questo. Posso farlo funzionare usando l'uomo povero DI, o almeno penso che si chiami "povero uomo".

come questo:

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(); 
    } 
} 

Ma io semplicemente non posso ottenere la mia testa intorno a come utilizzare un contenitore CIO per iniettare le mie dipendenze perché i cant ottenere il servizio per l'esecuzione senza un costruttore senza parametri. Si prega di essere gentile, non sono un programmatore esperto e ho appena iniziato a testare l'iniezione di dipendenze e ho funzionato correttamente sulla mia applicazione di moduli Windows con structuremap ma sono rimasto bloccato su questo.

risposta

33

Sfortunatamente non esiste un modo per eseguire un'iniezione del costruttore con servizi Web in ASP.NET. È un requisito di ASP.NET quello di fornire un costruttore predefinito. Il costruttore di MyService si avvicina alla radice della composizione che è possibile ottenere con questo tipo di servizio Web, senza utilizzare un contenitore DI.

Con ASP.NET non è insolito avere più radici di composizione. Quali possono essere i costruttori dei singoli servizi Web e pagine web. Se si utilizza ASP.NET MVC, ControllerFactory è più intuitivo.

Con la vostra implementazione la parte importante non è spostare la costruzione del grafico dell'oggetto dal servizio Web, poiché questa è la vostra radice di composizione. La cosa principale da fare è mantenere il servizio Web il più sottile possibile, mantenere la maggior parte della logica nella dipendenza in modo che possa essere testata o riutilizzata. Estrarre le informazioni dalle intestazioni HTTP è un esempio di un'attività che il servizio Web potrebbe quindi trasferire tali informazioni alla dipendenza.

Un buon libro a cui fare riferimento per i modelli e le tecniche DI è Dependency Injection in .NET di Mark Seemann.

Se il servizio Web implementato System.Web.IHttpHandler anziché derivante da System.Web.Services.WebService si potrebbe implementare il DI in questo modo:

Global.ashx.cs

public class Global : HttpApplication 
{ 
    protected void Application_PreRequestHandlerExecute(object sender, EventArgs e) 
    { 
     var context = ((HttpApplication)sender).Context; 

     var needsMyBusinessService = context.Handler as INeedMyBusinessService; 
     if (needsMyBusinessService != null) 
      needsMyBusinessService.MyBusinessService = new MyBusinessService(); 
    } 
} 

MyService.ashx.cs

public class MyService : IHttpHandler, INeedMyBusinessService 
{ 
    public IMyBusinessService MyBusinessService { get; set; } 

    public bool IsReusable { get { return true; } } 

    public void ProcessRequest(HttpContext context) 
    { 
     // uses my dependency 
    } 
} 

INeedMyBusinessService.cs

public interface INeedMyBusinessService 
{ 
    IMyBusinessService MyBusinessService { get; set; } 
} 

Tuttavia, la cattura con questa implementazione è che è fa non lavoro con i servizi web che implementano System.Web.Services.WebService come l'oggetto servizio Web non è inizializzato fino a dopo l'evento PreRequestHandlerExecute è chiamata, che è l'ultimo evento prima ProcessRequest si chiama.

L'esempio precedente funziona se si desidera disporre di un'istanza univoca per ciascun servizio Web. Se si desidera avere la stessa istanza (Singleton lifecycle) di MyBusinessService per ogni richiesta di servizio Web, è possibile implementare il file Global.ashx.cs in questo modo:

public class Global : HttpApplication 
{ 
    private static IMyBusinessService businessService; 

    protected void Application_Start(object sender, EventArgs e) 
    { 
     Global.businessService = new MyBusinessService(); 
    } 

    protected void Application_PreRequestHandlerExecute(object sender, EventArgs e) 
    { 
     var context = ((HttpApplication)sender).Context; 

     var needsMyBusinessService = context.Handler as INeedMyBusinessService; 
     if (needsMyBusinessService != null) 
      needsMyBusinessService.MyBusinessService = Global.businessService; 
    } 
}