【问题标题】:Controller does not have a default constructor 500 internal server error控制器没有默认构造函数 500 内部服务器错误
【发布时间】:2015-10-17 00:24:07
【问题描述】:

这是我的控制器

 public class SuggestionController : ApiController
{
    public ISuggestionRepository Repository { get; private set; }

    public SuggestionController(ISuggestionRepository repository)
    {
        this.Repository = repository;
    }

    // to post suggestion
    [HttpPost]
    [ActionName("PostSuggestion")]
    public HttpResponseMessage PostSuggestion(Suggestion suggestion)
    {
        var answerCorrect = this.Repository.CreateSuggestion(suggestion);

        if (answerCorrect == true)
            return Request.CreateResponse(HttpStatusCode.OK);
        else
            return Request.CreateResponse(HttpStatusCode.Conflict);
    }
}

这是我在 NinjectWebCommon.cs 中的 RegisterServices 方法

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ICompetitionRepository>().To(typeof(CompetitionRepository))
            .WithConstructorArgument("serviceContext", new InMemoryDataContext<Competition>());

        kernel.Bind<ISubmissionRepository>().To(typeof(SubmissionRepository))
            .WithConstructorArgument("serviceContext", new InMemoryDataContext<Submission>());

        kernel.Bind<IUserRepository>().To(typeof(UserRepository))
            .WithConstructorArgument("serviceContext", new InMemoryDataContext<User>());

        kernel.Bind<ISuggestionRepository>().To(typeof(SuggestionRepository))
           .WithConstructorArgument("serviceContext", new InMemoryDataContext<Suggestion>());
    } 

但是我得到一个例外,我的建议控制器没有默认构造函数,并且当我从客户端应用程序访问控制器时它显示 500 内部服务器

我知道如果 ninject 依赖项不能正常工作,我们会得到控制器没有默认构造函数的异常,但下面是我实现的另一个控制器,类似于建议控制器,它工作得非常好。

 public IUserRepository Repository { get; private set; }

    public SSOController(IUserRepository repository)
    {
        this.Repository = repository;
    }

    [HttpPost]
    [ActionName("PostUser")]
    public HttpResponseMessage PostUser([FromBody]string id)
    {
        var accessToken = id;
        var client = new FacebookClient(accessToken);
        dynamic result = client.Get("me", new { fields = "name,email" });
        string name = result.name;
        string email = result.email;


        var existingUser = this.Repository.FindByUserIdentity(name);

        if (existingUser == null)
        {
            var newUser = new User
            {
                Username = name,
                Email = email,

            };

            var success = this.Repository.CreateAccount(newUser);

            if (!success)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError);
            }

            //return created status code as we created the user
            return Request.CreateResponse<User>(HttpStatusCode.Created, newUser);
        }

        return Request.CreateResponse(HttpStatusCode.OK);

    }

}

我不知道哪里出错了。如果您有任何建议,请告诉我。

编辑:

我的 Global.asax

 public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        AuthConfig.RegisterAuth();

        GlobalConfiguration.Configuration.IncludeErrorDetailPolicy =
IncludeErrorDetailPolicy.Always;

    }

依赖解析器正在使用

 // Provides a Ninject implementation of IDependencyScope
// which resolves services using the Ninject container.
public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;

    public NinjectDependencyScope(IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }

    public object GetService(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return resolver.TryGet(serviceType);
    }

    public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");

        return resolver.GetAll(serviceType);
    }

    public void Dispose()
    {
        IDisposable disposable = resolver as IDisposable;
        if (disposable != null)
            disposable.Dispose();

        resolver = null;
    }
}

// This class is the resolver, but it is also the global scope
// so we derive from NinjectScope.
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
    IKernel kernel;

    public NinjectDependencyResolver(IKernel kernel)
        : base(kernel)
    {
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope()
    {
        return new NinjectDependencyScope(kernel.BeginBlock());
    }
}

并在 NinjectWebCommon 的 CreateKernel() 方法中调用它

 private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);

        // Install our Ninject-based IDependencyResolver into the Web API config
        GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

        return kernel;
    }

建议库

 public class SuggestionRepository : Repository<Suggestion>, ISuggestionRepository
{
    public SuggestionRepository(IServiceContext<Suggestion> servicecontext)
        : base(servicecontext)
    { }

    public bool CreateSuggestion(Suggestion suggestion)
    {
        this.ServiceContext.Create(suggestion);
        this.ServiceContext.Save();

        return true;
    }
}

ISuggestionRepository

public interface ISuggestionRepository
{
    bool CreateSuggestion(Suggestion suggestion);

}

存储库

public abstract class Repository<T>
{
    public IServiceContext<T> ServiceContext { get; private set; }

    public Repository(IServiceContext<T> serviceContext)
    {
        this.ServiceContext = serviceContext;
    }
}

IserviceContext

 public interface IServiceContext<T>
{
    IQueryable<T> QueryableEntities { get; }

    void Create(T entity);

    void Update(T entity);

    void Delete(T entity);

    void Save();
}

【问题讨论】:

  • 你能把你的 global.asax 也粘贴一下吗?
  • @Kristof - global.asax 中的任何内容都不会影响这一点
  • 这是注册 DI 容器的常见错误。查看DependencyResolver 以及如何将容器注册为依赖解析器。
  • 我可以想象至少有几种方法可以在 OnBeginRequest 中触发此行为。关键是粘贴的所有内容对我来说都很好,所以我猜测错误出现在其他文件中的 1 个中;)
  • 您可以为您的IServiceContext&lt;&gt; 参数绑定到泛型,您可以这样做:kernel.Bind(typeof(IServiceContext&lt;&gt;)).To(typeof(InMemoryDataContext&lt;&gt;)),这摆脱了令人讨厌的 WithConstructorArgument 语法,并让您使用泛型 .To&lt;&gt;()

