.Net 4.0 MemoryCache Clearing - wcf

I am using a .Net 4.0 MemoryCache in my WCF service.
I originally was using the Default Cache as below:
var cache = MemoryCache.Default;
Then doing the usual pattern as trying to find something in the Cache, getting, then
setting into the cache if did not find (code snippet / pseudo code as below):
var geoCoordinate = cache.Get(cacheKey) as GeoCoordinate;
if (geoCoordinate == null)
{
geoCoordinate = get it from somewhere;
cache.Set(cacheKey, geoCoordinate, DateTimeOffset.Now.AddDays(7));
}
I was finding that my entries were disappearing after approx. 2 minutes. Even if my code placed the missing entries back into the cache, subsequent cache Gets would return null.
My WCF Service is being hosted by IIS 7.5. If I recycled the App Pool, everything would work normally for 2 minutes, but then the pattern as described above would repeat.
After doing some researching I then did the below to replace:
var cache = MemoryCache.Default;
// WITH NEW CODE TO CREATE CACHE AS BELOW:
var config = new NameValueCollection();
//Hack: Set Polling interval to 10 days, so will no clear cache.
config.Add("pollingInterval", "10:00:00:00");
config.Add("physicalMemoryLimitPercentage", "90");
config.Add("cacheMemoryLimitMegabytes", "2000");
//instantiate cache
var cache = new MemoryCache("GeneralCache", config);
It seems that no matter what I place into physicalMemoryLimitPercentage, or cacheMemoryLimitMegabytes does not seem to help. But placing the pollingInterval to a large datespan does.
ie: If I set as below:
config.Add("pollingInterval", "00:00:15:00");
Then everything works fine for 15 minutes.
Note: If my WCF service is hosted by IISExpress on my dev environment, I cannot reproduce.
This also seems to happen when my WCF service is hosted by IIS 7.5.
My app pool on IIS 7.5 is NOT recycling.
Has anybody experienced something like this?
I have seen the below:
MemoryCache does not obey memory limits in configuration
Thanks,
Matt

I too have seen this issue and filed a bug with MS here with a simple reproducer project.
This has been resolved by MS in the above bug I filed - with a work around there and an upcoming QFE for .net 4 as well as confirmation that this isn't a problem in 4.5
I have not yet tried the work around
I can however give some more information on conditions required by myself to recreate this. The application pool needed to be in Integrated Pipeline mode for me to see this issue - Classic mode fixes this issue though removes some of the benefits of moving to IIS 7.5.
Equally when using Integrated mode I also did not see this issue if I used a built-in application pool identity such as ApplicationPoolIdentity. However my app needs to run as a custom identity using a service account and it is at this point at which I see the behavior. Therefore if you don't need Integrated mode or a custom Identity you can maybe work around this.
Perhaps the built-in accounts have permissions to do the cache memory statistics gathering initiated by the pollingInterval that my custom Identity does not have, I don't know.
Hope this helps or even that someone else can join more of the dots to figure out a better work around.

Related

Serilog using EnrichDiagnosticContext with additional properties not being logged in SignalR Hub

