HttpContext.Current.Session is null when injecting it to interceptor / or using in inside interceptor (mvc4 webapi) - asp.net-mvc-4

I have mvc4 WebAPI application with castle Windsor interception.
The interceptor class needs HttpContext.Current.Session.
When I call it directly from the interceptor, it is null.
So I read here that I need to inject the Session and not just access it in the interceptor.
This the code I ended up with...
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container.Kernel));
this.RegisterDependencyResolver();
this.container.Install(new WindsorWebApiInstaller());
}
public class WindsorWebApiInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// the following interceptor needs Session object
container.Register( Component.For<IInterceptor>()
.ImplementedBy<SecurityInterceptor>()
.LifestylePerWebRequest()
.Named("SecurityInterceptor"));
// session is null here, So Castle wont inject it and throw exception...
container.Register(
Component.For<HttpSessionStateBase>().UsingFactoryMethod(
() => new HttpSessionStateWrapper(HttpContext.Current.Session)).LifestylePerWebRequest());
}
}
Is there any other way to access the session from the interceptor?
Thanks

I always forget that WEBAPI is not MVC.
this is not castle issue.
this did the trick!
public override void Init()
{
this.PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
System.Web.HttpContext.Current.SetSessionStateBehavior(
SessionStateBehavior.Required);
}
https://stackoverflow.com/a/15038669/936651
+1 to #Soren

Related

Session.IsNewSession in ASP.NET Core

I am migrating an ASP.NET MVC application to ASP.NET Core 3.1.
And I have a code to check if the session was timed out in my controller, like this:
if (Session.IsNewSession) {
How can I check it in ASP.NET Core?
Thanks
The default implementation of ISession is DistributedSession. This does not expose any property for IsNewSession although its constructor accepts a parameter named isNewSessionKey. So you can use reflection to get that private field of _isNewSessionKey to check it. But that way is not very standard, the name may be changed in future without notifying you any design-time error.
You have several points to intercept and get the info here. The first point is to create a custom ISessionStore (default by DistributedSessionStore) to intercept the call to ISessionStore.Create which gives access to isNewSessionKey. You can capture that value into a request feature just like how the framework set the ISessionFeature after creating the session. Here's the code:
//create the feature interface & class
public interface ISessionExFeature {
bool IsNewSession { get; }
}
public class SessionExFeature : ISessionExFeature {
public SessionExFeature(bool isNewSession){
IsNewSession = isNewSession;
}
public bool IsNewSession { get; }
}
//the custom ISessionStore
public class CustomDistributedSessionStore : DistributedSessionStore, ISessionStore
{
readonly IHttpContextAccessor _httpContextAccessor;
public CustomDistributedSessionStore(IDistributedCache cache,
ILoggerFactory loggerFactory,
IHttpContextAccessor httpContextAccessor) : base(cache, loggerFactory)
{
_httpContextAccessor = httpContextAccessor;
}
ISession ISessionStore.Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)
{
var httpContext = _httpContextAccessor.HttpContext;
if(httpContext != null)
{
var sessionExFeature = new SessionExFeature(isNewSessionKey);
httpContext.Features.Set<ISessionExFeature>(sessionExFeature);
}
return Create(sessionKey, idleTimeout, ioTimeout, tryEstablishSession, isNewSessionKey);
}
}
//register the custom ISessionStore inside Startup.ConfigureServices
services.Replace(new ServiceDescriptor(typeof(ISessionStore), typeof(CustomDistributedSessionStore), ServiceLifetime.Transient));
//an extension method to help get the ISessionExFeature conveniently
public static class SessionExFeatureHttpContextExtensions {
public static bool HasNewSession(this HttpContext context){
return context.Features.Get<ISessionExFeature>()?.IsNewSession ?? false;
}
}
To use it in your code:
if (HttpContext.HasNewSession()) {
//...
}
Another point to intercept and get the info is customize both the ISessionStore and ISession. Which means you create a sub class of DistributedSession and expose the property for IsNewSession. That may require more code but it looks more like the old way of getting the info (directly from the Session not kind of via an extension method on HttpContext).

Set up logging with Blazor WebAssembly

