C# 使用类库的 WebApi 控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13938551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:08:34  来源:igfitidea点击:

WebApi controller using a class library

c#windows-servicesasp.net-web-api

提问by TheKingDave

I'm trying to create a system that will allow me to host a "WebAPI" website either through a web application or through a windows service. To this end I want all my buisness logic to be contained within one class library so that I can reference this in both my windows service and my "web" (IIS) service.

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

My current idea is using the self hosted options included in HttpSelfHostServer. For the web end I would just create a standard webapi website and add some reference to my class library.

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

What I have found is that if I have the controller in the same namespace as the HttpSelfHostServer it works correctly but as soon as the controller is within an external class library the server can no longer resolve the route to my control / action.

我发现,如果控制器与 HttpSelfHostServer 位于相同的命名空间中,它可以正常工作,但是一旦控制器位于外部类库中,服务器就无法再解析到我的控件/操作的路由。

My code:

我的代码:

Windows service:

视窗服务:

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

When I try to navigate to: "http://localhost:8080/api/" I get:

当我尝试导航到:“http://localhost:8080/api/”时,我得到:

No HTTP resource was found that matches the request URI 'http://localhost:8080/api/'. No type was found that matches the controller named 'Test'.

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

Any suggestions? I think I should be able to do this.

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

回答by AndyD

Have a look at this article http://www.strathweb.com/2012/06/using-controllers-from-an-external-assembly-in-asp-net-web-api/

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

In it they describe how to load in extra assemblies with controllers in them.

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

回答by TheKingDave

I eventually found out how to do this I had to re-arrange my code as such:

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

Windows Service:

视窗服务:

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

Class library:

类库:

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

I think there where various configuration problems with the solution so I deleted all my reference and added only the ones required for each project.

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

Thanks to all who posted suggestions.

感谢所有发布建议的人。

回答by granadaCoder

For future readers.

对于未来的读者。

Here is (one way) how you use a different assembly and use IIS.

这是(一种方式)您如何使用不同的程序集和使用 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 }
        );
    }
}

and

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

and (Global.asax)

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

回答by NthDeveloper

For self hosting scenario provide a custom IAssembliesResolver implementation as other solutions suggest and add the required assemblies to the collection either by using a type in the controller's assembly or by its file path.

对于自托管方案,请按照其他解决方案的建议提供自定义 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;
    }

Then in a console application's Main method or in a service class's OnStart method, replace the assembly resolver service.

然后在控制台应用程序的 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();

回答by dimath

I have a similar problem and i do the following actions and i solve it.

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

  1. First of all add the reference from the external class library in the api project.
  2. The controller must inherit from ApiController
  3. The controller class must have public acess modifier and must the controller name to end with Controller.For example TestController ,EmployeeControlleretc
  4. And the very important the nuget packages must have the same version.
  1. 首先在api工程中添加来自外部类库的引用。
  2. 控制器必须继承自 ApiController
  3. 控制器类必须具有公共访问修饰符,并且控制器名称必须以 Controller 结尾。例如TestController ,EmployeeController
  4. 非常重要的 nuget 包必须具有相同的版本。

I also sugget the using of attributes like [HttpGet],[HttpPost]

我还建议使用 [HttpGet]、[HttpPost] 等属性