Disposing of EF DbContext with ninject, when moving away from using statements - c#

I am working with SQL server 2008, .NET4.5, MVC4, EF6 and Ninject3.2.
I have application that needs to be migrated to use DI with Ninject. DbContext that has to be injected in to Controllers is OnlineLegal.
Currently it is used following in each of Actions.
using (var db = new OnlineLegal())
{
...
}
This makes it clearly visible where OnlineLegal is being used and disposed of.
If I would set up ninject kernel.Bind<OnlineLegal>().ToSelf().InRequestScope(); would this be sufficient to make sure that it is disposed properly on each request in MVC4? If not should I manually register OnePerRequestModule? Or use some other way to do it?

It is sufficient. Provided you have installed the Ninject.MVC4 package ;-).
However, there's recently been quite a few question about InRequestScope not working. I think currently the ninject setup is a bit error prone to mistake and/or issues with package installation/upgrade routines.
As such i would recommend to use .InRequestScope() but also add one (exemplar and automated) integration test which verifies that .InRequestScope() actually properly performs the disposal.
That will show you that you've integrated it correctly and if in future there should be trouble with package upgrade routines you'll find out immediately and can fix it, rather than finding out in production or through some obscure effects.
Documentation link: https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope
Ninject.MVC4 depends on Ninject.Web.Common.Webhost. Ninject.Web.Common.WebHost adds NinjectWebCommon.cs code to your application's app_start folder.
NinjectWebCommon.cs loads the OnerPerRequestModule. However if you remove that file you will break .InRequestScope(). The bad thing about this is, that it fails without exception. You can still bind .InRequestScope() but it just won't have any effect.

Related

How to best deploy Sentry in cross-assembly environment?

