How to detect application pool restart of a WCF service? - wcf

In my WCF service I use a static dictionary to hold some resource intensive data. I need to clean up the resources when the application pool gets recycled. Is there any method (for example event) by which I can detect that application pool is being recycled?

if your application pool gets recycled all your static objects will be reset. you can clean all external resources (like files or ...) when creating an instance of your static dictionary. something like this:
public static partial class ProjectValues
{
public static ConcurrentDictionary<string, string> MessageDictionary { private set; get; }
static ProjectValues()
{
try
{
MessageDictionary = new ConcurrentDictionary<string, string>();
//then clear the resource here
}
catch (Exception ex)
{
return;
}
}
}

Is there any method( for example event) by which I can detect that
application pool is being recycled?
Kinda.
According to Phill Haack, IIS exposes a static method called HostingEnvironment.RegisterObject, which allows you to pass implementations of IRegisteredObject into it.
In theory, this tells IIS to call the IRegisteredObject.Stop operation before it decides to kill the w3wp.exe process your app is running in.
I say in theory because this approach is not fail-safe and there are instances where the AppDomain can go away without calling, or even to call but then shut down anyway, before you're finished doing your cleanup.

Related

RedisTimeoutException is crashing my aspnet core application

When my application traffic gets high, StackExchange.Redis starts to throw RedisTimeoutException and after some minutes, my asp.net core application crashes.
The Windows event viewer says The process was terminated due to an unhandled exception. Exception Info: StackExchange.Redis.RedisTimeoutException.
Ok, I understand that there is some issue between my app and Redis, but while I can't solve this, how can I prevent the application to shutdown?
Inside startup.cs, I tried to put:
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) =>
{
eventArgs.SetObserved();
eventArgs.Exception.Handle(ex => true);
};
no success....
Any help ?
Tks
How are you creating the ConnectionMultiplexer instances?
Maybe you are not reusing a multiplexer instance and creating a lot of connections.
The ConnectionMultiplexer object should be shared and reused between callers. It is not recommended to create a ConnectionMultiplexer per operation. Check StackExchange.Redis documentation here for more information.
About the exception handling on Asp.NET Core, you can use the UseExceptionHandler diagnostic middleware to handle exceptions globally. Check this article for a complete explanation
Have you tried to put the block that throws the exception in a try/catch block? And perhaps make it try a few times with Polly when there is a timeout. https://github.com/App-vNext/Polly
Normally it shouldn't terminate your app, but since you didn't share any code, We can not be sure.
If you create a service class like below, you can encapsulate all of your redis calls, therefore catch the exceptions.
public class EmptyClass
{
private readonly ConnectionMultiplexer _connectionMultiplexer;
public EmptyClass(ConnectionMultiplexer connectionMultiplexer)
{
_connectionMultiplexer = connectionMultiplexer;
}
public void Execute(Action<ConnectionMultiplexer> action)
{
try
{
action.Invoke(_connectionMultiplexer);
}
catch(RedisTimeoutException ex)
{
}
}
public void TestRun()
{
Execute((ConnectionMultiplexer obj) =>
{
//do stuff with obj.
});
}
}
I agree with #thepirat000's answer, reason is ConnectionMultiplexer
You can use ConnectionMultiplexer according your Redis package (StackExchange.Redis or ServiceStack.Redis) and according your deployment environment
In my aspnet core application (like you) i have used StackExchange.Redis and i have deployed to windows server without any error within below Startup.cs settings
#region Redis settings ConnectionMultiplexer
services.AddDataProtection().ProtectKeysWithDpapi(protectToLocalMachine: true);
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp-keys"))
.ProtectKeysWithDpapiNG($"CERTIFICATE=HashId:{thumbPrint}", flags: Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiNGProtectionDescriptorFlags.None);
services.AddDataProtection().ProtectKeysWithDpapiNG();
services.Configure<StorageConfiguration>(new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build());
var redisConf = Configuration.GetSection("RedisConnection").Get<RedisConnection>();
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf.Host.ToString() + ":" + redisConf.Port.ToString());
services.AddDataProtection().PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(redisConf.Host.ToString() + ":" + redisConf.Port.ToString()));
#endregion
Look here for basic usage https://stackexchange.github.io/StackExchange.Redis/Basics.html

How to share fluent configuration in a Castle Windsor IOC container

