Ошибка MVC MEF: убедитесь, что контроллер имеет открытый конструктор без параметров - PullRequest
0 голосов
/ 01 апреля 2019

Для приложения MVC, использующего MEF, иногда я получаю erorr ""

У меня есть решение .NET с

  1. Один проект веб-приложения MVC и,
  2. Многие проекты библиотек классов, которые занимаются аутентификацией, получением конфигураций, выполнением внешних вызовов API и т. Д.

Я настроил MEF, как показано ниже, с помощью кода и развернул его на веб-сервере с использованием IIS. Наблюдал ошибку ниже пару раз, после чего я пытался загрузить страницу несколько раз, но она по-прежнему выдает ту же ошибку.

После обновления пула приложений исчезает только ошибка. Я изо всех сил пытался отладить и понять ошибку, но безуспешно. Я неправильно настраиваю MEF где-нибудь?

enter image description here

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

IHttpHandlers, используемые в проекте MVC:

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


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


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

  }

1 Ответ

1 голос
/ 01 апреля 2019

Эта ошибка указывает, что существует по крайней мере один контроллер, что его параметры конструктора не разрешены.
Каждый контроллер нуждается в конструкторе, который должен быть разрешен во время выполнения.По умолчанию каждый класс c # имеет конструктор по умолчанию (без параметров), который можно вызывать, когда требуется создать экземпляр класса.
Однако после определения явного конструктора вы теряете конструктор по умолчанию, поэтому вынеобходимо убедиться, что все ваши контроллеры имеют либо конструктор без параметров, либо, если вместо этого у них есть параметрический конструктор, параметры должны быть зарегистрированы посредством внедрения зависимостей.

...