ReflectionTypeLoadException in ASP.NET Core MVC application - asp.net-core

I'm running into a problem running an ASP.NET Core 1.0 application targeting .NET Framework 4.6. The problem didn't occur until we tried to run the application on a server running Windows Server 2016. The app is hosted in IIS and I have the .NET Core 1.0 Windows Hosting Bundle installed on the server.
Upon loading the site a 500 error is returned and this is written to the Logs:
An unhandled exception has occurred: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information. (fc7986d0)
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Researching this it appears to relate to a missing dll or mismatched version, and that I should look at the LoaderExceptions property to get more info, but I'm not sure how to do that in this instance. The log entry is created just from setting up the loggerFactory in the Configure() method of Startup.cs.
I tried adding an IExceptionFilter ActionFilter implementation and reading the LoaderExceptions property if the exception is of type ReflectionTypeLoadException, but it doesn't get hit when ran on the server.
Is there a way to drill down into the Exception to read the LoaderExceptions property (in a production environment, there is no error when running in Visual Studio so debugging didn't help), or else another way to troubleshoot the original error to determine what is wrong with the server setup?

Instead of using IExceptionFilter, I wrote my own Middleware for catching this sort of exception and was able to log each exception from the LoaderExceptions property and determine what my problem is. Here is what I added to log the LoaderExceptions:
public class ExceptionCatchMiddleware
{
private readonly RequestDelegate _delegate;
private readonly ILogger _logger;
public ExceptionCatchMiddleware(RequestDelegate requestDelegate, ILogger<ExceptionCatchMiddleware> logger)
{
_delegate = requestDelegate;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
try
{
await _delegate(context);
}
catch (ReflectionTypeLoadException e)
{
foreach (Exception ex in e.LoaderExceptions)
{
_logger.LogCritical(ex.Message + Environment.NewLine + ex.StackTrace);
}
}
}
}
And then I just needed to add the Middleware to the Configure() method in Startup.cs:
app.UseMiddleware<ExceptionCatchMiddleware>();
In my case it was a missing dll that wasn't included in the project but since it was in my dev machine's GAC it ran there just fine.

Related

Can't get Azure Function .Net 5.0 Dependency Injection to inject service in another Project with dependencies

I am trying to inject a Service into my Azure Function that lives in another Project.
Here is my code.
public static async Task Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(s =>
{
s.AddTransient<ILocationService, LocationService>();
})
.Build();
Console.WriteLine("Host running!");
await host.RunAsync();
}
The LocationService is dependent on the DBContext.
private readonly MyAppDBContext _context;
public LocationService(MyAppDBContext context)
{
_context = context;
}
Here is my Function.
private readonly ILocationService _locationService;
private readonly TelemetryClient _telemetryClient;
public Function1(ILocationService locationService, TelemetryConfiguration telemetryConfiguration)
{
_locationService = locationService;
_telemetryClient = new TelemetryClient(telemetryConfiguration);
}
Here is the error.
Result: Failure Exception: System.InvalidOperationException: Unable to resolve service for type 'MyApp.Data.MyAppDBContext' while attempting to activate 'MyApp.Services.LocationService'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) at
I've tried both version 6.0 and 5.0.2 of Microsoft.Extensions.DependencyInjection.
This guide seems to suggest I'm doing it right.
https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide#dependency-injection
Any help is much appreciated! Thanks!
Turns out that this was an issue with Visual Studio 2019. I couldn't get web publishing to work, so I used FTP. To do that, I used the publish to folder method. I then zipped the files and used Power Shell to upload the zip file. Turns out that the publish to folder method was not working properly. It was never updating the files. All the changes I made never made it to the server. So frustrating! I wasted hours and hours on this. Here is what is now working. I also fixed the web publishing method by downloading a new publish profile.
s.AddDbContext<MyDBContext>();
s.AddLogging();
s.AddScoped<IMyService, MyService>();

microsoft grpc-for-wcf-developers-master code fails on IIS

