首页 文章

使用NInject的API应用程序无法在IIS上运行,它仅适用于调试器Visual Studio

提问于
浏览
1

我有一个API应用程序,可以在Visual Studio 2015调试器上完美运行;我试图在IIS上发布我的应用程序(我已通过控制面板安装了服务器打开/关闭Windows功能) .

我的应用程序有一个安全系统来检查任何请求是来自注册的用户,任何请求传递首先抛出 ApiAuthorizationFilter ,解析由Base64字符串组成的令牌,它在 Headers 中作为 Authorization 并返回具有JSON的特定 HttpStatusCode .

部署后发生异常,如果我在IIS上的应用程序上运行测试,则会在 Filter.ApiAuthorizationFilter 处抛出 NullReferenceException ,但如果我在Visual Studio上运行相同的应用程序 - 它可以正常工作 .

这是错误消息:

500:内部服务器错误“消息”:“发生错误 . ” “ExceptionMessage”:“对象引用未设置为对象的实例 . ” “ExceptionType”:“System.NullReferenceException”“StackTrace”:“在System.Web.Http.Filters.AuthorizationFilterAttribute.OnAuthorizationAsync(HttpActionContext actionContext,CancellationToken cancellationToken)的API.CARDS.Models.Filter.ApiAuthorizationFilter.OnAuthorization(HttpActionContext actionContext)中 - - 从抛出异常的先前位置开始的堆栈跟踪结束---在System.Web.Http的System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)的System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)处.Filters.AuthorizationFilterAttribute.d__2.MoveNext()---在抛出异常的前一个位置的堆栈跟踪结束---在System.Runtime.CompilerServices.TaskAwaiter的System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)处 . System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()中的HandleNonSuccessAndDebuggerNotification(任务任务)

这是代码:

ApiAuthorizationFilter

public class ApiAuthorizationFilter : AuthorizationFilterAttribute
{
    [Inject]
    public IEncryptionSystemService service { get; set; }

    [Inject]
    public IUserService userService { get; set; }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        //Hace una petición (request) al actionContext
        HttpRequestMessage request = actionContext.Request;
        try
        {
            //Establece la cultura (Ejemplo: es-MX) para los mensajes i18n
            string culture = actionContext.Request.Headers.AcceptLanguage.ToString();
            if (culture.Length == 5)
            {
                Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
                Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
            }
            //Crea un token con los valores que se obtienen del actionContext, mismos que serán las credenciales para accesar.
            string token = actionContext.Request.Headers.GetValues("Authorization").FirstOrDefault().Replace("Credentials", "").Trim();
            //Desencripta las credenciales con el servicio del tipo IEncryptionService.
            string[] userPass = service.DecryptText(token);
            User model = new User { email = userPass[0], password = userPass[1] };
            ////Verifica que sean correctas las credenciales que ser obtuvieron del token.
            AuthorizationResult result = userService.LoginUser(model);
            switch (result)
            {
                case AuthorizationResult.ACCESS_GRANTED:
                    User user = new User { email = model.email };
                    ApiIdentity identity = new ApiIdentity(user);
                    ApiPrincipal principal = new ApiPrincipal(identity);
                    Thread.CurrentPrincipal = principal;
                    break;
                case AuthorizationResult.ACCESS_DENIED:
                    actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound, "ErrorResources.NotFound");
                    break;
                case AuthorizationResult.PERMISSION_DENIED:
                    actionContext.Response = request.CreateResponse(HttpStatusCode.Unauthorized, "ErrorResources.Unauthorized");
                    break;
            }
        }
        catch (Exception e)
        {
            throw;
            //Si existe un error durante la petición, regresa un estatus de InternalServerError (Error interno del Servidor).
            //actionContext.Response = request.CreateErrorResponse(HttpStatusCode.InternalServerError, string.Format("ErrorResources.AuthenticationError ---- {0}",e.Message));

        }
    }
}

Image response from the debugger

Image response from IIS

1 回答

  • 2

    经过一番大研究后我找到了答案!这个答案适用于 API Application with NInject, Leppie是对的问题是 Dependency Injection Configuration.

    首先我必须清理从 NuGet 安装的数据包,我不得不用这些数据包重新安装 Ninject .

    • Ninject

    • Ninject.web.WebApi

    • Ninject.web.WebApi.WebHost - 我错过了这个, this is required for IIS support

    • Ninject.MVC3

    • Ninject.web.Common

    • Ninject.web.Common.WebHost - 将此版本更新为最新版本(3.2.3), this is required for IIS support

    之后检查你的类 NInjectWebCommon.cs ,在名为 CreateKernel() 的方法中,我有这一行

    GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
    

    你需要删除它,因为这将抛出

    使用从ModelValidatorProvider到NinjectDefaultModelValidatorProvider的绑定激活ModelValidatorProvider时出错

    如果一切都好!您的应用程序将在 IIS Server 上运行 .

    这些文件是我在App_Start文件夹中的NInject的最后一个配置

    NinjectWebCommon.cs

    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();
    
        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }
    
        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }
    
        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
    
                RegisterServices(kernel);
    
               // GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }
    
        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            // kernel.BindFilter<ApiAuthorizationFilter>(FilterScope.Controller, 0).WhenControllerHas<ApiAuthorizationFilter>();
    
            NInjectHelper.SetupKernel(kernel);
            kernel.Bind<IEncryptionSystemService>().To<EncryptionSystemService>();
            kernel.Bind<IUserService>().To<UserService>();
            kernel.Bind<IRoleService>().To<RoleService>();
            kernel.Bind<IStatusService>().To<StatusService>();
            kernel.Bind<ICardService>().To<CardService>();
            kernel.Bind<ICardTypeService>().To<CardTypeService>();
    
    
        }
    
    }
    

    NinjectResolver.cs

    public class NinjectResolver : NinjectScope, IDependencyResolver
    {
        private IKernel _kernel;
    
        public NinjectResolver(IKernel kernel)
            : base(kernel)
        {
            _kernel = kernel;
        }
    
        public IDependencyScope BeginScope()
        {
            return new NinjectScope(_kernel.BeginBlock());
        }
    }
    

    NinjectScope.cs

    public class NinjectScope : IDependencyScope
    {
        protected IResolutionRoot resolutionRoot;
    
        public NinjectScope(IResolutionRoot kernel)
        {
            resolutionRoot = kernel;
        }
    
        public object GetService(Type serviceType)
        {
            IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
            return resolutionRoot.Resolve(request).SingleOrDefault();
        }
    
        public IEnumerable<object> GetServices(Type serviceType)
        {
            IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
            return resolutionRoot.Resolve(request).ToList();
        }
    
        public void Dispose()
        {
            IDisposable disposable = (IDisposable)resolutionRoot;
            if (disposable != null) disposable.Dispose();
            resolutionRoot = null;
        }
    }
    

    IMPORTANT! For SQL Server Users 正如你在我的 ApiFilterConfiguration 上看到的那样我有这一行 AuthorizationResult result = userService.LoginUser(model); 这个 userService 是我用方法创建的类 LoginUser(model) 这个方法从 Request Headers 获取一个模型并转到 SQL SERVER 以验证用户是否存在 .

    如果你用我的默认配置安装 SQL Server ,也许你有另一个问题抛出 Null reference after a consult ,请查看这个主题 Login failed for user IIS APPPOOL\AppPool4.5 or APPPOOL\ASP.NET 也许你需要在 SQLSERVER 上为 IIS 创建一个登录名

相关问题