IRequiresRequest and Injecting IRequest

@mythz, just wondering whether you think this is a good strategy.

I have a number of dependencies of my services that require the IRequest.
It would be useful to have the IRequest instance injected to these dependencies, just like other dependencies are.

I know that we can override OnPreExecuteServiceFilter and do the injection of IRequest manually (using reflection), if the dependency derives from IRequiresRequest, as we are already doing like this:

       public override object OnPreExecuteServiceFilter(IService service, object request, IRequest httpReq, IResponse httpRes)
        {
            service.InjectRequestIntoServiceDependencies(httpReq);

            return base.OnPreExecuteServiceFilter(service, request, httpReq, httpRes);
        }

This can cost dearly in performance though on every request.

Is there another way to get the current IRequest instance into the IOC container every request? Perhaps with a GlobalFilter or some other mechanism in the request pipeline?

Failing that ( I think in the past you have recommended that the container stay readonly), so what about registering a IRequestFactory in the container that has a method that can return the current IRequest. Then some clever way (i.e. globalfilter or OnPreExecuteServiceFilter() code) that sets the IRequest that the factory uses?

Seems like this is an area where the framework has not gone too far (probably for good reason), but we are finding it difficult to access the IRequest reliably from our dependencies in a maintainable way that keeps things modular.

In my point of view is much reliable to pass IRequest (or even not the whole IRequest, but only properties that you need to access to) as parameter to methods of your code instead of injecting it. This will bring on additional dependencies, but in this case you can control lifetime of the object in parameter and can be sure that you access current request in the scope of proper request and not mixed with another.

If some object like instance of IRequest is saved into a static object to keep the current context it must have [AsyncLocal] attribute when used with async methods (ServiceStack uses async methods for processing requests). Otherwise when other thread with another Request or the same thread in other async context and other Request accesses this property it will receive wrong value. Reproducing, debugging and resolving such async context switching issues is a very difficult task.

In contrary passing IRequest (or some of its properties) as parameter guarantees that you always on the same thread and same async context when accessing this object. And it will not mixed with another requests when switching threads or async context on the same thread and you do not need to use time-consuming reflection to inject it into other classes. So in this case is much simpler to debug the code and see when and what was changed.

2 Likes

I agree with @xplicit your problems are stemming from trying to treat items that are only available at runtime such as IRequest as a statically configured dependency. If you just pass the info you need from IRequest as parameters into your dependency APIs that need them then you wouldn’t have any issues and your classes would also be much easier to test.

OK, thanks guys. I accept all that.

It must be that we have been seeing the async issues manifest themselves with registered dependencies that use the injected IRequest when using ReuseScope.Request.

We will take steps to design the pattern.