DryIoc: Enabling 'throwIfUnresolved' always throw an exception - asp.net-web-api2

I want to know name of dependencies that are missed (not injected)!
I Use this extensions:
DryIoc.dll v4.0.7
DryIoc.WebApi.dll v4.0.0
DryIoc.Web.dll v4.0.0
and I tried to use throwIfUnresolved parameter to solve the problem
Like this:
public static void Register(HttpConfiguration config)
{
var container = new Container().WithWebApi(config, throwIfUnresolved: type => true);
//...
}
but after that I always get this exception even if there is no dependency!
DryIoc.ContainerException: 'Unable to resolve ModelMetadataProvider IsResolutionCall
from Container with ambient ScopeContext DryIoc.AsyncExecutionFlowScopeContext without Scope
Where no service registrations found
and no dynamic registrations found in 0 of Rules.DynamicServiceProviders
and nothing found in 0 of Rules.UnknownServiceResolvers'

Use this:
public static void Register(HttpConfiguration config)
{
var container = new Container()
.WithWebApi(
config,
throwIfUnresolved: type => type.IsController());
//...
}

Related

Asp.Net Core AddAutoMapper Dynamic from Multi Projects

I want to register AutoMapper form different project each project have it's public function to register his functions
like this
public static class Binder
{
public static IServiceCollection UseInjection(this IServiceCollection services)
{
services.AddAutoMapper(typeof(MappingProfile));
}
}
if i do it on each layer it's not working .
i need to write everything ones
like this : (work)
services.AddAutoMapper(
typeof(Project1.Mapping.MappingProfile),
typeof(Project2.Mapping.MappingProfile),
typeof(Project3.Mapping.MappingProfile));
i try to scan the folder for the dll's and take the type to register ones :
var target = typeof(JustForLocation).Assembly;
bool DefaultFilter(Assembly x) => true;
var path = Path.GetDirectoryName(target.Location) ?? throw new Exception();
var assembliesToLoad = Directory.GetFiles(path, "*.dll").
Select(dll => Assembly.LoadFile(dll))
.Where(DefaultFilter)
.ToList();
assembliesToLoad.Add(target);
var types = assembliesToLoad.SelectMany(a => a.GetExportedTypes()).Where(w => w.BaseType == typeof(AutoMapper.Profile)).ToArray();
services.AddAutoMapper(types);
but it's still throw error from the AutoMappe that say:
AutoMapperMappingException: Missing type map configuration or unsupported mapping. Mapping types
any advise why it's happen ?
// Auto mapper registration
services.AddAutoMapper(typeof(Startup).Assembly, typeof(BaseRepository).Assembly);
// Dapper Column Mapping
SqlMapper.SetTypeMap(typeof(Sample), new ColumnTypeMapper(typeof(Sample)));

Cannot change port when migrating to .net core 3.1.3 from 2.2.0

On 2.2.0, I have the following to create a WebHostBuilder. I then call .Build().Run() on it
public IWebHostBuilder CreateWebHostBuilder(CommandLineOptions commandLineOptions, Type startupType, IConfiguration configuration, ILogger logger)
{
if (builder == null)
{
builder = WebHost.CreateDefaultBuilder(commandLineOptions?.Args)
.ConfigureAppConfiguration(configBuilder =>
{
configBuilder.Sources.Clear();
configBuilder.AddConfiguration(configuration);
})
.UseEnvironment(configuration.GetValue<string>("Environment"))
.UseStartup(startupType)
.UseUrls(configuration.GetValue<string>("HostUrl")) //"http://*:8000/"
.UseSerilog(logger);
}
return builder;
}
After upgrading to 3.1.3, it still works. I then changed to the below based on the migration doc
public IHostBuilder CreateHostBuilder(CommandLineOptions commandLineOptions, Type startupType, IConfiguration configuration, ILogger logger)
{
if (builder == null)
{
builder = Host.CreateDefaultBuilder(commandLineOptions?.Args)
.ConfigureAppConfiguration(configBuilder =>
{
configBuilder.Sources.Clear();
configBuilder.AddConfiguration(configuration);
})
.UseEnvironment(configuration.GetValue<string>("Environment"))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup(startupType);
webBuilder.UseUrls(configuration.GetValue<string>("HostUrl")); //"http://*:8000/"
})
.UseSerilog(logger);
}
return builder;
}
However, now no matter what I do it listens on the default ports of http://localhost:5000 and https://localhost:5001.
I don't have a hostsettings.json file, launchSettings.json also has nothing set, there's no setting in my enviroment variables. I've run from the command line specifying the desired url, but nothing works.
EDIT: Thanks to Martin Staufcik's suggestion to minimize the configuration, I've noticed that changing ConfigureAppConfiguration to ConfigureHostConfiguration has resolved the issue. I also noticed that if I left it as ConfigureAppConfiguration and remove the configBuilder.Sources.Clear(); line, it works too.
I've looked up the difference between the two, but I still don't understand what is happening here.
I lost a couple of hours working with .UseUrls myself. I finally got it working after noticing that the order of code lines was important! What worked in my case was calling UseUrls before UseStartup.
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseUrls(configuration.GetValue<string>("HostUrl")); //"http://*:8000/"
webBuilder.UseStartup(startupType);
})

