My old code looks like this:
public static class DbHelper {
// One conection per request
public static Database CurrentDb() {
if (HttpContext.Current.Items["CurrentDb"] == null) {
var retval = new DatabaseWithMVCMiniProfiler("MainConnectionString");
HttpContext.Current.Items["CurrentDb"] = retval;
return retval;
}
return (Database)HttpContext.Current.Items["CurrentDb"];
}
}
Since we don't have HttpContext anymore easily accesible in core, how can I achieve the same thing?
I need to access CurrentDb() easily from everywhere
Would like to use something like MemoryCache, but with Request lifetime. DI it's not an option for this project
There are at least 3 options to store an object per-request in ASP.NET Core:
1. Dependency Injection
You could totally re-design that old code: use the built-in DI and register a Database instance as scoped (per web-request) with the following factory method:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<Database>((provider) =>
{
return new DatabaseWithMVCMiniProfiler("MainConnectionString");
});
}
Introduction to Dependency Injection in ASP.NET Core
.NET Core Dependency Injection Lifetimes Explained
2. HttpContext.Items
This collection is available from the start of an HttpRequest and is discarded at the end of each request.
Working with HttpContext.Items
3. AsyncLocal<T>
Store a value per a current async context (a kind of [ThreadStatic] with async support). This is how HttpContext is actually stored: HttpContextAccessor.
What's the effect of AsyncLocal<T> in non async/await code?
ThreadStatic in asynchronous ASP.NET Web API
Will not the database or connection string would be same across the
requests?
If so then you could do it by a static variable and middleware.
The middleware would check and set the info on each request start and static variable would store the value then your method could read it from the static variable.
Other simpler approach would be to inject/pass the IHttpContextAccessor as parameter. With this you could do with minimal changes but you have the pass the IHttpContextAccessor service from each calling method.
Related
Scenario
I am trying to change my existing HttpClient to IHttpClientFactory. When I verified the existing code, its using using{...} statement which causes issues and it is mentioned here. So I thought of implementing singleton Http client and reached another blog related to this and it is here.
From all these, I understood that the best one is IHttpClientFactory introduced in .NET Core.
Implementation Plan
As this application is in ASP.NET MVC 4 and does not use DI, I have to do something to use without the DI framework. Based on my search, got answers from StackOverflow and planned to implement the same way. Meanwhile, I also got another project, which already removed all the dependencies and is ready to use in earlier projects without doing all things. The repo is HttpClientFactoryLite.
Question
Now I can use HttpClientFactoryLite by initializing this class? The description also mentioned it can be used along with the existing DI framework so that ClientFactory can be registered as a singleton. Please find the wordings from the readme
using HttpClientFactoryLite;
var httpClientFactory = new HttpClientFactory(); //bliss
If you are using dependency injection, make sure that IHttpClientFactory is registered as a singleton.
In my scenario, I don't have any DI framework added. So I am going to initialize the factory wherever I needed. Here I am confused that in 2 things
Is it necessary to make a singleton class for HttpClientFactoryLite?
How is this HttpClientFactory class disposed? Is there a need to dispose of it as part of the controller or same using statement etc?
Based on the answer from this, Microsoft.Extensions.Http provides the HttpClientFactory only, not the new optimized HttpClient. This is only available in .NET Core 2.1. So any difference in implementing IHttpClientFactory?
Please advise
ASP.NET 3.1:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<IHttpClientFactory, HttpClientFactory>();
}
ASP.NET will automatically pass the correct singleton to controllers which demand an IHttpClientFactory in their constructor.
Poormans variation without DI-Container:
public static class Singleton<TInterface>
{
private static TInterface instance;
public static TInterface Instance
{
get => instance;
private set => instance ??= value;
}
public static void Add<TConcrete>() where TConcrete : TInterface, new()
=> Instance = new TConcrete();
public static void Add<TConcrete>(TConcrete instance) where TConcrete : TInterface
=> Instance = instance;
// put dispose logic if necessary
}
Usage:
// Application Entrypoint
Singleton<IHttpClientFactory>.Add<HttpClientFactory>();
// Class/Controller Property
private readonly IHttpClientFactory httpClientFactory
= Singleton<IHttpClientFactory>.Instance;
It seems like the execution context is not kept until Dispose is called on elements resolved in the controller scope. This is probably due to the fact that asp.net core has to jump between native and managed code and resets the execution context at each jump. Seems like the correct context is not restored any more before the scope is disposed.
The following demonstrates the issue - simply put this in the default asp.net core sample project and register TestRepo as a transient dependency.
When calling GET api/values/ we set the value for the current task to 5 in a static AsyncLocal at the start of the call. That value flows as expected through awaits without any problem. But when the controller and its dependencies are disposed after the call the AsyncLocal context is already reset.
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly TestRepo _testRepo;
public ValuesController(TestRepo testRepo) => _testRepo = testRepo;
[HttpGet()]
public async Task<IActionResult> Get()
{
_testRepo.SetValue(5);
await Task.Delay(100);
var val = _testRepo.GetValue(); // val here has correctly 5.
return Ok();
}
}
public class TestRepo : IDisposable
{
private static readonly AsyncLocal<int?> _asyncLocal = new AsyncLocal<int?>();
public int? GetValue() => _asyncLocal.Value;
public void SetValue(int x) => _asyncLocal.Value = x;
public void Foo() => SetValue(5);
public void Dispose()
{
if (GetValue() == null)
{
throw new InvalidOperationException(); //GetValue() should be 5 here :(
}
}
}
Is this intentional? And if yes is there any workaround around this problem?
The behavior you are seeing is an unfortunate quirk in the way that ASP.NET Core works. It's unclear to me why Microsoft choose this behavior, but it seems copied from the way Web API worked, which has the exact behavior. Disposing is obviously done at the end of the request, but for some reason the asynchronous context is already cleared before that point, making it impossible to run the complete request in a single asynchronous context.
You've basically got two options:
Instead of using ambient state to share state, flow state through the object graph instead of using ambient state. In other words, make TestRepo Scoped, and store value in a private field.
Move the operation that uses that value to an earlier stage in the request. For instance, you can define some middleware that wraps a request and invokes that operation at the end. At that stage, the asynchronous context will still exist.
Some DI containers actually apply this second technique. Simple Injector, for instance, uses scoping that is based on ambient state, using AsyncLocal<T> under the covers. When integrated in ASP.NET Core, it will wrap the request in a piece of middleware that applies this scope. This means that any Scoped component, resolved from Simple Injector, will be disposed before the ASP.NET Core pipeline disposes its services, and this happens while the asynchronous context is still available.
How would I go about setting and accessing application-wide variables in ASP.NET Core 2.0?
Details:
I have a variable, let's call it CompanyName, which resides in the database and is used on literally every page. I don't want to hit the database every time I need to display the CompanyName. 100 years ago, I would have set Application["CompanyName']=CompanyName but I understand that this is not the way to do things in .NET Core. What would be the alternative?
A lot has progressed in the last 100 years. Some time ago, I believe in ASP.NET 1.0, the Application object in ASP classic was superseded with caching (although the Application object was left in for backward compatibility with ASP classic).
AspNetCore has replaced the caching mechanism of ASP.NET and made it DI-friendly, but it is still very similar to how the state of things was in ASP.NET. The main difference is that you now need to inject it instead of using the static HttpContext.Current.Cache property.
Register the cache at startup...
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
And you can inject it like...
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
public IActionResult Index()
{
string companyName = _cache[CacheKeys.CompanyName] as string;
return View();
}
Then to make it work application wide, you can use a filter or middleware combined with some sort of cache refresh pattern:
Attempt to get the value from the cache
If the attempt fails
Lookup the data from the database
Repopulate the cache
Return the value
public string GetCompanyName()
{
string result;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.CompanyName, out result))
{
// Key not in cache, so get data.
result = // Lookup data from db
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromMinutes(60));
// Save data in cache.
_cache.Set(CacheKeys.CompanyName, result, cacheEntryOptions);
}
return result;
}
Of course, you could clean that up and make a service with strongly typed properties as a wrapper around your cache that is injected into controllers, but that is the general idea.
Note also there is a distributed cache in case you want to share data between web servers.
You could alternatively use a static method or a statically registered class instance, but do note if hosting on IIS that the static will go out of scope every time the application pool recycles. So, to make that work, you would need to ensure your data is re-populated using a similar refresh pattern.
The primary difference is that with caching there are timeout settings which can be used to optimize how long the data should be stored in the cache (either a hard time limit or a sliding expiration).
You could create a Singleton-class called ApplicationWideSettings. Give that class public Properties. Initialize all the values you need one time and then use them by accesing the only instance of your class via:
ApplicationWideSettings.Instance.PropertyName;
Just make sure the namespace of the ApplicationWideSettings-class is referenced when you want to access it.
I prefer this over global/static settings because you have one class to save all your globally available data.
If you are unsure what a Singleton is I can just suggest you look into this article from Jon Skeet:
C# In Depth: Implementing the Singleton Pattern in C#
I am currently trying to get my head around structuremap now that the ObjectFactory static function has been marked as obsolete.
In the long run I have to use this in a MVC and WebApi application. When previously used, a line to a static method was placed in the the global.asax to initialise everything using the ObjectFactory.
ObjectFactory.Initialize{
container.For .....
}
Trying to convert this to the new IContainer approach I have come up with the following however am wondering if I have actually inadvertently implemented this often mentioned Anti-Pattern in my approach.
Static method to return container:
public class StructureMapConfig
{
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
}
Userservice's contstructor looks like this:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IStringService _stringService;
public UserService(IUserRepository userRepository, IStringService stringService)
{
_userRepository = userRepository;
_stringService = stringService;
}
Finally the initialise (this instance in a console app) looks somthing like this:
private static IUserService _userService;
private static IContainer _container;
static void Main(string[] args)
{
_container = StructureMapConfig.GetContainer();
_userService = _container.GetInstance<IUserService>();
}
So to my questions.
Am I doing anything seriously wrong here
In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.
Is returning the IContainer from the static method the best approach
If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.
Thanks for any advice.
To go through your questions in order:
Am I doing anything seriously wrong here
No, I don't see anything seriously wrong here. There are a few improvements you could make that I'll talk about shortly.
In the UserService, should I be passing the IContainer in and using
the object factory to get the instance or should I leave as is.
You're correct in injecting UserService over an instance of IContainer. If your controller only requires the UserService then why inject the entire container. Really you only want to inject the bare minimum of what you need to reduce unnecessary coupling and dependencies.
Is returning the IContainer from the static method the best approach
Within the removal of the ObjectFactory then yes, returning an instance of the container via a static method is a common approach for those classes whose creation is not managed via MVC's Dependency Resolution.
If this was a MVC app, is it best practice to build this once in the
Global.asax or should the controller constructor call the static
method every time.
Creating the container in Global.asax.cs is your best approach as it's done once on Application_Start, however see below for my recommendation of using a nested container per http request.
Improvements:-
Take advantage of StructureMap's registries:
Instead of referencing the dependencies directly like this:
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
Opt to use StructureMap's registries instead. This way you can group your dependencies (such as MVC specific dependencies or WebAPI specific dependencies, like so:
public class WebsiteRegistry : Registry
{
public WebsiteRegistry()
{
this.For<IUserService>().Use<UserService>();
this.For<IStringService>().Use<StringService>();
this.For<IUserRepository>().Use<UserRepository>();
}
}
Then load your registries like this:
container.Configure(c => {
c.IncludeRegistry<WebsiteRegistry>();
c.IncludeRegistry<TaskRegistry>();
});
HTTP Context bound containers:
Another recommended pattern when using StructureMap with ASP.NET MVC or WebApi (or any HTTP based application) is to use nested containers that are bound to each HTTP request. This basically involves creating a new nested container on each HTTP request and then disposing it at the end of the request. This ensures that dependencies such as session objects, database connections, or UoW contexts are disposed of as soon as the HTTP request is over.
I would recommend taking a look over this article which goes into more detail on the matter and talks about how this can be set up.
This is exactly the same technique that's used in the StructureMap.MVC5 package that's often recommended by StructureMap's creator, Jeremy Miller.
Auto registering dependencies
Instead of registering every dependency with StructureMap manually you can take advantage of StructureMap's auto-registration. You can also specify your own scanning conventions.
The simple injector documentation provides great examples on how to setup the container for WebRequest, Web API, WCF, ... but the examples are specific to one technology/lifestyle at a time. Our web application uses most of them together!
It is not clear to me how to configure the container to work with several lifestyles.
Let's say I have a MVC project with Web API. I have the following objects:
MyDbContext : My entity code first db context
IMyDataProvider implemented by MyDataProvider : Contains query logic and uses MyDbContext
MyController : MVC controller that uses IMyDataProvider
MyApiController : WebApi controller that uses IMyDataProvider
Should I create and configure one container for each type of lifestyle ?
When I register everything with RegisterPerWebRequest<T> is works in both types of controllers. Is this safe ? Or will I run into trouble when using async/await in a Web API controller?
What is the best configuration when I have both MVC and Web API controllers who get injected the same instances ?
Should I use a hybrid lifestyle ?
Now to complicate things... our application also uses background tasks and SignalR.
Both of these will sometimes occur outside of a WebRequest and need access to the same objects as described above.
The best solution would be to use a Lifetime scope ?
Would I need to create a new container for that lifestyle? or can I reuse/reconfigure my MVC/Web API container ?
Is there a triple lifestyle?
I have to say, I stumble on a similar scenario some time ago, I ended up by sharing my configuration over my web API and signalR, but you need to implement a custom lifestyle for signalR since it's not based on web request.
specially in signalR you'll find some issues handling per-web-request dependencies in a Hub some of them are going to be null like httpContext.Current among others.
The solution:
You need a hybrid lifestyle between WebRequestLifestlye and either Lifestyle.Transient, Lifestyle.Singleton, or LifetimeScopeLifestyle. I ended up I finished using the decorator pattern, you may read this post and this other post.
my decorator
public class CommandLifetimeScopeDecorator<T> : ICommandHandler<T>
{
private readonly Func<ICommandHandler<T>> _handlerFactory;
private readonly Container _container;
public CommandLifetimeScopeDecorator(
Func<ICommandHandler<T>> handlerFactory, Container container)
{
_handlerFactory = handlerFactory;
_container = container;
}
public void Handle(T command)
{
using (_container.BeginLifetimeScope())
{
var handler = _handlerFactory(); // resolve scoped dependencies
handler.Handle(command);
}
}
}
public interface ICommandHandler<in T>
{
void Handle(T command);
}
I managed the dependencies using a hub activator for signalR
public class MyHubActivator : IHubActivator
{
private readonly Container _container;
public MyHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return _container.GetInstance(descriptor.HubType) as IHub;
}
}
a composite root file which is where you are going to handle your dependencies
public CompositRoot(Container container)
{
_container = container;
}
public container Configure()
{
// _container.Registerall container dependencies
return _container;
}
then share your composite root configuration when you are bootstrapping your app
var compositRoot = new CompositRoot(simpleInjector.Container); //simple injector instance
compositRoot.Configure();
For signalR
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new MyHubActivator(compositRoot));
and you may reuse your configuration among other projects!
my two cents
hope that helps!
Usually you don't need to have one container per lifestyle; In general you want to have one container instance per AppDomain. However, mixing Web API in the same project with MVC is from an architectural point of view a horrible idea IMO (as explained here, here, and here). So in case you are separating those parts into their own architectural blocks, you will already have less problems already.
But in case you are running MVC and Web API in the same project, this basically means that you will always be using Web API. The WebApiRequestLifestyle was explicitly built to work:
well both inside and outside of IIS. i.e. It can function in a
self-hosted Web API project where there is no HttpContext.Current.
(source)
In general, it is safe to use the WebRequestLifestyle in case you are only running in IIS when you have no intention to spin of parallel operations using ConfigureAwait(false) (which should be really rare IMO) as explained here.
So in the case you are still mixing Web API with MVC in the same project, there's no reason to use a hybrid lifestyle; you can simply use the same lifestyle. For doing background processing you might however need to build a hybrid lifestyle, but it every scenario needs a different hybrid. However, hybrids can be stacked up and you can easily create a 'triple lifestyle' if needed.
Since you want to do background processing with SignalR, you need to decide in what type of scoped lifestyle to run those background operations. The most obvious lifestyle is the LifetimeScopeLifestyle and this means you should make your scoped registrations using the following scoped lifestyle:
var hybridLifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => HttpContext.Current != null,
trueLifestyle: new WebRequestLifestyle(),
falseLifestyle: new LifetimeScopeLifestyle());
A lifetime scope however needs to be started explicitly (as were the web request scope gets started implicitly for you if you include the SimpleInjector.Integration.Web.dll in your web application). How to do this depends on your design, but this q/a about SignalR might point you in the right direction.