添加 Owin 后依赖注入中断,没有为此对象定义无参数构造函数

Dependency Injection broken after adding Owin, no parameterless constructor defined for this object

我的项目中存在依赖注入问题,在实施 Owin 之前它运行良好。在我添加 Owin 并启动后 class 问题开始出现。已经有很多关于这个问题的文档。但是我似乎无法使用任何其他关于此事的帖子来解决它。

涉及的服务确实有一个无参数的构造函数,控制器也有一个,服务保持为空。

我正在使用以下软件包:

每当我浏览到需要依赖注入的控制器时,就会发生以下错误。

 [MissingMethodException: No parameterless constructor defined for this object.]
       System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
       System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +119
       System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +232
       System.Activator.CreateInstance(Type type, Boolean nonPublic) +83
       System.Activator.CreateInstance(Type type) +11
       System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +55

    [InvalidOperationException: An error occurred when trying to create a controller of type '_Servicebus.Controllers.AuthenticationController'. Make sure that the controller has a parameterless public constructor.]
       System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +178
       System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +76
       System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +88
       System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +194
       System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +50
       System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
       System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
       System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155 

我认为这与 Global.asax.cs 和 Startup.cs 有关。

Global.asax.cs:

 using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http;
    using System.Web.Mvc;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Timers;
    using Microsoft.Practices.Unity;
    using BusinessLayer.HourRegistration.Services;
    using BusinessLayer.HourRegistration.Interfaces;
    using DataAccessLayer.HourRegistration.Repositories;
    using DataAccessLayer.HourRegistration.Entities;
    using System.Data.Entity;
    using System.IO;

    namespace Servicebus
    {
        public class WebApiApplication : System.Web.HttpApplication
        {

            Timer timer;
            bool firsttime;
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
                /*firsttime = true;
                timer = new Timer();
                timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                timer.Interval = 20000;
                timer.AutoReset = false;
                timer.Start();*/
            }

            private ICrmUserFilterRepository uService
            {
                get
                {
                    return GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(ICrmUserFilterRepository)) as ICrmUserFilterRepository;
                }
            }

            private IHourRegistrationService hService
            {
                get
                {
                    return GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IHourRegistrationService)) as IHourRegistrationService;
                }
            }

            private void timer_Elapsed(object sender, ElapsedEventArgs e)
            {
                if (firsttime)
                {
                    firsttime = false;
                    timer.Stop();
                    List<CrmUserFilter> tempList = uService.GetAll().ToList();
                    hService.setFourWeeksOldClosed();
                    CrmFetchXml.getCrmFetchXmlInstance.reload24HoursCache(tempList);
                    timer.Interval = GetTimeUntilNextCacheRefresh(2);
                    timer.Start();
                }
                else {
                    timer.Stop();
                    List<CrmUserFilter> tempList = uService.GetAll().ToList();
                    hService.setFourWeeksOldClosed();
                    CrmFetchXml.getCrmFetchXmlInstance.reload24HoursCache(tempList);
                    timer.Interval = GetTimeUntilNextCacheRefresh(2);
                    timer.Start();
                }
            }

            public static double GetTimeUntilNextCacheRefresh(int hour)
            {
                var currentTime = DateTime.Now;
                var desiredTime = new DateTime(DateTime.Now.Year,
                    DateTime.Now.Month, DateTime.Now.Day, hour, 0, 0);
                var timeDifference = (currentTime - desiredTime);
                var timePeriod = currentTime.Hour >= hour ?
                    (desiredTime.AddDays(1) - currentTime) :
                    -timeDifference;
                return Convert.ToInt32(timePeriod.TotalMilliseconds);
            }
        }
    }

Startup.cs:

  using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Practices.Unity;
using Owin;
using System.Security.Claims;
using System.Web.Helpers;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Unity.WebApi;

[assembly: OwinStartup(typeof(Servicebus.App_Start.Startup))]

namespace Servicebus.App_Start
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
        public void ConfigureAuth(IAppBuilder app)
        {
            //unity fix
            HttpConfiguration config = new HttpConfiguration();

            UnityContainer container = WebApiConfig.Register(config);

            // ... Configure you web api routes
            config.DependencyResolver = new UnityDependencyResolver(container);

            app.UseWebApi(config);
            //GlobalConfiguration.Configure(config);
            //app.UseWebApi(GlobalConfiguration.DefaultServer);


            // Enable the application to use a cookie to store information for the signed in user
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Authentication/Login")
            });

            //app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
        }
    }
}