Enrich Serlilogs with unique value per hangfire job

I'm using Hangfire for background jobs, and Serilog for logging. I'm trying to enrich my serilogs with a TrackingId so that all logs from a specific Hangfire job will have the same TrackingId that I can filter on.
I configure Serilog like this in Startup.cs:
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.WriteTo.Seq(serverUrl: serverUrl, apiKey: apiKey)
// Enrich the logs with a tracking id. Will be a new value per request
.Enrich.WithProperty("TrackingId", Guid.NewGuid())
.CreateLogger();
And I enqueue jobs like this:
BackgroundJob.Enqueue<MyService>(myService => myService.DoIt(someParameter));
But doing like this will not set a separate TrackingId per Hangfire job. Is there any way I can achieve that?
For what it's worth, I ended up pulling this off using the server/client filter and GlobalJobFilters registration shown below. One annoying issue I ran into is that the AutomaticRetryAttribute is added by default to the GlobalJobFilters collection, and that class will log errors for failed jobs without knowledge of the Serilog LogContext created in our custom JobLoggerAttribute. Personally, I know I will only allow manual retry, so I just removed that attribute and handled the error within the IServerFilter.OnPerformed method. Check the end of my post to see how to remove it if that works for you.
If you are going to allow automatic retry, then you will need to: 1) create a custom attribute that decorates the AutomaticRetryAttribute and makes it aware of a custom LogContext, 2) again remove the default AutomaticRetryAttribute from the GlobalJobFilters collection, and 3) add your decorator attribute to the collection.
public class JobLoggerAttribute : JobFilterAttribute, IClientFilter, IServerFilter
{
private ILogger _log;
public void OnCreating(CreatingContext filterContext)
{
_log = GetLogger();
_log.Information("Job is being created for {JobType} with arguments {JobArguments}", filterContext.Job.Type.Name, filterContext.Job.Args);
}
public void OnCreated(CreatedContext filterContext)
{
_log.Information("Job {JobId} has been created.", filterContext.BackgroundJob.Id);
}
public void OnPerforming(PerformingContext filterContext)
{
if (_log == null)
_log = GetLogger();
_log.Information("Job {JobId} is performing.", filterContext.BackgroundJob.Id);
}
public void OnPerformed(PerformedContext filterContext)
{
_log.Information("Job {JobId} has performed.", filterContext.BackgroundJob.Id);
if (filterContext.Exception != null)
{
_log.Error(
filterContext.Exception,
"Job {JobId} failed due to an exception.",
filterContext.BackgroundJob.Id);
}
_log = null;
}
private ILogger GetLogger()
{
return Log.ForContext(GetType()).ForContext("HangfireRequestId", Guid.NewGuid());
}
}
And the registration...
GlobalJobFilters.Filters.Add(new JobLoggerAttribute());
Removing the AutomaticRetryAttribute...
var automaticRetryFilter = GlobalJobFilters.Filters.Where(x => x.Instance is AutomaticRetryAttribute).Single();
GlobalJobFilters.Filters.Remove(automaticRetryFilter.Instance);

Global object onStart fails all my tests