getting the grpc-for-wcf-developers-master, I tried to host the WCF service in the tradersys on IIS version 10 on Windows 10, which throws an exception:
Error by IIS
The AutofacServiceHost.Container static property must be set before services can be instantiated.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The AutofacServiceHost.Container static property must be set before services can be instantiated.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
I'm aware of this issue as discussed several times here, such as this post.
Yet the code by Microsft contains the appropriate autofac container.
the question is:
Is there any special settings on IIS for resolving this issue?
as I said earlier IISExpress just works fine.
seems the AppInitialize() method in which
AutofacHostFactory.Container = builder.Build();
resides, doesn't invoke.
Based on your code, I found that you need to integrate IOC with WCF, which needs to change your code.
Here is my demo:
This is my project directory.We need to add two classes: ManualProxy and CustomServiceHostFactory.
public class CustomServiceHostFactory : ServiceHostFactory
{
protected override System.ServiceModel.ServiceHost
CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ManualProxy.TargetFactory = () => new PortfolioService(new PortfolioRepository());
return base.CreateServiceHost(typeof(ManualProxy), baseAddresses);
}
}
This is the CustomServiceHostFactory class.
public class ManualProxy : IPortfolioService
{
private readonly IPortfolioService _target;
public static Func<object> TargetFactory;
public ManualProxy()
{
_target = (IPortfolioService)TargetFactory();
}
public Task<Portfolio> Get(Guid traderId, int portfolioId)
{
return _target.Get(traderId,portfolioId);
}
public Task<List<Portfolio>> GetAll(Guid traderId)
{
return _target.GetAll(traderId);
}
}
This is the ManualProxy class.
The SVC file needs to be changed as above picture.

How to bypass .NET Core 2.2 and 3.1 error handling and display standard IIS status code pages?

In Asp.NET Core 2.2 and 3.1 there is a method called Configure() in the Startup class where you declare what exception handling method you want to use. For example, if you want to send a custom response when an exception occurs, you can do the following:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHttpContextAccessor accessor, IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
app.UseExceptionHandler(delegate (IApplicationBuilder errorApp)
{
errorApp.Run(async delegate (HttpContext Context)
{
Context.Response.StatusCode = 500;
Context.Response.ContentType = "text/plain";
await Context.Response.WriteAsync("An error occurred.");
});
});
//var x = ((string)null).Length; <--if this is uncommented, the custom handler won't catch it
//other configuration settings go here
}
Asp.Net Core will default to a standard developer exception page and show all the details of the exception if you don't define a custom handler.
My question is, how do I disable both the .Net Core developer exception page and the custom exception handler, and just have the errors bubble up to IIS so the old-fashioned error pages display?
The reason for wanting to do this is because custom handlers defined in the Configure() method only take effect after the Configure() method has completed. This means any exception that occurs in the Configure() method (see the commented-out line in the example) will send the user a full-blown developer error page, and there is (as far as I've researched) no way to disable this detailed developer page.
Obviously, I don't want these error details to appear on a production site. I figure disabling the Asp.NET Core error handling mechanism altogether will allow for 100% control of exceptions using the standard IIS error pages.
If you don't change any configuration and keep it as default, I assume you run .NET Core with IIS in in-process mode. You can try to disableStartUpErrorPage in this guideline.
Remember, In-Process means your .NET Core process is running on the same process with IIS so whenever you got startup exception, it will be fallback into Program.Main, not in your ExceptionHandler delegate. That is the reason why user can see full stack trace.

Invalid Token when confirming email address - Asp.Net Core

I'm occasionally getting an "Invalid Token" error from my call to
userManager.ConfirmEmailAsync(user, token) . I've narrowed down the problem to the fact that my 2 web servers are sitting behind a load balancer, and the web server that generated the token isn't always the web server that is attempting to confirm the token. I had a similar problem with anti-forgery tokens in a different web site, which I fixed by persisting the data protection key to disk and sharing it between the web servers, so I tried a similar approach here.
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\API"));
I then copied the key to the same folder in my other web server but still wasn't successful. Debugging through the AspNetCore.Identity code I can see an exception thrown on the call to
var unprotectedData = Protector.Unprotect(Convert.FromBase64String(token))
in the DataProtectorTokenProvider class. the catch block for the exception in Microsoft's code is simply
catch
{
// Do not leak exception
}
so I decided to inject an IDataProtector into my own Controller and try making that call myself.
public UserController(Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager, Microsoft.AspNetCore.Identity.RoleManager<IdentityRole> roleManager,
ILoggerFactory loggerFactory,
IDataProtectionProvider dataProtectionProvider)
{
Protector = dataProtectionProvider.CreateProtector("DataProtectorTokenProvider");
}
try
{
var unconverted = Convert.FromBase64String(request.EmailConfirmationToken);
var unprotectedData = Protector.Unprotect(unconverted);
}
catch (Exception e)
{
}
I can now catch the exception thrown on the Unprotect call and it's:
The payload was invalid
Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(Byte* pbCiphertext, UInt32 cbCiphertext, Byte* pbAdditionalAuthenticatedData, UInt32 cbAdditionalAuthenticatedData)\r\n at Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment1 ciphertext, ArraySegment1 additionalAuthenticatedData)\r\n at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)\r\n at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)\r\n at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)\r\n at VTR.API.Controllers.UserController.d__16.MoveNext() in C:\Projects\Brewster.Travel\src\cres\trunk\VTR.API\src\VTR.API\Controllers\UserController.cs:line 409
If I make that call with a token generated on the same server then it gets unprotected successfully. I obviously have some problem with how I'm attempting to share my data protection keys, if anyone could shed some light on my problem I would appreciate it.
I managed to get this working thanks to the documentation here: https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview
I needed to add a call to SetApplicationName() in ConfigureServices:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\someDirectory"))
.SetApplicationName("myApplicationName");