标签: c# asp.net-web-api ninject


【解决方案1】:

由于您使用的是 WebApi,因此您需要为 Ninject 使用 WebApi 扩展。不幸的是,当前的 Ninject.WebApi nuget 包已经过时,并且不能与已发布的 WebApi 版本一起使用。

在 Remo 开始将 Ninject.WebApi 更新到发布版本之前,您可以暂时使用 Ninject.WebApi-RC http://nuget.org/packages/Ninject.Web.WebApi-RC

http://www.eyecatch.no/blog/2012/06/using-ninject-with-webapi-rc/

编辑:

回顾 cmets 中讨论的信息,以下是建议:

1) 如上所述使用 Ninject.MVC3 和 Ninject.Web.WebApi(但在官方更新之前使用 Ninject.Web.WebApi-RC)。不要使用自定义的 DependencyResolver,让 Ninject.Web.Mvc 和 .WebApi 完成它们的工作。

2) 将您的绑定更改为:

kernel.Bind<ICompetitionRepository>().To<CompetitionRepository>();
... similar bindings

3) 为您的 ServiceContext 添加通用绑定

kernel.Bind(typeof(IServiceContext<>)).To(typeof(InMemoryDataContext<>));

【讨论】:

  • 我安装了 Ninject.WebApi-RC 并再次尝试,但同样的错误即将到来:(
  • @Bitsian - 无论它在哪里创建!您在上面列出了您的依赖关系解析器,但在使用 Ninject.MVC3 和 Ninject.WebApi 时不使用它
  • 对不起,当我问那个愚蠢的问题时,我正在考虑其他事情......我删除了我正在安装自定义依赖解析器但仍然无法正常工作的声明!我不确定问题是否与ninject有关,因为它对其他控制器工作正常......?
  • @Bitsian - SuggestionRepository 和 ISuggestionRepository 是什么样的?
【解决方案2】:

我认为问题在于您使用的是 ApiController。 控制器和 apiControllers 使用不同的依赖注入容器。 然而,它们都暴露了相同的方法。
如果工作控制器继承了 Controller 类,那么这就是你的原因。
有关解决方法,请查看 this topic

【讨论】:

    【解决方案3】:

    我也遇到过同样的问题。

    这是我纠正的方式: 我创建了一个 WebContainerManager,它只是容器的静态包装器。

    当您不控制实例化并且不能依赖注入时,静态容器包装器很有用 - 例如动作过滤器属性

    public static class WebContainerManager
    {
        public static IKernel GetContainer()
        {
            var resolver = GlobalConfiguration.Configuration.DependencyResolver as NinjectDependencyResolver;
            if (resolver != null)
            {
                return resolver.Container;
            }
    
            throw new InvalidOperationException("NinjectDependencyResolver not being used as the MVC dependency resolver");
        }
    
        public static T Get<T>()
        {
            return GetContainer().Get<T>();
        }
    }
    

    在你的控制器中,像这样不带参数地调用你的空构造函数:

    public SuggestionController() : this(WebContainerManager.Get<ISuggestionRepository>())
    {
    
    }
    

    这应该可行。

    这项技术是从 Jamie Kurtz @jakurtz 的 MVC4 书中得到的。

    【讨论】:

      【解决方案4】:

      您可能需要进行一些依赖注入,以便可以在 SuggestionController 构造函数中注入 ISuggestionRepository 参数。为此,您需要覆盖 DefaultControllerFactory 类中的方法来自定义控制器的创建。由于您使用的是 NInject,因此您可以使用以下内容:

      public class NInjectControllerFactory : DefaultControllerFactory 
      {
          private IKernel kernel = new StandardKernel(new CustomModule());
      
          protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
          {
              return controllerType == null ? null : (IController)kernel.Get(controllerType);  
          }
      
          public class CustomModule : NinjectModule
          {
              public override void Load()
              {
                  this.Bind<ICompetitionRepository>().To(typeof(CompetitionRepository))
                      .WithConstructorArgument("serviceContext", new InMemoryDataContext<Competition>());
      
                  this.Bind<ISubmissionRepository>().To(typeof(SubmissionRepository))
                      .WithConstructorArgument("serviceContext", new InMemoryDataContext<Submission>());
      
                  this.Bind<IUserRepository>().To(typeof(UserRepository))
                      .WithConstructorArgument("serviceContext", new InMemoryDataContext<User>());
      
                  this.Bind<ISuggestionRepository>().To(typeof(SuggestionRepository))
                     .WithConstructorArgument("serviceContext", new InMemoryDataContext<Suggestion>());
              }
          }
      }
      

      然后在你的 Global.asax.cs 中,你可以添加一行来换出控制器工厂

      protected void Application_Start()
      {
          AreaRegistration.RegisterAllAreas();
      
          RegisterRoutes(RouteTable.Routes);
          ControllerBuilder.Current.SetControllerFactory(new NInjectControllerFactory());  
      }
      

      【讨论】:

      • Ninject 模块和 DefaultControllerFactory 在哪个包中?我在这些方面遇到错误...
      • 我正在使用这两个包...使用 Ninject;使用 Ninject.Syntax;
      • 提问者使用的是 Ninject.MVC3,它使用 Microsoft 的 WebActivator 系统。它已经连接了自己并且不需要控制器工厂,因为它使用了 MVC3+ 中内置的 IDependencyResolver
      • ControllerFactory 不适用于 MVC3 和 4。您需要使用 DependencyResolver
      • 如果你不知道自己哪里做错了。你应该在使用它之前了解它。显然作为DependencyResolver,你需要注册ninject DependencyResolver。你在 Global.asax 中没有这个
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多