So we built this library/framework thing full of code related to business processes and common elements that are shared across multiple applications (C#, .Net 4.7.1,WPF, MVVM). Our Logging stuff is all set up through this framework so naturally it felt like the best place for Sentry. All the references in our individual applications are manually pointed to the dlls the folder where our shared library thingy installs itself. So far so good.
When we set up Sentry initially everything seemed to work great. We do some updates and errors seem to be going way down. That's cause we are awesome and Sentry helped us be more awesome, right? Nope! Well I mean kind of.
The scope is being disposed of so we are no longer getting Unhandled exceptions. We didn't notice at first because we are still getting sentry logs when we are handling errors through our Logging.Log() method. This logging method calls SentrySdk.Init() which I suspect is disposing the client in the executing assembly.
We also started using Sentry for some simple Usage tracking by spinning up a separate project in Sentry called Usage-Tracker and passing a simple "DoThingApplication has been launched" with an ApplicationName.UsageTracker Enum as a parameter to our Logging method.
Question: What is a good way to handle this where my setup can have a Sentry instance that wraps my using(sentryClientStuff){ ComposeObjects(); } and still have my logging method look for the existing client and use it if it exists?
Caveats:
I believe before any of this happens we still need to make a call to send a Sentry log to our UsageTracker.
I would like to pass in as few options as possible if I'm setting up the Sentry Client/Scope in our shared library. Maybe Release and Environment. Maybe check tags for Fingerprint and set it in the Log method.
I'm open to new approaches to any of this.
Some related thoughts
Maybe there is a better way to handle references that could solve both this and some other pains of when they have become mismatched between client and shared framework/library thing
Maybe the answer can be found through adding some Unit Tests but I could use a Sentry specific example or a nudge there because I don't know a muc about that.
Maybe there is a way to use my shared library to return a Sentry Client or Scope that I could use in my client assembly that would not be so fragile and the library could somehow also use it.
Maybe there is a better solution I can't conceive because I'm just kind of an OK programmer and it escapes me. I'm open to any advice/correction/ridicule.
Maybe there is a smarter way to handle "Usage-Tracker" type signals in Sentry
Really I want a cross-assembly singleton kind of thing in practice.
There are really many things going on here. Also without looking at any code it's hard to picture how things are laid out. There's a better chance you can get the answer your are looking for if you share some (dummy even) example of the structure of your project.
I'll try to break it down and address what I can anyway:
With regards to:
Usage-Tracker:
You can create a new client and bind to a scope. That way any use of the SentrySdk static class (which I assume your Logger.Log routes to) will pick up.
In other words, call SentrySdk.Init as you currently do, with the options that are shared across any application using your shared library, and after that create a client using the DSN of your Usage-Tracker project in sentry. Push a scope, bind the client and you can use SentrySdk with it.
There's an example in the GitHub repo of the SDK:
using (SentrySdk.PushScope())
{
SentrySdk.AddBreadcrumb(request.Path, "request-path");
// Change the SentryClient in case the request is to the admin part:
if (request.Path.StartsWith("/admin"))
{
// Within this scope, the _adminClient will be used instead of whatever
// client was defined before this point:
SentrySdk.BindClient(_adminClient);
}
SentrySdk.CaptureException(new Exception("Error at the admin section"));
// Else it uses the default client
_middleware?.Invoke(request);
} // Scope is disposed.
The SDK only has to be initialized once but you can always create a new client with new SentryClient, push a new scope (SentrySdk.PushScope()) and bind it to that new scope (SentrySdk.BindClient). Once you pop the scope the client is no longer accessdible via SentrySdk.CaptureException or any other method on the static class SentrySdk.
You can also use the client directly, without binding it to the scope at all.
using (var c = new SentryClient(new SentryOptions { Dsn = new Dsn("...") })) {
c.CaptureMessage("hello world!");
}
The using block is there to make sure the background thread flushes the event.
Central place to initialize the SDK:
There will be configuration which you want to have fixed in your shared framework/library but surely each application (composition root) will have its own setting. Release is auto-discovered.
From docs.sentry.io:
The SDK will firstly look at the entry assembly’s AssemblyInformationalVersionAttribute, which accepts a string as value and is often used to set a GIT commit hash.
If that returns null, it’ll look at the default AssemblyVersionAttribute which accepts the numeric version number.
If you patch your assemblies in your build server, the correct Release should be reported automatically. If not, you could define it per application by taking a delegate that passes the SentryOptions as argument.
Something like:
Framework code:
public class MyLogging
{
void Init(Action<SentryOptions> configuration)
{
var o = new SentryOptions();
// Add things that should run for all users of this library:
o.AddInAppExclude("SomePrefixTrueForAllApplications");
o.AddEventProcessor(new GeneralEventProessor());
// Give the application a chance to reconfigure anything it needs:
configuration?.Invoke(o);
}
}
App code:
void Main()
{
MyLogging.Init(o => o.Environment = "my env");
}
The scope is being disposed of so we are no longer getting Unhandled exceptions."
Not sure I understand what's going on here. Pushing and popping (disposing) scopes don't affect the ability of the SDK to capture unhandled exceptions. Could you please share a repro?
This logging method calls SentrySdk.Init() which I suspect is disposing the client in the executing assembly.:
Unless you create a client "by hand" with new SentryClient, there's only 1 client in the running process. Please note I said running process and not assembly. Instances are not held within an assembly. The assembly only contains the code that can be executed. If you call SentrySdk.CaptureException it will dispatch the call to the SentryClient bound to the current scope. If you didn't PushScope, there's always an implicit scope, the root scope. In this case it's all transparent enough you shouldn't care there's a scope in there. You also can't dispose of that scope since you never got a handle to do so (you didn't call PushScope so you didn't get what it returns to call Dispose on).
All the references in our individual applications are manually pointed to the dlls the folder where our shared library thingy installs itself.:
One thing to consider, depending on your environment is to distribute packages via NuGet. I'm unsure whether you expect to use these libraries in non .NET Framework applications (like .NET Core). But considering .NET Core 3.0 is bringing Windows Desktop framework support like WPF and WinForm, it's possible that eventually you will. If that's the case, consider targeting .NET Standard instead of .NET Framework for your code libraries.

Msoft.Practices.Unity injection of a library that uses services pattern

Good Morning,
I have a legacy full framework(4.7) MVC application. This application uses unity for DI.
We need to make use of the Steeltoe.CloudFoundry.Connector.Redis nuget package. This package however is expecting / used by startup.cs which I don't have.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddRedisConnectionMultiplexer(Configuration);
.PersistKeysToRedis();
services.AddDistributedRedisCache(Configuration);
}
What I am trying to figure out is how to use this with unity so I can have the Steeltoe redis connection object available for DI.
Since the steeltoe projects is OSS I could just grab the source and implement directly but then I have to maintain it.
(Speculation) I could have unity generate specific classes in the nuget package...
using Steeltoe.CloudFoundry.Connector.Redis;
....
container.Resolve(RedisCacheServiceCollectionExtensions)
Any other ideas?
TIA
You could do the initial implementation under Steeltoe, submit a pull request and let the community maintain it from there.
Steeltoe's lack of support for any given DI framework isn't intentional, but rather due to a lack of pre-existing demand. We'd be happy to help you through the process of getting the code included if you're interested.