The type initializer for 'NHibernate.Cfg.Configuration' threw an exception

After upgrading from nhibernate 1.0.4.0 to nhibernate 3.3 im encountering the following error when I try to run "Configuration cfg = new Configuration();"
System.TypeInitializationException was caught
Message="The type initializer for 'NHibernate.Cfg.Configuration' threw an exception."
Source="NHibernate"
TypeName="NHibernate.Cfg.Configuration"
StackTrace:
at NHibernate.Cfg.Configuration..ctor()
at KEH.Web.Data.NHibernateUtil..cctor() in F:\Projects\KEH nHibernate\KEHWeb\Data\Data\NHibernateUtil.cs:line 24
InnerException: System.NotSupportedException
Message="The invoked member is not supported in a dynamic assembly."
Source="mscorlib"
StackTrace:
at System.Reflection.Emit.AssemblyBuilder.get_Location()
at log4net.Util.SystemInfo.AssemblyLocationInfo(Assembly myAssembly)
at log4net.Core.DefaultRepositorySelector.GetInfoForAssembly(Assembly assembly, String& repositoryName, Type& repositoryType)
at log4net.Core.DefaultRepositorySelector.CreateRepository(Assembly repositoryAssembly, Type repositoryType, String repositoryName, Boolean readAssemblyAttributes)
at log4net.Core.DefaultRepositorySelector.CreateRepository(Assembly repositoryAssembly, Type repositoryType)
at log4net.Core.DefaultRepositorySelector.GetRepository(Assembly repositoryAssembly)
at log4net.Core.LoggerManager.GetLogger(Assembly repositoryAssembly, String name)
at log4net.LogManager.GetLogger(Assembly repositoryAssembly, String name)
at log4net.LogManager.GetLogger(Type type)
at lambda_method(ExecutionScope , Type )
at NHibernate.Log4NetLoggerFactory.LoggerFor(Type type)
at NHibernate.LoggerProvider.LoggerFor(Type type)
at NHibernate.Cfg.Configuration..cctor()
InnerException:
Any help would be greatly appreciated.
The NHibernateUtil class code is as follows :
public class NHibernateUtil
{
private static readonly Configuration cfg;
private static readonly ISessionFactory sessionFactory;
private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
static NHibernateUtil()
{
try
{
logger.Debug("Before Initializing NHibernate");
cfg = new Configuration();
cfg.AddAssembly("KEH.Web.Data");
sessionFactory = cfg.BuildSessionFactory();
logger.Debug("Initialized NHibernate");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static ISession OpenSession()
{
logger.Debug("Before Getting Connection");
return sessionFactory.OpenSession();
}
}
I had the same problem.
The actual reason was i used a library that used old version of log4net.
NHibernate tries to use it if find.
So i had to force it to use (or actually not use) other logger by adding such line:
LoggerProvider.SetLoggersFactory(new NoLoggingLoggerFactory());
Not sure why it's not working, but I'd just replace
cfg.AddAssembly("KEH.Web.Data");
with
cfg.AddAssembly(typeof(Entity).Assembly);
where Entity is some class that exists in the assembly of your mapping files.
For the benefit of others who might find this question via Google:
For us, this error was a red-herring. Our app ran fine until we deployed a new component AND it would fail (in an unknown way) AND IIS would recycle the app pool. The problem was an HTML to JPG component we were using was erroring somehow and causing all of our w3wp.exe worker processes to consume maximum CPU. When the app pool was recycled via IIS, the entire site would go down and NHibernate would throw this error continuously until an iisreset. Before the recycle, the site would still be very responsive even with the CPU load.
While we still don't know how the component was failing or why it was cascading to problems with NHibernate initializing, the point is it was a red-herring. Be sure to watch for this error "suddenly" occurring shortly after a new deployment, and keep logs of your CPU utilization so it can help spot when trouble is brewing. Finally, if the downtime is happening near the same time every day, it's probably an automatic IIS app pool recycle, and that should be another clue that something is bugging out your application and surfacing during the recycle.
Ultimately, we disabled the HTML to JPG component until a workaround can be found and our up-time sprung back to 100%.
Hope this helps someone.