I have recently implemented Serilog logging into my ASP.NET Core/.NET5 web app that uses SignalR. I'm using the Elasticsearch sink and everything is largely working as expected. I decided to add some additional HttpContext properties to be logged on each request, so I went down the road of extending the call to UseSerilogRequestLogging() in StartUp.cs as to enrich the diagnostic context with a couple of extra properties (mainly because this seemed like the simplest way to do it):
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress);
diagnosticContext.Set("UserName", httpContext.User?.Identity?.Name == null ? "(anonymous)" : httpContext.User.Identity.Name);
};
});
At first, this seemed to work as expected until I noticed it wasn't always working. I really want the extra properties logged on all log records written, and it seems to work fine on log records that are written automatically by Serilog when typical HTTP GETs, HTTP POSTs, etc. occur... But in my Signalr Hub class, I have a couple of places where I'm manually writing my own log records like Logger.Log(LogLevel.Information, "whatever.."), but these extra properties are simply not there on these records.
What am I missing here? Is it something about this being in a Signalr Hub that makes them unavailable? Or perhaps there's something I'm doing wrong with my Logger.Log() calls?
Any ideas would be appreciated.
Thanks-
It's not gonna to work with signalR.
Behind the screen, app.UseSerilogRequestLogging make use of a middleware in the request pipeline, that call RequestLoggingMiddleware as what you can see in detail here.
SignalR use the first Http request to setting to connection up to websocket, which won't goes through the pipeline at all. Therefore, doesn't have anything to do with RequestLoggingMiddleware, which you are using to logging out the request.
I finally ended up going with a couple of custom Enrichers. I did experiment briefly with middleware vs enrichers and they both seem to work as expected. Both always added the additional properties to all log entries. I'm still not quite sure I understand why the DiagnosticContext option behaves the way it does, unless it is simply due to the logging in question being in a SignalR hub as #Gordon Khanh Ng. posted. If that were the root of the problem though, you wouldn't think the enrichers or middleware would work either.

How to use Miniprofiler storage to support multiple web instances?

