Use log4net with Ninject logging extensions in WebForms application - asp.net

After some struggling I managed to get a working ASP.NET webforms application that uses the Ninject logging extension and log4net as logging framework. (credits to this blog for the basics).
But I have some questions on how to continue.
First, I needed to make the ILogger property public, because it remained null if it was private or protected.
So now I have this:
[Inject]
protected ILogger _logger { get; set; }
Instead of:
private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
I can live with it, but it seems strange.
Another thing is the ThreadContext that log4net uses to fill the current context. I can still use it like this
using (ThreadContext.Stacks["NDC"].Push(MethodBase.GetCurrentMethod().Name))
{
_logger.Info("test");
}
But offcourse that takes away all the abstraction that I just added..
So I'm looking for some experiences / best practices that other people may have with this scenario.
Additional question: I've upgraded log4net to 1.2.11.0 which is the current version in NuGet, and now Ninject.Logging.log4net is broken because it expects version 1.2.10.0 ... is there a way to fix that?

Additional question: I've upgraded log4net to 1.2.11.0 which is the
current version in NuGet, and now Ninject.Logging.log4net is broken
because it expects version 1.2.10.0 ... is there a way to fix that?
Did you try to fix the allowed versions with [xx] in the Packages.config file ?
<package id="log4net" version="1.2.10" allowedVersions="[1.2.10]" /> />
It will prevent next updates to upgrade to 1.2.11 or more.
http://docs.nuget.org/docs/reference/versioning

Related

Upgrading Wicket 9.0.0 to 9.3.0: runtime error when try to access database

I am attempting to upgrade from Wicket 9.0.0 to Wicket 9.3.0. When I change the version in a quick-start application, everything is fine.
The problem occurs in my real application, where we were originally using Jakarta Enterprise Beans 8.0.0. At runtime, when a database access was attempted, we got an exception with the following message:
Last cause: net.sf.cglib.proxy.MethodInterceptor not found by org.objectweb.asm [23]
Trying to use Jakarta EE 9.1 instead
I changed my pom.xml as follows:
<jakartaee>9.1.0</jakartaee>
<wicket.version>9.3.0</wicket.version>
I downloaded the jar for Jakarta EE 9.1, changed "javax" to "jakarta" throughout my application, rebuilt it and tried to run again.
The result was still not perfect, but significantly better than before: a plain old null pointer exception instead of any weird errors about cglib.
Here's the section of code that now causes the trouble:
#EJB(name = "AdminNotesFacade")
private AdminNotesFacade adminNotesFacade;
public AdminNotesFacade getAdminNotesFacade() {
return adminNotesFacade; //ACTUALLY RETURNS NULL
}
So now the big question is: what do I need to do/change to make the #EJB work instead of returning null?
Checking the Payara log, I get this error:
java.lang.RuntimeException: Unable to load the EJB module. DeploymentContext does not contain any EJB. Check the archive to ensure correct packaging for D:\Dev\icase2\target\icase2.
If you use EJB component annotations to define the EJB, and an ejb or web deployment descriptor is also used, please make sure that the deployment descriptor references a Java EE 5 or higher version schema, and that the metadata-complete attribute is not set to true, so the component annotations can be processed as expected
at org.glassfish.ejb.startup.EjbDeployer.prepare(EjbDeployer.java:189)
Adding further details, 2022-05-06
I wonder if we were going off on the wrong track when we thought that we could fix this by upgrading our jakartaee version. From Wicket 9.0 to 9.3 is only a change of minor version and you wouldn't expect to have to make such fundamental changes to get a minor upgrade working.
I've tried using Wicket 9.9.1 instead, in case this problem has been fixed in more recent versions, but it's exactly the same.
Anyway, I have created a very small "quick-start" application, based on Wicket's own templates, to reproduce the problem. I have stuck with the original "javax" version, and added just one EJB - a JavaMail bean. I think it's probably interesting to know that it's not a specifically database-related issue. We just can't seem to load any EJBs at all.
In the Wicket 9.0.0 version, a simple form is displayed on the home page, allowing the user to enter their email address. When they submit the form, a test message is sent to that address. It works fine.
Then if I change the Wicket version to 9.3.0 but make no other changes at all, it doesn't even get to the stage of displaying the home page, it immediately crashes with the message "Last cause: net.sf.cglib.proxy.MethodInterceptor not found by org.objectweb.asm [23]"
For what it's worth, here's the code that triggers the error.
public class HomePage extends WebPage {
#EJB(name = "EmailerFacade")
private EmailerFacade emailerFacade;
private static final long serialVersionUID = 1L;
private String sendTo = "";
public HomePage(final PageParameters parameters) {
super(parameters);
add(new Label("version", getApplication()
.getFrameworkSettings().getVersion()));
FeedbackPanel feedback = new FeedbackPanel("feedback");
add(feedback);
final Form emailForm = new Form("emailForm") {
#Override
protected void onSubmit() {
emailerFacade.sendMessage(sendTo, "Test message from quick-start",
"Version is " + getApplication().getFrameworkSettings()
.getVersion());
info("Tried to send message to " + sendTo);
}
};
add(emailForm);
final TextField<String> emailAddress = new TextField<>("emailAddress",
new PropertyModel<>(this, "sendTo"));
emailAddress.setLabel(Model.of("Email address"));
emailAddress.setRequired(true);
emailForm.add(emailAddress);
}
}
Wicket 9.x is based on javax.servlet APIs. To deploy it on jakarta.servlet supporting web container you will need to migrate the bytecode with a tool like https://github.com/apache/tomcat-jakartaee-migration.
I am not sure whether Payara does something smart at runtime to support both javax.** and jakarta.** classes.
Tomcat 10.x supports migration of the classes at application start time by deploying your app in the special $CATALINA_HOME/webapps-javaee folder.
This answer was actually provided by Sven Meier. He commented:
Use the new system property to switch to ByteBuddy in Wicket 9.x:
-Dwicket.ioc.useByteBuddy=true
To expand a bit on this, I found I needed to do three things:
Set the system property "wicket.ioc.useByteBuddy" to true as specified by Sven
Add a dependency on byte buddy
Upgrade to a higher version than I was initially attempting to do: 9.3.0 was not good enough. I see in a comment above by Sven, he says that the migration to byte buddy was actually done in 9.5. So in fact I upgraded to the latest version, which is currently 9.9.1.
Here is the dependency on byte buddy that I added:
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.12.10</version>
</dependency>

