Unity Bootstrapper(Unity.Mvc),Unity 3,MVC 5,EF6接收错误:控制器上的无参数公共构造函数

时间:2014-04-18 03:07:37

标签: c# dependency-injection unity-container asp.net-mvc-5 entity-framework-6

好的,在搜索谷歌,在这里和几个ASP / MVC论坛后,我一定要问我到底在做什么错了。

我对我的应用程序有一个良好的开端,对DI,IoC和使用Repository,Service和UnitOfWork模式的正确理解。当我尝试从Unity加载需要DI的控制器时,就好像Unity没有解析任何已注册的项目,或者我做得不好。从我可以看到的这个版本的所有示例(不是创建随后从Global.asax调用的Bootstrap.cs文件的版本)我正在做其他人没有来自Unity的爱。

我的核心问题是:我是否已根据需要设置/配置Unity以将项目注入控制器构造函数。如果我有,任何想法为什么它不像我见过的例子那样工作?

我不断收到AssetController需要具有无参数公共构造函数的错误。如果我添加一个,那么它在没有DI的情况下使用它,如果我不添加一个,那么它会大喊大叫没有它。

谢谢,下面的代码。

UnityConfig.cs

namespace CARS.web.App_Start
{
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
            // container.LoadConfiguration();

            // TODO: Register your types here
            // container.RegisterType<IProductRepository, ProductRepository>();
            container.RegisterType<IDataContext, CARSDEMOContext>(new PerRequestLifetimeManager())
                .RegisterType<IAssetService, AssetService>()
                .RegisterType<IUnitOfWork, UnitOfWork>()
                .RegisterType<IRepository<Asset>, Repository<Asset>>();
                //.RegisterType<AssetController>(new InjectionConstructor(typeof(IAssetService), typeof(IUnitOfWork)));
        }
    }
}

AssetController.cs (我在做注入参数的构造函数部分)

namespace CARS.web.Controllers
{
    public class AssetController : Controller
    {
        private readonly IAssetService _assetService;
        private readonly IUnitOfWork _unitOfWork;

        public AssetController(IAssetService assetService, IUnitOfWork unitOfWork)
        {
            _assetService = assetService;
            _unitOfWork = unitOfWork;
        }
        //other methods for CRUD etc stripped for brevity
    }
}

IAssetService.cs (第一个参数是assetService)

namespace CARS.service
{
    public interface IAssetService : IService<Asset>
    {
        Task<IEnumerable<Asset>> GetAsync();
        Task<Asset> FindAsync(Guid id);
        Asset Add(Asset asset);
        Asset Update(Asset asset);
        void Remove(Guid id);
    }
}

AssetService.cs (IAssetService交互的具体实现)

namespace CARS.service
{


    public class AssetService : Service<Asset>, IAssetService
    {
        private readonly IRepositoryAsync<Asset> _repository;

        public AssetService(IRepositoryAsync<Asset> repository) : base(repository)
        {
            _repository = repository;
        }

        public Task<IEnumerable<Asset>> GetAsync()
        {
            //return _repository.Query().SelectAsync();
            return _repository.Query().SelectAsync();
        }

        public Task<Asset> FindAsync(Guid id)
        {
            return _repository.FindAsync(id);
        }

        public Asset Add(Asset asset)
        {
            _repository.Insert(asset);
            return asset;
        }

        public Asset Update(Asset asset)
        {
            _repository.Update(asset);
            return asset;
        }

        public void Remove(Guid id)
        {
            _repository.Delete(id);
        }
    }

}