NHibernate - Creating a proxy instance failed (on IIS8 but ok with dev server)

I have to work on already developed solution which is using NHibernate (v1.2.1.4000) with SQL Server 2008.
The application is using .NET Framework 2.0 due to Membership authentication and other stuffs.
This is working in Visual Studio - I can debug it, run in. But failed when deployed in IIS (v8.0)
Exception is:
Duplicate type name within an assembly.
HibernateException: Creating a proxy instance failed.
And it occurred whenever database is fetched to get some models.
I have googled on this issue and have some suggestion to use nhiberante (v3.3.x).
But the lots of interfaces and method parameters are different in v3. so it is breaking implementaion of the source code.
Several questions regarding this exist on stackoverflow but no luck yet
Maybe you have a concurrency trouble, something like singleton initialization failing to ensure uniqueness of its initialization, occurring only under load.
Especially check your session factory. Put logs when building it, check it is not built multiple times. Try triggering your singleton initializations from Application_Start if they are not already triggered from there.
Avoid singleton lazy initializations unless they are really heavy and not needed for most of you application HTTP requests. In such case, make sure their logic is thread safe and avoid running concurrent initializations (something like LazyThreadSafetyMode ExecutionAndPublication instead of PublicationOnly: it requires stricter locking but must be done that way for building the ISessionFactory, if it is done through lazy initialization.)

DbConfigurationTypeAttribute in code vs. codeConfigurationType in web.config

We're working on an EF6 application, that uses a custom DbConfiguration class. Up til now, we've been configuring system to use our DbConfiguration, rather than creating a default, by decorating each DbContext class with a DbConfigurationTypeAttribute.
We installed an instance on our QA site, today, and were getting HTTP 500 errors. After turning off CustomErrors, so we could see the detail, we saw:
An instance of 'DbConfigurator' must be set at application start
before using any Entity Framework features or must be registered in
the application's config file.
This confused me, because according to Microsoft, the DbConfigurationTypeAttributes should have worked:
https://msdn.microsoft.com/en-us/data/jj680699#Moving
And they did work, on our Development machines. And I am absolutely certain that each of our DbContext objects is so decorated.
Not knowing what else to do, I added the codeConfigurationType attribute to the entityFramework element in the web.config and everything ran fine.
I then tried removing the DbConfigurationTypeAttributes from the code, thinking that defining this in multiple places was a bad idea. And all my unit tests proceeded to fail - they don't access the web.config. That part, at least, makes sense.
The rest of it, though, confuses me. Why do the DbConfigurationTypeAttributes not work, when running in IIS7?

How to easily tell if Ninject can resolve a class

I'm introducing Ninject into a large mess of a existing project. I want to write a diagnostic test to make sure that all of the classes Ninject will end up creating can actually BE resolved by Ninject...without actually creating any of them.
The reason I want to avoid the actual construction is that many of these classes have a tendency to start up database operations in their constructors (sigh yes I know). Otherwise I would just run them all through Get<T> with a try/catch
There's a CanResolve extension on IResolutionRoot (i.e., you can use it against Kernel if you have the right usings in place). There's a CreateRequest that you use to create the request. Have a look in the sources and tests if you need an example or any deeper information.
I know this is an old post but it was the first one I found when searching for how to find if a class can be resolved by Ninject without actually calling get() and risking an exception.
Ninject version 3.0.2 have a method CanResolve which returns a boolean:
kernel.CanResolve<T>()
I got 3.0.2 from nuget but its currently market unstable (Ninject.3.0.2-unstable-9037) so I'm not sure if I use this in production just yet.

Categories

Resources