WebApiConfig.cs:

        using System.Web.Http;
        using Microsoft.Practices.Unity;
        using BusinessLayer.HourRegistration.Interfaces;
        using BusinessLayer.HourRegistration.Services;
        using DataAccessLayer.HourRegistration.Repositories;
        using System.Net.Http.Formatting;
        using System.Data.Entity;
        using Unity.WebApi;
        using System.Web.Mvc;
        using Servicebus.Security;
        using System.Diagnostics;
        using BusinessLayer.MTO.Interfaces;
        using DataAccessLayer.MTO.Repositories.InterfaceRepositories;
        using BusinessLayer.MTO.Services;
        using DataAccessLayer.MTO.Repositories;
        using DataAccessLayer.Common.DatabaseFactory;
        using DataAccessLayer.HourRegistration.UnitOfWork;
        using DataAccessLayer.MTO.UnitOfWork;

        namespace Servicebus
        {
            public static class WebApiConfig
            {
                public static UnityContainer Register(HttpConfiguration config)
                {

                    config.EnableCors();

                    UnityContainer container = new UnityContainer();
container.RegisterType<IAuthenticationService, AuthenticationService>();
                    container.RegisterType<IDatabaseFactory, DatabaseFactory>(new PerResolveLifetimeManager());
                    container.RegisterType<IUnitOfWorkHourregistration, UnitOfWorkHourregistration>();
                    container.RegisterType<ICrmProjectRepository, CrmProjectRepository>();
                    container.RegisterType<ICrmOrderRepository, CrmOrderRepository>();
                    container.RegisterType<IHourRegistrationRepository, HourRegistrationRepository>();
                    container.RegisterType<IOverTimeHoursRepository, OverTimeHoursRepository>();
                    container.RegisterType<IWorkhoursRepository, WorkHoursRepository>();
                    container.RegisterType<IRoleRepository, RoleRepository>();
                    container.RegisterType<IUserRepository, UserRepository>();
                    container.RegisterType<IHourRegistrationService, HourRegistrationService>();
                    container.RegisterType<IRoleProviderService, RoleProviderService>();
                    container.RegisterType<ICrmUserFilterRepository, CrmUserFilterRepository>();

                    //for MTO
                    container.RegisterType<IMTOService, MTOService>();
                    container.RegisterType<IUnitOfWorkMTO, UnitOfWorkMTO>();
                    container.RegisterType<IMtoRepository, MtoRepository>();
                    container.RegisterType<IChapterRepository, ChapterRepository>();
                    container.RegisterType<IQuestionRepository, QuestionRepository>();
                    container.RegisterType<IQuestionKindRepository, QuestionKindRepository>();
                    container.RegisterType<IAnswerRepository, AnswerRepository>();
                    container.RegisterType<IDepartmentRepository, DepartmentRepository>();
                    container.RegisterType<IReportRepository, ReportRepository>();
                    container.RegisterType<IActionPointRepository, ActionPointRepository>();
                    container.RegisterType<IUserMtoRepository, UserMtoRepository>();
                    container.RegisterType<IRoleMtoRepository, RoleMtoRepository>();
                    container.RegisterType<IMtoUserResponseRepository, MtoUserResponseRepository>();

                    config.DependencyResolver = new UnityDependencyResolver(container);
                    config.Formatters.JsonFormatter.MediaTypeMappings.Add(new UriPathExtensionMapping("json", "application/json"));

                    config.Formatters.XmlFormatter.MediaTypeMappings.Add(new UriPathExtensionMapping("xml", "application/xml"));


                    // Web API routes
                    config.MapHttpAttributeRoutes();

                    config.Routes.MapHttpRoute(
                        name: "DefaultApi",
                        routeTemplate: "api/{controller}/{id}",
                        defaults: new { id = RouteParameter.Optional }
                    );
                    config.Routes.MapHttpRoute(
                        name: "Api UriPathExtension",
                        routeTemplate: "api/{controller}.{ext}/{id}",
                        defaults: new { id = RouteParameter.Optional }
                    );
                    config.Routes.MapHttpRoute(
                        name: "MtoApi",
                        routeTemplate: "api/{controller}/{id}",
                        defaults: new { controller = "mto", id = RouteParameter.Optional }
                        );
                    return container;
                }
            }
        }

涉及的服务确实有一个无参数的构造函数,控制器也有一个,服务保持为空。

随机[未完成]服务:

using BusinessLayer.Authentication.Interfaces;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLayer.Authentication.Services
{
    public class AuthenticationService : IAuthenticationService
    {

        public AuthenticationService()
        { }

        public bool CheckRedirects(string applicationName, string jsonString)
        {
            JObject jsonObj = JObject.Parse(jsonString);
            ////Exists? --> Search in JSON.
            foreach (KeyValuePair<string, JToken> sub_obj in (JObject)jsonObj["Redirects"])
            {

            }

            return true;
        }
    }
}