I had a number of tests, it ran perfectly, untill I write Global object:
#Override
public void onStart(Application app) {
Mails.plugin = app.plugin(MailerPlugin.class).email();
Mails.from = app.configuration().getString("smtp.from");
if (Mails.plugin != null) Logger.info("Mailer plugin successfully loaded");
if (Mails.from != null) Logger.info("Mail account is " + Mails.from);
}
Here I am loading plugin for email messages. Now when I try to run my fakeApplication with inMemoryDatabase I get a null pointer exception. Probably it is becouse fakeApplication don't use configuration file, and can't load configuration from this file. Please help me to sort out this problem.
Try adding custom config parameters in your FakeApplication:
Map<String, Object> additionalConfiguration = new HashMap<String, Object>();
additionalConfiguration.put("smtp.from", "foo#bar.com");
running(fakeApplication(additionalConfiguration), new Runnable() {
...
I find the solution , for this reason I create fake Global class (or you also can mock it):
class Global extends GlobalSettings{
}
and Then can pass it:
#BeforeClass
public static void startApp() {
app = Helpers.fakeApplication(new Global());
Helpers.start(app);
}

What is the reason that Policy.getPolicy() is considered as it will retain a static reference to the context and can cause memory leak

I just read some source code is from org.apache.cxf.common.logging.JDKBugHacks and also in
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java. In order to make my question clear not too broad. :)
I just ask one piece of code in them.
// Calling getPolicy retains a static reference to the context
// class loader.
try {
// Policy.getPolicy();
Class<?> policyClass = Class
.forName("javax.security.auth.Policy");
Method method = policyClass.getMethod("getPolicy");
method.invoke(null);
} catch (Throwable e) {
// ignore
}
But I didn't understand this comment. "Calling getPolicy retains a static reference to the context class loader". And they trying to use JDKBugHacks to work around it.
UPDATE
I overlooked the static block part. Here it is. This is the key. Actually it already has policy cached. So why cache contextClassLoader also? In comment, it claims #deprecated as of JDK version 1.4 -- Replaced by java.security.Policy.
I have double checked the code of java/security/Policy.java. It really removed the cached classloader. So my doubt is valid! :)
#Deprecated
public abstract class Policy {
private static Policy policy;
private static ClassLoader contextClassLoader;
static {
contextClassLoader = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
};
I also add the getPolicy source code.
public static Policy getPolicy() {
java.lang.SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(new AuthPermission("getPolicy"));
return getPolicyNoCheck();
}
static Policy getPolicyNoCheck() {
if (policy == null) {
synchronized(Policy.class) {
if (policy == null) {
String policy_class = null;
policy_class = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<String>() {
public String run() {
return java.security.Security.getProperty
("auth.policy.provider");
}
});
if (policy_class == null) {
policy_class = "com.sun.security.auth.PolicyFile";
}
try {
final String finalClass = policy_class;
policy = java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction<Policy>() {
public Policy run() throws ClassNotFoundException,
InstantiationException,
IllegalAccessException {
return (Policy) Class.forName
(finalClass,
true,
contextClassLoader).newInstance();
}
});
} catch (Exception e) {
throw new SecurityException
(sun.security.util.ResourcesMgr.getString
("unable to instantiate Subject-based policy"));
}
}
}
}
return policy;
}
Actually I dig deeper, I find some interesting thing. Someone report a bug to apache CXF about the org.apache.cxf.common.logging.JDKBugHacks for this piece code recently.
In order for disabling url caching, JDKBugHacks runs:
URL url = new URL("jar:file://dummy.jar!/");
URLConnection uConn = url.openConnection();
uConn.setDefaultUseCaches(false);
When having the java.protocol.handler.pkgs system property set, that can lead to deadlocks between the system classloader and the file protocol Handler in particular situations (for instance if the file protocol URLStreamHandler is a signleton).
Besides that, the code above is really there for the sake of setting defaultUseCaches to false only, so actually opening a connection can be avoided, to speed up the execution.
So the fix is
URL url = new URL("jar:file://dummy.jar!/");
URLConnection uConn = new URLConnection(url) {
#Override
public void connect() throws IOException {
// NOOP
}
};
uConn.setDefaultUseCaches(false);
It's normal that JDK or apache cxf to have some minor bugs. And normally they will fix it.
javax.security.auth.login.Configuration has the same issues with Policy but it's not Deprecated.
The Policy class in java 6 contains a static reference to a classloader that is initialized to the current threads context classloader on the first access to the class:
private static ClassLoader contextClassLoader;
static {
contextClassLoader =
(ClassLoader)java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction() {
public Object run() {
return Thread.currentThread().getContextClassLoader();
}
});
};
Tomcats lifecycle listener is making sure to to initialize this class from within a known environment where the context classloader is set to the system classloader. If this class was first accessed from within a webapp, it would retain a reference to the webapps classloader. This would prevent the webapps classes from getting garbage collected, creating a leak of perm gen space.