I am trying to create an IOC container in Castle Windsor that's configuration is shared across assemblies.
(What follows is an example of how this works in Unity. What I want to do is to make it work the same way using Castle Windsor)
I have the following project configuration...
TestCompany.Services.Host
(Web project hosting a number of .svc files)
PrintService.svc
Web.Config
Unity.Config
TestCompany.Services.PrintService
IPrintService.cs
PrintService.cs
The actual implementation of my "PrintService" is not implemented inside my Services.Host but in the TestCompany.Services.PrintService assembly.
As part of my shared project code (not shown) I have a container helper which is responsible for loading the unity configuration...
public static IUnityContainer GetContainer()
{
// Checks for existance of container (_container == null) ommitted.
var section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
section.Configure(_container, name);
...
...
}
This method loads the unity configuration section from the Unity.Config and uses it to configure the container.
The advantage of this method is that one Unity.Config loaded inside (I presume) the AppDomain can service a number of assemblies. Simply calling GetContainer() from any of the assemblies consumed by my service host will return a container populated with the same type resolution's etc.
I really want to use the fluent configuration in Castle Windsor but I dont see how without this "shared" configuration file that can be acheived. PrintService and any future services will all need to resolve the same dependencies and I dont want to have to repeat my fluent configuration between these services.
Ideally I need some sort of container configured in the service host app that can "flow" into all of the assemblies that it makes use of.
Thanks.
I think I may not be understanding your question but I think I understand your scenario and here is how I do something similar, if it helps at all...
My Philosophy:
Each part of the application should be in charge of registering what
it knows about and nothing more, so there is no need for a single
central configuration file and things that are shared between
components are registered in one place and their interfaces are
available everywhere via a common library.
So let's take an example...
First of all, let us just say (for the purposes of my example) that IPrintService is something that you want to register an implementation of once and use throughout the application and that we have some other component that needs to be implemented by some external module from the main application. We, therefore, create an assembly called Common like so:
Common
public interface IPrintService
{
void Print();
}
public interface IMyService
{
void DoSomething();
}
Now let us think about the main part of the application (maybe it is an ASP .NET application, maybe justa console application, does not really matter). Here we construct the container and ask it to find all the possible components. We can do that like so:
Main Application
// Could be the Global.asax code behind but for simplicity this is
// just a console application
class Program
{
private static readonly IWindsorContainer Mycontainer
= BootstrapContainer();
// Allow access to the raw container - this is probably a bad idea but
// in the rare case that you need it you can get it from here
public static IWindsorContainer Container { get { return Mycontainer; } }
private static IWindsorContainer BootstrapContainer()
{
// Here we will just install every IWindsorInstaller found in any
// assembly in the same folder as the application (so no need for
// references or anything).
var c = new WindsorContainer();
string folder = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location);
c.Install(FromAssembly.InDirectory(new AssemblyFilter(folder)));
return c;
}
}
// Here is the print service implementation
public class MyPrintService : IPrintService
{
public void Print()
{
// Print!
}
}
// This is the installer for the main module - here we are saying exactly
// what is implementing the interface
public class MainApplicationInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container,
IConfigurationStore store)
{
container
.Register(Component
.For<IPrintService>()
.ImplementedBy<MyPrintService>());
}
}
So now we have a common library with our shared inetrfaces and a main application that will register an implementation for our shared interface and also load up any other modules in the system.
The only thing, therefore, left to do is to consume that print service and use it. We can do this anywhere that is using the container so let's create a third assembly that references only Common (we will call it test module.
Test Module
// This installer installs just the things inside this module since that
// is all it knows about but those things can use things that are
// registered in the container by anybody.
public class TestModuleInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container,
IConfigurationStore store)
{
container
.Register(Component
.For<IMyService>()
.ImplementedBy<MyServiceThatDoesSomething>());
}
}
public class MyServiceThatDoesSomething : IMyService
{
private readonly IPrintService _printService;
public MyServiceThatDoesSomething(IPrintService printService)
{
_printService = printService;
}
public void DoSomething()
{
// Use the print service!
_printService.Print();
}
}
Finally compile everything and copy the test module to the same folder as the main application and then from the main you can do this:
Container.Resolve<IMyService>().DoSomething();
And then the magic happens! Well, some code runs and you find that the print service is called by the class from the module even though it knows nothing about it.
Anyway, maybe that helps a little bit, maybe not, good luck!

Managing Configuration Changes in WCF

What is the preferable way to manage configuration file changes in WCF webservices? I know usually in desktop applications people use a FileSystemWatcher to watch for changes in App.config, but how exactly does one go about configuring one in WCF? I tried using something like the following code:
public class Service : IService
{
private static readonly FileSystemWatcher ConfigurationWatcher = new FileSystemWatcher(PathToRootDirectory);
private void ReloadConfiguration(object sender, FileSystemEventArgs e)
{
ConfigurationManager.RefreshSection("appSettings");
ConfigurationManager.RefreshSection("connectionStrings");
}
// IService implementation goes here.
static Service()
{
ConfigurationWatcher.Filter = "web.config";
ConfigurationWatcher.NotifyFilter = NotifyFilter.LastWrite;
ConfigurationWatcher.Change += ReloadConfiguration;
}
}
However, that didn't seem to work since ConfigurationWatcher seemed to being initialized upon every call to the service... How does one go about accomplishing this?
This happens automatically for a service hosted in IIS.
Any change to the web.config or any assembly in the bin folder will cause the current AppDomain to shut down and a new AppDomain to be started for subsequent requests - just like with ASP.NET.