I'm doing some experiments with Blazor and want to set up logging. I see that Blazor logs to Microsoft.Extensions.Logging out of the box and that the log messages go to the developer console inside the browser. That is a nice start.
Now I want to try and log messages to other destinations as well. It could be a cloud-service. I'm wondering where to set that up. In ASP.NET Core, you would set it up using the ConfigureLogging method in Program.cs. But this isn't available with Blazor:
public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) =>
BlazorWebAssemblyHost.CreateDefaultBuilder()
.UseBlazorStartup<Startup>()
.ConfigureLogging(...); // <- compile error
As a fallback, I'm trying to set it up through ConfigureServices in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(builder => builder
.AddMyLogger()
.SetMinimumLevel(LogLevel.Information));
}
with AddMyLogger:
public static ILoggingBuilder AddMyLogger(this ILoggingBuilder builder)
{
builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
return builder;
}
and MyLoggerProvider:
public class MyLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new MyLogger();
}
public void Dispose()
{
}
}
and MyLogger:
public class MyLogger : ILogger
{
public MyLogger()
{
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
}
}
The AddMyLogger-method is called but my logger is never created or receives any Log-calls.
Am I doing something wrong here or is logging with Blazor WebAssembly simply not ready yet?
I was trying something similar. In my case, the Log method in MyLogger gets called; however it fails at following line of code
using (var streamWriter = new StreamWriter(fullFilePath, true)) //Fails here
{
streamWriter.WriteLine(logRecord);
}
When I put it in try catch block, I got the exception "Children could not be evaluated".
While researching I came across following link. Steve Sanderson's response might make sense of the behavior
Reading local files #16156
BTW It's been a long time, please let me know the solution you came up with.

SignalR, WebAPI and MVC sharing the same dependency resolver kernel

