Внедрение конструктора не работает. NET 4.7.2 Внедрение зависимостей в ASP. NET WebForms - PullRequest
0 голосов
/ 04 августа 2020

Я использовал статью «Использование внедрения зависимостей в приложении WebForms». https://devblogs.microsoft.com/aspnet/use-dependency-injection-in-webforms-application/ Перенацеливание проекта на. NET Framework 4.7.2 в свойствах проекта и в web.config:

    <system.web>
    <httpRuntime targetFramework="4.72" ...

As pNet .WebFormsDependencyInjection.Unity NuGet-пакет установлен. Тип зарегистрирован в Global:

    public class Global : System.Web.HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            var container = this.AddUnity();
            container.RegisterType<IVCRole, eVCRole>();
        }
        ...

Я проверил контейнер, он работает и регистрирует отображение интерфейса IVCRole в класс eVCRole. Default.aspx.cs подвергся рефакторингу:

  public partial class Default : System.Web.UI.Page
  {
    private IVCRole vcr; 
    public Default(IVCRole avcr) 
    { 
      vcr = avcr;
    }   
    protected void Page_Load(object sender, EventArgs e)
    {
    ...

Но когда я запускаю веб-приложение, появляется ошибка «Конструктор типа 'ASP .default_aspx' не найден». Если я добавлю этот конструктор:

  public partial class Default : System.Web.UI.Page
  {
    private IVCRole vcr;
    public Default() {}
    public Default(IVCRole avcr)
    { 
      vcr = avcr;
    }   
    protected void Page_Load(object sender, EventArgs e)
    {
    ...

, конструктор для DI

    public Default(IVCRole avcr) 
    { 
      vcr = avcr;
    }

никогда не вызывается, а «vcr» всегда имеет значение null в Page_Load. Есть статья: «Внедрение зависимостей в ASP. NET Web Forms»: https://makingloops.com/dependency-injection-in-web-forms/, где упоминается эта ошибка: «Иногда вы можете увидеть ошибку сборки с жалобой на отсутствие конструктор без аргументов на странице. Я заметил, что эта ошибка волшебным образом исчезнет go в зависимости от контекста. Кто-то еще предложил использовать инъекцию свойств с атрибутом Dependency на страницах, чтобы обойти это, но я не нашел, что это было необходимо . " Но в моем случае нет "magi c". В Stackoverflow есть аналогичный вопрос: . NET 4.7.2 Внедрение зависимостей в ASP. NET Веб-сайт WebForms - Внедрение конструктора не работает Но в моем случае инъекция свойств не работает:

public partial class Default : System.Web.UI.Page
{
    [Dependency]
    public IVCRole vcr { get; set; }    

    protected void Page_Load(object sender, EventArgs e)
    {
    ...

«vcr» в Page_Load все еще равно нулю. Есть решение, чтобы заставить его работать с пользовательской реализацией поставщика DI, но я уже использую. NET 4.7.2 Unity. Автор отметил, что для веб-приложения не должно быть никаких проблем, так как проблема связана с компилятором веб-сайта. Как заставить конструктор DI или внедрение свойств работать на странице по умолчанию, используя. NET 4.7.2 и Unity?

Это стек:

[MissingMethodException: Constructor on type 'ASP.default_aspx' not found.]
   System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) +1173
   System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +130
   System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) +21
   Microsoft.AspNet.WebFormsDependencyInjection.Unity.ContainerServiceProvider.DefaultCreateInstance(Type type) +17
   Microsoft.AspNet.WebFormsDependencyInjection.Unity.ContainerServiceProvider.GetService(Type serviceType) +161
   __ASP.FastObjectFactory_app_web_mmaneivx.Create_ASP_default_aspx() in c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\vs\19e4d468\8c7800a0\App_Web_mmaneivx.2.cs:0
   System.Web.Compilation.BuildResultCompiledType.CreateInstance() +31
   System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp) +104
   System.Web.UI.PageHandlerFactory.GetHandlerHelper(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) +33
   System.Web.UI.PageHandlerFactory.GetHandler(HttpContext context, String requestType, String virtualPath, String path) +39
   System.Web.MaterializeHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +386
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +50
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +163

1 Ответ

2 голосов
/ 04 августа 2020

Отказ от ответственности: я поддерживаю этот пакет NuGet и проект , которые используют Microsoft.Extensions.DependencyInjection для ASP. NET WebForms (и MVC, SignalR и WCF) в . NET Framework 4.7.2 - однако содержимое этого сообщения c не относится к моей реализации DI для ASP. NET.

  • Проверьте свой .csproj:

    • Убедитесь, что вы настроили таргетинг. NET Framework 4.7.2 или новее (обратите внимание, что многие общие веб-хосты - включая Azure App Services - могут работать под управлением более старых версий. NET Framework):

      <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
      
  • Проверьте свой web.config

    • Убедитесь, что у вас есть <system.web><compilation targetFramework="4.7.2">
    • Убедитесь, что у вас есть <system.web><httpRuntime targetFramework="4.7.2"/>
    • Если у вас <assemblies><clear />, убедитесь, что у вас <add assembly="*"/> после <clear /> или иным образом убедитесь, что вы явно перечисляете все необходимые сборки в элементах <add />.
  • Ваш метод ConfigureServices (или что-либо, что настраивает DI) должен запускаться перед Global.asax s Application_Start!

    • В настоящее время ваш код создает экземпляр контейнера Unity как локального внутреннего Application_Start - это плохая идея ( поскольку вы не сохраняете сильную ссылку в поле - ошибка в другом месте может привести к тому, что G C заберет ваш контейнер DI, что было бы плохо.

    • Вы также необходимо добавить IHttpModule для поддержки контейнеров DI с заданной областью (мой пакет уже делает это за вас).

    • Это делается с помощью атрибута PreApplicationStartMethod (из WebActivatorEx .

      • Обратите внимание, что PreApplicationStartMethod - это не то же самое , что и атрибут [assembly: Microsoft.Owin.OwinStartup() OWIN! Вашему проекту может потребоваться использовать оба варианта, если вы используете DI с SignalR.
      • Код вашего класса Startup должен выглядеть следующим образом:
      [assembly: PreApplicationStartMethod ( typeof( global::MyProject.RssStartup ), methodName: nameof( global::MyProject.MyStartup.OnPreStart ) )]
      
      namespace MyProject
      {
          internal static class MyStartup
          {
              internal static void OnPreStart()
              {
                  // Set-up your DI system here and then call your `ConfigureServices` method before this method returns.
              }
          }
      }
      
...