Why do I need any Saga storage? - c#

I'm struggling with an error message I'm getting from the NServiceBus.Host during startup and not sure where I'm going wrong. I initially encountered the problem within a large project but I seem to be able to reproduce this from scratch.
In VS2012, start with a new C# Class Library project, set for .NET 4.6.2. Then add NuGet packages - NServiceBus (6.0.0), NServiceBus.Host (7.0.1) and NServiceBus.NHibernate (7.2.0).
Then edit the EndpointConfiguration class to be as follows:
using NServiceBus.Features;
using NServiceBus.Persistence;
namespace NSB6_Pure
{
using NServiceBus;
public class EndpointConfig : IConfigureThisEndpoint
{
public void Customize(EndpointConfiguration endpointConfiguration)
{
//TODO: NServiceBus provides multiple durable storage options, including SQL Server, RavenDB, and Azure Storage Persistence.
// Refer to the documentation for more details on specific options.
endpointConfiguration.UsePersistence<NHibernatePersistence, StorageType.Timeouts>();
endpointConfiguration.DisableFeature<MessageDrivenSubscriptions>();
endpointConfiguration.DisableFeature<Sagas>();
// NServiceBus will move messages that fail repeatedly to a separate "error" queue. We recommend
// that you start with a shared error queue for all your endpoints for easy integration with ServiceControl.
endpointConfiguration.SendFailedMessagesTo("error");
// NServiceBus will store a copy of each successfully process message in a separate "audit" queue. We recommend
// that you start with a shared audit queue for all your endpoints for easy integration with ServiceControl.
endpointConfiguration.AuditProcessedMessagesTo("audit");
}
}
}
Then compile (in this case a debug build) and, from a command prompt, try to run NServiceBus.Host.exe in the bin\Debug directory. In my case, I get this output, most of it in Red:
2017-04-28 12:46:11.876 INFO DefaultFactory Logging to 'C:\blah\bin\Debug\' with level Info
2017-04-28 12:46:13.446 FATAL NServiceBus.LicenseManager Your license has expire
d! You can renew it at https://particular.net/licensing.
2017-04-28 12:46:13.561 ERROR NServiceBus.GenericHost Exception when starting en
dpoint.
System.InvalidOperationException: In order to use NServiceBus with NHibernate yo
u need to provide at least one connection string. You can do it via (in order of
precedence):
* specifying 'NServiceBus/Persistence/NHibernate/Saga' connection string for th
e Saga persister
* specifying 'NServiceBus/Persistence' connection string that applies to all pe
rsisters
* specifying 'NServiceBus/Persistence/connection.connection_string' or 'NServic
eBus/Persistence/connection.connection_string_name' value in AppSettings or your
NHibernate configuration file.
For most scenarios the 'NServiceBus/Persistence' connection string is the best o
ption.
at NServiceBus.Persistence.NHibernate.NHibernateConfigurationBuilder.Validate
ConfigurationViaConfigFile(Configuration configuration, String configPrefix) in
C:\BuildAgent\work\5135de308b2f3016\src\NServiceBus.NHibernate\Internal\NHiberna
teConfigurationBuilder.cs:line 130
at NServiceBus.Features.NHibernateStorageSession.Setup(FeatureConfigurationCo
ntext context) in C:\BuildAgent\work\5135de308b2f3016\src\NServiceBus.NHibernate
\SynchronizedStorage\NHibernateStorageSession.cs:line 45
at NServiceBus.Features.FeatureActivator.ActivateFeature(FeatureInfo featureI
nfo, List`1 featuresToActivate, IConfigureComponents container, PipelineSettings
pipelineSettings) in C:\Build\src\NServiceBus.Core\Features\FeatureActivator.cs
:line 194
at NServiceBus.Features.FeatureActivator.SetupFeatures(IConfigureComponents c
ontainer, PipelineSettings pipelineSettings) in C:\Build\src\NServiceBus.Core\Fe
atures\FeatureActivator.cs:line 57
at NServiceBus.InitializableEndpoint.<Initialize>d__1.MoveNext() in C:\Build\
src\NServiceBus.Core\InitializableEndpoint.cs:line 50
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at NServiceBus.GenericHost.<Start>d__1.MoveNext() in C:\BuildAgent\work\fc89e
968acb99302\src\NServiceBus.Hosting.Windows\GenericHost.cs:line 48
2017-04-28 12:46:13.582 ERROR NServiceBus.Hosting.Windows.WindowsHost Start fail
ure
System.InvalidOperationException: In order to use NServiceBus with NHibernate yo
u need to provide at least one connection string. You can do it via (in order of
precedence):
* specifying 'NServiceBus/Persistence/NHibernate/Saga' connection string for th
e Saga persister
* specifying 'NServiceBus/Persistence' connection string that applies to all pe
rsisters
* specifying 'NServiceBus/Persistence/connection.connection_string' or 'NServic
eBus/Persistence/connection.connection_string_name' value in AppSettings or your
NHibernate configuration file.
For most scenarios the 'NServiceBus/Persistence' connection string is the best o
ption.
at NServiceBus.Persistence.NHibernate.NHibernateConfigurationBuilder.Validate
ConfigurationViaConfigFile(Configuration configuration, String configPrefix) in
C:\BuildAgent\work\5135de308b2f3016\src\NServiceBus.NHibernate\Internal\NHiberna
teConfigurationBuilder.cs:line 130
at NServiceBus.Features.NHibernateStorageSession.Setup(FeatureConfigurationCo
ntext context) in C:\BuildAgent\work\5135de308b2f3016\src\NServiceBus.NHibernate
\SynchronizedStorage\NHibernateStorageSession.cs:line 45
at NServiceBus.Features.FeatureActivator.ActivateFeature(FeatureInfo featureI
nfo, List`1 featuresToActivate, IConfigureComponents container, PipelineSettings
pipelineSettings) in C:\Build\src\NServiceBus.Core\Features\FeatureActivator.cs
:line 194
at NServiceBus.Features.FeatureActivator.SetupFeatures(IConfigureComponents c
ontainer, PipelineSettings pipelineSettings) in C:\Build\src\NServiceBus.Core\Fe
atures\FeatureActivator.cs:line 57
at NServiceBus.InitializableEndpoint.<Initialize>d__1.MoveNext() in C:\Build\
src\NServiceBus.Core\InitializableEndpoint.cs:line 50
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at NServiceBus.GenericHost.<Start>d__1.MoveNext() in C:\BuildAgent\work\fc89e
968acb99302\src\NServiceBus.Hosting.Windows\GenericHost.cs:line 54
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
ification(Task task)
at NServiceBus.Hosting.Windows.WindowsHost.Start() in C:\BuildAgent\work\fc89
e968acb99302\src\NServiceBus.Hosting.Windows\WindowsHost.cs:line 33
And the bit I'm focussing on is here:
In order to use NServiceBus with NHibernate you need to provide at least one connection string. You can do it via (in order of precedence):
specifying 'NServiceBus/Persistence/NHibernate/Saga' connection string for the Saga persister
I've checked the NServiceBus code - this isn't a generic message. If the issue was the lack of config for Timeouts1, I'm sure it would be talking about it rather than Saga, since that part of the error message is parameterized.
But I don't want to use Sagas in this particular project. I'd have thought DisableFeature<Sagas> would be sufficient to indicate to NServiceBus that I don't want to use sagas here, but apparently not.
So why is NServiceBus trying to configure Saga storage and, more importantly, how do I stop it from doing so?
1Of course, I am expecting such an error to occur since I haven't done anything such as even adding an app.config to the class library yet. So even once the Saga issue is resolved, I'm expecting this code to still produce errors. Just hopefully ones I can work out how to fix for myself.
(The rationale behind my wanting to avoid configuring any storage is that the real work to do is to upgrade some existing endpoints that have dedicated databases for each feature (Timeouts/Subscriptions/Sagas) and although I've been recommending for a while that we ought to merge these databases, and could thus just configure a NServiceBus/Persistence database for each endpoint, that's not been approved. But I'm loath to add another database for some of these endpoints when they only use timeouts at present)

I'm Dennis van der Stelt, a developer at Particular Software, makers of NServiceBus. I replied on your support case already, but wanted to update this question as well, so that others can find this as well. Evk mentioned most of it already, I just wanted to mention the GH issue and the complete code.
The following code configuration makes sure it doesn't complain about the saga connectionstring.
endpointConfiguration.DisableFeature<NHibernateStorageSession>();
endpointConfiguration.DisableFeature<MessageDrivenSubscriptions>();
endpointConfiguration.DisableFeature<Sagas>();
endpointConfiguration.UsePersistence<NHibernatePersistence, StorageType.Timeouts>();
Then just provide a connectionstring for timeouts
<add name="NServiceBus/Persistence/NHibernate/Timeout" connectionString="server=.\sqlexpress;database=nservicebus; Trusted_Connection=True;" />
That will make it work properly and as expected.
The reason why disabling the NHibernateStorageSession is necessary is because it is a feature inside the persister that is enabled. More information can be found in a GitHub issue I've created based on this case, which can be found here.

I must admit I have not much knowledge about NServiceBus, I just feel obliged to try to help people with high reputation when they ask questions :) So I don't have an explanation why it works like this, only where it fails. In stack trace you can see NHibernateStorageSession.Setup, and NHibernateStorageSession is one of the features. So it fails when trying to activate that feature. Setup starts like this:
protected override void Setup(FeatureConfigurationContext context)
{
NHibernateConfiguration config = new NHibernateConfigurationBuilder(context.Settings, "Saga", new string[1]
{
"StorageConfiguration"
}).Build();
// the rest
}
Where second parameter is connection string suffix. In this case it is hardcoded to "Saga", and as you see - there is no check that Sagas feature is enabled or not. NHibernateConfigurationBuilder then tries to find a connection string for saga (or any more general connection string) and fails to do so with the exception message you observe.
So easy solution is to disable that feature via
endpointConfiguration.DisableFeature<NHibernateStorageSessio‌​n>();
However you should take care of course and ensure functionality you need is not dependent on that feature. It's not entirely clear for me what this feature is for, and I didn't found any documentation for it (though of course its name tells us something about its purpose).

