【问题标题】:MVC MEF Error: Make sure that the controller has a parameterless public constructorMVC MEF 错误:确保控制器具有无参数的公共构造函数
【发布时间】:2019-04-01 06:43:27
【问题描述】:

对于使用 MEF 的 MVC 应用程序,有时我会收到错误“”

我有一个带有 .NET 的解决方案

  1. 一个 MVC Web 应用程序项目和,
  2. 许多类库项目负责身份验证、获取配置、进行外部 API 调用等。

我已通过代码如下所示配置了 MEF,并使用 IIS 将其部署在 Web 服务器上。多次观察到以下错误,之后我尝试多次加载页面,但仍然抛出相同的错误。

刷新应用程序池后,只有错误消失了。我一直在努力调试和理解错误,但没有成功。我是否在任何地方错误配置了 MEF?

全球.asax:

public class Global : HttpApplication
  {
    void Application_Start(object sender, EventArgs e)
    {
      AreaRegistration.RegisterAllAreas();
      GlobalConfiguration.Configure(WebApiConfig.Register);
      RouteConfig.RegisterRoutes(RouteTable.Routes);

      var pluginFolders = LoadMefComponents();
      Bootstrapper.Compose(pluginFolders);
      IControllerFactory mefControllerFactory = new MefControllerFactory(Bootstrapper.Container);
      ControllerBuilder.Current.SetControllerFactory(mefControllerFactory);
    }

    protected List<string> LoadMefComponents()
    {
      var pluginFolders = new List<string>();
      string ModulesPath = CommonUtility.GetApplicationDirectory();
      var plugins = Directory.GetDirectories(ModulesPath).ToList();
      plugins.ForEach(path =>
      {
        var directoryInfo = new DirectoryInfo(path);
        pluginFolders.Add(directoryInfo.Name);
      });
      return pluginFolders;
    }
  }

MEFControllerFactory.cs:此文件位于 App_Start 中

public class MefControllerFactory : DefaultControllerFactory
    {
        private readonly CompositionContainer _container;
        private readonly Dictionary<IController, Lazy<object, object>> exports;
        private readonly object syncRoot;

        public MefControllerFactory(CompositionContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }

            this._container = container;
            this.exports = new Dictionary<IController, Lazy<object, object>>();
            this.syncRoot = new object();

        }

        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            Lazy<object, object> export = _container.GetExports(controllerType, null, null).FirstOrDefault();

            var controller = null == export ? base.GetControllerInstance(requestContext, controllerType)
                                : (IController)export.Value;
            lock (this.syncRoot)
            {
                this.exports.Add(controller, export);
            }
            return controller;
        }

        public override void ReleaseController(IController controller)
        {
            lock (this.syncRoot)
            {
                var export = this.exports[controller];
                this.exports.Remove(controller);
               // this._container.ReleaseExport(export);
            }
            ((IDisposable)controller).Dispose();
        }
    }

Bootstrapper.cs:此文件位于 App_Start 中

public class Bootstrapper
    {
        private static CompositionContainer compositionContainer;
        private static bool IsLoaded = false;

        public static CompositionContainer Container
        {
            get { return compositionContainer; }
            set { compositionContainer = value; }
        }

        public static void Compose(List<string> pluginFolders)
        {
            if (IsLoaded) return;
            var catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            catalog.Catalogs.Add(new DirectoryCatalog(CommonUtility.GetApplicationDirectory()));
            compositionContainer = new CompositionContainer(catalog);
            compositionContainer.ComposeParts();
            IsLoaded = true;
        }

        public static T GetInstance<T>(string contractName = null)
        {
            var type = default(T);
            if (compositionContainer == null) return type;
            if (!string.IsNullOrWhiteSpace(contractName))
                type = compositionContainer.GetExportedValue<T>(contractName);
            else
                type = compositionContainer.GetExportedValue<T>();
            return type;
        }
    }

CommonUtility.cs:此文件位于 App_Start 中

public class CommonUtility
    {

        public static string GetApplicationDirectory()
        {
            string codeBase = Assembly.GetExecutingAssembly().CodeBase;
            UriBuilder uri = new UriBuilder(codeBase);
            string path = Uri.UnescapeDataString(uri.Path);
            return Path.GetDirectoryName(path);

        }
    }

HomeController.cs:

[CommonExceptionFilter]
  public class HomeController : Controller
  {
    private IConfigurationManager _configurationManager;

    [ImportingConstructor]
    public HomeController()
    {
      _configurationManager = Bootstrapper.GetInstance<IConfigurationManager>();
    }

    public async Task<ActionResult> Index()
    {
      //Business Logic
      return View()

    }
  }

IConfigurationManager.cs

[InheritedExport]
    public interface IConfigurationManager
    {
        string GetConfigurationValue(string keyName)
    }

ConfigurationManager.cs

[PartCreationPolicy(CreationPolicy.Shared)]
    public class ConfigurationManager: IConfigurationManager
    {
        [ImportingConstructor]
        public ConfigurationManager()
        {

        }

        public string GetConfigurationValue(string keyName)
        {
            return "";
        }
    }

MVC项目中使用的IHttpHandlers:

public class CommonServiceHandler : HttpTaskAsyncHandler, IRequiresSessionState
  {
    private ICommonServiceHandlerManager _commonServiceHandlerManager;


    public CommonServiceHandler()
    {
      _commonServiceHandlerManager = Bootstrapper.GetInstance<ICommonServiceHandlerManager>();
    }


    public override bool IsReusable
    {
      get
      {
        return false;
      }
    }

  }

【问题讨论】:

    标签: c# model-view-controller mef


    【解决方案1】:

    此错误表明至少存在一个控制器,其构造函数参数未解析。
    每个控制器都需要在运行时解析一个构造函数。默认情况下,每个 c# 类都有一个默认(无参数)构造函数,当需要创建该类的实例时可以调用该构造函数。
    但是,在定义显式构造函数后,您将丢失默认构造函数,因此,您需要确保所有控制器都具有无参数构造函数,或者如果它们具有参数构造函数,则需要通过依赖注入注册参数。

    【讨论】:

    • 我检查过,但所有控制器都定义了一个参数构造函数。 MVC 应用程序中有一个 WebAPI 控制器,它没有参数构造函数。这会导致问题吗?这个问题很少发生,不是很频繁。如果这是因为 WebAPI 控制器,那么它不应该总是发生。另外,我刚刚检查了我没有在 Controller 类上方添加[Export] [PartCreationPolicy(CreationPolicy.NonShared)]。这会导致问题吗?
    • 不,它不会始终如一地发生,只有当您尝试从该特定控制器调用方法时才会发生。您可以通过检查导致此问题的方法来找到控制器。
    • 我再次验证,但所有控制器都有参数构造函数。不知道出了什么问题。显示实现后,是否需要在 Controller 类上方添加 [Export] [PartCreationPolicy(CreationPolicy.NonShared)]?我在每个参数构造函数中调用 Bootstrapper.GetInstance。
    • 所有构造函数中的所有参数都注册(注入)了吗?
    • 据我所知,export 属性不是必需的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 2018-03-21
    • 1970-01-01
    • 2014-08-03
    相关资源
    最近更新 更多