21

I've got a MVC WebApi owin (soft hosted) project, that uses Unity for resolving controller dependencies

which look like this

public class PacientaiController : ODataController
    {
        private readonly IEntityRepo<Ent.Pacientas> repo;

        public PacientaiController(IEntityRepo<Ent.Pacientas> repo)
        {
            this.repo = repo;
        }

the problem I'm trying to solve - is how do I pass 'OwinContex' into a Repo.

public class PacientasEntityRepo:IEntityRepo<Pacientas>,IDisposable
    {
        public PacientasEntityRepo(IOwinContext ctx)
        {
        .........

If I try to register it like this in the Startup.cs

Container.RegisterType<IOwinContext>(new InjectionFactory(o => HttpContext.Current.GetOwinContext()));

I get a null ref, saying that HttpContext.Current is NULL

The main idea here, is to pass the currently authenticated user to the repo, because Repo host the Logic for querying the Database, depending on the user. (say if the user is Admin, then return this data, if the user is guest - return this data)

The point being - that this is a self Host !

Alexandr Nikitin
  • 7,258
  • 2
  • 34
  • 42
Marty
  • 3,485
  • 8
  • 38
  • 69
  • Disregard my answer, I hadn't read the *self-hosted* part – Jcl Jan 05 '15 at 14:20
  • 3
    I can't be the only person who reads this and thinks there a smell, specifically, about the Repo needing access to the *OWIN* context? Yes, it might need to make some decisions based on the current user but surely obtaining that information and just exposing an `IPrincipal` or something similar to the repo would make more sense? – Damien_The_Unbeliever Jan 05 '15 at 15:02
  • 1
    Yes it might. It doesn't affect the problem in anyway, cause I still need to access the OwinContext or RequestContext, take out the current principal, and give it to IoC to inject to the dependency being constructed. Doesn't matter if it's a IOwinContext or IPrinciple, or IUserRole. It still live's in the 'RequestsContext'. the the Question is about the communication principles in such or similar situation. – Marty Jan 05 '15 at 15:10

4 Answers4

27

Lets put aside why you have this design and concentrate to the problem: injecting the IOwinContext:

you can also get it from a HttpRequestMessage instance with the GetOwinContext method, however you also need to get a HttpRequestMessage somehow.

Unity does not support injection of the HttpRequestMessage out of the box but you can use a custom DelegatingHandler which stores the current HttpRequestMessage in the container as described here: Inject WebAPI UrlHelper into service using Autofac

The linked question is about Autofac but you can transfer it for work with Unity:

The CurrentRequest and the CurrentRequestHandler can be used from Andrew Davey's answer as it is:

public class CurrentRequest
{
    public HttpRequestMessage Value { get; set; }
}

public class CurrentRequestHandler : DelegatingHandler
{
    protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var scope = request.GetDependencyScope();
        var currentRequest = (CurrentRequest)scope.GetService(typeof(CurrentRequest));
        currentRequest.Value = request;
        return await base.SendAsync(request, cancellationToken);
    }
}

Then you just need to register the DelegatingHandler with:

httpConfiguration.MessageHandlers.Insert(0, new CurrentRequestHandler());

And register the CurrentRequest and IOwinContext in the container

container.RegisterType<CurrentRequest>(
            new HierarchicalLifetimeManager());

container.RegisterType<IOwinContext>(
    new HierarchicalLifetimeManager(),
    new InjectionFactory(c => c.Resolve<CurrentRequest>().Value.GetOwinContext()));

httpConfiguration.DependencyResolver = new UnityHierarchicalDependencyResolver(container);

Beside the custom delegation handler there are other places to hook into Web.API to capture the HttpRequestMessage for example you can create your own IHttpControllerActivator and use the ExecuteAsync method as described here: Dependency Injection in ASP.NET Web API 2

Community
  • 1
  • 1
nemesv
  • 138,284
  • 16
  • 416
  • 359
3

In a selfhosted application you do not have a HttpContext. You need an other way to move the state around. An option is to use a self implemented HttpContext like:

https://github.com/danielcrenna/graveyard/tree/master/httpcontext-shim

Peter
  • 27,590
  • 8
  • 64
  • 84
  • I know that there is no HttpContext. Thus the question. But - there IS "OwinContext" that is present in each request and in each controller, action ect.. The problem is getting it at the point of constructing the dependencies ! – Marty Jan 05 '15 at 15:02
  • You can pass the context around by using constructor injection. Inject the owincontext into your logic layer as constructor parameter. – Peter Jan 06 '15 at 07:12
1

I think the problem is that HttpContext does not exist at the time Startup is called, so what you probably need, is to have a Func instead, like this:

public class PacientasEntityRepo:IEntityRepo<Pacientas>,IDisposable
{
    public PacientasEntityRepo(Func<IOwinContext> ctx)
    {
    .........

and then change the code in Startup to this:

Container.RegisterType<IOwinContext>(new InjectionFactory(() => HttpContext.Current.GetOwinContext()));
Steen Tøttrup
  • 3,755
  • 2
  • 22
  • 36
  • 2
    In a selfhosted application you do not have a `HttpContext` because you don't even reference `System.Web` so the `HttpContext.Current.GetOwinContext()` does not compile! Your anwer is only usable if the Web.Api is hosted in IIS but the OP explicitly asked for the self-hosted scenario. – nemesv Jan 08 '15 at 07:43
  • Well, the OP stated the HttpContext was null, so I guess he has a reference to System.Web, so I was asking the question – Steen Tøttrup Jan 08 '15 at 08:15
  • Yeah, maybe the OP has the HttpContext type but it is definitly will be always Null in selfhosted mode as stated in [peer](http://stackoverflow.com/a/27781420/872395)'s and also in [Jcl](http://stackoverflow.com/users/68972/jcl)'s already deleted answer which by the away suggested a very similar solution as you. – nemesv Jan 08 '15 at 08:17
0

In my Asp.Net Mvc (AutoFac) project (not core) i have used below registeration andthat was successed

builder.RegisterType<OwinContext>().AsImplementedInterfaces().InstancePerRequest();
Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35