You can do it via (in order of precedence):
It just means the first point would take precedence over the other, if you need to set Saga, but otherwise just do one of the other points:
specifying 'NServiceBus/Persistence' connection string that applies to all persisters
specifying 'NServiceBus/Persistence/connection.connection_string' or 'NServiceBus/Persistence/connection.connection_string_name' value in AppSettings or your NHibernate configuration file.
For most scenarios the 'NServiceBus/Persistence' connection string is the best option.
So you are not required to setup Saga, but it looks like you will not avoid setting a connection string somewhere.

Related

How do I figure out the exact cause of error in EF update?

I have read the other threads on this, and none of them have answers that resolve my current scenario, nor are they similar. My scenario is reproducible on each run of my application, though I can't seem to produce a smaller piece of code that creates this error.
I'm getting the following error:
An exception has been raised that is likely due to a transient failure. If you are connecting to a SQL Azure database consider using SqlAzureExecutionStrategy.
The inner exception says:
A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The semaphore timeout period has expired.)
I am not connecting to a SQL Azure database. The connection is to a remote database through VPN, hosted on premises. To give some more context, I'm importing data from an external system, and every time it gets up to a specific record, it always fails when I try to update the entity after creating it. I've tried setting debug logging on in EF and copying the statement it generates into SSMS and running it with the same credentials with no errors. The only differentiating factor between this record and the previous records are the audit fields (time created/modified) and the name, which has changed from 1USD - Holding 99 to 1USD - Holding 100. I actually tested out changing the order which the records get imported, and it always fails at 100 when editing in EF after creation, so there's probably some other underlying issue at hand here. The field itself in the database is handling strings with a higher length than this, including this same process with no errors.
This obviously doesn't seem to actually be a transient failure, nor does it seem to be a connection issue, so how do I find the exact reason why this doesn't work?
Edit: Adding some code below. Also, I've noticed that if I change the name to 1USD - Holding 99 - Test 2, it works without any error despite the name being longer. Automatic ChangeDetection is not enabled for performance reasons.
security = new Security
{
Name = securityName,
IsActive = true,
CreatedAt = DateTime.Now,
CreatedBy = ADMIN_USER,
ModifiedAt = DateTime.Now,
ModifiedBy = ADMIN_USER
};
_repository.Save(security); //Ctx.Set<T>().Add(security); Ctx.SaveChanges();
//some attributes with a foreign key referencing this entity are saved, which is why we update audit fields below, but error occurs regardless if anything additional is saved
security.ModifiedBy = ADMIN_USER;
security.ModifiedAt = DateTime.Now;
_repository.Save(security); //Ctx.Set<T>().Attach(security); Ctx.Entry(security).State = EntityState.Modified; Ctx.SaveChanges();
Edit 2: It definitely seems to be something else other than a connection issue since it's happening for anything ending in a 3 character combination, such as A10, B10, or 10A. 1, 2, or 4 characters seem to be fine. Still have no idea what the actual issue is, however.

