nservicebus using generic host with azure queues causes msmq error - azure

I have an on premise service bus that is configured to handle messages from an azure queue. The problem i am having is that the host is reporting an msmq error saying that it could not create the error queue. Aside from the fact that it should not be using msmq, it also handles the messages with no problems despite the error so it does not seem to be critical.
My Host is running as a class library configured to start with the nservicebus.host.exe process.
Here is my host code and config:
internal class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization
{
#region IWantCustomInitialization Members
public void Init()
{
Configure.With()
.DefaultBuilder()
.AzureMessageQueue()
.JsonSerializer()
.UnicastBus()
.IsTransactional(true)
.InMemorySubscriptionStorage();
}
#endregion
}
Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="AzureQueueConfig" type="NServiceBus.Config.AzureQueueConfig, NServiceBus.Azure"/>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
</configSections>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
<AzureQueueConfig QueueName="sender" ConnectionString="UseDevelopmentStorage=true" PeekInterval="5000" MaximumWaitTimeWhenIdle="60000" />
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedruntime version="v4.0" />
<requiredruntime version="v4.0.20506" />
</startup>
</configuration>
And Here is the actual Error Message:
2012-04-24 07:57:10,973 [1] ERROR NServiceBus.Utils.MsmqUtilities [(null)] <(nul
l)> - Could not create queue error#UseDevelopmentStorage=true or check its exist
ence. Processing will still continue.
System.Messaging.MessageQueueException (0x80004005): Message Queue service is no
t available.
at System.Messaging.MessageQueue.Create(String path, Boolean transactional)
at NServiceBus.Utils.MsmqUtilities.CreateQueue(String queueName, String accou
nt)
at NServiceBus.Utils.MsmqUtilities.CreateQueueIfNecessary(Address address, St
ring account)
EDIT: Adding .MessageForwardingInCaseOfFault() to the initialization corrected the issue.

Looks like AsA_Server assumes msmq, guess you'll have to configure the process manually

Adding .MessageForwardingInCaseOfFault() to the init method resolved the issue. Still feels like there is an underlying bug, but it is working.
I suspect that below described the next hurdle (not handling errors correctly) but i will have to try to force a failed message to verify.
As described in:
NServiceBus error queues in Azure

Related

.NET Standard 2.0 logging NLOG gives System.TypeInitializationException

I did 2 projects to test out NLog on a .NET Framework 4.6.1 standard console app and on .NET Standard 2.0 Library. My intention is to port as much code as I can to .NET Standard 2.0 for future multiplatform compatibility.
Both share the same code but the .NET Standard version produces an exception.
Here's the code
Console.WriteLine("Writing log");
Logger _errorLog = LogManager.GetLogger("ErrorsLogger");
Logger _tradesLog = LogManager.GetLogger("TradesLogger");
_errorLog.Error("This is the log message!!!");
Console.WriteLine("End log");
Console.Read();
Here's the App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="ErrorsLogger" xsi:type="File" fileName="ErrorsLog.txt" />
<target name="TradesLogger" xsi:type="File" fileName="TradesLog.txt" />
</targets>
<rules>
<logger name="ErrorsLogger" minlevel="Info" writeTo="ErrorsLogger" />
<logger name="TradesLogger" minlevel="Info" writeTo="TradesLogger" />
</rules>
</nlog>
</configuration>
I get the log fine in the .NET 4.6.1 Console app and produces the expected log file with the log message in it.
If I run the .NET Standard 2.0 library through some Microsoft Unit Test project I get this exception when it tries to call _errorLog.GetLogger
UnitTestProject.UnitTest1.TestMethod1 threw exception:
System.TypeInitializationException: The type initializer for
'NLog.LogManager' threw an exception. --->
System.TypeInitializationException: The type initializer for
'NLog.LogFactory' threw an exception. --->
System.MissingMethodException: Method not found:
'System.AppDomainSetup System.AppDomain.get_SetupInformation()'.
EDIT:
Nuget NLOG Version: 4.4.12
Exception thrown in a non static method:
About the non static method to get a better exception:
The exception is thrown at the GetLogger("X") level, which is a non static constructor. The initialization routine crashes even before trying to log something.
In addition, I get a WARNING (yellow exclamation mark) in the error list saying:
Warning The 'configuration' element is not declared.
Adding internal logging doesn't produce any output. This is the configuration i have used, starting from their Internal logging guide:
InternalLogger.LogLevel = LogLevel.Trace;
InternalLogger.LogFile = #"C:\temp\int.txt";
InternalLogger.LogToConsole = true;
InternalLogger.LogToConsoleError = true;
InternalLogger.LogWriter = new StringWriter(new StringBuilder());
InternalLogger.LogToTrace = true;
LogManager.ThrowConfigExceptions = true;
LogManager.ThrowExceptions = true;
Logger logger = LogManager.GetLogger("foo");
I'm administrator and Visual Studio 2017 is started as administrator and I have permission to write in C:\temp ad .NET 4.6.1 console application is able to write in that folder and it's in the same project.
The internal log file is empty and the Unit test project runs the test successfully.
I have no clue of what is happening. No error is thrown now.
Any suggestion to debug the issue is welcome.
An ISSUE on GitHub is already opened.
HERE is a test solution that I made to show you (PASSWORD: logging123). Now that I've updated to Nlog 4.5 you will see that the .NET framework solution throws an error trying to get an old version of Nlog (that I've never referenced) and that .NET Core unit test solution works but doesn't produce any file.
I was experiencing the same issue though I was running .NET 4.7. I updated my NLog package from 4.4.12 to 4.5.0-rc04 and it worked. Knowing its pre-release you may want to be cautions about putting it on live environment though.
Your zipped solution is password protected, so now it is just me guessing, but it looks like you are using app.config to hold nlog.config.
Pretty sure app.config are not being used by NetCoreApps. Try to put your Nlog-config in a separate file called nlog.config and make sure it is Copy Always (In Visual Studio File Properties).

