2012-12-18 2 views
11

J'essaie de créer un système qui me permettra d'héberger un site Web "WebAPI" soit par le biais d'une application web, soit via un service Windows. Pour ce faire, je souhaite que toute ma logique métier soit contenue dans une bibliothèque de classes afin que je puisse la référencer à la fois dans mon service Windows et dans mon service "web" (IIS).Contrôleur WebApi utilisant une bibliothèque de classes

Mon idée actuelle utilise les options auto-hébergées incluses dans HttpSelfHostServer. Pour la fin du Web, je voudrais juste créer un site web standard webapi et ajouter des références à ma bibliothèque de classe. Ce que j'ai trouvé est que si j'ai le contrôleur dans le même espace de nom que HttpSelfHostServer cela fonctionne correctement mais dès que le contrôleur est dans une bibliothèque de classes externe le serveur ne peut plus résoudre la route à mon contrôle/action .

Mon code:

service Windows:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceProcess; 
using System.Text; 
using System.Reflection; 
using System.IO; 

using System.Web.Http.SelfHost; 
using System.Web.Http; 
using System.Web.Http.Dispatcher; 

using WebApiClasses; 
using WebApiClasses.Controllers; 

namespace WebAPISelfHost 
{ 
    public partial class Service1 : ServiceBase 
    { 
     private HttpSelfHostServer _server; 
     private readonly HttpSelfHostConfiguration _config; 
     public const string ServiceAddress = "http://localhost:8080"; 

     public Service1() 
     { 
      InitializeComponent(); 

      _config = new HttpSelfHostConfiguration(ServiceAddress); 

      //AssembliesResolver assemblyResolver = new AssembliesResolver(); 
      //_config.Services.Replace(typeof(IAssembliesResolver), assemblyResolver); 

      _config.Routes.MapHttpRoute("DefaultApi", 
       "api/{controller}/{id}", 
       new { id = RouteParameter.Optional }); 

     } 

     protected override void OnStart(string[] args) 
     { 
      _server = new HttpSelfHostServer(_config); 
      _server.OpenAsync(); 
     } 




     protected override void OnStop() 
     { 
      _server.CloseAsync().Wait(); 
      _server.Dispose(); 
     } 
    } 

    //public class TestController : ApiController 
    //{ 
    // public string Get() 
    // { 
    //  return "This is an internal test message."; 
    // } 
    //} 

    class AssembliesResolver : DefaultAssembliesResolver 
    { 
     public override ICollection<Assembly> GetAssemblies() 
     { 
      ICollection<Assembly> baseAssemblies = base.GetAssemblies(); 
      List<Assembly> assemblies = new List<Assembly>(baseAssemblies); 

      // Add whatever additional assemblies you wish 

      var controllersAssembly = Assembly.LoadFrom(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\WebApiClasses.dll"); 
      baseAssemblies.Add(controllersAssembly); 
      return assemblies; 
     } 
    } 
} 

Controller:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.Web.Http; 

namespace WebApiClasses.Controllers 
{ 
    public class TestController : ApiController 
    { 
     public string Get() 
     { 
      return "hello from class library"; 
     } 
    } 
} 

Lorsque je tente de naviguer vers: "http: // localhost: 8080/api /" I get:

Aucune ressource HTTP a été trouvée à l'adresse URI de la requête 'http: // localhost: 8080/api /'. Aucun type correspondant au contrôleur nommé 'Test' n'a été trouvé.

Une suggestion? Je pense que je devrais être capable de faire ça.

+0

Juste pour être clair - vous êtes à la recherche d'héberger votre projet WebAPI aussi bien dans IIS et auto-hébergé dans un service Windows? –

+0

Oui, en principe, héberger dans IIS ou auto-hébergé mais surtout je veux seulement une base de code, c'est-à-dire je ne veux pas avoir un code différent pour les choses hébergées IIS à partir du service Windows hébergé. – TheKingDave

Répondre

0

J'ai finalement trouvé comment faire ce que je devais réarranger mon code en tant que tel:

service Windows:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceProcess; 
using System.Text; 
using System.Reflection; 
using System.IO; 

using System.Threading.Tasks; 
using System.Web.Http; 
using System.Web.Http.Dispatcher; 
using System.Web.Http.SelfHost; 

namespace WebAPISelfHost 
{ 
    public partial class Service1 : ServiceBase 
    { 
     static HttpSelfHostServer CreateHost(string address) 
     { 
      // Create normal config 
      HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(address); 

      // Set our own assembly resolver where we add the assemblies we need 
      AssembliesResolver assemblyResolver = new AssembliesResolver(); 
      config.Services.Replace(typeof(IAssembliesResolver), assemblyResolver); 

      // Add a route 
      config.Routes.MapHttpRoute(
       name: "default", 
       routeTemplate: "api/{controller}/{id}", 
       defaults: new { controller = "Home", id = RouteParameter.Optional }); 

      HttpSelfHostServer server = new HttpSelfHostServer(config); 
      server.OpenAsync().Wait(); 

      return server; 
     } 