How to add ApplicationInsights Logging Provider in Framework Console App Using Autofac

I am working on a .NET (full framework 4.7.1) console app that uses AutoFac for DI purposes.
We are in the process of migrating slowly to .NET Core, and have switched to using the ILogger abstractions provided by Microsoft.Extensions.Logging.Abstractions.
I have wired up ILogger<> and ILoggerFactory in AutoFac using the following
private static void RegisterLogging(ContainerBuilder builder)
{
builder.RegisterType<LoggerFactory>().As<ILoggerFactory>().SingleInstance();
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).InstancePerDependency();
}
This depends on Microsoft.Extensions.Logging - and it seems to be working.
Now I want to wire up the Application Insights Logging provider, however all the documentation I can find only mentions how to add it to the .NET Core DI Container, and looking through the source code on various repos, I am a bit mystified on how to do it.
I figured that I might be able to do it like this:
builder.RegisterType<ApplicationInsightsLoggerProvider>().As<ILoggerProvider>();
But it depends on IOptions<TelemetryConfiguration> telemetryConfigurationOptions and IOptions<ApplicationInsightsLoggerOptions> applicationInsightsLoggerOptions neither of which I have.
Have anybody done this, or have suggestions on how to accomplish it?
I managed to get something going by doing it like this:
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging();
serviceCollection.AddApplicationInsightsTelemetryWorkerService();
builder.Populate(serviceCollection);
Not the very best solution, but I guess it does allow me to use the footwork of the ServiceCollection extensions methods, so I might have to live with that if nobdoy has a better answer

ASP .NET Boilerplate + MongoDb

I am using ASP.Net boilerplate framework + SQL Server 2016 in my project. Recently I have faced a challenge with migration from SQL Server to MongoDB. I have found that it is possible with ASP .NET boilerplate and installed required NuGet packages, however, due to the lack of documentation the only thing I have managed to do is to define respective RepositoryBase class:
public abstract class MyRepositoryBase<TEntity, TPrimaryKey> : MongoDbRepositoryBase<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
protected MyRepositoryBase(IMongoDatabaseProvider databaseProvider)
: base(databaseProvider)
{
}
}
As far as I understand, first of all, I need to define connection string somewhere now. And then populate the database with required basic data(which previously had been done by EF Core migrations). Obviously, EF Core in the new approach is obsolete so does that mean for my DbContext class that it is obsolete as well?
Actually, there are plenty of questions in relation to ASP .NET boilerplate and MongoDB integration, therefore my current post is actually a request for provision of some kind of example of the existing integration. Thank you in advance.
You can register your module by depending on it on your web module.
[DependsOn(typeof(YourMongoDbModule))]
public class YourWebModule : AbpModule
{
}
I think you have to register the repository with:
IocManager.Register(typeof(IMongoRepository<>), typeof(MongoRepository<>), Abp.Dependency.DependencyLifeStyle.Singleton);
You can refer this sample.
Look at this comment also.
Here is a framework which maps EF Core to Mongo DB.