ELMAH - Get SMTP credentials from Azure Application Settings

I've got an Azure Web App using ELMAH to log unhandled exceptions.
When I first deployed it, the web.config had the full SMTP setup defined in it, and ELMAH emailed exceptions:
<system.net>
<mailSettings>
<smtp from="me#mydomain.com">
<network host="smtp.mailprovider.com"
port="123"
userName="myUserName"
password="p#ssw0rd" />
</stmp>
</mailSettings>
</system.net>
The username and password have since been removed from the web.config, and they're now stored as application settings, configured through the Azure Portal.
Most of the emails I send still work fine, as the email code can access these application settings and use them when instantiating the SmtpClient, e.g.:
var userName = WebConfigurationManager.AppSettings["smtp.userName"];
var password = WebConfigurationManager.AppSettings["smtp.password"];
var credentials = new NetworkCredential(userName, password);
using (var smtpClient = new SmtpClient { Credentials = credentials })
{
await smtpClient.SendMailAsync(mailMessage);
}
What's the best way to get ELMAH to use the credentials stored in the application settings?
Options I can see:
There is a page on the wiki explaining how to use ELMAH's ErrorTweetModule to do an HTTP form post with the error details to any URL. The controller receiving the post could then use the stored credentials to email the details on.
The WebBase has a link to an article suggesting you can send emails directly to the recipient's SMTP server without authentication, but it says this may not work if you have DomainKeys set up, which I do.
This answer links to an article about intercepting the Mailing event, to customise the message.
I ended up creating a custom version of Elmah's ErrorMailModule, derived from the standard one, but overriding the SendMail method, based on some advice from Atif Aziz in a discussion on Google Groups.
The only changes required were to create the new module, and switch the Web.Config to use the custom module instead of the standard one.
Module
using System;
using System.Net.Mail;
namespace Test
{
public class ErrorMailModule : Elmah.ErrorMailModule
{
protected override void SendMail(MailMessage mail)
{
if (mail == null) throw new ArgumentNullException(nameof(mail));
// do what you want with the mail
// (in my case this fires up the email service, which
// gets the credentials from the Azure settings)
}
}
}
Web Config Changes
All that's required is to change the two occurrences of Elmah.ErrorLogModule, Elmah to your own module, in this case Test.ErrorMailModule.
So, instead of this...
<system.web>
<httpModules>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
</modules>
</system.webServer>
...you should now have this:
<system.web>
<httpModules>
<add name="ErrorMail" type="Test.ErrorMailModule" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<add name="ErrorMail" type="Test.ErrorMailModule" preCondition="managedHandler" />
</modules>
</system.webServer>
You will still need the errorMail section, as Elmah is still responsible for creating the email. Mine looks like this:
<elmah>
<errorMail from="user#domain.com" to="user#domain.com" subject="Custom Email Module"/>
</elmah>
Creating a HTTP request could work, but that should be the solution if everything else doesn't work IMO. Intercepting the Mailing event doesn't work, since you do not have access to the SmtpClient with the credentials in that event.
I've looked at different ways to update the SMTP settings from code. At first I though that I could just get a reference to the smtp section and update the properties, since they all have setter. But the code throw a configuration exception on runtime.
From what I can find, the only way to update the username and password in smtp section, is to read the web.config, update it and write the new version. Here's an example of writing updates to web.config:
var configuration = WebConfigurationManager.OpenWebConfiguration("~");
var section = configuration.GetSection("system.net/mailSettings/smtp") as SmtpSection;
section.Network.UserName = ConfigurationManager.AppSettings["myusername"];
section.Network.Password = ConfigurationManager.AppSettings["mypassword"];
configuration.Save();
The code actually updates the web.config. The code can be run at startup, but that would modify your web.config file locally as well. Another approach would be to run the code as part of a post deployment task with Azure.

Azure AppInsight with Log4Net