I have an ASP.NET MVC app with SignalR and WebAPI. The app uses Ninject for dependency injection, but apparently SignalR and WebAPI are getting different kernels, so it fails to share a singleton object that should be shared for all the application.
I can see clearly in the log how an instance is created when SignalR gets a connection request, and other when WebAPI gets a request.
I want to have the same Ninject kernel shared among these three elements, so I can have unique singletons.
This is what I have done so far:
The first thing I have done is creating a NinjectModule declaring the binding:
public class MyDependencyModule: NinjectModule
{
public override void Load()
{
var binding = Bind<MustBeSingleton>().ToSelf();
binding.OnActivation((ctx, o) =>
{
Debug.Print("Registering item " + o.GetHashCode());
HostingEnvironment.RegisterObject(o);
});
binding.OnDeactivation(o =>
{
Debug.Print("Unregistering game connection " + o.GetHashCode());
});
binding.InSingletonScope();
}
}
I have also created a wrapper for Ninject in order to plug it in WebAPI:
public class NinjectDependencyScope : IDependencyScope
{
private IResolutionRoot resolver;
internal NinjectDependencyScope(IResolutionRoot resolver)
{
this.resolver = resolver;
}
public void Dispose()
{
IDisposable disposable = resolver as IDisposable;
if (disposable != null)
disposable.Dispose();
resolver = null;
}
public object GetService(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (resolver == null)
throw new ObjectDisposedException("this", "This scope has already been disposed");
return resolver.GetAll(serviceType);
}
}
public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kernel)
: base(kernel)
{
this.kernel = kernel;
}
public IDependencyScope BeginScope()
{
return new NinjectDependencyScope(kernel.BeginBlock());
}
}
Also, I have created another wrapper for SignalR:
public class SignalRNinjectDependencyResolver : DefaultDependencyResolver
{
private readonly IKernel _kernel;
public SignalRNinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public override object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType).Concat(base.GetServices(serviceType));
}
}
Then I have created a Ninject kernel that does all the config:
public class ApplicationDependencies:StandardKernel
{
public ApplicationDependencies()
:base(new MyDependencyModule())
{
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(this);
Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(this);
}
}
The MVC application, uses NinjectHttpApplication as base class, so I indicate the kernel that must be used this way:
public class MvcApplication : Ninject.Web.Common.NinjectHttpApplication
{
protected override Ninject.IKernel CreateKernel()
{
return new ApplicationDependencies();
}
}
Also, in the SignalR configuration I specify the Resolver:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR<MyPersistentConnection>("/updates", new ConnectionConfiguration()
{
Resolver = GlobalHost.DependencyResolver
});
}
}
(I have tried also without specifying the resolver, and it does not work either).
Any idea?
Cheers.
I found the answer in another post: Singleton Scope binding not working as intended
Rather than binding as a singleton, "ToConstant" must be used:
var binding = Bind<MustBeSingleton>().ToConstant(new MustBeSingleton());
I have created a simple demo project with ASP.NET MVC, WebAPI and SignalR using the same dependency injection context.
https://drive.google.com/file/d/0B52OsuSSsroNX0I5aWFFb1VrRm8/edit?usp=sharing
The web app, contains a single page that shows the AppDomain and GetHashCode of an object that is supposed to be unique across the three frameworks, giving a result similar to:
Dependency Test
Framework IMySingletonService instance
MVC AppDomainId:2 / HashCode:5109846
WebAPI AppDomainId:2 / HashCode:5109846
SignalR AppDomainId:2 / HashCode:5109846
Other problem was, that Ninject was disposing my singleton because was IDisposable. I don't really understand why this happens, but that is another war.
Cheers.
In order keep this 3 things working.. you should check these references out:
Web API + Ninject
http://www.peterprovost.org/blog/2012/06/19/adding-ninject-to-web-api/
SignalR + Ninject https://github.com/SignalR/SignalR/wiki/Extensibility (last part:
When using ASP.NET MVC, configure SignalR first, then ASP.NET MVC)
For the second one, I refactored a little bit, since I need the kernel for SignalR Dependency Resolver
// Route SignalR.
GlobalHost.DependencyResolver = NinjectWebCommon.GetSignalrResolver();
RouteTable.Routes.MapHubs();
I defined GetSignalrResolver inside of NinjectWebCommon like this:
public static Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver GetSignalrResolver()
{
return new Microsoft.AspNet.SignalR.Ninject.NinjectDependencyResolver(bootstrapper.Kernel);
}
Note: There are 2 different DependencyResolver: one for Web API (1) assigned to GlobalConfiguration.Configuration.DependencyResolver and the other for SignalR (2) assigned to GlobalHost.DependencyResolver
in order to use a dependency resolver for both WebApi and SignalR you need to implement a class that looks like this:
public class NinjectDependencyResolver : Microsoft.AspNet.SignalR.DefaultDependencyResolver,
System.Web.Http.Dependencies.IDependencyResolver
{
public readonly IKernel Kernel;
public NinjectDependencyResolver(string moduleFilePattern)
: base()
{
Kernel = new StandardKernel();
Kernel.Load(moduleFilePattern);
}
public override object GetService(Type serviceType)
{
var service = Kernel.TryGet(serviceType) ?? base.GetService(serviceType);
return service;
}
public override IEnumerable<object> GetServices(Type serviceType)
{
IEnumerable<object> services = Kernel.GetAll(serviceType).ToList();
if (services.IsEmpty())
{
services = base.GetServices(serviceType) ?? services;
}
return services;
}
public System.Web.Http.Dependencies.IDependencyScope BeginScope()
{
return this;
}
public void Dispose()
{ }
}
then in your startup class you should register NinjectDependencyResolver for both WebApi and SignalR, like this:
public void Configuration(IAppBuilder app)
{
var dependencyResolver = new NinjectDependencyResolver("*.dll");
var httpConfiguration = new HttpConfiguration();
httpConfiguration.DependencyResolver = dependencyResolver;
app.UseWebApi(httpConfiguration);
var hubConfig = new HubConfiguration { Resolver = dependencyResolver };
app.MapSignalR(hubConfig);
}

Castle Windsor not supplying NLog component when using ASP.NET MVC filters

