How to use Hangfire in ASP.NET Core with Azure database and Active Directory Password authentication - azure-active-directory

We're trying our first use of Hangfire (v1.7.19) in an ASP.NET Core WebApi application (.NET 5). Previously they've all been old school ASP.NET, and have worked without issue.
Hangfire packages used (per the Hangfire documentation) are Hangfire.Core, Hangfire.SqlServer and Hangfire.AspNetCore. We've also tried to just use the combined Hangfire package, but are having the same results.
Lifting directly from the code on that documentation page, in ConfigureServices we add
services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(connectionString), new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
}));
which, at runtime, gives
System.ArgumentException
HResult=0x80070057
Message=Keyword not supported: 'authentication'.
Source=System.Data.SqlClient
StackTrace:
at System.Data.Common.DbConnectionOptions.ParseInternal(Dictionary`2 parsetable, String connectionString, Boolean buildChain, Dictionary`2 synonyms)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Dictionary`2 synonyms)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
at Hangfire.SqlServer.SqlServerStorage.<.ctor>b__6_0()
at Hangfire.SqlServer.SqlServerStorage.CreateAndOpenConnection()
at Hangfire.SqlServer.SqlServerStorage.UseConnection[T](DbConnection dedicatedConnection, Func`2 func)
at Hangfire.SqlServer.SqlServerStorage.UseConnection(DbConnection dedicatedConnection, Action`1 action)
at Hangfire.SqlServer.SqlServerStorage.Initialize()
at Hangfire.SqlServer.SqlServerStorage..ctor(String nameOrConnectionString, SqlServerStorageOptions options)
at Hangfire.SqlServer.SqlServerStorage..ctor(String nameOrConnectionString)
at Hangfire.SqlServerStorageExtensions.UseSqlServerStorage(IGlobalConfiguration configuration, String nameOrConnectionString)
The value of connectionString is
Initial Catalog=XXX;Data Source=YYY;Authentication=Active Directory Password;UID=ZZZ;PWD=PPP"
This works fine with local SqlServer and LocalDb, but not with AzureDB. The connection string is exactly the one we're also using for EntityFrameworkCore 5 (in fact, the value is assigned from context.Database.GetConnectionString()).
I've read where there were issues with AzureDB and .NET Core, but those were resolved quite some time ago. Looking through the Hangfire.SqlServer package dependencies, I see where it uses System.Data.SqlClient, and current documentation for AzureDB use all refer to Microsoft.Data.SqlClient, which makes me think that the enhancements to support Active Directory Password authentication weren't made in System.Data.SqlClient but only in the newer Microsoft.Data.SqlClient package. If that's the case, I can put in a request that Hangfire replace its SqlClient package, but want to get confirmation before I do that.
Any ideas if this is indeed the case? Is there something we can do in the meantime to fix this instead?
Thanks in advance.

Hangfire IO GitHub Issue 1827
Pointers from Sergey Odinokov
As early as 1.7.8 there has been support to use an overload of UseSqlServerStorage that accepts a Func<DbConnection> instead of a connection string where you can use a connection factory to provide the newer Microsoft.Data.SqlClient.SqlConnection which supports the Authentication keyword.
Here is the related source code
You can use this like
services.AddHangfire(config => config
// other options you listed above removed for brevity
.UseSqlServerStorage(
() => new Microsoft.Data.SqlClient.SqlConnection(<connection_string>)
, new SqlServerStorageOptions() {...}
)
);

Related

Using .Net Framework CertificationValidationMode is ignored?

So I have two demo applications to test. One in .net 4.7 and the other in .net core 3.1.
When running the applications I'm getting different results depending the one used.
In both of them I put the CertificationValidationMode to None.
In .Net core I'm getting this error:
ITfoxtec.Identity.Saml2.Cryptography.InvalidSignatureException: Signature is invalid.
at ITfoxtec.Identity.Saml2.Saml2Request.ValidateXmlSignature(SignatureValidation documentValidationResult)
at ITfoxtec.Identity.Saml2.Saml2Request.Read(String xml, Boolean validateXmlSignature)
at ITfoxtec.Identity.Saml2.Saml2Response.Read(String xml, Boolean validateXmlSignature)
at ITfoxtec.Identity.Saml2.Saml2AuthnResponse.Read(String xml, Boolean validateXmlSignature)
at ITfoxtec.Identity.Saml2.Saml2PostBinding.Read(HttpRequest request, Saml2Request saml2RequestResponse, String messageName, Boolean validateXmlSignature)
at ITfoxtec.Identity.Saml2.Saml2PostBinding.UnbindInternal(HttpRequest request, Saml2Request saml2RequestResponse, String messageName)
at ITfoxtec.Identity.Saml2.Saml2Binding`1.Unbind(HttpRequest request, Saml2Response saml2Response)
which is good because I modified the assertion to extend the time for testing and at that point I'm assuming that the validation was bypassed and it is failing because it does not match.
In .Net Framework, this error is coming up:
ID4037: The key needed to verify the signature could not be resolved from the following security key
identifier
'SecurityKeyIdentifier(
IsReadOnly = False,
Count = 1,
Clause[0] = System.IdentityModel.Tokens.Saml2SecurityKeyIdentifierClause
)
'. Ensure that the SecurityTokenResolver is populated with the required key.
at System.IdentityModel.EnvelopedSignatureReader.ResolveSigningCredentials()
at System.IdentityModel.EnvelopedSignatureReader.OnEndOfRootElement()
at System.IdentityModel.EnvelopedSignatureReader.Read()
at System.Xml.XmlReader.ReadEndElement()
at System.IdentityModel.Tokens.Saml2SecurityTokenHandler.ReadAssertion(XmlReader reader)
at System.IdentityModel.Tokens.Saml2SecurityTokenHandler.ReadToken(XmlReader reader)
at ITfoxtec.Identity.Saml2.Saml2AuthnResponse.ReadSecurityToken(XmlNode assertionElement)
at ITfoxtec.Identity.Saml2.Saml2AuthnResponse.Read(String xml, Boolean validateXmlSignature)
at ITfoxtec.Identity.Saml2.Saml2PostBinding.Read(HttpRequest request, Saml2Request saml2RequestResponse, String messageName, Boolean validateXmlSignature)
at ITfoxtec.Identity.Saml2.Saml2Binding`1.ReadSamlResponse(HttpRequest request, Saml2Response saml2Response)
Here I'm thinking that the validation is happening, it is not bypassed, and it is failing. Basically the Validation Mode is ignored.
Am I thinking this wrong?
Thanks
As you say the result looks correct regarding .NET core.
It looks like the .Net Framework cannot find a certificate that match the certificate used in the SAML. 2.0 AuthnResponse. Maybe the .Net Framework application is not configured with the correct certificate? I do not think it has anything to do with the Validation Mode.

Entity Framework Core - error: keyword not supported: '"server'

I am using Entity Framework Core 2.1. I scaffold my entity classes aka database first. When I try to get the data from one of the db tables, I get an error "keyword not supported for 'server'."
I googled and it looks like my connection string is not correct. Here it is setting in my json file
"DefaultConnection": "\"Server=myDb.com;Database=MyDb;user id=admin;Password=Password;MultipleActiveResultSets=true;Provider=System.Data.SqlClient"
I have seen other type of EF connection like
connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="data source=(local);initial catalog=test;integrated security=True;multipleactiveresultsets=True;App=EntityFramework""
I am not sure about the .csdl, ssdl and msl.
Any help is appreciated. Thanks.
Error:
System.ArgumentException: Keyword not supported: '"server'.
at System.Data.Common.DbConnectionOptions.ParseInternal(Dictionary2 parsetable, String connectionString, Boolean buildChain, Dictionary2 synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Dictionary2 synonyms)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(DbConnectionPoolKey key)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.CreateDbConnection()
at Microsoft.EntityFrameworkCore.Internal.LazyRef1.get_Value()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func3 operation, Func3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.Enumerator.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable1 results, QueryContext queryContext, IList1 entityTrackingInfos, IList1 entityAccessors)+MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext()
Exception thrown: 'System.ArgumentException' in Microsoft.EntityFrameworkCore.dll
'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.2\System.IO.MemoryMappedFiles.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The program '[3112] dotnet.exe' has exited with code -1 (0xffffffff).
Simple removing \" from front and end of connection string will work. In this case you can use complete connection string.
"DefaultConnection": "\"Server=tcp:myDb.com,1433;Initial Catalog=MyDb;Persist Security Info=False;User ID=admin;Password=Password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"\;"
to
"DefaultConnection": "Server=myDb.com,1433;Initial Catalog=MyDb;Persist Security Info=False;User ID=admin;Password=Password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
After playing with different connection string, here what I changed in my json to file to get it working
"DefaultConnection": "Server=myDb.com;Database=MyDb;user id=admin;Password=Password;
This is because the connection strings have been replaced after scaffolding the identity. The replacement string may look very similar but has some escaped characters in it.
I had appSettings.Development.json, appSettings.Staging.json and appSettings.Production.json, each with DIFFERENT connection strings.
After scaffolding my Identity using an EXISTING dbContext, it had replaced the connection string in appSettings.json files with the one single connection string. I have no idea why it picked that one but I realised the string was escaped so
"Server=MYCOMPNAME\\SQLEXPRESS;...
had become
"\"Server=KRYTEN\\\\SQLEXPRESS;
and this is why we get the error.

System.ArgumentException: An entry with the same key already exists. in sssi pack

I deploy the pack from ssis to SSISD, and try to create agent job to run the package.
after deploy to SSMS, getting the error
System.ArgumentException: An entry with the same key already exists.
===================================
An entry with the same key already exists. (System)
Program Location:
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.TreeSet1.AddIfNotPresent(T item)
at System.Collections.Generic.SortedDictionary2.Add(TKey key, TValue value)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcCollatedDictionaryCollection3.AddShadow(T obj)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcCollection3.Microsoft.SqlServer.Management.Sdk.Sfc.ISfcCollection.AddShadow(SfcInstance sfcInstance)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcInstance.CreateNewObjectFromRow(ISfcCollection childColl, IDataReader reader)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcInstance.InitObjectsFromEnumResultsRec(ISfcCollection childColl, IDataReader reader, Int32 columnIdx, Object[] parentRow)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcInstance.InitObjectsFromEnumResults(ISfcCollection childColl, IDataReader reader)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcInstance.InitChildLevel(ISfcCollection childColl)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcCollection3.InitializeChildCollection(Boolean refresh)
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcCollection3.EnsureCollectionInitialized()
at Microsoft.SqlServer.Management.Sdk.Sfc.SfcCollection3.Microsoft.SqlServer.Management.Sdk.Sfc.ISfcCollection.EnsureInitialized()
at Microsoft.SqlServer.Management.IntegrationServices.PackageInfo.get_Parameters()
at Microsoft.SqlServer.IntegrationServices.UITasks.ExecuteDataProvider.AddParametersDataGridToDataBus()
at Microsoft.SqlServer.IntegrationServices.UITasks.ExecuteDataProvider.AddToDataBus()
at Microsoft.SqlServer.IntegrationServices.UITasks.PropertiesDataProvider.Initialize(ITaskManager taskManager, IPropertyDictionary properties)
at Microsoft.SqlServer.Management.TaskForms.TaskManager.InitializeTaskFormComponent(Object component, ITaskFormComponentInfo info)
at Microsoft.SqlServer.Management.TaskForms.TaskFormManager.InitializeTaskFormComponent(Object component, ITaskFormComponentInfo info)
at Microsoft.SqlServer.Management.TaskForms.TaskManager.InitializeTaskFormComponents(IList1 taskFromComponentsInfo)
at Microsoft.SqlServer.Management.TaskForms.TaskFormManager.InitializeTaskFormComponents(IList1 taskFromComponentsInfo)
at Microsoft.SqlServer.Management.TaskForms.TaskManager.Initialize(String moniker, IContext context, IList1 taskFromComponents)
at Microsoft.SqlServer.Management.TaskForms.TaskFormManager.Initialize(String moniker, IContext context, ITaskFormInfo taskFormInfo)
at Microsoft.SqlServer.Management.TaskFormFactoryService.CreateTaskFormInstance(String taskFormMoniker, IContext context)
at Microsoft.SqlServer.Management.ActionHandlers.ShowTaskUIDialogActionHandler.RunTaskForm(IContext context)
at Microsoft.SqlServer.Management.ActionHandlers.DialogBasedActionHandler.RunTaskFormThread(Object contextObject)
Please help to fix it
This looks to be an error that one encounters when deploying SSIS packages having connection managers not in sync i.e. if a connection manager is changed as 'project connection manager' and this change is not reflected in the other packages using the same connection manager. Refer to the link for more details.
This issue has been occurred due to same connection name used for multiple packages.
Solution: Check which connections name are same for multiple packages .
Change the duplicate connection names and then Build and Deploy..
It worked for me :)

Elmah.MVC - MVC 5 ArgumentNullException: Value cannot be null. Parameter name id:

I am receiving an error when trying to render the elmah error logs and using SQL DB. "http://localhost:5525/elmah" [ArgumentNullException: Value cannot be null.
Parameter name: id]
Elmah.ErrorLogEntry..ctor(ErrorLog log, String id, Error error) in c:\builds\ELMAH-1.2-SP2\src\Elmah\ErrorLogEntry.cs:57
Elmah.SqlErrorLog.ErrorsXmlToList(XmlReader reader, IList errorEntryList) in c:\builds\ELMAH-1.2-SP2\src\Elmah\SqlErrorLog.cs:365
Elmah.SqlErrorLog.ErrorsXmlToList(String xml, IList errorEntryList) in c:\builds\ELMAH-1.2-SP2\src\Elmah\SqlErrorLog.cs:332
Elmah.SqlErrorLog.GetErrors(Int32 pageIndex, Int32 pageSize, IList errorEntryList) in c:\builds\ELMAH-1.2-SP2\src\Elmah\SqlErrorLog.cs:186
Elmah.ErrorLogPage.OnLoad(EventArgs e) in c:\builds\ELMAH-1.2-SP2\src\Elmah\ErrorLogPage.cs:76
System.Web.UI.Control.LoadRecursive() +54
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +772
I have the latest Core Elmah 1.2-SP2 and the latest Elmah.MVC 2.1.2. I installed the Nuget package Elmah.MVC with default web.config settings.
When I configure web.config to log errors to the database the errors are recorded in the database but I can't render the error page. When I don't configure the database the elmah page renders just fine.
<elmah>
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="Company" />
</elmah>
Decompiling Elmah I see in the constructor where the argument is thrown.
if (id == null)
throw new ArgumentNullException("id");
if (id.Length == 0)
throw new ArgumentException((string) null, "id");
All my ErrorId's in the database are populated GUIDs.
I am stumped as to what id is not being passed to the core elmah. Has anyone ran into this before?
I downloaded the core Elmah code and stepped through to find in SqlErrorLog.cs, method ErrorsXmlToList(XmlReader reader, IList errorEntryList) there is a call to get id which was the parameter missing: string id = reader.GetAttribute("errorId"); I lower cased "errorid" and everything worked. Obviously this is not a good solution because this is core code that everyone works with so I dug deeper.
This led me to look at stored procedure ELMAH_GetErrorsXml. I found in our database we had a lower case "errorid". I updated the stored procedure to select "errorId" and changed the core Elmah back to the original code and of course everything worked.

Azure Diagnostics: Access to the path '(GUID)-mswapd-lock' is denied?

Code and configuration:
I've enabled Diagnostics per the official tutorial at https://www.windowsazure.com/en-us/develop/net/common-tasks/diagnostics/. My diagnostic initializer is invoked from Global.asax (no WebRole.cs for this WCF ported to Azure WebRole) and its quite simple like:
public bool Initialize()
{
DiagnosticMonitorConfiguration config = DiagnosticMonitor.GetDefaultInitialConfiguration();
config.WindowsEventLog.DataSources.Add("Application!*");
config.WindowsEventLog.ScheduledTransferPeriod = System.TimeSpan.FromMinutes(1.0);
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", config);
return true;
}
Cloud and Local strings same:
I'm using the SAME cloud based diagnostic connection string for local and cloud configurations.
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="MyApp.API.Azure1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2012-05.1.7">
<Role name="MyApp.API">
<Instances count="1" />
<ConfigurationSettings>
...
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.ConfigStoreConnectionString" value="DefaultEndpointsProtocol=https;AccountName=myapi;AccountKey=MyVeryLongStringHereWhichIsActuallyAKeyForAPlaceInTheCloudWhereUnicornsDanceUnderDoubleRainbows" />
</ConfigurationSettings>
<Certificates>
<Certificate name="Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption" thumbprint="ThumbPrintStringsAreBiggerThanPinkiePrintString" thumbprintAlgorithm="sha1" />
</Certificates>
</Role>
</ServiceConfiguration>
Error:
When I run the above within Azure Emulator (local compute) I do not get the error (despite the cloud connection string for diagnostics). When I run the webrole on Azure (with same diagnostic sting and of course, code), I get the following error:
[UnauthorizedAccessException: Access to the path '05d5e525-e1bc-4a37-8bfb-010bb2941301-mswapd-lock' is denied.]
System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) +12895415
System.Threading.MutexTryCodeHelper.MutexTryCode(Object userData) +229
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) +0
System.Threading.Mutex..ctor(Boolean initiallyOwned, String name, Boolean& createdNew, MutexSecurity mutexSecurity) +629
System.Threading.Mutex..ctor(Boolean initiallyOwned, String name, Boolean& createdNew) +18
Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.StartDiagnosticsMonitorProcess(DiagnosticMonitorStartupInfo info) +171
Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.ReconfigureMonitoringProcess(ConfigRequest req) +209
Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.UpdateState(DiagnosticMonitorStartupInfo startupInfo) +207
Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.StartWithExplicitConfiguration(DiagnosticMonitorStartupInfo startupInfo, DiagnosticMonitorConfiguration initialConfiguration) +643
Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.Start(CloudStorageAccount storageAccount, DiagnosticMonitorConfiguration initialConfiguration) +47
Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.Start(String diagnosticsStorageAccountConfigurationSettingName, DiagnosticMonitorConfiguration initialConfiguration) +108
myApp.api.Diag.Diagnostics.Initialize() in c:\Work\MyApp.API\source\Diag\Diagnostics.cs:42
Global.Application_Start(Object sender, EventArgs e) in c:\Work\MyApp.API\source\Global.asax.cs:30
Attempts: None worked
Disabled all Azure monitoring and logging (from portal) for this storage account in case Azure's own monitoring/logging mechanisms were locking it down
Replaced UseDevelopmentStorage=true with real cloud connection string for diagnostics even for local configuration (local compute/Azure emulator).
Simplified diagnostic initializer to bare minimum (seen above). However, DiagnosticMonitor.Start(...) always fails.
Created another diagnostic connection string in .cscfg file (with reference in .csdef too) so that if the original Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString is also used by Azure infrastructure, I have another string for it. No help, same error.
I've burnt many hours trying to debug this but I always get this error on Azure.
Question:
Can someone help me get rid of this error? I can try a few ideas you may have. I'm disappointed by the MS tutorial but disappointment doesn't help.
Exactly the same symptoms here (but in an ASP.NET MVC application).
Basically you shouldn't be using the DiagnosticMonitor.Start() any more.
The below worked for me (Azure SDK 1.8, October 2012)
I simplified the init code from this article:
http://convective.wordpress.com/2010/12/01/configuration-changes-to-windows-azure-diagnostics-in-azure-sdk-v1-3/
private void ConfigureDiagnostics()
{
var wadConnectionString ="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
var cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue(wadConnectionString));
var roleInstanceDiagnosticManager =
cloudStorageAccount.CreateRoleInstanceDiagnosticManager(
RoleEnvironment.DeploymentId,
RoleEnvironment.CurrentRoleInstance.Role.Name,
RoleEnvironment.CurrentRoleInstance.Id);
var diagnosticMonitorConfiguration = roleInstanceDiagnosticManager.GetCurrentConfiguration();
diagnosticMonitorConfiguration.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1d);
diagnosticMonitorConfiguration.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1d);
diagnosticMonitorConfiguration.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
roleInstanceDiagnosticManager.SetCurrentConfiguration(diagnosticMonitorConfiguration);
}
I'm calling it from the Application_Start() in Global.asax.cs and it works fine now. Both locally and in the cloud.
You also need this in your web.config:
<system.diagnostics>
<trace>
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>
</system.diagnostics>
and this in your ServiceDefinition.csdef 's WebRole section:
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
These are added by the wizard by default, but still worth checking when migrating existing code to Azure.
A note to log4net users:
Specialized appenders are not really necessary, you can use the standard log4net.Appender.TraceAppender which comes with log4net - just configure it in your web.config and init log4net as usual it in your Application_Start() or prior to the 1st use.
Removing from trace listeners element this line fixed the problem for me.
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="AzureDiagnostics" />
Know I'm thinking how to update already existing application configuration and not create one during the application start.

Resources