Access .NET Core Configuration Class From Another Assembly

In The Olden Days
In a web.config file, settings could be placed in an appSettings section like so:
<appSettings>
<add key="mysetting" value="123"/>
</appSettings>
Even though my web.config file was in my web project, any assemblies/libraries used in that project could access the settings using:
ConfigurationManager.AppSettings["mysetting"]
Today (and the problem)
I am starting to use .NET core, and just like before, I have assemblies/libraries that are not web projects in of themselves and need to access various configuration settings.
Microsoft's Configuration documentation (https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration) along with all of the other examples I can find, have the configuration class being consumed by a controller and don't provide any guidance on how to make it work with a class in another assembly/library that is not a controller.
For ONE example, if I have a custom attribute that I can decorate a class with and that custom attribute is defined in another library (not in a web project) and it needs to access a configuration setting, how do I do that today? I can't pass in anything to a constructor in such an instance either.
I'm going to assume you're talking about a ASPNET Core project as you specifically mention web.config.
Here's what you need to do.
IOptions<FooSettingsClass> is usually configured at application start which means that it's available at runtime with code that looks something like this.
// Adds services required for using options.
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("FooAppSettings"));
The easiest way is to have the framework inject it through the constructor. Typically you'll see it (as you mentioned) being injected in the controller like this:
class FooController : Controller {
public FooController(IOptions<FooSettingsClass> settings) { .
//..
}
}
If you need to access this configuration is say, a service, then you simply have a constructor, in a different assembly, which accepts those options. So:
public class SomeServiceInAnotherAssembly {
public SomeServiceInAnotherAssembly(IOptions<FooSettingsClass> settings) {
//..
}
}
This obviously means that your FooSettingsClass class needs to be outside of your ASPNET Core project (to avoid circular dependencies), but this is one way of propagating your configuration without writing any code, which is what I've seen other developers do. To me, writing code is a hoop jumping solution bound to have bugs.
Don't forget that your class (in this exampe SomeServiceInAnotherAssembly) needs to be registered at startup, i.e. services.AddScoped<SomeServiceInAnotherAssembly>();
The nice thing about this approach is that it makes your classes testable.
In 8-2017 Microsoft came out with System.Configuration.Manager for .NET CORE v4.4. Currently v4.5 and v4.6 preview.
Install this nuget package. Add directive to a code file
using System.Configuration;
Now, you can do your
var val = ConfigurationManager.AppSettings["mysetting"];
There is one trick for web sites though - you no longer use web.config for application settings and configuration sections. You use app.config as well as other types of projects. But if you deploy in ISS, you might need to use both. In web.config you supply strictly ISS-related entries. Your app-specific entries go to app.config

ASP.NET MVC 6 AspNet.Session Errors - Unable to resolve injected dependency?

I've been having a problem using the new Microsoft.AspNet.Session features in ASP.NET MVC 6 (vNext).
The error occurs when accessing all pages, including those that don't use the session features themselves. I'm using the beta4 version for everything, including all of my packages and my dnvm environment. The project is running on Visual Studio 2015 RC.
Here are some resources that might be important (if there's anything else anybody needs just comment):
Project.json: http://pastebin.com/qCA2AjGd
DNVM List: http://puu.sh/ja8us/4f912c0a9a.png
Global.json: http://pastebin.com/CFZp75KE
I think it's a problem with the dependency injection for the session package (see first two lines of the stack trace) but after that I'm not sure what to do about it.
Are you sure you've correctly registered the appropriate services in ConfigureServices?
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddOptions();
services.AddSession();
}
public void Configure(IApplicationBuilder app) {
app.UseSession();
}
}
Note: you need to explicitly register the options services as you're using beta4 packages.
This issue was fixed recently: https://github.com/aspnet/Session/commit/dab08ba7e90027a3bf1ef69f740427e93a310f09#diff-2990206dea5be4b3850cad8d4759d577R14

Resources