2016-06-08 7 views
0

Ich habe eine MVC/Webapi-Anwendung, die ich um eine benutzerdefinierte Fabrik Bindung mit Ninject zu kämpfen habe. Ich muss in der Lage sein, auf HttpContext zuzugreifen, von meinem Verständnis muss ich eine benutzerdefinierte Fabrik haben, um das zu verwenden.Erstellen einer Factory mit Ninject zu binden HttpContextBase nicht erhalten Werte

So habe ich

public interface IHttpContextFactory 
{ 
    HttpContextBase Create(); 
} 

public class HttpContextFactory:IHttpContextFactory 
{ 
    private readonly HttpContextWrapper _httpContext; 

    public HttpContextFactory(HttpContextWrapper contextWrapper) 
    { 
     _httpContext = contextWrapper; 
    } 

    public virtual HttpContextBase Create() 
    { 
     return _httpContext; 
    } 
} 

Ich versuche, die Fabrik in einem Dienst zu nutzen über

public class ApplicationService:IApplicationService 
{ 
    private readonly ILog _log; 
    private readonly IHttpContextFactory _contextFactory; 

    public ApplicationService(ILog log,IHttpContextFactory contextFactory) 
    { 
     _log = log; 
     _contextFactory = contextFactory; 
     if (_httpContextService == null) 
     { 
      throw new ArgumentNullException("httpContextService"); 
     } 
     if (_log == null) 
     { 
      throw new ArgumentNullException("log"); 
     } 
    } 

    public virtual string GetControllerName() 
    { 
     var factory = _contextFactory.Create(); 
     var controllerName = factory.Request.RequestContext.RouteData.Values["controller"].ToString(); 
     return controllerName; 

    } 
} 

Meine ninject Bindung sieht aus wie

public static class NinjectWebCommon 
{ 
    private static readonly Bootstrapper bootstrapper = new Bootstrapper(); 

    /// <summary> 
    /// Starts the application 
    /// </summary> 
    public static void Start() 
    { 
     DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule)); 
     DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule)); 
     bootstrapper.Initialize(CreateKernel); 
    } 

    /// <summary> 
    /// Stops the application. 
    /// </summary> 
    public static void Stop() 
    { 
     bootstrapper.ShutDown(); 
    } 

    /// <summary> 
    /// Creates the kernel that will manage your application. 
    /// </summary> 
    /// <returns>The created kernel.</returns> 
    private static IKernel CreateKernel() 
    { 
     var kernel = new StandardKernel(); 
     //Instruct the Kernel to rebind the HttpConfiguration to the default config instance provided from the GlobalConfiguration 
     kernel.Rebind<HttpConfiguration>().ToMethod(context => GlobalConfiguration.Configuration); 

     try 
     { 
      kernel.Bind<Func<IKernel>>().ToMethod(ctx =>() => new Bootstrapper().Kernel); 
      kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); 

      RegisterServices(kernel); 
      return kernel; 
     } 
     catch 
     { 
      kernel.Dispose(); 
      throw; 
     } 
    } 

    /// <summary> 
    /// Load your modules or register your services here! 
    /// </summary> 
    /// <param name="kernel">The kernel.</param> 
    private static void RegisterServices(IKernel kernel) 
    { 
     kernel.Bind<IApplicationService>().To<ApplicationService>(); 
     kernel.Bind<IHttpContextFactory>() 
      .To<HttpContextFactory>().WithConstructorArgument("contextWrapper",ninjectContext=> new HttpContextWrapper(HttpContext.Current)); 

    }   
} 

Allerdings, wenn ich einen Haltepunkt setzen auf GetControllerName Controller ist innerhalb RouteData.Values nicht verfügbar.

Warum ist das der Fall?

+0

Was passiert, wenn Sie den HTTPContext.Current direkt verwenden? –

Antwort

0

HttpContext ist nicht verfügbar, wenn der Konstruktor des Controllers aufgerufen wird. Das ist höchstwahrscheinlich, wenn Ihr Konstruktordelegat aufgerufen wird.

Sie müssen Ihre Factory neu entwerfen, um den Kontext später im Aufruffluss zu erhalten. Das ist eine Menge, wie die IHttpContextAccessor in asp.net-Kern eingeführt

public interface IHttpContextAccessor { 
    HttpContextBase HttpContext { get; } 
} 

public class HttpContextProvider : IHttpContextAccessor { 
    private Lazy<HttpContextWrapper> _httpContext; 

    public HttpContextProvider() { 
     _httpContext = 
     new Lazy<HttpContextWrapper>(() => new HttpContextWrapper(HttpContext.Current)); 
    } 

    public virtual HttpContextBase HttpContext { 
     get { 
      return _httpContext.Value; 
     } 
    } 
} 

Sie registrieren es, wie Sie normalerweise würde

kernel.Bind<IHttpContextAccessor>().To<HttpContextProvider>(); 

Und die den Kontext erhalten, wenn nötig.

public class ApplicationService : IApplicationService { 
    private readonly ILog log; 
    private readonly IHttpContextAccessor httpContextProvider; 

    public ApplicationService(ILog log, IHttpContextAccessor httpContextProvider) { 
     this.log = log; 
     this.httpContextProvider = httpContextProvider; 
     if (httpContextProvider == null) { 
      throw new ArgumentNullException("httpContextProvider"); 
     } 
     if (log == null) { 
      throw new ArgumentNullException("log"); 
     } 
    } 

    public virtual string GetControllerName() { 
     var httpContext = httpContextProvider.HttpContext; 
     var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString(); 
     return controllerName; 
    } 
}