I am using a third party tool which internally adds trace messages using the following code:
System.Diagnostics.Trace.WriteLineIf(
new System.Diagnostics.TraceSwitch("Switch", "").TraceInfo, message);
In this scenario, it appears that I must add the switch to my app.config file to get the trace messages to appear:
<system.diagnostics>
<switches>
<add name="Switch" value="3" />
</switches>
</system.diagnostics>
Since not all of my users are granted administrator rights to make changes in the Program Files directory this becomes an issue.
Is it possible to set the TraceSwitch programmatically and allow the third party tool to write the trace messages?
Yes to first part of question. Probably no to second part, since the third-party is creating a new TraceSwtich on each call to WriteLineIf. In my opinion, it seems the third-party control has a failed implementation because 1) it should allow you to change the "switch" programmatically through a property, method, or function, and 2) it is reading the config file on every trace statement.
Related
I am doing some practice tests for Microsoft's "Programming in C#" exam 70-483 and one of the questions has me in a stump and I don't know enough about tracing to test it properly.
The question is this:
You are developing an application that uses a .config file.
The relevant portion of the .config file is shown as follows:
<system.diagnostics>
<trace autoflush="false" indentsize="0">
<listeners>
<add name="appListener"
type="System.Diagnostics.EventLogTraceListener"
initializeData="TraceListenerLog" />
</listeners>
</trace>
</system.diagnostics>
You need to ensure that diagnostic data for the application writes to the event log by using the configuration specified in the .config file.
What should you include in the application code?
A. EventLog log = new EventLog();
<br/>log.WriteEntry("Trace data...");
B. Debug.WriteLine("Trace data...");
C. Console.SetOut(new StreamWriter("System.Diagnostics.EventLogTraceListener")); <br/>Console.WriteLine("Trace data...");
D. Trace.WriteLine("Trace data...");
I'm thinking "C" because it's the only option that has something to do with the .config file, but it says the correct answer is "D" for some reason. Mind you these questions have been wrong before about completely simple and obvious stuff, so...
Can you please explain which is the correct answer and why?
The solution is to read about tracing instead of trying to just find the correct answer.
C is the absolute worst - not only does it have nothing to do with System.Diagnostics or the EventLog, it will try to create a file named System.Diagnostics.EventLogTraceListener.
The only options that actually use System.Diagnostics are B and D.
The <system.diagnostics><trace> section in app.config configures the System.Diagnostics classes, including sources, listeners, switches that activate or deactive specific sources in the application etc. It's no different really than the configuration files used for any other log library like log4net, Serilog or NLog.
Debug.WriteLine("Trace data..."); will write the output to all the configured trace listeners, only in a debug build.
Trace.WriteLine("Trace data..."); will write to all configured trace listeners both in debug and release builds.
Option A is wrong too. It does involve the event log, but won't work because the Source isn't set. EventLog.WriteEntry doesn't send any diagnostic information either, it just writes an Information message to the Event Log.
The System.Diagnostics listener on the other hand will receive diagnostic events from the myriad of trace sources in .NET, including the application's own, filter it, and write it to its target.
Do you have a problem with networking for example? You can switch the System.Net trace listeners on and collect trace messages from the HTTP level all the way down to sockets, SSL, TCP and even packet operations.
The correct answer is the "D", What that configuration file is doing.. is adding an instance to the trace.Listeners. So whenever you call Trace.WriteLine one of the outputs will be to that listener you set up in the config file.
"C" would work too, but it does say that you need to ensure that you use the config file, and what you are doing in C has nothing to do with the config file.
I am confused on how to modify the web.config appSettings values at runtime. For example, I have this appSettings section:
<appSettings>
<add key="productspagedesc" value="TODO: Edit this default message" />
<add key="servicespagedesc" value="TODO: Edit this default message" />
<add key="contactspagedesc" value="TODO: Edit this default message" />
<add key="aboutpagedesc" value="TODO: Edit this default message" />
<add key="homepagedesc" value="TODO: Edit this default message" />
</appSettings>
Let's say, I want to modify the "homepagedesc" key at runtime. I tried ConfigurationManager and WebConfigurationManager static classes, but the settings are "read-only". How do I modify appSettings values at runtime?
UPDATE:
Ok, so here I am 5 years later. I would like to point out that experience has told me, we should not put any configuration that intentionally is editable at runtime in the web.config file but instead we should put it in a separate XML file as what one of the users commented below. This will not require any of edit of web.config file to restart the App which will result with angry users calling you.
You need to use WebConfigurationManager.OpenWebConfiguration():
For Example:
Dim myConfiguration As Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
myConfiguration.ConnectionStrings.ConnectionStrings("myDatabaseName").ConnectionString = txtConnectionString.Text
myConfiguration.AppSettings.Settings.Item("myKey").Value = txtmyKey.Text
myConfiguration.Save()
I think you might also need to set AllowLocation in machine.config. This is a boolean value that indicates whether individual pages can be configured using the element. If the "allowLocation" is false, it cannot be configured in individual elements.
Finally, it makes a difference if you run your application in IIS and run your test sample from Visual Studio. The ASP.NET process identity is the IIS account, ASPNET or NETWORK SERVICES (depending on IIS version).
Might need to grant ASPNET or NETWORK SERVICES Modify access on the folder where web.config resides.
Changing the web.config generally causes an application restart.
If you really need your application to edit its own settings, then you should consider a different approach such as databasing the settings or creating an xml file with the editable settings.
And if you want to avoid the restart of the application, you can move out the appSettings section:
<appSettings configSource="Config\appSettings.config"/>
to a separate file. And in combination with ConfigurationSaveMode.Minimal
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.Save(ConfigurationSaveMode.Minimal);
you can continue to use the appSettings section as the store for various settings without causing application restarts and without the need to use a file with a different format than the normal appSettings section.
2012
This is a better solution for this scenario (tested With Visual Studio 2008):
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("MyVariable");
config.AppSettings.Settings.Add("MyVariable", "MyValue");
config.Save();
Update 2018 =>
Tested in vs 2015 - Asp.net MVC5
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
config.Save();
if u need to checking element exist, use this code:
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
if (config.AppSettings.Settings["MyVariable"] != null)
{
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
}
else { config.AppSettings.Settings.Add("MyVariable", "MyValue"); }
config.Save();
I know this question is old, but I wanted to post an answer based on the current state of affairs in the ASP.NET\IIS world combined with my real world experience.
I recently spearheaded a project at my company where I wanted to consolidate and manage all of the appSettings & connectionStrings settings in our web.config files in one central place. I wanted to pursue an approach where our config settings were stored in ZooKeeper due to that projects maturity & stability. Not to mention that fact that ZooKeeper is by design a configuration & cluster managing application.
The project goals were very simple;
get ASP.NET to communicate with ZooKeeper
in Global.asax, Application_Start - pull web.config settings from ZooKeeper.
Upon getting passed the technical piece of getting ASP.NET to talk to ZooKeeper, I quickly found and hit a wall with the following code;
ConfigurationManager.AppSettings.Add(key_name, data_value)
That statement made the most logical sense since I wanted to ADD new settings to the appSettings collection. However, as the original poster (and many others) mentioned, this code call returns an Error stating that the collection is Read-Only.
After doing a bit of research and seeing all the different crazy ways people worked around this problem, I was very discouraged. Instead of giving up or settling for what appeared to be a less than ideal scenario, I decided to dig in and see if I was missing something.
With a little trial and error, I found the following code would do exactly what I wanted;
ConfigurationManager.AppSettings.Set(key_name, data_value)
Using this line of code, I am now able to load all 85 appSettings keys from ZooKeeper in my Application_Start.
In regards to general statements about changes to web.config triggering IIS recycles, I edited the following appPool settings to monitor the situation behind the scenes;
appPool-->Advanced Settings-->Recycling-->Disable Recycling for Configuration Changes = False
appPool-->Advanced Settings-->Recycling-->Generate Recycle Event Log Entry-->[For Each Setting] = True
With that combination of settings, if this process were to cause an appPool recycle, an Event Log entry should have be recorded, which it was not.
This leads me to conclude that it is possible, and indeed safe, to load an applications settings from a centralized storage medium.
I should mention that I am using IIS7.5 on Windows 7. The code will be getting deployed to IIS8 on Win2012. Should anything regarding this answer change, I will update this answer accordingly.
Who likes directly to the point,
In your Config
<appSettings>
<add key="Conf_id" value="71" />
</appSettings>
in your code(c#)
///SET
ConfigurationManager.AppSettings.Set("Conf_id", "whateveryourvalue");
///GET
string conf = ConfigurationManager.AppSettings.Get("Conf_id").ToString();
Try This:
using System;
using System.Configuration;
using System.Web.Configuration;
namespace SampleApplication.WebConfig
{
public partial class webConfigFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Helps to open the Root level web.config file.
Configuration webConfigApp = WebConfigurationManager.OpenWebConfiguration("~");
//Modifying the AppKey from AppValue to AppValue1
webConfigApp.AppSettings.Settings["ConnectionString"].Value = "ConnectionString";
//Save the Modified settings of AppSettings.
webConfigApp.Save();
}
}
}
Attempting to publish a website to my host which contains my custom database and the default like so:
<add name="PortfolioContext" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Portfolio;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=TestDB;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>
When publishing the site I can't login which I assume is down to because the DefaultConnection db isn't being created (containing the membership user tables), I might be wrong? I can generate the script for my custom database in Management studio but DefaultConnection doesn't even appear to allow me to manually create tables associated.
My error log displays this
2016-02-02 12:28:35 W3SVC30 217.194.213.135 GET /Login
ReturnUrl=%2Fdashboard 80 - 95.147.124.217
Mozilla/5.0+(Windows+NT+10.0;+WOW64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/48.0.2564.97+Safari/537.36
- 500 0 0 1198 416 203
Though I'm not sure what that means. Sorry this is my first attempt at publishing a site. Thanks
Edit:
Could not find a part of the path 'C:\HostingSpaces\hannahha\hannahhamlin.co.uk\wwwroot\Assets\Common\images'.
This is the error it displays. This leads to me a problem I knew i was going to have to confront anyway. How do I include necessary directories for publishing?
First, that's not an error log. That's IIS' default request log. All it tells you is that a client using a particular browser requested /Login via GET. In other words, nothing at all useful to this issue.
You need a real error, with a stacktrace. You can either turn off custom errors temporarily (<customErrors mode="Off" /> in your Web.config), install something like Elmah to log errors for you, or use remote debugging.
However, most likely, the connection string only works locally, and the error you would see is just a DB connection error. It's rare that the connection string you'd be using in development would match exactly with what would be required for production, so you should utilize config transforms to change it when publishing.
That's assuming of course you even have a database server set up in production to connect to. Visual Studio employs a lot of database magic to allow you to focus on your code rather than menial implementation details like connecting to a database. However, when you go live, the training wheels are off, and you're responsible for making sure everything necessary is wired up. If you don't have a database server, install one. If you don't have a database, create one. Then, just alter your connection string to connect to that.
UPDATE
The error message is so far removed from this question was originally about, I think you would be best served by creating a new question and deleting this one.
That said, I'm not sure what you're trying to achieve exactly, but anything under your project directory will be published along with your site (except certain special directories like App_Data). If the files you're referencing are in some directory outside of your project directory, they will not be included, and there's really not a way to include them. You can, however, create a build action that copies the files somewhere under your project, and by virtue of that, they should then be published.
While trying to figure out how to get log information for an Azure Web/Worker role, lots of posts suggest that I need to set my configuration settings in -two- places.
1 Configure .config file
<system.diagnostics>
<switches>
<add name="logLevel" value="2" />
</switches>
<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>
2. Programatically (ie. OnStart method)
DiagnosticMonitorConfiguration config = DiagnosticMonitor.GetDefaultInitialConfiguration();
config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Warning;
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", config);
I don't understand why everyone are suggesting that we have to define the logging filter level twice?
Shouldn't the configuration file be sufficient?
In the 1st one, you're telling your application (website etc.) what kind of trace listener you would like to use. Or in other words, when you write something like Trace.WriteLine("Something"), who should listen to that message.
While in the 2nd place, you're telling the diagnostics monitor engine running in your VM what to do with the tracing data sent to it.
For example, in your code (OnStart method) you have configured:
config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Warning;
What that means is that diagnostics monitor engine will only accept trace messages with log level Warning or above i.e. only those messages will be considered for transferring into storage. So even if you're writing Trace.Information("Something") in your code, that will be ignored by the diagnostics monitor.
Another thing you do in your code is telling the diagnostics engine what to do with the diagnostics data it has collected. Some of the other things you configure there are:
Buffer Quota - How much data should be held in the buffer before it gets rolled over.
Transfer to Storage - How frequently you would like to transfer the data to Windows Azure Storage.
#Gaurav Mantri 's answer probably touches exactly what you needed.
However,
Shouldn't the configuration file be sufficient?
I am not sure what you mean by "sufficient".
Azure Cloud services are already predefined with default values for the DiagnosticsMontiro, and therefor you don't HAVE to add those code lines.
Actually, since almost everything in Azure configurations can be controlled from outside the application, it is also preferred not to change configurations in code.
The following is taken from MSDN:
The Windows Azure SDK gives you the ability to configure Diagnostics using an XML configuration file (diagnostics.wadcfg) instead of programmatically configuring diagnostics in the OnStart method of your role. This approach has several advantages over writing code:
Diagnostics starts before the OnStart method is called, so errors in start-up tasks can be caught and logged.
Any changes made to the configuration at run time will remain after a restart.
Diagnostics configuration changes do not require the code to be rebuilt.
You can automatically start the diagnostics monitor in a specific configuration without needing additional code (which might cause an exception that would prevent your role from starting).
I am developing c# application, which is running as a windows service.
What ever transactions we are doing in the application i am writing it into log file.
A log directory is added in app.config file as below.
<add key ="LogDir" value="log" />
<add key ="LogLevel" value="2" />
And in the c# code the above one is accessing as below.
int logLevel = Convert.ToInt32(ConfigurationManager.AppSettings["logLevel"]);
if (logLevel > 0)
{
logger = new Logger();
logger.TraceLevel = logLevel - 1;
logger.logDir = ConfigurationManager.AppSettings["logDir"];
logger.logFileBaseName = "touchserver";
}
And then when any process is happening i am writing the data to the log as below.
TouchServer.Log(Logger.MessageType.Trace, 1, "Item successfully deleted");
And when i run my application in debug mode (i mean as console application) the log file will be created in the application's debug folder and the data will write into the log file.
But my problem is that when i install my application as service the log file is not getting created in the debug folder, and i am unable to see the actions performed , in case if anything went wrong.
Please help me to find a solution in this.
And i am installing service using Installutil command.
Thanks in advance
sangita
While you could get into why this is not working and fix the solution, overall there is no need to implement a logging component.
There are excellent free libraries available that do this very well. log4net is very popular. It is easy to use, feature rich and efficient. Take a look at it.
But my problem is that when i install my application as service the log file is not getting created in the debug folder, and i am unable to see the actions performed , in case if anything went wrong.
Check out what are the result of the IO operations by using Process Monitor. I suspect you'll find the identity being used to run the service process does not have write permissions where it is trying to write the log file.
But the better option is to use an existing logging library as Hemal suggests.