I've hooked up Miniprofiler to my local ASP.NET Core project and it works as expected. Now I need it to work in a hosted environment where there are multiple instances of the same website and there are no sticky sessions. It is my understanding that this should be supported if you just set the storage option when configuring the profiler. However, setting the storage does not seem to do anything. I initialize the storage like this:
var redisConnection = "...";
MiniProfiler.DefaultOptions.Storage = new RedisStorage(redisConnection);
app.UseMiniProfiler();
After doing this, I expected that I could open a profiled page and a result would be added to my redis cache. I would then also expect that a new instance of my website would list the original profiling result. However, nothing is written to the cache when generating new profile results.
To test the connection, I tried manually saving a profiler instance (storage.Save()) and it gets saved to the storage. But again, the saved result is not loaded when showing profiler results (and regardless, none of the examples I've seen requires you to do this). I have a feeling that I've missed some point about how the storage is supposed to work.
It turns out that my assumption that MiniProfiler.DefaultOptions.Storage would be used was wrong. After changing my setup code to the following, it works.
// Startup.cs ConfigureServices
var redisConnection = "...";
services.AddMiniProfiler(o =>
{
o.RouteBasePath = "/profiler";
o.Storage = new RedisStorage(redisConnection); // This is new
});
// Startup.cs Configure
app.UseMiniProfiler();

Service Bus for Windows Server / SubscriptionDescription MessageCountDetails properties are all zeros! (0's)

I'm writing a 'Service Bus Monitor' [Windows] service so that we can keep an eye on our topic/subscription(s) and have run into an interesting issue. (And of course by "interesting" I mean "super frick'en annoying.")
For each of my topic/subscription pairs, I create a SubscriptionDescription so that I can get the MessageCount. This works just fine.
var subscriptionDescription = namespaceManager.GetSubscription(
busTargetModel.Topic, busTargetModel.Subscription);
var messageCountThisSubscription = subscriptionDescription.MessageCount;
However, in one particular case messageCountThisSubscription == 51 and I happen to know
that all 51 are actually sitting in the dead letter box/queue/whatever, but, when I try to get the MessageCountDetails...
// I actually make this call BEFORE the MessageCount call above.
// (In case that matters somehow)
var messageCountDetails = subscriptionDescription.MessageCountDetails;
...all 5 of it's properties (ActiveMessageCount, DeadLetterMessageCount, ScheduledMessageCount, TransferDeadLetterMessageCount and TransferMessageCount) have a value of 0 (Zero!)
I cannot for the life of me imagine what I could be doing wrong here; seems pretty straight forward, yet.. ZEROS.
Thoughts, insights, ANY help appreciated!
(This is for Service Bus for Windows Server but I don't see any tags for this except for all the Azure stuff, and from what I've read, they are NOT created equal.. at least not yet, so hoping I got the tags right.)
Scott,
Service Bus 1.0 for Windows Server does not have support for message count details. That feature was implemented after the bits locked down so these properties are not returning the expected values. We have a symmetric (single) client library for both Server and Service offering of Service Bus so you see them available but the values are only populated when targeting the Service or the recently released preview for Service Bus 1.1 for Windows Server. You can install this from WebPI, more details are here: http://msdn.microsoft.com/en-us/library/windowsazure/dn282144(v=azure.10).aspx

Object already exists exception in RSACryptoServiceProvider

First let me start by saying I'm sorry if I posted this question in the wrong place. I saw the entry at Object already exists in RSACryptoServiceProvider. I tried the solutions offered there. But, they did not solve my issue. Also, I didn't see an option to re-ask the question.
I have almost the same issue. I have a class that uses RSACryptoServiceProvider that runs in two projects on the same machine and under the same account. Both projects live in the same solution and share the same encryption code. One project, the server, is a Windows service and the other, the client, is a Windows application. They use the RSACryptoServiceProvider to talk to each other over a named pipe using asymmetric encryption. I started out by just having the server run in another Windows form within the same application as the client. Everything ran fine. Then, I moved the server to a Windows service.
The Windows service starts up fine. It seems to be able to create it's instance of the RSACryptoServiceProvider fine. But, when the client, which runs in the Windows application, starts up it gets a runtime error when it tries to create it. Here is the code that runs in both projects.
rule = New CryptoKeyAccessRule("everyone", CryptoKeyRights.FullControl, AccessControlType.Allow)
csp = New CspParameters
csp.KeyContainerName = _KeyContainerName
csp.Flags = CspProviderFlags.UseMachineKeyStore
csp.CryptoKeySecurity = New CryptoKeySecurity()
csp.CryptoKeySecurity.SetAccessRule(rule)
//Object already exists exception happens here
rsa = New RSACryptoServiceProvider(_KeySize, csp)
As you can see, I have the code that sets the access rule as mentioned in the other post on this subject. Unfortunately, this did not solve my issue. Is there anything else that needs to change?

WSSecurityTokenSerializer ReadToken method performance

I have a Dispatch MessageInspector which is deserializing a SAML Token contained in the SOAP message header.
To do the deserialization I am using a variation of the following code:
List<SecurityToken> tokens = new List<SecurityToken>();
tokens.Add(new X509SecurityToken(CertificateUtility.GetCertificate()));
SecurityTokenResolver outOfBandTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(new ReadOnlyCollection<SecurityToken>(tokens), true);
SecurityToken token = WSSecurityTokenSerializer.DefaultInstance.ReadToken(xr, outOfBandTokenResolver);
The problem I am seeing is that the performance of the ReadToken call varies depending on the account that is running the windows service (in which the WCF service is hosted).
If the service is running as a windows domain account the elapsed time for the ReadToken call is virtually zero. When running as a local machine account the call takes between 200 and 1000 milliseconds.
Can anyone shed any light on what is going on here and why the account running this bit of code makes a difference as to its performance?
Thanks,
Martin
When the service is running under a local account that there is considerably more activity taking place, examples of this are :
Accessing and using C:\WINDOWS\system32\certcli.dll
Accessing and using C:\WINDOWS\system32\atl.dll
Attempting to access registry keys e.g.
HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration
None of this extra activity appears to occur when running under a domain account.
A quick search on the internet for "certcli.dll domain user" brings up microsoft knowledge base article 948080 which sounds similar.
Unsure how to resolve this as ultimately a .Net method is being called (WSSecurityTokenSerializer.ReadToken) where you have little to no control over the internals.
This appears to also describe the same problem :
http://groups.google.com/group/microsoft.public.biztalk.general/browse_thread/thread/402a159810661bf6?pli=1