     public Service1() 
     { 
      InitializeComponent(); 

     } 

     protected override void OnStart(string[] args) 
     { 
      HttpSelfHostServer server = CreateHost("http://localhost:8080"); 
     } 

     protected override void OnStop() 
     { 
     } 
    } 

    class AssembliesResolver : DefaultAssembliesResolver 
    { 
     public override ICollection<Assembly> GetAssemblies() 
     { 
      ICollection<Assembly> baseAssemblies = base.GetAssemblies(); 
      List<Assembly> assemblies = new List<Assembly>(baseAssemblies); 

      assemblies.Add(Assembly.LoadFrom(@"C:\Users\david.kolosowski\Documents\Visual Studio 2010\Projects\WebAPISelfHost\WebAPISelfHost\bin\Debug\ClassLibrary1.dll")); 

      return assemblies; 
     } 
    } 
} 

Bibliothèque de classes:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.Web.Http; 

namespace ClassLibrary1 
{ 
    public class TestController : ApiController 
    { 
     public string Get() 
     { 
      return "hello from class library2"; 
     } 
    } 
} 

Je pense qu'il où divers problèmes de configuration avec la solution j'ai donc supprimé toute ma référence et ajouté seulement ceux requis pour chaque projet.

Merci à tous ceux qui ont posté des suggestions.

+0

Votre réponse est presque identique à la solution dans l'article que j'ai lié dans ma réponse. L'avez-vous utilisé? – AndyD

+0

Désolé, vous avez oublié de répondre ici. J'avais déjà lu cet article, mais merci quand même. – TheKingDave

0

Pour les futurs lecteurs.

Voici comment utiliser un assembly différent et utiliser IIS.

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     // Web API configuration and services 
     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      //routeTemplate: "api/{controller}/{id}", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 
    } 
} 

et

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 
using System.Web; 
using System.Web.Http.Dispatcher; 

public class MyCustomAssemblyResolver : DefaultAssembliesResolver 
{ 
    public override ICollection<Assembly> GetAssemblies() 
    { 
     ICollection<Assembly> baseAssemblies = base.GetAssemblies(); 
     List<Assembly> assemblies = new List<Assembly>(baseAssemblies); 
     Type myType = typeof(MyControllerInAnotherAssembly); 
     var controllersAssembly = Assembly.GetAssembly(myType); 
     baseAssemblies.Add(controllersAssembly); 
     return assemblies; 
    } 
} 

et (Global.asax)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Http; 
using System.Web.Http.Dispatcher; 
using System.Web.Security; 
using System.Web.SessionState; 


public class Global : System.Web.HttpApplication 
{ 
    protected void Application_Start(object sender, EventArgs e) 
    { 
     WebApiConfig.Register(GlobalConfiguration.Configuration);  
     GlobalConfiguration.Configuration.Services.Replace(typeof(IAssembliesResolver), new MyCustomAssemblyResolver()); 
    } 
} 
Questions connexes