How to add Application Insights to ILogger<T> for Unity DI into WCF Service - wcf

I have the unfortunate task of updating a WCF project to .NET Framework 4.8 and replacing the existing log4net exception handling with Microsoft Logging and Application Insights.
My approach was to implement Dependency Injection to make instantiation easier and because I am already used to that design approach with .NET Core. As you may know, WCF services adds its own complexity since WCF is responsible for instantiating the services and lower level objects (like custom customUserNamePasswordValidatorType). I was able to handle most of this by implementing a WCF Service Factory and updating the svc markup with it.
I have added Application Insights to the project via the appropriate NuGet packages which updates the web.config with appropriate httpModules for general exception handling. I was even able to add a custom TelemetryInitializer in Application_Start to include a few custom properties in the message.
My problem is getting an instance of ILogger<T> with the attached Application Insights provider into the instantiated service.
At first, I was getting an exception because of the parameterless constructor of Logger<T>. This was fixed by updating my WcfServiceFactory to the following
container
...
.RegisterType<ILoggerFactory, LoggerFactory>(TypeLifetime.Singleton)
.RegisterType(typeof(ILogger<>), typeof(Logger<>), TypeLifetime.Singleton);
This allowed an instance of the logger to be passed into the constructor of each service. However, calls to log messages are never written to App Insights and an inspection of the logger shows zero providers.
My guess is that because a new instance of LoggerFactory is being created, the already existing instance used in the httpModules is ignored.
According to https://github.com/unitycontainer/microsoft-logging, I need to refactor what I am doing and actually create an instance of a LoggerFactory and manually add the desired providers. My issue is that I cannot figure out how to do that with Application Insights. Everywhere else I used it, I would just call the AddApplicationInsights() extension method but that does not seem to be an option here (at least not with Unity).
So I guess my issue boils down to the following questions
Can I get the WcfServiceFactory to use the existing App Insights logging? Maybe establish something in Global.asx?
How can I manually register App Insights as a provider in the WcfServiceFactory including the custom telemetry?

No need to use ILogger if the intention is just to log a custom error. You can log exception on AppInsights directly using the telemetry client, like this:
var telemetryClient = new TelemetryClient(TelemetryConfiguration.Active);
telemetryClient.TrackException(new Exception("Logged random exception message."));

Related

System.InvalidOperationException: An attempt was made to use the context while it is being configured