Registration
container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.NLog)
.WithConfig("NLog.config"));
This code is as per this documentation page.
Now this is the code where NLog will be used i.e. Castle Windsor will supply NLog as the _logger implementation:
public class EmailController : Controller
{
private ILogger _logger = NullLogger.Instance;
...
public ILogger Logger
{
get { return _logger; }
set { _logger = value; }
}
public ActionResult Send(UserMessageModel userMessage, bool captchaValid, string captchaErrorMessage)
{
if (ModelState.IsValid)
{
try
{
// Do something
}
catch (Exception ex)
{
_logger.Error(string.Format("Error msg:{0}\rError stacktrace:{1}", ex.Message, ex.StackTrace));
...
}
}
...
}
}
However if I change the code thus:
[CustomHandleError]
public class EmailController : Controller
{
[CustomHandleError]
public ActionResult Send(UserMessageModel userMessage, bool captchaValid, string captchaErrorMessage)
{
if (ModelState.IsValid)
{
// Do something
}
...
}
...
}
public class CustomHandleError: HandleErrorAttribute
{
private ILogger _logger = NullLogger.Instance;
public ILogger Logger
{
get { return _logger; }
set { _logger = value; }
}
public override void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
base.OnException(null);
}
_logger.Error(string.Format("Error msg:{0}\rError stacktrace:{1}", filterContext.Exception.Message, filterContext.Exception.StackTrace));
if (filterContext.HttpContext.IsCustomErrorEnabled)
{
filterContext.ExceptionHandled = true;
base.OnException(filterContext);
}
}
}
In this case the _logger is "NullLogger.Instance". I thought that the fact that I had a "Logger" property meant that Castle Windsor would then change _logger to NLog similar to the previous code.
What could I be misunderstanding?
EDIT
I've now added the code here and if anyone can have a look at it that would be great.
FYI: There are 4 commits.
The first commit was the initial commit
The second commit was showing that I could get NLog to work as I required
The third commit was demonstrating that I could get the Data Attribute working i.e. I successfully registered the Filters in Castle Windsor
The last commit is the issue I described above i.e. I can't get the centralised logging to use NLog.
Filters are not created automatically through the container. You need to leverage IActionInvoker into your controller factory.
Read this post
Castle Windsor - Injecting IActionInvoker Implementation Issue
EDIT
Your custom filter needs to derive from ActionFilterAttribute instead of HandleErrorAttribute in order to have dependencies injected by the container (leveraging on the IActionInvoker implemented in your sample).
If the purpose of your filter is handling errors, implements IExceptionFilter as well.

Does StructureMap have scoping corresponding to NInject's DefinesNamedScope/InNamedScope?

The problem I'd like to solve is sharing an ISessionProvider between IXyzRepositories (where ISessionProvider holds the current NHibernate ISession).
I'm tweaking the "Setting up session per presenter" recipe from NHibernate 3 Cookbook, and would like to keep StructureMap (brownfield project).
I think you would have to create a custom Lifecyle to do that, although I am not sure what exactly you are trying to accomplish...
To create a custom Lifecycle, you just have to implement the ILifecycle interface and the use it in your registration. Here is an example you can look at: http://blog.mikeobrien.net/2010/01/creating-structuremap-lifecycle-for-wcf.html.
In a web application I use Singleton for the sessionFactory and HybridHttpOrThreadLocalScoped for the session:
This is my structuremap registry:
public class NhibernateRegistry: Registry
{
public NhibernateRegistry()
{
For<ISessionFactory>()
.Singleton()
.Use(new NHibernateSessionFactory(connectionString).SessionFactory);
For<ISession>()
.HybridHttpOrThreadLocalScoped()
.Use(o => o.GetInstance<ISessionFactory>().CurrentSession);
}
}
My NHibernateSessionFactory is similar to SessionProvider class used in the book.
Everything is disposed at the end of the request (web app):
protected void Application_EndRequest(object sender, EventArgs e)
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
I use a generic repository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly ISession _session;
public GenericRepository(ISession session)
{
_session = session;
}
public T Load(Guid Code)
{
return (_session.Load<T>(Code));
}
}
but you can easily change it with your own implementation.
I register the repository here:
public class RepositoriesRegistry : Registry
{
public RepositoriesRegistry()
{
For <Data.IRepository<Domain.Reminder, Guid>>()
.HybridHttpOrThreadLocalScoped()
.Use<Data.NH.Repository<Domain.Reminder, Guid>>();
}
}