IUnitOfWork.cs (这是来自Long Le的通用UofW和存储库 - http://genericunitofworkandrepositories.codeplex.com/

namespace Repository.Pattern.UnitOfWork
{
    public interface IUnitOfWork : IDisposable
    {
        int SaveChanges();
        Task<int> SaveChangesAsync();
        void Dispose(bool disposing);
        IRepository<TEntity> Repository<TEntity>() where TEntity : IObjectState;
        void BeginTransaction();
        bool Commit();
        void Rollback();
    }
}

UnitOfWork.cs (再次来自Long Le的框架)

namespace Repository.Pattern.Ef6
{
    public class UnitOfWork : IUnitOfWork, IUnitOfWorkAsync
    {
        #region Private Fields

        private readonly IDataContextAsync _dataContext;
        private bool _disposed;
        private ObjectContext _objectContext;
        private Dictionary<string, object> _repositories;
        private DbTransaction _transaction;

        #endregion Private Fields

        #region Constuctor/Dispose

        public UnitOfWork(IDataContextAsync dataContext)
        {
            _dataContext = dataContext;
        }

        public void Dispose()
        {
            if (_objectContext != null && _objectContext.Connection.State == ConnectionState.Open)
                _objectContext.Connection.Close();

            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public virtual void Dispose(bool disposing)
        {
            if (!_disposed && disposing)
                _dataContext.Dispose();
            _disposed = true;
        }

        #endregion Constuctor/Dispose

        public int SaveChanges()
        {
            return _dataContext.SaveChanges();
        }

        public IRepository<TEntity> Repository<TEntity>() where TEntity : IObjectState
        {
            return RepositoryAsync<TEntity>();
        }

        public Task<int> SaveChangesAsync()
        {
            return _dataContext.SaveChangesAsync();
        }

        public Task<int> SaveChangesAsync(CancellationToken cancellationToken)
        {
            return _dataContext.SaveChangesAsync(cancellationToken);
        }

        public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : IObjectState
        {
            if (_repositories == null)
                _repositories = new Dictionary<string, object>();

            var type = typeof (TEntity).Name;

            if (_repositories.ContainsKey(type))
                return (IRepositoryAsync<TEntity>) _repositories[type];

            var repositoryType = typeof (Repository<>);
            _repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof (TEntity)), _dataContext, this));

            return (IRepositoryAsync<TEntity>) _repositories[type];
        }

        #region Unit of Work Transactions

        public void BeginTransaction()
        {
            _objectContext = ((IObjectContextAdapter) _dataContext).ObjectContext;
            if (_objectContext.Connection.State != ConnectionState.Open)
            {
                _objectContext.Connection.Open();
                _transaction = _objectContext.Connection.BeginTransaction();
            }
        }

        public bool Commit()
        {
            _transaction.Commit();
            return true;
        }

        public void Rollback()
        {
            _transaction.Rollback();
            ((DataContext)_dataContext).SyncObjectsStatePostCommit();
        }

        #endregion

        // Uncomment, if rather have IRepositoryAsync<TEntity> IoC vs. Reflection Activation
        //public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : EntityBase
        //{
        //    return ServiceLocator.Current.GetInstance<IRepositoryAsync<TEntity>>();
        //}
    }
} 

已更新,以包含UnityMvcActivator.cs中的SetResolver信息

using System.Linq;
using System.Web.Mvc;
using Microsoft.Practices.Unity.Mvc;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(CARS.web.App_Start.UnityWebActivator), "Start")]

namespace CARS.web.App_Start
{
    /// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
    public static class UnityWebActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start() 
        {
            var container = UnityConfig.GetConfiguredContainer();

            FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
            FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

            DependencyResolver.SetResolver(new UnityDependencyResolver(container));

            // TODO: Uncomment if you want to use PerRequestLifetimeManager
             Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
        }
    }
}

我已阅读/尝试了以下信息/数据,但没有修复它:

The type IUserStore`1 does not have an accessible constructor

How to add MVC 5 authentication to Unity IoC?

Types not resolving with Unity [MVC 5]

我已经准备好必须为Unity编写ControllerFactory才能做到这一点,但是当我发现的所有示例都只是注册了配置并且注入显然发生在控制器上时,这似乎相当有用。和其他需要的课程。

最后是错误:

The following server error was encountered: 
An error occurred when trying to create a controller of type           'CARS.web.Controllers.AssetController'. Make sure that the controller has a parameterless     public constructor.Details are: 
at     System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext    requestContext, Type controllerType) at    System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext,     String controllerName) at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase     httpContext, IController& controller, IControllerFactory& factory) at     System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback     callback, Object state) at     System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionSte    p.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&     completedSynchronously)

由于

3 个答案:

答案 0 :(得分:4)

您需要设置DependencyResolver。我无法看到你提供的示例中的代码。

设置UnityContainer并注册类型后,需要设置 System.Web.MVC.DependencyResolver

 DependencyResolver.SetResolver(new UnityDependencyResolver(container));

答案 1 :(得分:0)

您可能错过了(就像我一样)在UnityConfig.cs中注册异步类型
检查你是否有这个:

container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager())
            .RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
            .RegisterType<IDataContextAsync, SomeDBContext>(new PerRequestLifetimeManager())
            .RegisterType<IDataContext, SomeDBContext>(new PerRequestLifetimeManager())
            .RegisterType<ISomeService, SomeService>(new PerRequestLifetimeManager())
            .RegisterType<IRepositoryAsync<Some>, Repository<Some>>(new PerRequestLifetimeManager());

答案 2 :(得分:0)

1: 取消注释文件UnityMvcActivator这一行:

Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

2: 使用Unity + UnitOfwork +存储库进行基本注册 这必须存在于文件中:UnityConfig

container.RegisterType<IDataContextAsync, KlussendirectContext>(new PerRequestLifetimeManager());
container.RegisterType<IDataContext, KlussendirectContext>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager());

3: 在控制器(api)中使用依赖注入时,应该存在参数less构造函数: e.g。

 public MyNameController() : base(){}

如果遵循这些步骤,它应该可以工作(编辑,插入,删除等)。