【问题标题】:API App with NInject doesnt work on IIS, It only works on debugger Visual Studio带有 NInject 的 API 应用程序不能在 IIS 上运行,它只能在调试器 Visual Studio 上运行
【发布时间】:2016-03-29 16:32:17
【问题描述】:

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

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

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

这是错误信息:

500:内部服务器错误 “消息”:“发生错误。” “ExceptionMessage”:“对象引用未设置为对象的实例。” “异常类型”:“System.NullReferenceException” "StackTrace": " at API.CARDS.Models.Filter.ApiAuthorizationFilter.OnAuthorization(HttpActionContext actionContext) at System.Web.Http.Filters.AuthorizationFilterAttribute.OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancelToken) --- 来自先前位置的堆栈跟踪结束抛出异常的地方---在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext( ) --- 从先前引发异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Web 的 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) .Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"

代码如下:

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

【问题讨论】:

  • 发布 PDB,这样您至少可以看到行号。我怀疑你的 DI 不工作。
  • 如果我的 Visual Studio 具有默认配置,我在哪里可以找到 PDB?你的意思是依赖注入吗?我对 NInject 也有同样的感觉,但我不知道为什么它只在 Debug 上有效

标签: c# asp.net .net api iis


【解决方案1】:

经过大量研究,我找到了答案!,这个答案适用于 API Application with NInject, Leppie 是对的,问题在于 依赖注入配置。

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

  • 忍者
  • Ninject.web.WebApi
  • Ninject.web.WebApi.WebHost -- 我错过了这个,这是 IIS 支持所必需的
  • Ninject.MVC3
  • Ninject.web.Common
  • Ninject.web.Common.WebHost -- 将此更新到最新版本 (3.2.3),这是 IIS 支持所必需的

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

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

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

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

如果一切正常!您的应用程序将在 IIS 服务器上运行。

这些文件是我在 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;
    }
}

重要!对于 SQL Server 用户 正如您在我的 ApiFilterConfiguration 上看到的那样,我有这一行 AuthorizationResult result = userService.LoginUser(model); 这个 userService 是我用 LoginUser(model) 方法创建的一个类,这个方法从 Request Headers 获取一个模型并转到 LoginUser(model) strong>SQL SERVER 验证用户是否存在。

如果您像我一样使用默认配置安装了 SQL Server,也许您还有一个问题会引发咨询后出现空引用,请检查此主题 Login failed for user IIS APPPOOL\AppPool4.5 or APPPOOL\ASP.NET 也许您需要在 SQLSERVER 上为 IIS 创建一个登录名

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    相关资源
    最近更新 更多