I have an Azure Cloud Service with a single worker role that will deploy, start, and run without fail every time, but I ran into some intermittent problems I wanted to diagnose with Application Insights. I followed directions from this article as well as here.
After installing the nugget packages and adding the one line of code, I ran the cloud service locally in both debug and release mode, and was able to see the AI info being reported to the Application Insights resource. So I packaged it up and uploaded the new configuration to my cloud service.
But then from the cloud the worker role will not actually start--it goes into a recycle death spiral, and in the "Diagnose and Solve Problems" blade I get a variation of the error below, always about "System.Threading.AsyncLocal'1'" and not being able to load the RoleEntryPoint. Following this article did not shed much light onto things, as the error pretty much tells me why it keeps recycling but not any clues on what to do about it.
Production - WebReportDownloader_IN_0: BusyRole
Waiting for role to start... Failed to load role entrypoint. System.TypeLoadException: Could not load type 'System.Threading.AsyncLocal`1' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. at Microsoft.ApplicationInsights.Extensibility.SdkInternalOperationsMonitor.Exit() at Microsoft.ApplicationInsights.Extensibility.Implementation.TelemetryConfigurationFactory.Initialize(TelemetryConfiguration configuration, TelemetryModules modules, String serializedConfiguration) at Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.get_Active() at WebReportDownloader..ctor() in C:\Users\User\Source\Repos\Program\WebReportDownloader\WebReportDownloader.cs:line 21 --- End of inner exception stack trace --- at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Activator.CreateInstance(Type type) at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetRoleEntryPoint(Assembly entryPointAssembly) at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.CreateRoleEntryPoint(RoleType roleTypeEnum) at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.InitializeRoleInternal(RoleType roleTypeEnum) [2017-09-14T15:28:21Z] Last exit time: [2017/09/14, 15:28:21.944]. Last exit code: 0.
Normally I can get enough of a hint from searching the exception and/or details, but this time I can't find anything that resembles my problem. All I can guess is that something small but critical is awry with my configuration, but I haven't been able to determine where I've gone off the rails based on the instructions I linked above.
My ServiceConfiguration.Cloud file...
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="WebReportDownloader" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2015-04.2.6">
<Role name="WebReportDownloader">
<Instances count="2" />
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.Enabled" value="true" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountUsername" value="admin" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword" value="ENCRYPTEDVALUE" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountExpiration" value="2018-09-01T23:59:59.0000000-04:00" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled" value="true" />
<Setting name="APPINSIGHTS_INSTRUMENTATIONKEY" value="KEYVALUE" />
</ConfigurationSettings>
<Certificates>
<Certificate name="Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption" thumbprint="847EEDE0084CF57A5A774CAE9E700713726CC856" thumbprintAlgorithm="sha1" />
</Certificates>
</Role>
</ServiceConfiguration>
And my ApplicationInsights.config...
<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
<TelemetryInitializers>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.HttpDependenciesParsingTelemetryInitializer, Microsoft.AI.DependencyCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.AzureWebAppRoleEnvironmentTelemetryInitializer, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.BuildInfoConfigComponentVersionTelemetryInitializer, Microsoft.AI.WindowsServer"/>
</TelemetryInitializers>
<TelemetryModules>
<Add Type="Microsoft.ApplicationInsights.DependencyCollector.DependencyTrackingTelemetryModule, Microsoft.AI.DependencyCollector">
<ExcludeComponentCorrelationHttpHeadersOnDomains>
<!--
Requests to the following hostnames will not be modified by adding correlation headers.
This is only applicable if Profiler is installed via either StatusMonitor or Azure Extension.
Add entries here to exclude additional hostnames.
NOTE: this configuration will be lost upon NuGet upgrade.
-->
<Add>core.windows.net</Add>
<Add>core.chinacloudapi.cn</Add>
<Add>core.cloudapi.de</Add>
<Add>core.usgovcloudapi.net</Add>
<Add>localhost</Add>
<Add>127.0.0.1</Add>
</ExcludeComponentCorrelationHttpHeadersOnDomains>
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.PerformanceCollectorModule, Microsoft.AI.PerfCounterCollector">
<!--
Use the following syntax here to collect additional performance counters:
<Counters>
<Add PerformanceCounter="\Process(??APP_WIN32_PROC??)\Handle Count" ReportAs="Process handle count" />
...
</Counters>
PerformanceCounter must be either \CategoryName(InstanceName)\CounterName or \CategoryName\CounterName
NOTE: performance counters configuration will be lost upon NuGet upgrade.
The following placeholders are supported as InstanceName:
??APP_WIN32_PROC?? - instance name of the application process for Win32 counters.
??APP_W3SVC_PROC?? - instance name of the application IIS worker process for IIS/ASP.NET counters.
??APP_CLR_PROC?? - instance name of the application CLR process for .NET counters.
-->
</Add>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryModule, Microsoft.AI.PerfCounterCollector"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.DeveloperModeWithDebuggerAttachedTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnhandledExceptionTelemetryModule, Microsoft.AI.WindowsServer"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.UnobservedExceptionTelemetryModule, Microsoft.AI.WindowsServer">
<!--</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.FirstChanceExceptionStatisticsTelemetryModule, Microsoft.AI.WindowsServer">-->
</Add>
</TelemetryModules>
<TelemetryProcessors>
<Add Type="Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector.QuickPulse.QuickPulseTelemetryProcessor, Microsoft.AI.PerfCounterCollector"/>
<Add Type="Microsoft.ApplicationInsights.Extensibility.AutocollectedMetricsExtractor, Microsoft.ApplicationInsights"/>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
<ExcludedTypes>Event</ExcludedTypes>
</Add>
<Add Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.AdaptiveSamplingTelemetryProcessor, Microsoft.AI.ServerTelemetryChannel">
<MaxTelemetryItemsPerSecond>5</MaxTelemetryItemsPerSecond>
<IncludedTypes>Event</IncludedTypes>
</Add>
</TelemetryProcessors>
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel"/>
<!--
Learn more about Application Insights configuration with ApplicationInsights.config here:
http://go.microsoft.com/fwlink/?LinkID=513840
Note: If not present, please add <InstrumentationKey>Your Key</InstrumentationKey> to the top of this file.
--></ApplicationInsights>
And my "OnStart()" method where I actually set the InstrumentationKey...
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
TelemetryConfiguration.Active.InstrumentationKey = RoleEnvironment.GetConfigurationSettingValue("APPINSIGHTS_INSTRUMENTATIONKEY");
// For information on handling configuration changes
// see the MSDN topic at https://go.microsoft.com/fwlink/?LinkId=166357.
bool result = base.OnStart();
Trace.TraceInformation("WebReportDownloader has been started");
return result;
}
I would appreciate any insight (ha!) or guidance anyone can provide...
Update:
Through further experimentation, I've determined that whenever I'm trying to call the Application Insights assembly directly (such as when creating a Telemetry Client or setting the ApplicationInsights Resource Key directly) or when the ApplicationInsight TraceListener is called because of a trace the exception below is called
Could not load type 'System.Threading.AsyncLocal`1' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
If I do the run-time instrumentation, I'm able to get some basic traces and logs to my Insight resources, but attempting to get anything more still escapes me.
Additionally, I'm currently targeting .NET 4.6.1 (information I neglected to mention previously).
After much back and forth with Azure support, I was finally able to get a screen sharing session set up. The helpful gentleman zeroed in on the problem almost immediately: Because my worker role project targets .NET 4.6.1 the ServiceConfiguration files (both .Cloud.cscfg and .Local.cscfg) need to be targeting osFamily 5.
The defaults generated by the VS17 wizard set it at osFamily=4 as seen below...
However, what I needed to make everything run properly was to be targeting osFamily=5 as seen below...
That one small change allowed the web role to deploy properly while instantiating a TelemetryClient.
According to your description, I created my Azure Cloud Service project and added the single Worker Role targets on .NET Framework 4.5, then installed Microsoft.ApplicationInsights.WindowsServer 2.4.1 and just added the code as you mentioned for setting the instrumentation key as follows:
WorkerRole.cs
public class WorkerRole : RoleEntryPoint
{
private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private readonly ManualResetEvent runCompleteEvent = new ManualResetEvent(false);
public override void Run()
{
Trace.TraceInformation("WorkerRoleB is running");
try
{
this.RunAsync(this.cancellationTokenSource.Token).Wait();
}
finally
{
this.runCompleteEvent.Set();
}
}
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
TelemetryConfiguration.Active.InstrumentationKey = RoleEnvironment.GetConfigurationSettingValue("APPINSIGHTS_INSTRUMENTATIONKEY");
// For information on handling configuration changes
// see the MSDN topic at https://go.microsoft.com/fwlink/?LinkId=166357.
bool result = base.OnStart();
Trace.TraceInformation("WorkerRoleB has been started");
return result;
}
public override void OnStop()
{
Trace.TraceInformation("WorkerRoleB is stopping");
this.cancellationTokenSource.Cancel();
this.runCompleteEvent.WaitOne();
base.OnStop();
Trace.TraceInformation("WorkerRoleB has stopped");
}
private async Task RunAsync(CancellationToken cancellationToken)
{
// TODO: Replace the following with your own logic.
while (!cancellationToken.IsCancellationRequested)
{
Trace.TraceInformation("Working");
await Task.Delay(1000);
}
}
}
After deployed to Azure Cloud Service, it could work as expected and I could retrieve the diagnostic data from AI as follows:
Note: As Install the SDK in each project states that you need to set the ApplicationInsights.config file to be copied always to the output directory.
Additionally, you could refer to the quick start and instruments your app at run time to narrow this issue. Moreover, if I missed something or you did some other special code, you could update your question for us to troubleshoot this issue.
Related
I have a very frustrating NServiceBus problem that I cannot seem to figure out. I am hoping that you guys can shed some light on the situation.
I am currently using NServiceBus.Core v5.0 and NServiceBus.Host v6.0 and running it in Unobtrusive Mode.
It seems that no matter what configuration I use, I always get some kind of error. I will start with the configuration that produces the least problems:
Case 1 - Using custom assembly scanning:
public void Customize(BusConfiguration configuration)
{
var endpointName = typeof(EndpointConfig).Namespace;
configuration.SetUniqueHostId(endpointName);
configuration.UseSerialization<JsonSerializer>();
configuration.UsePersistence<NHibernatePersistence, StorageType.Outbox>();
configuration.AssembliesToScan(new List<Assembly>
{
GetType().Assembly,
typeof(ICustomCommand).Assembly
});
configuration.Conventions()
.DefiningCommandsAs(type => typeof(ICustomCommand).IsAssignableFrom(type));
configuration.EnableDurableMessages();
configuration.EnableInstallers();
var container = ContainerInitializer.Container;
configuration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
}
The issues I have noticed here are the following:
When starting the NServiceBus host application and the persistence SQL database does not yet exist, no exception is thrown saying that the database cannot be found (it does in case 2).
I keep getting the following exception:
NServiceBus.Timeout.Hosting.Windows.TimeoutPersisterReceiver Failed to fetch timeouts from the timeout storage
Which ultimately results in the application crashing because when this error occurs too many times, ServiceBus decides that enough is enough and just throws a fatal exception.
Besides the issues above, the application runs perfectly receiving and processing messages... until the fatal exception occurs
Now, this one is a bit more difficult:
Case 2 - Using default assembly scanning:
public void Customize(BusConfiguration configuration)
{
var endpointName = typeof(EndpointConfig).Namespace;
configuration.SetUniqueHostId(endpointName);
configuration.UseSerialization<JsonSerializer>();
configuration.UsePersistence<NHibernatePersistence, StorageType.Outbox>();
// !! DISABLED !!
// configuration.AssembliesToScan(new List<Assembly>
// {
// GetType().Assembly,
// typeof(ICustomCommand).Assembly
// });
configuration.Conventions()
.DefiningCommandsAs(type => typeof(ICustomCommand).IsAssignableFrom(type));
configuration.EnableDurableMessages();
configuration.EnableInstallers();
var container = ContainerInitializer.Container;
configuration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
}
In this case the following issues occur:
When the persistence SQL database does not yet exist:
When starting the NServiceBus host application and the SQL database does not exist, an exception is throw - Expected behavior (This is positive)
After creating the persistence SQL database:
ServiceControl.Plugin.Nsb5.Heartbeat.Heartbeats|Unable to send heartbeat to ServiceControl:
NServiceBus.Unicast.Queuing.QueueNotFoundException: Failed to send message to address: [Particular.ServiceControl#MYPCNAME]
Exception thrown: 'System.Messaging.MessageQueueException' in System.Messaging.dll
Additional information: External component has thrown an exception.
2017-09-15 16:25:45.6743|Warn|NServiceBus.Unicast.Messages.MessageMetadataRegistry|Message header 'SharedTemp.Interfaces.ICustomCommand'
was mapped to type 'SharedTemp.Interfaces.ICustomCommand' but that type was not found in the message registry [...]
Exception thrown: 'System.Exception' in NServiceBus.Core.dll
Additional information: Could not find metadata for 'Newtonsoft.Json.Linq.JObject'.
Now, exceptions 3 and 4 are particularly (no pun intended) odd since the NServiceBus documentation states:
By default all assemblies in the endpoint bin directory are scanned to find types implementing its interfaces so that it can configure them automatically.
And the "Newtonsoft.Json" and my "SharedTemp dll's" are indeed in the BIN folder, but NServiceBus does not seem to find them. As for point 1: NServiceBus does not create that queue for me, but it creates all the other queues that I need.
Finally the always requested app.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="MasterNodeConfig" type="NServiceBus.Config.MasterNodeConfig, NServiceBus.Core"/>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core"/>
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core"/>
<section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core"/>
</configSections>
<appSettings>
<add key="NServiceBus/Persistence/NHibernate/dialect" value="NHibernate.Dialect.MsSql2012Dialect"/>
<add key="NServiceBus/Outbox" value="true"/>
</appSettings>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
<UnicastBusConfig>
<MessageEndpointMappings />
</UnicastBusConfig>
<AuditConfig QueueName="audit"/>
<connectionStrings>
<add name="NServiceBus/Persistence" connectionString="Server=(LocalDB)\v11.0;Initial Catalog=NServiceBus;Integrated Security=true"/>
</connectionStrings>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri=""/>
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400"/>
</providers>
</roleManager>
</system.web>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
<MasterNodeConfig Node="localhost"/>
</configuration>
Does anyone have an idea about any of this?
After a lot of searching I finally found the problem!
First of all I was using a in-house NuGet package that was supposed to help me with configuring NServiceBus. The package worked fine for other projects, but for mine not so well, since I was using JsonSerialization instead of the default XML serialization.
The first problem with the package is that it used the "INeedInitialization" interface to configure NServiceBus. In my code I would then call "IConfigureThisEndpoint" to enable the JsonSerialization. The issue here was, that when starting the NServiceBus host, it would fail to find the NewtonSoft.Json library. If I then added custom assembly scanning to my own configuration code, it would not trigger "INeedInitialization", causing an incomplete/incorrect configuration.
I assume it could not load the NewtonSoft.Json library because scanning was triggered in the code/namespace of the package? Maybe #Sean Farmer can answer this?
The second problem with the package is that it would add connection strings to the app.config, one for "NServiceBus/Persistence" and one for "NServiceBus/Persistence/NHibernate/Saga". I am not using Saga, so the connection string for that was not needed. Initially this was not a problem since I caught it the first time, but I completely forgot about it after reinstalling the package. Removing this again also seemed to make NServiceBus happier.
So, what ended up working? I removed the package and did the configuration myself with the following result:
public void Customize(BusConfiguration configuration)
{
var endpointName = typeof(EndpointConfig).Namespace;
configuration.UniquelyIdentifyRunningInstance().UsingCustomIdentifier(endpointName);
configuration.EnableOutbox();
configuration.UsePersistence<NHibernatePersistence>();
configuration.Transactions().DefaultTimeout(TimeSpan.FromMinutes(5.0));
configuration.UseSerialization<JsonSerializer>();
configuration.Conventions()
.DefiningCommandsAs(type => typeof(ICustomCommand).IsAssignableFrom(type));
configuration.EnableDurableMessages();
configuration.EnableInstallers();
var container = ContainerInitializer.Container;
configuration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
}
#Sean: Thank you for allowing me to contact you. Luckily it was not necessary
#Mike: Thank you for the input
I have following code to start my server:
private static IXSocketServerContainer server = null;
public SocketServer()
{
server = XSockets.Plugin.Framework.Composable.GetExport<IXSocketServerContainer>();
}
this worked fine for me under WinXP and Win7, with exactly the same set of dll and exe files, but now I deployed my system under WinServer 2008 and I get following error:
clsSocketIntHandler|new , startin
servers|0|0||0||TypeInitializationException: ; The type initializer
for 'XSockets.Plugin.Framework.Composable' threw an exception. ; The
module was expected to contain an assembly manifest. (Exception from
HRESULT: 0x80131018)
Do you have any idea why could this be happening? What can be missing on my deployment machine? Can you please recommend me an alternative configuration to avoid this kind of dynamic loading?
My configuration now is as follows:
<appSettings>
<add key="XSockets.PluginCatalog" value="" />
<add key="XSockets.PluginFilter" value="*.dll,*.exe" />
</appSettings>
I answer this question only for completion and to help anyone that may face this problem. There are tow things you can do:
First: Upgrade to plug-in framework 1.3, (XSockets 3.0.3), this is mandatory
Second: try to limit the dll to load in case that you have a lot of libraries in the bin folder:
<appSettings>
<add key="XSockets.PluginCatalog" value="" />
<add key="XSockets.PluginFilter" value="XSockets.*,your.dlls.*" />
<!--
<add key="SocketServer.StartServers.Location" value="ws://localhost:3232" />
-->
</appSettings>
Uffe, thanks for your help!!
I'm having trouble getting IIS 7 to load this handler I've written. I'm keeping things really simple to start with. I have a Handler.cs file with the following code in it:
public class Handler :IHttpHandler
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("asdfasdf");
}
}
I have put this file in the root directory.
I want to execute this code whenever the root directory receives a request, so I have built the handler file like this:
<configuration>
<system.webServer>
<handlers>
<add name="Handler" verb="*"
path="*.*"
type="Handler"
resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>
IIS gives me the following error when I attempt to go to localhost/runt (my website root directory )
Server Error in '/' Application.
Could not load type 'Handler'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: Could not load type 'Handler'.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[HttpException (0x80004005): Could not load type 'Handler'.]
System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) +11247344
System.Web.Configuration.HandlerFactoryCache.GetHandlerType(String type) +23
System.Web.Configuration.HandlerFactoryCache..ctor(String type) +25
System.Web.HttpApplication.GetFactory(String type) +91
System.Web.MaterializeHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +338
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +263
Version Information: Microsoft .NET Framework Version:2.0.50727.5466; ASP.NET Version:2.0.50727.5459
Try setting the type to the fully qualified namesace.
You can find the default namespace through the properties of your web application.
<configuration>
<system.webServer>
<handlers>
<add name="Handler" verb="*"
path="*.*"
type="DefaultNamspaceFromProperties.ClassNamespace.Handler"
resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>
I suspect that creating a default handler for everything using the .NET Framework will have some security risks and you should probably do further reading / consultation to make sure you aren't adversely putting your sites' security at risk.
I need scheduling functionality on my .NET MVC website and I came across Quartz.net library which can do exactly what I need.
The problem is I'm running my site on a hosting (GoDaddy) and when I added Quartz.net 2.0.1 to my project I've got "that assembly does not allow partially trusted callers" exception. After some research I found out that many people have the same problem and some solved it by removing Common.Logging library from Quartz.net.
I followed some of the advice and removed all references to Common.Logging but I still have problems. It looks like it's not enough and now I'm getting Inheritance security rules violated while overriding member exception, more details:
Inheritance security rules violated while overriding member:
Quartz.Util.DirtyFlagMap`2<TKey,TValue>.GetObjectData
(System.Runtime.Serialization.SerializationInfo,
System.Runtime.Serialization.StreamingContext)'.
Security accessibility of the overriding method must match the
security accessibility of the method being overriden.
It looks like I really need to change something in Quartz.net to make it work.
Has anyone run Quartz.net on medium trust? If so what needs to be done? May be someone can suggest some alternatives?
Steinar's answer sent me in the right direction. Sharing the steps here that got QuartZNet to work in a medium trust hosting environment.
QuartzNet initially ran into permissions issues on medium trust, we needed to the do the following to fix the issue
(1) Downloaded QuartzNet code ( 2.1.0.400 ) from github and build it after making the following changes to AssemblyInfo.cs
Replaced
#if !NET_40
[assembly: System.Security.AllowPartiallyTrustedCallers]
#endif
with
[assembly: AllowPartiallyTrustedCallers]
#if NET_40
[assembly: SecurityRules(SecurityRuleSet.Level1)]
#endif
(2) Downloaded C5 code (v 2.1) and built it with
[assembly: AllowPartiallyTrustedCallersAttribute()
Ensure C5 is compiled in the same .NET version as Qartznet.
(3) Added the quartz section to web.config within TGH, section had requirepermission set to false. Common logging section also had requirepermission set to false, also configured it to use Common.Logging.Simple.NoOpLoggerFactoryAdapter.
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<sectionGroup name="common">
<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" requirePermission="false" />
</sectionGroup>
<section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<common>
<logging>
<factoryAdapter type="Common.Logging.Simple.NoOpLoggerFactoryAdapter, Common.Logging">
<arg key="showLogName" value="true" />
<arg key="showDataTime" value="true" />
<arg key="level" value="OFF" />
<arg key="dateTimeFormat" value="HH:mm:ss:fff" />
</factoryAdapter>
</logging>
</common>
<quartz>
<add key="quartz.scheduler.instanceName" value="QuartzScheduler" />
<add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
<add key="quartz.threadPool.threadCount" value="10" />
<add key="quartz.threadPool.threadPriority" value="2" />
<add key="quartz.jobStore.misfireThreshold" value="60000" />
<add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz" />
</quartz>
(4) Initialised the scheduler using constructor with namecollection as the parameter, namecollection was the quartz section picked up from web.config.
In global.asax
QuartzScheduler.Start();
The class
public class QuartzScheduler
{
public static void Start()
{
ISchedulerFactory schedulerFactory = new StdSchedulerFactory((NameValueCollection)ConfigurationManager.GetSection("quartz"));
IScheduler scheduler = schedulerFactory.GetScheduler();
scheduler.Start();
IJobDetail inviteRequestProcessor = new JobDetailImpl("ProcessInviteRequest", null, typeof(InviteRequestJob));
IDailyTimeIntervalTrigger trigger = new DailyTimeIntervalTriggerImpl("Invite Request Trigger", Quartz.TimeOfDay.HourMinuteAndSecondOfDay(0, 0, 0), Quartz.TimeOfDay.HourMinuteAndSecondOfDay(23, 23, 59), Quartz.IntervalUnit.Second, 1);
scheduler.ScheduleJob(inviteRequestProcessor, trigger);
}
}
public class InviteRequestJob : IJob
{
public void Execute(IJobExecutionContext context)
{
RequestInvite.ProcessInviteRequests();
}
}
I recommend building Common.Logging yourself rather than removing it from the project. You can get the latest source from http://netcommon.sourceforge.net/downloads.html.
I guess the second problem had to do with that the C5.dll wasn't trusted either. I would also just build that myself. The source can be found here: http://www.itu.dk/research/c5/.
Although there are other options than building the dlls (http://stackoverflow.com/questions/3072359/unblocking-a-dll-on-a-company-machine-how) I personally prefer to build the dlls myself unless I absolutely trust the downloaded product.
I have set of web services and I want to add a trace layer.
I don't want to modify each web service since I have many.
I would like to write log every entering to a web service: name of web service and parameters.
What is the best way to do so?
P.S. I am using asp.net and C#.
EDIT:
I only want to wrap the web services as each one will have log(..) at the beginning.
A common way to achieve this is to inject a SOAP extension. From there you can intercept every request/response packet in raw SOAP. The sample shows how to implement one, and the explanation describes how it works and how to configure it.
Sample:
http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapextension.aspx
Explanation:
http://msdn.microsoft.com/en-us/library/esw638yk(vs.71).aspx
Configuration:
http://msdn.microsoft.com/en-us/library/b5e8e7kk(v=vs.71).aspx
<configuration>
<system.web>
<webServices>
<soapExtensionTypes>
<add type="{Type name}, {Assembly}" priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
Add a Global Application Class Global.asax file to your project and add the logging logic to the Application_BeginRequest() method. The sender object will contain the HTTP Request and parameters. You can filter for just .asmx requests and log those.
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
EDIT--
Give PostSharp a try. It's the easiest way to get this functionality. For posterity I will leave my posting below but just ignore it and use PostSharp.
If your web services are WCF then you should check out http://msdn.microsoft.com/en-us/magazine/cc163302.aspx.
At each step along the way they provide extensibility points that you can plug into. You can use these extensibility points to implement a wide variety of custom behaviors including message or parameter validation, message logging, message transformations.
No doubt this is the way to go for WCF services. Otherwise, if they are just web services then you can use the Unity framework and hookup and Interceptor to do the same thing.
If the progamming language is not important, you may put Apache Synapse as proxy in front of your services. Your clients will then send the requests to Synapse, which will delegate the requests to your original services. The proxy can be configured to do something with the requests in between, such as logging.
Please see the following links for more information:
http://synapse.apache.org/Synapse_Configuration_Language.html#proxy,
http://synapse.apache.org/Synapse_Configuration_Language.html#send,
http://synapse.apache.org/Synapse_Configuration_Language.html#log
A combination of the following examples could work for you:
http://synapse.apache.org/Synapse_Samples.html#Sample0
http://synapse.apache.org/Synapse_Samples.html#ProxyServices
e.g.:
<definitions xmlns="http://ws.apache.org/ns/synapse"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ws.apache.org/ns/synapse http://synapse.apache.org/ns/2010/04/configuration/synapse_config.xsd">
<proxy name="StockQuoteProxy">
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<outSequence>
<!-- log all attributes of messages passing through -->
<log level="full"/>
<!-- Send the message to implicit destination -->
<send/>
</outSequence>
</target>
<publishWSDL uri="file:repository/conf/sample/resources/proxy/sample_proxy_1.wsdl"/>
</proxy>
How about writing your own HttpModule? That would negate the need to touch the existing web service code. You would just need to add your module to each web.config file.
I maintain an Open source web services framework that lets you simply achieve this by having all web services inherit from a base class and do your own logging.
Here is an example of a base-class where I maintain a distributed rolling log for all exceptions in redis - a very fast NoSQL data store:
public object Execute(TRequest request)
{
try
{
//Run the request in a managed scope serializing all
return Run(request);
}
catch (Exception ex)
{
return HandleException(request, ex);
}
}
protected object HandleException(TRequest request, Exception ex)
{
var responseStatus = ResponseStatusTranslator.Instance.Parse(ex);
if (EndpointHost.UserConfig.DebugMode)
{
// View stack trace in tests and on the client
responseStatus.StackTrace = GetRequestErrorBody() + ex;
}
Log.Error("ServiceBase<TRequest>::Service Exception", ex);
//If Redis is configured, maintain rolling service error logs in Redis (an in-memory datastore)
var redisManager = TryResolve<IRedisClientsManager>();
if (redisManager != null)
{
try
{
//Get a thread-safe redis client from the client manager pool
using (var client = redisManager.GetClient())
{
//Get a client with a native interface for storing 'ResponseStatus' objects
var redis = client.GetTypedClient<ResponseStatus>();
//Store the errors in predictable Redis-named lists i.e.
//'urn:ServiceErrors:{ServiceName}' and 'urn:ServiceErrors:All'
var redisSeriviceErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, ServiceName)];
var redisCombinedErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, CombinedServiceLogId)];
//Append the error at the start of the service-specific and combined error logs.
redisSeriviceErrorList.Prepend(responseStatus);
redisCombinedErrorList.Prepend(responseStatus);
//Clip old error logs from the managed logs
const int rollingErrorCount = 1000;
redisSeriviceErrorList.Trim(0, rollingErrorCount);
redisCombinedErrorList.Trim(0, rollingErrorCount);
}
}
catch (Exception suppressRedisException)
{
Log.Error("Could not append exception to redis service error logs", suppressRedisException);
}
}
var responseDto = CreateResponseDto(request, responseStatus);
if (responseDto == null)
{
throw ex;
}
return new HttpResult(responseDto, null, HttpStatusCode.InternalServerError);
}
Otherwise for normal ASP.NET web services frameworks I would look at the Global.asax events, specifically the 'Application_BeginRequest' event which Fires each time a new request comes in.
I don't know if this is what you are looking for ,just add this to you WCF config file after the ""
It will create very extensive logging that you will be able to read using the Microsoft Service Trace Viewer
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
<source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
propagateActivity="true">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\ServiceLog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
<add initializeData="C:\Tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>