AuthenticationController.cs:

using BusinessLayer.Authentication.Interfaces;
using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Mvc;

namespace Servicebus.Controllers
{
    [System.Web.Mvc.AllowAnonymous]
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class AuthenticationController : Controller
    {

        /// <summary>
        /// Service from the business layer to get the right information
        /// </summary>
        public IAuthenticationService aService;
        /// <summary>
        /// Constructor of the hourregistation controller gets the service from the unity container.
        /// </summary>

        public AuthenticationController(IAuthenticationService aService)
        {
            this.aService = aService;
        }

        public ActionResult Login()
        {
            NameValueCollection queryString = Request.QueryString;
            aService.CheckRedirects(queryString["applicationType"], System.IO.File.ReadAllText(Server.MapPath(Url.Content("~/Content/loginRedirects.json"))));


            String state = Guid.NewGuid().ToString();
            String url = this.Url.Action("Callback", "Authentication", null, this.Request.Url.Scheme).ToString();
            return Redirect(removed);
        }

        public ActionResult Callback()
        {
            NameValueCollection queryString = Request.QueryString;
            if (!queryString["code"].Equals(null))
            {
                IdentityStore(queryString["code"], queryString["state"]);
            }

            return null;
        }

        private void IdentityStore(string authToken, string queryString, bool isPersistent = false)
        {
            var claims = new List<Claim>();
            claims.Add(new Claim(ClaimTypes.NameIdentifier, authToken));
            claims.Add(new Claim("state", queryString));

            var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

            AuthenticationManager.SignIn(new AuthenticationProperties()
            {
                AllowRefresh = true,
                IsPersistent = isPersistent,
                ExpiresUtc = DateTime.UtcNow.AddDays(7)
            }, identity);
        }

        private IAuthenticationManager AuthenticationManager
        {
            get
            {
                return HttpContext.GetOwinContext().Authentication;
            }
        }

        public void IdentitySignout()
        {

            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie, DefaultAuthenticationTypes.ExternalCookie);
        }
    }
}

感谢任何帮助。

此致!

基本上,您需要确保所有依赖项都已在 OWIN 启动程序中注册 class,因为全局不会用于 WebApi 管道。

您也可以为依赖容器使用共享容器,这样您就不会初始化两个单独的实例。

快速修复:

namespace Servicebus.App_Start
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            WebApiConfig.Register(new HttpConfiguration());
            ConfigureAuth(app);
        }
    }
}

Unity 附带一个激活器,Provides the bootstrapping for integrating Unity with WebApi when it is hosted in ASP.NET 根据它自己的文档。

这是 nuget:

<package id="Unity.AspNet.WebApi" version="3.5.1405-prerelease" targetFramework="net45" />

我建议你实施那个

重要包裹

<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net45" />

你收到了吗?

最后的想法

我总是觉得做一个只有基础设施位的小项目是个好主意 - 看看你能不能建立一个基本的网站 运行。如果你能做到这一点,那么你应该能够自己调试问题所在。

如果您无法在您的机器上获得一个简单的网站 运行 - 尝试另一台机器 - 如果所有其他方法都失败,那么您有严重的问题。我有很多这类项目,运行 所以应该很简单。

事实证明,使用 Unity 时,常规控制器中的依赖注入不起作用。对控制器进行更改已解决问题。

控制器现在看起来像这样:

        using Microsoft.AspNet.Identity;
        using Microsoft.Owin.Security;
        using Newtonsoft.Json.Linq;
        using System;
        using System.Collections.Generic;
        using System.Collections.Specialized;
        using System.Diagnostics;
        using System.IO;
        using System.Linq;
        using System.Net.Http;
        using System.Security.Claims;
        using System.Threading.Tasks;
        using System.Web;
        using System.Web.Http;
        using System.Web.Http.Cors;
        using System.Web.Mvc;

        namespace Servicebus.Controllers
        {
            [System.Web.Mvc.AllowAnonymous]
            [EnableCors(origins: "*", headers: "*", methods: "*")]
            public class AuthenticationController : Controller
            {

                /// <summary>
                /// Service from the business layer to get the right information
                /// </summary>
                private IAuthenticationService _aService
                {
                    get
                    {
                        return GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IAuthenticationService)) as AuthenticationService;
                    }
                }
                /// <summary>
                /// Constructor of the hourregistation controller gets the service from the unity container.
                /// </summary>
                public AuthenticationController()
                {

                }
//other functions
    }
    }