I have been trying to write Logs(Trace, Information & Exception) in Azure AppInsights using Log4Net instead of default api Telemetry client. When I run the application from VS2013 neither I get any error message nor am seeing logs in Azure portal.
Pleaes help me figure out this issue.
Note: Am using Log4net appender for AppIinsights.
Web.Config
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="aiAppender" />
</root>
<appender name="aiAppender" type="Microsoft.ApplicationInsights.Log4NetAppender.ApplicationInsightsAppender, Microsoft.ApplicationInsights.Log4NetAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline" />
</layout>
</appender>
MVC Controller
public class HomeController : Controller
{
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public ActionResult Index()
{
//Trace.TraceInformation("Home accessed at : {0}", DateTime.UtcNow);
Log.Info(string.Format("Home accessed at : {0}", DateTime.UtcNow));
return View();
}
}
Regards,
Rajaram.
If you are not seeing any log4net output, i'm presuming you are missing some log4net startup code, like this:
log4net.Config.XmlConfigurator.Configure();
which you might want in your startup class / code somewhere. Without that, log4net doesn't know wo read the configuration that's in web.config.
In addition to the answer from #JohnGardner, you can instead add a line to your AssemblyInfo.cs file as so: -
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
There is more discussion on the two approaches in the following question: -
Configure Log4Net in web application
And in a comment in somewhere in that discussion is a link to the log4net FAQs that touches on the differences in the question "When should I log my first message?": -
https://logging.apache.org/log4net/release/faq.html#first-log
I found both of these to be of further use to me.

Exception Handling for Service Bus Queue Host Service

I have a WCF service that is connected to a service bus Queue ready to receive messages. This is working great but i would like to be able to mark the message as a DeadLetter if i have an issue processing the message. Currently if my code throws an exception the message still gets removed from the queue, but i want to be able in configuration to specify to not deleted from the queue but mark it as a DeadLetter. I've done some search and I can't figure out on how to do that. I am currently running the service as a windows service
Uri baseAddress = ServiceBusEnvironment.CreateServiceUri("sb",
"namespace", "servicequeue");
_serviceHost = new ServiceHost(typeof(PaperlessImportServiceOneWay), baseAddress);
_serviceHost.Open();
config:
<services>
<service name="Enrollment.ServiceOneWay">
<endpoint name="ServiceOneWay"
address="sb://namespace.servicebus.windows.net/servicequeue"
binding="netMessagingBinding"
bindingConfiguration="messagingBinding"
contract="IServiceOneWaySoap"
behaviorConfiguration="sbTokenProvider" />
</service>
</services>
<netMessagingBinding>
<binding name="messagingBinding" closeTimeout="00:03:00" openTimeout="00:03:00"
receiveTimeout="00:03:00" sendTimeout="00:03:00" sessionIdleTimeout="00:01:00"
prefetchCount="-1">
<transportSettings batchFlushInterval="00:00:01" />
</binding>
</netMessagingBinding>
<behavior name="sbTokenProvider">
<transportClientEndpointBehavior>
<tokenProvider>
<sharedSecret issuerName="owner" issuerSecret="XXXXXXXXXXXXXXXXXXXXXXXX" />
</tokenProvider>
</transportClientEndpointBehavior>
</behavior>
In your interface for the opertion Contract add this
[ReceiveContextEnabled(ManualControl = true)]
then you can manage to commit or abandon the message
Found it in this link:
http://msdn.microsoft.com/en-us/library/windowsazure/hh532034.aspx

Get .net to handle all requests in IIS7

I had an application that was running on IIS 6. All requests went through aspnet_isapi.dll. This was achieved via a wildcard application mapping (which did not verify the file existed).
I have copied said application to a machine running IIS7, and would like to get it working again.
In the application, any request with an extension of .aspx (or .ashx) are handled in the normal way. Other requests with different extensions (such as .html and .xml) are handled by a custom http module. Some requests have no extension, and are dynamically redirect to a file with an extension (e.g. visiting …/item/1 might redirect to …/item/1.html or …/item/1.xml, depending on values in the accept header).
The new location probably does not exist, but a response is generated dynamically.
Currently, the application pool is in “classic” mode, and is using .NET v4.0 (it was previously using .NET 3.5, but that doesn’t seem to be related to the problem). The custom http module is set only in the web.config.
The redirect (from …/item/1 to …/item/1.html) seems to work, which suggests that extension less requests are indeed being processed by the application (that redirect is written in the application itself). I think that means that the custom module is working.
Requests with extensions (.html, .xml etc) are failing however. The error I get is:
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
Module: IIS Web Core
Notification: MapRequestHandler
Handler: StaticFile
Error Code: 0x80070002
I have tried:
Adding a wildcard script mapping that mapped * to aspnet_isapi.dll
Tried adding a specific mapping for *.html to aspnet_isapi.dll
These still result in the same error message, and still seem to go to the handler "StaticFile".
I tried modifying "StaticFile" so that it uses the aspnet_isapi.dll executable, and this results in a new error:
HTTP Error 404.4 - Not Found
The resource you are looking for does not have a handler associated with it.
Handler: Not yet determined
Any help would be greatly appreciated.
Set application pool in integrated mode and set that all request run all managed modules
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
...
</modules>
...
</system.webServer>
Use this config in service config it worked for me.
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="WcfService.Service1">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="WcfService.IService1"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>

Resources