WebApi控制器使用类库

时间:2012-12-18 17:44:17

标签: c# windows-services asp.net-web-api

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

我目前的想法是使用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:// localhost:8080 / api /”我得到:

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

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

5 个答案:

答案 0 :(得分:10)

查看这篇文章http://www.strathweb.com/2012/06/using-controllers-from-an-external-assembly-in-asp-net-web-api/

在其中,他们描述了如何加载带有控制器的额外组件。

答案 1 :(得分:2)

对于自托管方案,提供其他解决方案建议的自定义IAssembliesResolver实现,并通过使用控制器程序集中的类型或其文件路径将所需的程序集添加到集合中。

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

        //Load by a type in the assembly
        var _serviceAssembly = Assembly.GetAssembly(typeof(CarsController));

        //Load from a file
        //var _serviceAssembly = Assembly.LoadFrom("abc.dll");

        //Check if the assembly is already in the list
        //if you are getting the assembly reference by a type in it,
        //The assembly will probably be in the list
        if (!assemblies.Contains(_serviceAssembly))
            assemblies.Add(_serviceAssembly);

        return assemblies;
    }

然后在控制台应用程序的Main方法或服务类的OnStart方法中,替换程序集解析程序服务。

var config = new HttpSelfHostConfiguration("http://localhost:3000");
config.Services.Replace(typeof(IAssembliesResolver), new AssembliesResolver());
config.Routes.MapHttpRoute("default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
var server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();

答案 2 :(得分: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";
        }
    }
}

我认为解决方案存在各种配置问题,所以我删除了所有参考资料,只添加了每个项目所需的参考资料。

感谢所有发布建议的人。

答案 3 :(得分: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;
    }
}

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

答案 4 :(得分:0)

我有一个类似的问题,我执行以下操作并解决了。

  1. 首先在api项目中添加来自外部类库的引用。
  2. 控制器必须继承自ApiController
  3. 控制器类必须具有public acess修饰符,并且控制器名称必须以Controller结尾。例如TestController ,EmployeeController
  4. 非常重要的nuget软件包必须具有相同的版本。

我也建议使用[HttpGet],[HttpPost]

之类的属性