How do I force GlassFish 2 to load EJBs on startup?

We're using EJB3 on GlassFish v2.
My application includes a GenericServlet called StartupServlet, which has an init method. java.util.TimerTask pollers started from this method cannot lookup facades from the InitialContext.
However if I make an HTTP request and do a lookup, it succeeds. Therefore I have a workaround now where my poller startup code makes an HTTP connection to a page which looks up the interfaces they need.
How can I rearrange my application so I don't need to use such a hack? If possible the solution needs to work on GFv3 as well.
Thanks in advance for your help!
On GF 2, I have a servlet that on start ensures that my timer is created. This looks up a remote session bean and calls it successfully from the init() (not actual code, distilled down to the important parts):
#EJB(name="TimerSessionRef", beanInterface=TimerSessionRemote.class)
public class StartTimers extends HttpServlet {
#Override
public void init() throws ServletException {
super.init();
try {
Context ctx = new InitialContext();
TimerSessionRemote timerSession = (TimerSessionRemote) ctx.lookup("java:comp/env/TimerSessionRef");
timerSession.createTimer();
} catch (NamingException ex) {
logger.blah();
}

How can we detect when a WCF client has disconnected?

Is there any way of finding out when a WCF client has disconnected. Currently the only approach seems to be to wait until a call on the client from the service eventually times out.
I have tried subscribing to the OperationContext.Current.Channel.Faulted event but unfortunately it is never called; my understanding was that this event should be fired when the client disappears. On the other hand, when things close down gracefully OperationContext.Current.Channel.Closed is called.
In our application we only support a single client connection at a time, hence when somebody closes and re-starts the client app it would be nice if the server could be made aware of the the disconnection, tidy up gracefully and then accept another connection.
Yes, clients will disconnect gracefully most of the time, but this can't be guaranteed. Currently the only option seems to be to poll the client and wait for a CommunicationTimeout, which is hardly ideal.
Any suggestions greatly appreciated.
Theoretically, a service need not have knowledge of client's state. But it can insist on whom to serve for by dictating the authentication needs, concurrency limitation etc.
If you intention is to make sure only one client is served at a time, you can simply opt for Single Concurrency mode.
For example.
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Single)]
public class CalculatorService : ICalculatorConcurrency
This will ensure only one client request is served at a time. Following link may help you as well.
http://msdn.microsoft.com/en-us/library/ms731193.aspx
EDIT
If you think an user's action of keeping the channel open does disturb the other user's work, it may not be the usual case.
Because each user's call is considered to be a different session. By default WCF calls are considered to be instantiated per call.
If you would like to persist data between user's calls, you may opt for perSession instancing mode.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class CalculatorService : ICalculatorInstance
This would make sure that each user would have an instance of the service which would not inturrupt servicing the other user.
You can set the concurrency mode accordingly i.e Multiple or Reentrant if you wish. Even if the concurrency mode is single, when a response is sent back to the user the service would be ready to serve the next user. It won't wait for the client to close the connection. User's connection would be useful only to keep the session live.
You can use IChannelInitializer and hook up Channel Close and Channel faulted events to detect graceful or abrupt closing of the client. Refer to a very nice post on this by Carlos - http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/14/wcf-extensibility-initializers-instance-context-channel-call-context.aspx
You could use Callback Operations to make a call to the client to see if its still connected.
Take a look at this article on MSDN magazine
if (HttpContext.Current.Response.IsClientConnected == false
{
...
}
it can help you
I've had success using a "disconnection detector" like this:
// Code based on https://blogs.msdn.microsoft.com/carlosfigueira/2012/02/13/wcf-extensibility-initializers-instance-context-channel-call-context/
public class WcfDisconnectionDetector : IEndpointBehavior, IChannelInitializer
{
public event Action Disconnected;
public int ConnectionCount { get; set; } = 0;
public WcfDisconnectionDetector() { }
public WcfDisconnectionDetector(Action onDisconnected) => Disconnected += onDisconnected;
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime cr)
=> cr.ChannelInitializers.Add(this);
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher ed)
=> ed.ChannelDispatcher.ChannelInitializers.Add(this);
void IEndpointBehavior.Validate(ServiceEndpoint endpoint) { }
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
void IChannelInitializer.Initialize(IClientChannel channel)
{
ConnectionCount++;
Trace.WriteLine($"Client {channel.SessionId} initialized");
channel.Closed += OnDisconnect;
channel.Faulted += OnDisconnect;
}
void OnDisconnect(object sender, EventArgs e)
{
ConnectionCount--;
Disconnected?.Invoke();
}
}
Install it before calling ServiceHost.Open:
var detector = new WcfDisconnectionDetector();
serviceHost.Description.Endpoints.Single().EndpointBehaviors.Add(
new WcfDisconnectionDetector(() => {/*disconnected*/}));