0

We are having a problem with our solution when it's hosted in a windows container that I don't encounter on my local. I have a WebAPI project using .Net Framework 4.6.2. It is referencing a custom Nuget package we wrote targeting net461;net462;netstandard2.0;. As I said in my title when I run this on my local machine everything is fine. When we publish it to a docker container image: microsoft/dotnet-framework:4.7-windowsservercore-10.0.14393.1884 we get the following error when we try to hit one of the end points in the Nuget Package. Could anyone suggest a solution or possible next trouble shooting step? We've been throwing some guesses based on Stack Overflow searches, but haven't found anything that works.

   The ProjectAPI service is now running, press Control+C to exit.
2019-02-18 08:33:12,522 ERROR lobalExceptionLogger: CustomNugetPackageName Exception
System.IO.FileNotFoundException: Could not load file or assembly 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
  at CustomNugetPackageName.Controllers.ReportsController.GetReport(Int32 reportId, Report& report, IHttpActionResult& unauthorized)
  at CustomNugetPackageName.Controllers.ReportsController.GetReport(Int32 reportId)
  at lambda_method(Closure , Object , Object[] )
  at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_2.<GetExecutor>b__2(Object instance, Object[] methodParameters)
  at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
  at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
  at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()

I've tried setting binding redirects int he WebAPI project like so:

<dependentAssembly>
   <assemblyIdentity name="System.Net.Http" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
   <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>

When I add that the application silently fails when I try to use Autofac to inject the NetStandard app to the WebAPI project. I've been really stumped on what could possibly be going on that's causing it to break in the container.

Here is my Autofac module and startup if you that matters:

Module:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using API.Claims;
using API.ControllerBase;
using Autofac;
using Autofac.Integration.WebApi;
using ReportingServiceBase.Base;
using Module = Autofac.Module;

namespace ReportingAPIBase.Initializers
{
    /// <summary>
    /// 
    /// </summary>
    public class ReportingStartupModule : Module
    {
        /// <summary>
        /// 
        /// </summary>
        public int RestrictAccessValue { get; set; }

        /// <inheritdoc />
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterModule(new ReportingServiceModule());
            var assembly = Assembly.GetExecutingAssembly();  // this
            List<Type> controllers = (from t in assembly.GetTypes()
                              where t.IsClass  && typeof(ApiControllerBase).IsAssignableFrom(t)
                              select t).ToList();

            // Add Restrict Attribute
            foreach (Type controller in controllers)
            {
                TypeDescriptor.AddAttributes(controller, new API.Claims.RestrictAttribute(RestrictAccessValue, ClaimValues.FullAccess | ClaimValues.ReadOnly));
            }

            builder.RegisterApiControllers(assembly);

        }
    }
}

Startup

using System.Reflection;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;
using API.Base;
using API.Common;
using API.Jwt;
using API.RoleManager;
using Autofac;
using Autofac.Integration.WebApi;
using AutoMapper;
using AutoMapper.Configuration;
using log4net.Config;
using Microsoft.Owin;
using Microsoft.Owin.FileSystems;
using Microsoft.Owin.StaticFiles;
using Model.Reporting;
using Owin;
using ReportingAPIBase.Initializers;
using Service;
using Service.Utilities;

[assembly: XmlConfigurator(ConfigFile = "l4n.config", Watch = true)]

namespace API
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Configure Web API for self-host.
            var config = new HttpConfiguration();

            // Register modules and types
            var builder = new ContainerBuilder();

            builder.RegisterModule(new ReportingDataPointsModule());

            // FAILS HERE
            builder.RegisterModule(new ReportingStartupModule()
            {
                RestrictAccessValue = Claims.ClaimTypes.Reports
            });

            builder.RegisterModule(new ServiceModule());
            builder.RegisterModule(new EfModule());
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            // Register service handles
            config.Services.Add(typeof(IExceptionLogger), new GlobalExceptionLogger());

            builder.RegisterWebApiFilterProvider(config);
            MapperConfigurationExpression mapperConfig = new AutoMapperConfiguration().Configure();
            Mapper.Initialize(mapperConfig);
            Mapper.AssertConfigurationIsValid();

            // Build container
            var container = builder.Build();
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            // The Autofac middleware must go before any Web Api middleware
            app.UseAutofacMiddleware(container);
            app.UseAutofacWebApi(config);
            WebApiConfig.Register(config, container);

            // Non-Autofac OWIN pipeline
            app.UseJsonWebTokens(container.Resolve<IRoleManager>());
            app.UseRoleManager(container.Resolve<IRoleManager>());
            app.UseWebApi(config);

            // Ensures configuration is ready
            config.EnsureInitialized();

    }
}

John Graham
  • 573
  • 4
  • 20

1 Answers1

2

Thank you for being my rubber duck. Shortly after posting this I found the following answer that solved this for me. I was able to track down that I was using the wrong version for the binding redirect. Changing it to the following solved this problem.

<dependentAssembly>
   <assemblyIdentity name="System.Net.Http" culture="neutral" publicKeyToken="b03f5f7f11d50a3a" />
   <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
John Graham
  • 573
  • 4
  • 20