请确保控制器具有无参数的公共构造函数

2020-09-24  乐帮网

owin c#

使用了WebApi2和MVC5混合的项目,使用到了Microsoft.Owin 和Autofac ,着同时兼容MVC和WebApi,在写完代码后发现MVC控制器可以正常拿到Autofac的映射,但是WebApi的控制中报错:请确保控制器具有无参数的公共构造函数 An error occurred when trying to create a controller of type 'xxxController'. Make sure that the controller has a parameterless public constructor.",多方查找原因均无功而返,一个偶然的机会让我找到了原因。

1、使用VS新建一个Web项目 ,勾选MVC和WebApi的模板。

如图

2、使用Nuget添加Owin等依赖包 同时也添加WebApi的Owin依赖包。

Install-Package Microsoft.Owin
Install-Package Microsoft.Owin.Host.SystemWeb
Install-Package Microsoft.AspNet.WebApi.Owin

3、添加Autofac的依赖包,主要包含如下

Install-Package Autofac.Mvc5
Install-Package Autofac.Mvc5.Owin
Install-Package Autofac.WebApi2
Install-Package Autofac.WebApi2.Owin

4、添加IOC注册和相关类。

4.1、映射数据库操作类

public interface ITestRepository
 {
        string Method1();
 }

  public class TestRepository : ITestRepository
    {
        public string Method1()
        {
            return "Method1 Value";
        }
    }

4.2、建立Startup 类如下:

[assembly: OwinStartup(typeof(OwinAutofac.Demo.Startup))]
namespace OwinAutofac.Demo
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // For more information on how to confffigure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
            AreaRegistration.RegisterAllAreas();
            //GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            var assembly = Assembly.GetExecutingAssembly();
            var builder = new ContainerBuilder();

            builder.RegisterApiControllers(assembly);
            builder.RegisterControllers(assembly);
            builder.RegisterFilterProvider();

            // 注册单个实例
            //builder.RegisterInstance(new NLogger()).As<ILogger>();

            // 扫描assembly中的组件(类名以Repository结尾)
            builder.RegisterAssemblyTypes(assembly)
                   .Where(t => t.Name.EndsWith("Repository"))
                   .AsImplementedInterfaces();

            IContainer container = builder.Build();
            var webApiResolver = new AutofacWebApiDependencyResolver(container);
            GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            HttpConfiguration config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            app.UseWebApi(config);
        }

    }
}

4.3、修改HomeController 添加构造函数如下:

public class HomeController : Controller
    {
        public ITestRepository _testRepository;
        public HomeController(ITestRepository testRepository)
        {
            _testRepository = testRepository;
        }
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }
        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }

4.4、添加apiContoller如下:

 public class TestController : ApiController
    {
        public ITestRepository _testRepository;
        public TestController(ITestRepository testRepository)
        {
            _testRepository = testRepository;
        }

        // GET: api/Test
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

    }

4.5、去掉Global.asax中的逻辑如下

 public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            //AreaRegistration.RegisterAllAreas();
            //GlobalConfiguration.Configure(WebApiConfig.Register);
            //FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            //RouteConfig.RegisterRoutes(RouteTable.Routes);
            //BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

5、此进访问HomeController 发现首页能正常打开,一切都正常。再访问我们写的TestApi
发现autofac没有正常工作报以下的错误:

An error has occurred
An error occurred when trying to create a controller of type 'TestController'. Make sure that the controller has a parameterless public constructor.
类型“OwinAutofac.Demo.Controllers.api.TestController”没有默认构造函数

6、解决办法引起这个问题的排查如下:

6.1 排查Autofac写的注册是不是确定注册过构造函数中引用的类。比如我上面写的ITestRepository 和主项目都是在一起,如果映射的类不在一个项目中,那你的这部分需要改动

builder.RegisterAssemblyTypes(assembly)
                   .Where(t => t.Name.EndsWith("Repository"))
                   .AsImplementedInterfaces();

assembly 至少是丢了一部分,需要修改一下。具体怎么修改需要自行决定。

6.2 WebApi的注册IOC容器和MVC的不一样,需要分别替换,看一下漏了下面这一段不。

// Set MVC DI resolver to use our Autofac container
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

// Set the dependency resolver for Web API.
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;

6.3 以上两点能排除很多问题,网上都是以上两个回答,但是最基本和最简单的一种情况还没有说。~_~ ,我写的例子一点儿也没有漏,还是不能正常工作。下面这段是我的终级解决方案。
如果有表述不对的地方欢迎指正。
我的终极解决方案请点击捐赠按钮或者直接去下载我的代码Demo。

WebApi2 Owin Autofac Demo

 

 

公众号二维码

关注我的微信公众号
在公众号里留言交流
投稿邮箱:1052839972@qq.com

庭院深深深几许?杨柳堆烟,帘幕无重数。
玉勒雕鞍游冶处,楼高不见章台路。
雨横风狂三月暮。门掩黄昏,无计留春住。
泪眼问花花不语,乱红飞过秋千去。

欧阳修

付款二维码

如果感觉对您有帮助
欢迎向作者提供捐赠
这将是创作的最大动力