I am using StructureMap.MVC5 which relies on the PreApplicationStart method to register an HttpModule and initialize the IoC container. Is it possible to get the server name the page is executing on at this point so that I can set an environment specific property in the IoC initialization?
I was able to resolve this issue by moving the IoC initialization to the Application_BeginRequest method, where the HttpContext has already been set. In order to ensure that the IoC container was not reinitialized on each call to Application_BeginRequest, I was able to use a mutex block, thus negating the need to move this code to somewhere earlier in the page lifecycle.
public class FirstInitialization
{
private static Object s_lock = new Object();
public static string URL { get; protected set; }
// Initialise only on the first request
public static string Initialize(HttpContext context)
{
if (string.IsNullOrEmpty(URL))
{
lock (s_lock)
{
if (string.IsNullOrEmpty(URL))
{
URL = HttpContext.Current.Request.Url.AbsoluteUri;
}
DependencyResolver.SetResolver(IoC.GetDependencyResolver(URL));
}
}
return URL;
}
}
Related
In an MVC / WebAPI environment I would use InRequestScope to bind the DbContext.
However, I am now on a Console application / Windows service / Azure worker role (doesn't really matter, just there's no Web request scope), which periodically creates a number of Tasks that run asynchronously. I would like each task to have its own DbContext, and since tasks run on their own thread, I tried binding DbContext using InThreadScope.
Unfortunately, I realize that the DbContext is not disposed when a task is finished. What actually happens is, the thread returns to the Thread Pool and when it is assigned a new task, it already has a DbContext, so DbContexts stay alive forever.
Is there a way InThreadScope can be used here or should I use some other scope? How can ThreadScope be used when threads are returning from ThreadPool every now and then?
If you decide to go on with custom scope, the solution is:
public sealed class CurrentScope : INotifyWhenDisposed
{
[ThreadStatic]
private static CurrentScope currentScope;
private CurrentScope()
{
}
public static CurrentScope Instance => currentScope ?? (currentScope = new CurrentScope());
public bool IsDisposed { get; private set; }
public event EventHandler Disposed;
public void Dispose()
{
this.IsDisposed = true;
currentScope = null;
if (this.Disposed != null)
{
this.Disposed(this, EventArgs.Empty);
}
}
}
Binding:
Bind<DbContext>().To<MyDbContext>().InScope(c => CurrentScope.Instance)
And finally:
using (CurrentScope.Instance)
{
// your request...
// you'll get always the same DbContext inside of this using block
// DbContext will be disposed after going out of scope of this using block
}
I have an MVC application in which I have a controller that receives data from the user and then uploads a file to Azure blob storage. The application is using Unity IoC to handle dependency injection.
During the workflow I have isolated the following code as demonstrating the problem
public class MvcController : Controller
{
private IDependencyResolver _dependencyResolver;
public MvcController() : this(DependencyResolver.Current)
{
}
public MvcController(IDependencyResolver dependencyResolver)
{
this._dependencyResolver = dependencyResolver;
}
public GetService<T>()
{
T resolved = _dependencyResolver.GetService<T>()
if (resolved == null)
throw new Exception(string.Format("Dependency resolver does not contain service of type {0}", typeof(T).Name));
return resolved;
}
}
public class MyController : MvcController
{
[NoAsyncTimeout]
public async Task<ActionResult> SaveFileAsync(/* A bunch of arguments */)
{
/* A bunch of code */
//This line gets a concrete instance from HttpContext.Current successfully...
IMyObject o = GetService<IMyObject>();
await SaveFileToAzure(/* A bunch of parameters */);
.
.
/* Sometime later */
Method2(/* A bunch of parameters */);
}
private Method2(/* A bunch of parameters */)
{
//This line fails because HttpContext.Current is null
IMyObject o = GetService<IMyObject>();
/* A bunch of other code */
}
private async Task SaveFileToAzure(/* A bunch of parameters */)
{
//Grab a blob container to store the file data...
CloudBlobContainer blobContainer = GetBlobContainer();
ICloudBlob blob = blobContainer.GetBlockBlobReference(somePath);
Stream dataStream = GetData();
System.Threading.CancellationToken cancelToken = GetCancellationToken();
//All calls to DependencyResolver.GetService<T>() after this line of code fail...
response = await blob.UploadStreamAsync(dataStream, cancelToken);
/* A bunch of other code */
}
}
Unity has a registration for my object:
container.RegisterType<IMyObject, MyObject>(new HttpLifetimeManager());
My lifetime manager is defined as follows:
public sealed class HttpRequestLifetimeManager : LifetimeManager
{
public Guid Key { get; private set; }
public HttpRequestLifetimeManager()
{
this.Key = Guid.NewGuid();
}
public override object GetValue()
{
return HttpContext.Current.Items[(object)this.Key];
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[(object)this.Key] = newValue;
}
public override void RemoveValue()
{
HttpContext.Current.Items.Remove((object)this.Key);
}
}
Nothing complicated.
Stepping into the HttpRequestLifetimeManager on the failing GetService() calls shows that after the UploadStreamAsync() call HttpContext.Current is null...
Has anyone else come across this problem? If so, is this a bug? Is this expected behaviour? Am I doing something out of the ordinary? What should I do to resolve it?
I can hack around it by storing a reference to HttpContext.Current prior to the offending call and restoring it after, but that doesn't seem like the right approach.
Any ideas?
To echo #Joachim - http context may not be available to your async thread. Compare the current thread id where you can see httpcontext is available, to the thread id where you can see that it isn't - i'm assuming you will see they are 2 different threads. If my assumption is correct this may be a sign that your main thread (the one with httpcontext) does not have a "synchronizationcontext". (you can see http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx for more details of how that works) If so, it may mean that the code immediately after your await statement is actually not running on the same thread as the code prior to the await statement! So from your perspective, one moment you have http context and the next you don't because execution has actually been switched to another thread! You should probably look at implementing / setting a synchronizationcontext on your main thread if that's the case and then control will be returned to your original thread with http context and that should fix your problem, or alternatively you could retrieve your object from http context on the original thread and find a way to pass it as a parameter to the async method/s so that they don't need to access http context to get their state.
I'm trying to create a long running windows service, so I need to run the actual worker class on a separate thread, to avoid the "service did not respond in a timely fashion" error when I right click and select start in Windows Service Manager.
The worker class ("NotificationProcess") has a whole raft of dependencies and I'm using Autofac to satisfy these.
I'm really not sure how to set up Autofac for the worker class. At the moment I'm getting errors telling me that the DbContext has been disposed when I go to use it in the "Execute" method of the worker class.
I guess I'm looking for how to write a windows service and use a new thread for the worker class with dependencies satisfied by autofac.
I've googled and can't find any examples of this.
Any suggestions would be awesome.
Here's what I've got so far...
Program.cs:
static class Program
{
static void Main()
{
using (var container = ServiceStarter.CreateAutoFacContainer())
{
var service = container.Resolve<NotificationService>();
if (Environment.UserInteractive)
{
service.Debug();
}
else
{
ServiceBase.Run(container.Resolve<NotificationService>());
}
}
The Service class:
public partial class NotificationService : ServiceBase
{
private NotificationProcess _app;
readonly ILifetimeScope _lifetimeScope;
public NotificationService(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_app = _lifetimeScope.Resolve<NotificationProcess>();
_app.Start();
}
The worker class:
public class NotificationProcess
{
private Thread _thread;
private readonly IBankService _bankService;
private readonly IRateService _rateService;
private readonly IEmailService _emailService;
private readonly IRateChangeSubscriberService _rateChangeSubscriberService;
private readonly IRateChangeNotificationService _rateChangeNotificationService;
private readonly ILogManager _logManager;
public NotificationProcess(IBankService bankService, ILogManager logManager, IRateService rateService, IEmailService emailService,
IRateChangeSubscriberService rateChangeSubscriberService, IRateChangeNotificationService rateChangeNotificationService)
{
_bankService = bankService;
_rateService = rateService;
_emailService = emailService;
_rateChangeSubscriberService = rateChangeSubscriberService;
_rateChangeNotificationService = rateChangeNotificationService;
_logManager = logManager;
}
public void Start()
{
_thread = new Thread(new ThreadStart(Execute));
_thread.Start();
}
public void Execute()
{
try
{
var rateChangeToNotify = _rateService.GetRateChangesForNotification();
foreach (var rateChange in rateChangeToNotify)
{
//do whatever business logic.....
}
}
}
The answer is actually simple: use scoping! You should do the following:
Register all services (such as DbContext) that should live for the duration of a request or action with the LifetimeScope lifestyle. You'll usually have a timer in your windows service. Each 'pulse' can be considered a request.
On the beginning of each request begin a lifetime scope.
Within that scope, resolve the root object from the object graph and call its method.
Dispose the scope.
In your case that means you need to change your design, since NotificationService is resolved once and its dependencies are reused on another thread. This is a no-no in dependency injection land.
Here's an alternative design:
// This method is called on a background thread
// (possibly in a timely manner)
public void Run()
{
try
{
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<NotificationService>();
service.Execute();
}
}
catch (Exception ex)
{
// IMPORTANT: log exception.
// Not logging an exception will leave us in the dark.
// Not catching the exception will kill our service
// because we run in a background thread.
}
}
Using a lifetime scope allows you to get a fresh DbContext for every request and it would even allow you to run requests in parallel (with each request its own DbContext).
I have created a plugin which inspects a param in the query string and loads up a user object based on this ID and populates
any request DTO with it. (All my request DTO's inherit from BaseRequest which has a CurrentUser property)
public class CurrentUserPlugin : IPlugin
{
public IAppHost CurrentAppHost { get; set; }
public void Register(IAppHost appHost)
{
CurrentAppHost = appHost;
appHost.RequestFilters.Add(ProcessRequest);
}
public void ProcessRequest(IHttpRequest request, IHttpResponse response, object obj)
{
var requestDto = obj as BaseRequest;
if (requestDto == null) return;
if (request.QueryString["userid"] == null)
{
throw new ArgumentNullException("No userid provided");
}
var dataContext = CurrentAppHost.TryResolve<IDataContext>();
requestDto.CurrentUser = dataContext.FindOne<User>(ObjectId.Parse(requestDto.uid));
if (requestDto.CurrentUser == null)
{
throw new ArgumentNullException(string.Format("User [userid:{0}] not found", requestDto.uid));
}
}
}
I need to have this User object available in my services but I don't want to inspect the DTO every time and extract from there. Is there a way to make data from plugins globally available to my services? I am also wondering if there is another way of instantiating this object as for my unit tests, the Plugin is not run - as I call my service directly.
So, my question is, instead of using Plugins can I inject a user instance to my services at run time? I am already using IoC to inject different Data base handlers depending on running in test mode or not but I can't see how to achieve this for User object which would need to be instantiated at the beginning of each request.
Below is an example of how I inject my DataContext in appHost.
container.Register(x => new MongoContext(x.Resolve<MongoDatabase>()));
container.RegisterAutoWiredAs<MongoContext, IDataContext>();
Here is an example of my BaseService. Ideally I would like to have a CurrentUser property on my service also.
public class BaseService : Service
{
public BaseService(IDataContext dataContext, User user)
{
DataContext = dataContext;
CurrentUser = user; // How can this be injected at runtime?
}
public IDataContext DataContext { get; private set; }
public User CurrentUser { get; set; }
}
Have you thought about trying to use the IHttpRequest Items Dictionary to store objects. You can access these Items from any filter or service or anywhere you can access IHttpRequest. See the src for IHttpRequest.
Just be mindful of the order that your attributes, services and plugins execute and when you store the item in the Items dictionary.
Adding:
We don't want to use HttpContext inside of the Service because we want use Service in our tests directly.
Advantages for living without it
If you don't need to access the HTTP
Request context there is nothing stopping you from having your same
IService implementation processing requests from a message queue which
we've done for internal projects (which incidentally is the motivation
behind the asynconeway endpoint, to signal requests that are safe for
deferred execution).
http://www.servicestack.net/docs/framework/accessing-ihttprequest
And we don't use http calls to run tests.
So our solution is:
public class UserService
{
private readonly IDataContext _dataContext;
public UserService(IDataContext dataContext)
{
_dataContext = dataContext;
}
public User GetUser()
{
var uid = HttpContext.Current.Request.QueryString["userId"];
return _dataContext.Get<User>(uid);
}
}
and
container.Register(x => new UserService(x.Resolve<IDataContext>()).GetUser()).ReusedWithin(ReuseScope.Request);
This is service signature:
public SomeService(IDataContext dataContext, User user) { }
Any suggestions?
I need to have this User object available in my services but I don't want to inspect the DTO every time and extract from there
How will your application know about the user if you're not passing the 'userid' in the querystring? Could you store the user data in the Session? Using a Session assumes the client is connected to your app and persists a Session Id (ss-id or ss-pid cookie in ServiceStack) in the client that can be looked up on the Server to get the 'session data'. If you can use the Session you can retrieve the data from your service doing something like
base.Session["UserData"] or base.SessionAs<User>();
Note: you will need to save your User data to the Session
Is there a way to make data from plugins globally available to my services? but I can't see how to achieve this for User object which would need to be instantiated at the beginning of each request.
This sounds like you want a global request filter. You're kind of already doing this but you're wrapping it into a Plugin.
I wrote about this topic in another question.
However, I've since refactored my code to get rid of configuration access, thus allowing the specs to pass. Or so I thought. They run fine from within Visual Studio using TestDriven.Net. However, when I run them during rake using the mspec.exe tool, they still fail with a serialization exception. So I've created a completely self-contained example that does basically nothing except setup fake security credentials on the thread. This test passes just fine in TD.Net, but blows up in mspec.exe. Does anybody have any suggestions?
Update: I've discovered a work-around. After researching the issue, it seems the cause is that the assembly containing my principal object is not in the same folder as the mspec.exe. When mspec creates a new AppDomain to run my specs, that new AppDomain has to load the assembly with the principal object in order to deserialize it. That assembly is not in the same folder as the mspec EXE, so it fails. If I copied my assembly into the same folder as mspec, it works fine.
What I still don't understand is why ReSharper and TD.Net can run the test just fine? Do they not use mspec.exe to actually run the tests?
using System;
using System.Security.Principal;
using System.Threading;
using Machine.Specifications;
namespace MSpecTest
{
[Subject(typeof(MyViewModel))]
public class When_security_credentials_are_faked
{
static MyViewModel SUT;
Establish context = SetupFakeSecurityCredentials;
Because of = () =>
SUT = new MyViewModel();
It should_be_initialized = () =>
SUT.Initialized.ShouldBeTrue();
static void SetupFakeSecurityCredentials()
{
Thread.CurrentPrincipal = CreatePrincipal(CreateIdentity());
}
static MyIdentity CreateIdentity()
{
return new MyIdentity(Environment.UserName, "None", true);
}
static MyPrincipal CreatePrincipal(MyIdentity identity)
{
return new MyPrincipal(identity);
}
}
public class MyViewModel
{
public MyViewModel()
{
Initialized = true;
}
public bool Initialized { get; set; }
}
[Serializable]
public class MyPrincipal : IPrincipal
{
private readonly MyIdentity _identity;
public MyPrincipal(MyIdentity identity)
{
_identity = identity;
}
public bool IsInRole(string role)
{
return true;
}
public IIdentity Identity
{
get { return _identity; }
}
}
[Serializable]
public class MyIdentity : IIdentity
{
private readonly string _name;
private readonly string _authenticationType;
private readonly bool _isAuthenticated;
public MyIdentity(string name, string authenticationType, bool isAuthenticated)
{
_name = name;
_isAuthenticated = isAuthenticated;
_authenticationType = authenticationType;
}
public string Name
{
get { return _name; }
}
public string AuthenticationType
{
get { return _authenticationType; }
}
public bool IsAuthenticated
{
get { return _isAuthenticated; }
}
}
}
Dan,
thank you for providing a reproduction.
First off, the console runner works differently than the TestDriven.NET and ReSharper runners. Basically, the console runner has to perform a lot more setup work in that it creates a new AppDomain (plus configuration) for every assembly that is run. This is required to load the .dll.config file for your spec assembly.
Per spec assembly, two AppDomains are created:
The first AppDomain (Console) is created
implicitly when mspec.exe is
executed,
a second AppDomain is created by mspec.exe for the assembly containing the specs (Spec).
Both AppDomains communicate with each other through .NET Remoting: For example, when a spec is executed in the Spec AppDomain, it notifies the Console AppDomain of that fact. When Console receives the notification it acts accordingly by writing the spec information to the console.
This communiciation between Spec and Console is realized transparently through .NET Remoting. One property of .NET Remoting is that some properties of the calling AppDomain (Spec) are automatically included when sending notifications to the target AppDomain (Console). Thread.CurrentPrincipal is such a property. You can read more about that here: http://sontek.vox.com/library/post/re-iprincipal-iidentity-ihttpmodule-serializable.html
The context you provide will run in the Spec AppDomain. You set Thread.CurrentPrincipal in the Because. After Because ran, a notification will be issued to the Console AppDomain. The notification will include your custom MyPrincipal that the receiving Console AppDomain tries to deserialize. It cannot do that since it doesn't know about your spec assembly (as it is not included in its private bin path).
This is why you had to put your spec assembly in the same folder as mspec.exe.
There are two possible workarounds:
Derive MyPrincipal and MyIdentity from MarshalByRefObject so that they can take part in cross-AppDomain communication through a proxy (instead of being serialized)
Set Thread.CurrentPrincipal transiently in the Because
(Text is required for formatting to work -- please ignore)
Because of = () =>
{
var previousPrincipal = Thread.CurrentPrincipal;
try
{
Thread.CurrentPrincipal = new MyPrincipal(...);
SUT = new MyViewModel();
}
finally
{
Thread.CurrentPrincipal = previousPrincipal;
}
}
ReSharper, for example, handles all the communication work for us. MSpec's ReSharper Runner can hook into the existing infrastructure (that, AFAIK, does not use .NET Remoting).