web-dev-qa-db-fra.com

Simple Injector - Assurez-vous que le contrôleur a un constructeur public sans paramètre en production

Je suis coincé avec une situation étrange. Je suis Onion Architecture et mon architecture ressemble à ceci:

1-Core
     - Domain Classes
     - Repository Interfaces
     - Service Interfaces
2-Infrastructure
     - Data
     - Dependency Injection // Here I am using Simple Injector as dependency injection
     - Repository Interfaces Implementation
     - Service Interfaces Implementation
3-WebApi
     - Web Api Project
4-WebClient
     - My AngularJs App
5-Test
     - Test Project

Injection de dépendance:

[Assembly: PreApplicationStartMethod(typeof(IocConfig), "RegisterDependencies")]
namespace Infrastructure.DependencyResolution
{
    public class IocConfig
    {
        public static void RegisterDependencies()
        {
            var container = new Container();

            container.RegisterWebApiRequest<IRepositoryAsync<Category>, Repository<Category>>();
            container.RegisterWebApiRequest<ICategoryService, CategoryService>();
            container.RegisterWebApiRequest<IDataContextAsync>(() => new MyContext());
            container.Verify();
            GlobalConfiguration.Configuration.DependencyResolver =
            new SimpleInjectorWebApiDependencyResolver(container);

        }
    }
}

Projet Web Api:

public class HomeController : ApiController
{
    private readonly ICategoryService _categoryService;
    public HomeController(ICategoryService categoryService)
    {
        _categoryService = categoryService;
    }
}

Tout fonctionne très bien sur mon local IIS. Mais maintenant, j'ai publié cette application sur le serveur de production et maintenant, il me donne l'erreur ci-dessous:

{"message": "Une erreur est survenue.", "exceptionMessage": "Une erreur s'est produite lors de la tentative de création d'un contrôleur de type 'HomeController'. Assurez-vous que le contrôleur a public, sans paramètre, constructeur . "," exceptionType ":" System.InvalidOperationException "," stackTrace ":" à System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, tapez controllerType)\r\n à System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (HttpRequestMessage request)\r\n à System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext () "," innerException ": {" message ":" Une erreur s'est produite. "," exceptionMessage " : "Le type 'JetAdz.WebApi.Controllers.HomeController' n'a pas de constructeur Par défaut", "exceptionType": "System.ArgumentException", "stackTrace": " à System.Linq.Expressions.Expression.New (Type)\r\n à System.Web.Http.Internal.TypeActivator.Create [TBase] (Tapez InstanceType)\r\n à System.Web .Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator (HttpRequestMessage] ____.] demande, HttpControllerDescriptor controllerDescriptor, tapez controllerType) "}}

5
Usman Khalid

S'il vous plaît jetez un oeil à l'exception interne de l'exception levée. Il contient les détails décrivant pourquoi cela se produit.

Il y a de multiples problèmes ici. Vous devez vous assurer que enregistrez tous vos types de racine explicitement dans le conteneur. Les contrôleurs sont des types racine, car ils sont résolus directement (rien ne dépend d'eux, mais ils ont des dépendances). Si vous ne les enregistrez pas explicitement, le conteneur ne peut pas vérifier s'ils peuvent être créés lorsque vous appelez Verify(). Vous pouvez enregistrer vos contrôleurs en appelant le numéro suivant:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

Ceci est décrit dans la documentation .

Après cela, vous voyez probablement directement que la méthode Verify() échoue lorsque vous démarrez l’application. Dans ce cas, vous recevez un message très détaillé expliquant ce qui ne va pas.

Dans l'exception interne, vous pouvez voir que la méthode DefaultHttpControllerActivator.GetInstanceOrActivator de l'API Web appelle TypeActivator.Create<T>(Type). Cela se produit uniquement lorsque l'appel à request.GetDependencyScope().GetService(controllerType) renvoie null. Mais il s’agit généralement de quelque chose qui ne peut pas arriver si vous avez branché la variable SimpleInjectorWebApiDependencyResolver au pipeline API Web. Cela est dû au fait que SimpleInjectorWebApiDependencyResolver ne retournera jamais null lorsqu'il est invité à résoudre une implémentation IHttpController. Au lieu de cela, il lève une exception lorsqu'un contrôleur ne peut pas être résolu.

Donc, ceci est pour moi une indication d'un problème de redirection de liaison dans votre application. Cela signifie que SimpleInjector.Integration.WebApi.dll fait référence à une version IHttpController différente de celle utilisée par votre application. Les redirections de liaisons ont pour but de résoudre ce problème. Assurez-vous donc que votre application dispose de la liaison correcte. Pour System.Web.Http.dll cela ressemble à ceci (mais notez que vous aurez peut-être aussi besoin d'autres liaisons):

<runtime>
  <assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
    ... 
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" 
          culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

En règle générale, les liaisons sont gérées par le gestionnaire de paquets NuGet, mais ce dernier ne le fait pas régulièrement.

Lorsque le problème de redirection de liaison est résolu, vous remarquerez que l'exception interne contient des informations provenant de Simple Injector avec les mêmes informations que lorsque vous appelez Verify().

9
Steven

Vous n'enregistrez pas le DependencyResolver correct pour WebApi. Selon la page WebApi Dependency Injection et la page Simple Injector WebApi , cela est supposé se faire comme ceci.

public static void Register(HttpConfiguration config)
{
    var container = new Container();

    container.RegisterWebApiRequest<IRepositoryAsync<Category>, Repository<Category>>();
    container.RegisterWebApiRequest<ICategoryService, CategoryService>();
    container.RegisterWebApiRequest<IDataContextAsync>(() => new MyContext());
    container.Verify();

    config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

    // Other Web API configuration not shown.
}

La configuration que vous avez indiquée concerne l'injection de dépendance MVC (dont vous pourriez également avoir besoin).

7
NightOwl888

J'utilise des fichiers XML spring pour injecter des variables dans mes classes. Dans mon cas, c’était un bug de copier/coller lorsque j’ai créé un nouveau contrôleur.

Ainsi, bien que cela ne soit pas exactement lié au problème OP, il reçoit le même message d'erreur et mon aide, quelqu'un d'autre.

J'avais copié (les crochets changés en crochets):

[object id="className" type="Project.ClassName" scope="request"]
    [constructor-arg name="OtherClassName" ref="otherclassName"/]
[/object]

quand j'avais besoin de:

[object id="className" type="Project.ClassName" scope="request"]
    [property name="OtherClassName" ref="otherclassName"/]
[/object]

Noter la propriété au lieu de constructeur-arg.

Parce que ma classe n'avait pas de constructeur à la recherche d'un paramètre.

0
isopropanol