2012-12-18 173 views
11

我正在尝试创建一个允许我通过Web应用程序或通过Windows服务托管“WebAPI”网站的系统。为此,我希望所有的buisness逻辑都包含在一个类库中,以便我可以在Windows服务和我的“web”(IIS)服务中引用它。使用类库的WebApi控制器

我目前的想法是使用HttpSelfHostServer中包含的自托管选项。对于Web端,我只需创建一个标准的webapi网站,并添加一些对我的类库的引用。

什么我发现是,如果我在相同的命名空间HttpSelfHostServer它工作正常,但只要控制器是一个外部类库中的服务器不再能够解决我的控制路径/动作控制器。

我的代码:

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

控制器:

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"; 
     } 
    } 
} 

当我尝试导航到: “HTTP://本地主机:8080/API /” 我得到:

没有找到HTTP资源匹配请求URI'http:// localhost:8080/api /'。 未找到与名为“Test”的控制器匹配的类型。

有什么建议吗?我想我应该可以做到这一点。

+0

只要是明确的 - 你打算同时托管在IIS和Windows服务自托管你的WebAPI项目? –

+0

是基本,主机在IIS或自托管的,但更重要的是我只想要一个代码库,即我不想要有不同的代码为IIS托管的东西从窗口服务承载的东西。 – TheKingDave

回答

0

我终于找到了如何做到这一点,我不得不重新安排我的代码,例如:

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

类库:

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"; 
     } 
    } 
} 

我想有在那里解决了各种配置问题,所以我删除了所有的参考资料,并只添加了每个项目所需的资源。

感谢所有发布建议的人。

+0

您的回答与我在答案中链接的文章中的解决方案几乎完全相同。你使用它了吗? – AndyD

+0

很抱歉,在这里回复。我已经阅读过这篇文章,不过谢谢。 – TheKingDave

0

对于未来的读者。

以下是(单向)如何使用不同的程序集并使用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 } 
     ); 
    } 
} 

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

和(全球。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()); 
    } 
}