CrystalDecisions.CrystalReports.Engine.LogOnException: Database logon failed

This happens on ReportDocument.Export() for a PDF generation.
But only sporadically/randomly.
In the overall picture it's not that bad, 1 or 2 errors per day (+10k request), but still this bugs me.
2 different kinds of errors:
CrystalDecisions.CrystalReports.Engine.LogOnException: Database logon failed.
CrystalDecisions.CrystalReports.Engine.LogOnException: Error in File < Reportname >.rpt
Unable to connect: incorrect log on parameters
I see that these errors are quite common in the community, i've found lots of sites with solutions to these error, i've tried a lot of them, but none have worked so far (one exception i'll mention below).
Facts
Version used is 13.0.21.2533 (SAP Crystal Reports runtime engine for .NET Framework (32 and 64 bits))
The reports generated work in all environments (even prod)
Some reports randomly/sporadically fail. Although the same (request) report can be generated almost immediately working fine.
No report viewer.
The fact that they work in prod, for me, discards many of the proposed solutions. Regardless i tried/checked them.
No connection to DB, i'm passing a DataSet as the DataSource of the report (multiple tables inside)
I use an "Using" pattern/syntax. I also tried explicitly disposing on Finally (isntead of using)
finally
{
report.Database.Dispose();
report.Close();
report.Dispose();
}
Testing/Replicating
To be able to replicate the issue, i use SOAP UI to Load test the request (1 minute, 2 threads, as many (exactly the same) requests as possible) and from time to time, one fails.
Error 1. Database Logon failed
This one is partially solved, i changed from setting the datasource this way:
report.SetDataSource(rawData);
to setting it for each table in the datasource, more or less like this:
foreach (DataTable dataTable in rawData.Tables)
{
foreach (CrystalDecisions.CrystalReports.Engine.Table table in report.Database.Tables)
{
if (table.Name == dataTable.TableName)
{
table.SetDataSource(dataTable);
break;
}
}
}
This fix removes almost entirely this error, almost.
I need more aggressive Load testing to get it to fail once sporadically, while previously it failed ,once or twice, each and every time i load tested it.
Error 2. Error in File < Reportname >.rpt. Unable to connect: incorrect log on parameters
With the fix above, there are also few instances of this error (1 or 2 exceptions), also need more aggressive load testing to happen, but occurs more than the above one. before it failed 3 to 7 times per load test.
Errors
An exception is thrown:
>>>>> Exception details=CrystalDecisions.CrystalReports.Engine.LogOnException: Database logon failed.
---> System.Runtime.InteropServices.COMException: Database logon failed.
at CrystalDecisions.ReportAppServer.Controllers.ReportSourceClass.Export(ExportOptions pExportOptions, RequestContext pRequestContext)
at CrystalDecisions.ReportSource.EromReportSourceBase.ExportToStream(ExportRequestContext reqContext)
--- End of inner exception stack trace ---
at CrystalDecisions.ReportAppServer.ConvertDotNetToErom.ThrowDotNetException(Exception e)
at CrystalDecisions.ReportSource.EromReportSourceBase.ExportToStream(ExportRequestContext reqContext)
at CrystalDecisions.CrystalReports.Engine.FormatEngine.ExportToStream(ExportRequestContext reqContext)
at CrystalDecisions.CrystalReports.Engine.FormatEngine.Export(ExportRequestContext reqContext)
at CrystalDecisions.CrystalReports.Engine.FormatEngine.Export()
at CrystalDecisions.CrystalReports.Engine.ReportDocument.Export()
at < mynamespace >.RptUtil.GeneratePDF(DataSet rawData, ...
the other one
An exception is thrown:
>>>>> Exception details=CrystalDecisions.CrystalReports.Engine.LogOnException: Error in File <
report name >_{1E5E29F7-E5A2-43EA-90E5-D62ECAA19A01}.rpt:
Unable to connect: incorrect log on parameters. ---> System.Runtime.InteropServices.COMException: Error in File <
report name >_{1E5E29F7-E5A2-43EA-90E5-D62ECAA19A01}.rpt:
Unable to connect: incorrect log on parameters.
at CrystalDecisions.ReportAppServer.Controllers.ReportSourceClass.Export(ExportOptions pExportOptions, RequestContext pRequestContext)
at CrystalDecisions.ReportSource.EromReportSourceBase.ExportToStream(ExportRequestContext reqContext)
--- End of inner exception stack trace ---
at CrystalDecisions.ReportAppServer.ConvertDotNetToErom.ThrowDotNetException(Exception e)
at CrystalDecisions.ReportSource.EromReportSourceBase.ExportToStream(ExportRequestContext reqContext)
at CrystalDecisions.CrystalReports.Engine.FormatEngine.ExportToStream(ExportRequestContext reqContext)
at CrystalDecisions.CrystalReports.Engine.FormatEngine.Export(ExportRequestContext reqContext)
at CrystalDecisions.CrystalReports.Engine.FormatEngine.Export()
at CrystalDecisions.CrystalReports.Engine.ReportDocument.Export()
at < mynamespace >.RptUtil.GeneratePDF(DataSet rawData, ...

0xC000027B exception in store UWP app (Windows.UI.XAML)

I've an C#/UWP-app in beta-release in the Microsoft App-Store. Most of the users have no problems with the App, but for one user the app is crashing on startup. You can't even see the Splash-Screen (it should be displaying a logo or color, however it is white).
In the eventlog this genreic event is logged:
0xc000027b (Windows.UI.XAML)
The only difference is, that his Windows-10 Build differs from the other users (10.0.10240 vs 10.0.10586). However, I've collected the crashdumps ("minidumps") and tried to follow this tutorial.
If i try this command:
dt <Parameter[0]> combase!_STOWED_EXCEPTION_INFORMATION_HEADER*
Windbg gives me this:
Memory read error (at Parameter[0])
Actually I've integrated the hockey-sdk for automatic crash-reports, but it doesn't report me that specific crash in the dashboard.
How can I trace down this crash?
Update:
I've managed to get the Call-Stack with PDE:
Windows_UI_Xaml!DirectUI::PropertyPathListener::GetValue+0x3e
Windows_UI_Xaml!DirectUI::BindingExpression::GetValue+0xbb
Windows_UI_Xaml!DirectUI::DependencyObject::SetValueExpression+0x24b
Windows_UI_Xaml!DirectUI::DependencyObject::SetBindingCore+0x56
Windows_UI_Xaml!DirectUI::DependencyObject::SetBindingCallback+0x146
Windows_UI_Xaml!CBinding::SetBinding+0x48
Windows_UI_Xaml!XamlNativeRuntime::SetValue+0x4c2
Windows_UI_Xaml!BinaryFormatObjectWriter::SetValueOnCurrentInstance+0x1ad
Windows_UI_Xaml!BinaryFormatObjectWriter::WriteNode+0x144a
Windows_UI_Xaml!CTemplateContent::LoadXbfVersion2+0xd1
Windows_UI_Xaml!CTemplateContent::Load+0x4d
Windows_UI_Xaml!CFrameworkTemplate::LoadContent+0x270
Windows_UI_Xaml!CControlTemplate::LoadContent+0x18
Windows_UI_Xaml!CFrameworkElement::ApplyTemplate+0x30a
Windows_UI_Xaml!CContentControl::ApplyTemplate+0x20
Windows_UI_Xaml!CFrameworkElement::InvokeApplyTemplate+0x17f
Windows_UI_Xaml!CFrameworkElement::MeasureCore+0x2a3
Windows_UI_Xaml!CUIElement::MeasureInternal+0x1cb
Windows_UI_Xaml!CUIElement::Measure+0x598
Windows_UI_Xaml!CGrid::MeasureOverride+0x307
Windows_UI_Xaml!CFrameworkElement::MeasureCore+0x707
Windows_UI_Xaml!CUIElement::MeasureInternal+0x1cb
Windows_UI_Xaml!CUIElement::Measure+0x598
Windows_UI_Xaml!CGrid::MeasureOverride+0x307
Windows_UI_Xaml!CFrameworkElement::MeasureCore+0x707
This would mean, that I've somewhere an incorrect binding?

Windows Service Bus - Rename topic?

Using Windows Serives Bus (not the cloud version), I'm trying to rename a topic programatically, so far I have
internal void UpdateTopic(Topic Topic)
{
Topic dbTopic = TopicManager.GetTopicById(Topic.Id);
TopicDescription topicDescription = _namespaceManager.GetTopic(dbTopic.Name);
topicDescription.Path = Topic.Name;
topicDescription.Status = Topic.Active ? EntityStatus.Active : EntityStatus.Disabled;
_namespaceManager.UpdateTopic(topicDescription);
...
The line _namespaceManager.UpdateTopic(topicDescription); throws Exception The remote server returned an error: (404) Not Found. Not Found.TrackingId:[some tracking id including a GUID],TimeStamp:20/12/2013 13:29:47
Questions:
- Can I actually rename a topic programmatically?
If yes:
- Any idea of what causes the exception?
Rename of a Topic is not supported. You can do Create, Update and Delete operations but since the name is the identifier of the particular resource it cannot be modified. There are several other properties on a TopicDescriptiontoo that cannot be modified, but only set at the time of creation (such as Size).

logging exception in c#

logging exception
the code below allows to save the content of an exception in a text file. Here I'm getting only the decription of the error.
but it is not telling me where the exception occured, at which line.
Can anyone tell me how can I achive that so I can get even the line number where the exception occured?
#region WriteLogError
/// <summary>
/// Write an error Log in File
/// </summary>
/// <param name="errorMessage"></param>
public void WriteLogError(string errorMessage)
{
try
{
string path = "~/Error/" + DateTime.Today.ToString("dd-mm-yy") + ".txt";
if (!File.Exists(System.Web.HttpContext.Current.Server.MapPath(path)))
{
File.Create(System.Web.HttpContext.Current.Server.MapPath(path))
.Close();
}
using (StreamWriter w = File.AppendText(System.Web.HttpContext.Current.Server.MapPath(path)))
{
w.WriteLine("\r\nLog Entry : ");
w.WriteLine("{0}", DateTime.Now.ToString(CultureInfo.InvariantCulture));
string err = "Error in: " + System.Web.HttpContext.Current.Request.Url.ToString()
+ ". Error Message:" + errorMessage;
w.WriteLine(err);
w.WriteLine("__________________________");
w.Flush();
w.Close();
}
}
catch (Exception ex)
{
WriteLogError(ex.Message);
}
}
#endregion
I find that the easiest way to log exceptions in C# is to call the ToString() method:
try
{
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
This usually gives you all the information you need such as the error message and the stack trace, plus any extra exception specific context information. (however note that the stack trace will only show you source files and line numbers if you have your application compiled with debug information)
It is worth noting however that seeing a full stack trace can be fairly offputting for the user and so wherever possible you should try to handle exceptions and print out a more friendly error message.
On another note - you should replace your method WriteLogError with a fully featured logging framework (like Serilog) instead of trying to write your own.
Your logging method is not thread safe (your log file will probably end up with log messages being intermingled with each other) and also should definitely not call itself if you catch an exception - this will mean that any exceptions that occur whilst logging errors will probably cause a difficult to diagnose StackOverflow exception.
I could suggest how to fix those things, however you would be much better served just using a proper logging framework.
Just log ToString(). Not only will it give you the stack trace, but it'll also include the inner exceptions.
Also, when you deploy a release build of your code to a production environment for instance, don't forget to include the .pdb files in the release package. You need that file to get the line number of the code that excepted (see How much information do pdb files contain? (C# / .NET))
Your solution is pretty good. I went through the same phase
and eventually needed to log more and more (it will come...):
logging source location
callstack before exception (could be in really different place)
all internal exceptions in the same way
process id / thread id
time (or request ticks)
for web - url, http headers, client ip, cookies, web session content
some other critical variable values
loaded assemblies in memory
...
Preferably in the way that I clicked on the file link where the error occurred,
or clicked on a link in the callstack, and Visual Studio opened up at the appropriate location.
(Of course, all you need to do is *.PDB files, where the paths from the IL code
to your released source in C # are stored.)
So I finally started using this solution:
It exists as a Nuget package - Desharp.
It's for both application types - web and desktop.
See it's Desharp Github documentation. It has many configuration options.
try {
var myStrangeObj = new { /*... something really mysterious ...*/ };
throw new Exception("Something really baaaaad with my strange object :-)");
} catch (Exception ex) {
// store any rendered object in debug.html or debug.log file
Desharp.Debug.Log(myStrangeObj, Desharp.Level.DEBUG);
// store exception with all inner exceptions and everything else
// you need to know later in exceptions.html or exceptions.log file
Desharp.Debug.Log(ex);
}
It has HTML log formats, every exception in one line,
and from html page you can open in browser, you can click
on file link and go to Visual Studio - it's really addictive!
It's only necessary to install this Desharp editor opener.
See some demos here:
Web Basic App
Web MVC App
Console App
Try to check out any of those repos and log something by the way above.
then you can see logged results into ~/Logs directory. Mostly anything is configurable.
I am only answering for the ask, other people have already mentioned about the code already. If you want the line number to be included in your log you need to include the generated debug files (pdb) in your deployment to the server. If its just your Dev/Test region that is fine but I don't recommend using in production.
Please note that the exception class is serializable. This means that you could easily write the exception class to disk using the builtin XmlSerializer - or use a custom serializer to write to a txt file for example.
Logging to output can ofcourse be done by using ToString() instead of only reading the error message as mentioned in other answers.
Exception class
https://learn.microsoft.com/en-us/dotnet/api/system.exception?redirectedfrom=MSDN&view=netframework-4.7.2
Info about serialization, the act of converting an object to a file on disk and vice versa.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/

Categories