I have implemented custom ASP.NET Core middleware which uses database context as a dependency. Sometimes it throws the following exception for the very first request coming to the API:
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: An attempt was made to use the
context while it is being configured. A DbContext instance cannot be
used inside OnConfiguring since it is still being configured at this
point. This can happen if a second operation is started on this
context before a previous operation completed. Any instance members
are not guaranteed to be thread safe.`
I could reproduce it only when API was called from SPA. When I called API from Swagger everything was working just fine. Changing order of middlewares didn't help. After digging around I realized that middleware was instantiated once per application while the database context had a scoped lifetime. So perhaps the issue was in injecting my database context right into middleware's constructor. I fixed my code by removing injection of database context from constructor and injecting it directly to InvokeAsync method. This helped and exception gone.
Though I solved my issue I don't quite understand yet how it worked at all. As far as I understand the EF.Core database context by default is registered with scoped lifetime what in terms of ASP.NET Core application means that new context gets instantiated for every new request and disposed upon its completion. Because I injected the database context into middleware's constructor it should have been disposed right after first request finished and this exceptions or another one saying that it's trying to use already-disposed context should have been thrown. Also it's absolutely not clear to me why this error was happening only when API got called from SPA while it was working good for all Swagger requests.
Seems I have figured it out. I didn't mention that I use Autofac service provider instead of default service provider in my application which in fact was worth to mention. According to ASP.NET Core documentation
The Default Service Provider in Development environment performs
checks to verify that:
Scoped services aren't directly or indirectly resolved from the root service provider.
Scoped services aren't directly or indirectly injected into singletons.
Apparently Autofac service provider doesn't perform such checks so it allows to inject scoped services from root service provider. And according to documentation
The root service provider's lifetime corresponds to the app/server's
lifetime when the provider starts with the app and is disposed when
the app shuts down.
This is why my application worked as expected though I injected scoped service into singleton. It used the instance of DbContext resolved from the root service provider and sometime I could get such situation when I tried to perform query to database before the context was actually initialized. This explains the sporadic nature of this issue.
I had the same issue, I resolved it as mentioned in the answers to this question.
added "ServiceLifetime.Transient" option to the db context.
at Startup.cs added:
services.AddDbContext<TableContext>(opt =>
..otherOptions.., ServiceLifetime.Transient);

How to save info in asp.net core startup to be available in app

I have a set of 7 .Net Framework WebApi-based services that all share some common design elements. One shared element is that each will include the service version in the data that it returns from any of its endpoints. In each service, I determine the version from the executing assembly using reflection. I do this in Application_Start and store the result in a property that I create on the Global class that inherits from System.Web.HttpApplication. That way I do the reflection work once and access the result later from each of my methods.
I'm building a new service and this one is built on ASP.NET Core. So I'm trying to figure out how to do the same thing in ASP.NET Core. I can add the reflection logic in Startup.Configure (though it's not really about configuring the Http pipeline which is what Configure is supposed to be doing). Is there a better place than Startup.ConfigureServices or Startup.Configure, to put code that you want to run once on startup?
And where would I store the result to make it readily accessible to each of the downstream methods called from my controller actions?

WCF deserializing body error because of adding async behind the method name

I've created a WCF service with a method GetTestValue. I've also created a test application to test this service.
When I add this WCF service with connected service to the test application I can only call GetTestValueAsync, there is no GetTestValue method. Somehow this add process add this async thing behind the method name. So in this test application, the WCF call works fine when I call GetTestValueAsync. I get the result back.
Then I've created a Xamarin cross application app where I added this WCF service too, and when I call the GetTestValueAsync from this application I get the following error:
Error in deserializing body of request message for operation 'GetTestValue'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GetTestValue' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'GetTestValueAsync' and namespace 'http://tempuri.org/'
Somehow strange in the test project it works fine, and in the Xamarin cross application not.
Did someone have the same problem?
Why is this connected service always this Async to my method name?
How can I stop this Async being added to the method name?
Thanks for any help.
At the moment Xamarin apps aren't compatible with the Task-based asynchronous WCF proxy methods that the WCF Web Service Reference connected service provider generates (bugzilla.xamarin.com Bug 51959).
One way to generate an older, compatible style of WCF proxy methods is to run SvcUtil.exe with the /async and /tcv:Version35 switches in a Developer Command Prompt. That will generate synchronous proxy methods, Begin/End style Asynchronous Programming Model (APM) callback proxy methods, and event-based proxy methods, all of which are compatible with Xamarin apps.
(Note: If you leave out the /async switch, SvcUtil.exe will generate the newer, incompatible Task-based proxy methods.)
Duplicate: By chance, I replied on a more recent duplicate of this question first:
How to use WCF services in .netstandard with Xamarin.Forms project?
I know this is old, but I had the same problem and searched a while. When you are adding the Reference in your project, you can check "generate synchronized operations" and the "Async"-suffix aren't generated anymore. My VS runs in german language, so I just translated the options. If your adding new methods the setting will be considered too.
Greetings from germany.

Ninject Di bindings using a WCF service

I recently created a WCF service library. I am planning on hosting it in IIS. Since I want to reuse my repository layer I decided to go use Ninject in my WCF service as well (I use it in other projects in the solution).
I installed the Ninject Wcf Extensions. I configured it using the NinjectServiceHostFactory in the svc file. I added a Global.asax file to override the CreateKernel() that inherits from NinjectWcfApplication but I am not sure if I am using the bindings correctly. I first started with:
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
But I quickly realized that this does not work since no data was saved to my database. It appears that the WCF service does not use the ASP.NET pipeline. I went ahead and tried both of these as well just to see if my data was committed to the database:
Bind<IUnitOfWork>().To<UnitOfWork>().InThreadScope();
Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
No luck. I then decided to try:
Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
This worked but I don't want my database context to be shared by every single request that comes in to the WCF service. I then did some research and found the following approach:
Bind<IUnitOfWork>().To<UnitOfWork>().InScope(c => OperationContext.Current);
This works but is it correct? I wan t something to resemble the InRequestScope for a MVC application. Each request to the service should get its own Database context.
I suggest to have a look at the latest build from the CI-Server http://teamcity.codebetter.com
You need Ninject, Ninject.Web.Common, Ninject.Extensions.Wcf
With this version you can use InRequestScope for Wcf.
I am new to Ninject, but I can tell you that OperationContext.Current is the equivalent to HttpContext.Current for web application.
So your first thought was to use .InRequestScope(); (which is equivalent to .InScope(c => HttpContext.Current);)
so I guess that using .InScope(c => OperationContext.Current); for WCF is pretty correct.

WCF - if service initialisation fails custom validation, deactivate service

how would you best go about the task of deactivating further use of a IIS6 or 7 hosted WCF service based on framework 3.5, when a custom condition is detected.
I thought perhaps that you could create a static constructor in the service implementation (i.e. .svc code behind file) that validates my app settings, should one of the settings be invalid, I could throw an exception. Thinking that the WCF infrastructure would fail to start and so IIS would provide a 401 error (or alike) when browsing the svc file.
I feel this is to easy, im thinking perhaps this is not the right thing to do, perhaps i need to be implementing another WCF interface to plug into some sort of WCF activation logic and signal a no-start. Or something like that?
Any ideas.
Many thanks
Chris
I have found that the best place to do this is by creating a custom service factory implementation. Perform the validation before service creation, if it fails then throw an exception there, not in the constructor of the service implementation.