I need to provide an api to a long running windows service which does a bunch of processing and retains a memory of that history. An api is required to provide status on current activity levels of the system (records processed, records waiting to be processed, etc).
I was wanting to use a self-hosted Owin ApiController to provide a nice interface to the system. However, the ApiController is completely stateless and there is no method (after searching dozens of IoC posts) for injecting an already active instance into the controller.
Is there a way to provide a class instance to an ApiController?
I don't think you can inject an old instance of the controller, because you get a new instance every time you perform a request.
However you can create a singleton object with a collection inside, and you can inject it into the controller constructor and use in every request.
You can also use some sort of persistence such as DB, that you can run on your device.
Here is an example for a singleton class:
using System;
public class Singleton
{
public Dictionary<string,object> State {get; private set;}
private static Singleton instance;
private Singleton() {
State = new Dictionary<string,object>();
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
Even though you can get Session state in web api controller, it is going to be questionable solution, instead, I would recommend going the following way:
include Hangfire as dependancy and use it for long running tasks
Use signal-r to to push state of background task
return JobID from your API method and use it on the client to subscribe to signal-r hub
Related
I need to keep an object in memory for the lifetime of the ASP.NET Core application in which I serialize this object and store it in durable storage as a snapshot. Later on in the life-cycle of the object I need to restore the state of this object by de-serializing it and replacing the singleton. It doesn't have to be a singleton but I need to guarantee that there's only a single instance of the object.
I tried the following but it seems it only replaces it for the current request and nothing after that. I assume the DI container makes it's own copy of the object but I'm not sure
internal static SingleObject SingleObject { get; set; } = new SingleObject();
services.AddSingleton<OrderBook>(SingleObject)
Is there a way to replace the singleton instance or will I have to roll my own singleton class that handles this scenario?
I would invite you to read How to configure services based on request in ASP.NET Core.
After that (container being built), the registrations can't be changed
anymore. #Tseng
You can only register scopes once during startup, so you could register functions related to what you want to update/refresh later on. I would recommend if you have something that needs to change implementing a cache or in memory storage that you trigger a refresh when desired.
I had a singleton of CachedData until realized needed to fast reset it at some point. So just implemented a wrapper (see below). Now the wrapper ResettableCachedData is singleton, and CachedData is transient. At any time a can do a quick Reset() to recreate CachedData, while accessing it's data via ResettableCachedData.Data.
public class ResettableCachedData
{
private readonly IServiceProvider _services;
public ResettableCachedData(IServiceProvider services)
{
_services = services;
Reset();
}
public CachedData Data { get; protected set; }
public void Reset()
{
Data = _services.GetRequiredService<CachedData>();
}
}
From https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2:
Singleton
Singleton lifetime services are created the first time they're requested (or when ConfigureServices is run and an instance is specified with the service registration). Every subsequent request uses the same instance. If the app requires singleton behavior, allowing the service container to manage the service's lifetime is recommended. Don't implement the singleton design pattern and provide user code to manage the object's lifetime in the class.
So, you don't need to implement the Singleton pattern your self. The DI takes care of that.
The only thing you should do now is injecting it.
Register as follow:
services.AddSingleton<SingleObject>(new SingleObject())
I'm in a situation where the classic functionality of vnext's DI container is not enough to provide me with the correct functionality. Let's say I have a DataService that gets data from a database like this:
public class DataService : IDataService, IDisposable {
public List<MyObject> GetMyObjects()
{
// do something to fetch the data...
return myObjects;
}
}
I can then register this service in the DI container during the configuration phase in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(typeof(IDataService), typeof(DataService));
}
This ensures the correct lifecylce of the service (one per request scope), however, I need the service to access a different database when a different request is made. For simplicity reasons, let's say the following scenario applies:
when a request to my Web API is made, the DataService will access the currently logged in user, which contains a claim called Database which contains the information which database to use.
the DataService is then instantiated with the correct database connection.
In order to get the second step to work, I have created a constructor for the DataService like this:
public DataService(IHttpContextAccessor accessor)
{
// get the information from HttpContext
var currentUser = accessor.HttpContext.User;
var databaseClaim = currentUser.Claims.SingleOrDefault(c => c.Type.Equals("Database"));
if (databaseClaim != null)
{
var databaseId = databaseClaim.Value;
// and use this information to create the correct database connection
this.database = new Database(databaseId);
}
}
By using the currently logged in user and his claims, I can ensure that my own authentication middleware takes care of providing the necessary information to prevent attackers from trying to access the wrong database.
Of course adding the IDisposable implementation is required to cleanup any database connections (and gets called correctly using the scope lifecycle).
I can then inject the DataService into a controller like this
public MyController : Controller
{
private IDataService dataService;
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
This all works fine so far.
My questions now are:
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Is this method really safe? Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
What you have is fine.
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Not really. You can use delegate registration but it's the same problem.
Is this method really safe?
Yes
Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
Nope. The IHttpContextAcessor uses AsyncLocal (http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html) to provide access to the "current" http context.
In a couple of .NET C# webservice projects that i have done i have made access to db static with help of the singleton pattern. Then the other day my friend told me that this is a bad thing to do, because if a lot of request is made for the same db entity then the db would be locked because of the static instance. Is my friends assumptations right? I thought that every new request would make a new instance of the class?
The implementation of the singleton class looks like this:
public class WebService
{
private readonly IFactory _factory;
public WebService(IFactory factory)
{
_factory = factory;
}
public IDataRepository Data
{
get
{
return _factory.GetDatabase();
}
}
}
public static class WebServiceImpl
{
private static readonly WebService _webService = new WebShop(new WebserviceFactoryImpl());
public static WebService webService { get { return _webService; } }
}
_factory.GetDatabase() returns a new instace of the Database class.
Looking at WebServiceImpl, all calls will be sharing a single WebService instance. Now, this isn't necessarily a problem, depending on how that is implemented; for example, if _factory.GetDatabase(); ends up getting called per-request, then it might be that you are getting away with it. Depending further on what GetDatabase() does - i.e. does it get a new instance per call? or does it give you the same instance every time? Simply: we don't have enough information there to answer fully. But:
sharing a single database connection between requests is dangerous; either you need to lock / synchronize, or you risk lots of errors (database connections are not usually written to be thread-safe)
sharing an ORM between requests is even worse: in addition to everything above, you also get issues with data accumulating in the identity / object cache; ORM instances (data-context, etc) are intended to be short-lived and then discarded (and sometimes: disposed)
Having static access to the database is not necessarily a problem; it all comes down to how that is implemented - for example, a static-based API could still create (and dispose) a connection on every call.
Background/Question:
I'm fairly new to the singleton design pattern. I've used it once in a web application (with the help of the SO community):
public static AppGlobal Instance
{
get
{
if (HttpContext.Current.Session != null)
{
HttpSessionState session = HttpContext.Current.Session;
if (session["AppGlobalInstance"] == null)
{
session["AppGlobalInstance"] = new AppGlobal();
}
return (AppGlobal)session["AppGlobalInstance"];
}
else
{
return null;
}
}
}
The above implementation makes sense to me because the instance of the AppGlobal is stored in the session. When the session dies, AppGlobal dies. What happens if I use the same design pattern in a class library that is called by a web application? For example, the users requests a page that calls methods in a DLL that doesn't know about the session. Will the data stored in the singleton instance be persisted through multiple calls?
private static readonly Singleton instance = new Singleton();
private Singleton() { }
public static Singleton Instance
{
get
{
return instance;
}
}
Additional Information:
Here's what I'm trying to accomplish: I have a web application that is going to receive XML requests from a third party application. This XML will tell my web application to do one of three things (or all three of them). I would like to have a singleton instance of a class that stores data that can be accessed by multiple classes. I want the singleton instance to DIE after each request. If the above doesn't accomplish this, what's the best way to accomplish it?
Note: This web application runs on a single server and will never run on a farm.
EDIT 1:
Based on the suggestion below, I've used System.Web.HttpContext.Current.Session to store my class instance. Does this look like the correct approach for a singleton that will be unique to each session (remember I'm in a class library)?
public static Ariba Instance
{
get
{
if (HttpContext.Current.Session != null)
{
HttpSessionState session = HttpContext.Current.Session;
if (session["AribaInstance"] == null)
{
session["AribaInstance"] = new Ariba();
}
return (Ariba)session["AribaInstance"];
}
else
{
return null;
}
}
}
It will be persisted through multiple calls, but there is one caveat. The static variables are scoped to the AppDomain, so any time the IIS worker process is recycled, any data stored in a static variable will be lost. The same is true of session data, if you're storing it "in proc."
If you want an object that will only exist for the duration of the HTTP request, you can use the HttpContext.Items property.
Because the singleton is static, your data will be available for all the requests in your web application, so it will not be available only for the session.
But in ASP.NET applications, you should avoid using Singletons. Instead you should use the Application object. Main reason for that is that if you will use a web farm then your singleton is no longer singelton for the application scope but only on the machine.
Oh!
If you want to use the instance PER REQUEST, why don't you pass it as a parameter to the methods you are calling or as a constructor parameter for the classes that requires the xml. This will be the best design approach, I think.
I have a WCF service that is using a custom UsernamePasswordValidator. The validator needs to access my entity framework context.
I would like to create one ObjectContext for the entire service call and then destroy/dispose it at the end of the call. So I created a singleton static class that provided this functionality, however, what's happening now is that if two service calls happen concurrently, one of the calls disposes the singleton.
I either keep a local reference to the ObjectContext, in which case the second service to use it sees it as disposed and throws and error, or, I put a wrapper property around the Singleton class wherever I need it and then all my changes get thrown away because I'm getting a new instance of the object if another call has disposed it.
So basically my question is how do I instantiate an ObjectContext per service call?
NOTE: The instance needs to be accesible in both the service code AND the custom UsernamePasswordValidator code.
I can't just do it in the constructor or use a using statement because then the custom UsernamePasswordValidator doesn't have access to it. Is there a way to have a static class per call? It does sound impossible, but what's the way around this? Should I be caching the object in a session?
My service is hosted in IIS.
UPDATE:
So I've nailed this down to storing state in the InstanceContext using an IExtension object. But How do I access the current InstanceContext in a UsernamePasswordValidator?
Ok, so in the end I solved it by using the following static class and relying on ASP.NET to cache the context for me.
I'm not sure if this is the best way to do things, but this allows me to use one ObjectContext per request so I'm not spinning up too many and this also means I don't have to use a lock on the object which would become a nightmare if many users were using the service.
public static class MyContextProvider
{
public static MyModel Context
{
get
{
if (HttpContext.Current.Items["context"].IsNull())
{
HttpContext.Current.Items["context"] = new MyModel();
}
return HttpContext.Current.Items["context"] as MyModel;
}
}
}
Then wherever I need an ObjectContext in the app I just call
var context = MyContextProvider.Context;
You have one instance per call, you also have 1 call per instance.
So it should be very simple, use a using () { } block in the toplevel of your OperationContract method.
Ok, here is the class with thread-safe static method that provides single ObjectContext entity model object for any WCF service call and automatically dispose it at the end of call:
public static class EntityModelProvider
{
private static readonly Dictionary<OperationContext, MyEntityModel> _entityModels = new Dictionary<OperationContext, MyEntityModel>();
public static MyEntityModel GetEntityModel()
{
if (OperationContext.Current == null)
throw new Exception("OperationContext is missing");
lock (_entityModels)
{
if (!_entityModels.ContainsKey(OperationContext.Current))
{
_entityModels[OperationContext.Current] = new MyEntityModel();
OperationContext.Current.OperationCompleted += delegate
{
lock (_entityModels)
{
_entityModels[OperationContext.Current].Dispose();
_entityModels.Remove(OperationContext.Current);
}
};
}
return _entityModels[OperationContext.Current];
}
}
For your service, you can specify a service behaviour which details the instance mode of the service:
[ServiceBehaviour(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService {
ObjectContext context;
}
A cleaner way may be to use the ServiceAuthenticationManager, which is in .NET 4.
http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx
From the Authenticate method (which you'll override) you can access the Message object and set properties on it. I've not used it in anger, so YMMV :)
EDIT the problem with this approach is that you don't have the Username and Password, so will still need the custom Authentication.
Take a look at the UsernameSecurityTokenAuthenticator...
http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.usernamesecuritytokenauthenticator(v=vs.90).aspx
Further reading from my research:
Answers to this question gives some hints about how to use it:
Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager?
If you can read (or ignore) the Russian, I found useful hints at:
http://www.sql.ru/forum/actualthread.aspx?tid=799046
This rather good CodeProject article goes further (encryption and compression as well as custom authorization)
http://www.codeproject.com/Articles/165844/WCF-Client-Server-Application-with-Custom-Authenti
Why not pass in the context into your CustomValidator when you assign to the service - store your object context in your validator, and in the overridden validation method new it up if need be. Then you still have access to the object through the Services CutomUserNameValidator ..
Depending on what you are asking :
Create your separate ObjectContext class as a dynamic object - add that as a property to you CustomValidator.
In your custom Validator - you can now check if the object is disposed and create the object again if need be.
Otherwise if this is not what you are after - just store the Context in the validator - you still have access on server side.
The code here is just generalized idea - I am just posting it as a frame of reference so you can have an idea of what I talking about.
public DynamicObjectContextObjectClass
{
ObjectContext internalObjectContext;
}
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator
{
public DynamicObjectContextObjectClass dynamiccontext;
public override void Validate(string userName, string password)
{
if(dynamiccontext.internalObjectContext.isdisposed)
{
dynamiccontext.internalObjectContext = new Context;
}
try
{
if (string.IsNullOrEmpty(userName) || password == null)
{
//throw new ArgumentNullException();
throw new FaultException("Username cannot be null or empty; Password cannot be null and should not be empty");
}
}
}
}