|
Yeah thanks a lot - my initial class was like this but then I added buffer thinking to increase efficiency of writing and decrease time for threads waiting for each other.
So what are shortcomings of this final version of the class you think? Just performance? You said also it is fine to be used by many processes because AppendAllText uses FileShare.None flag?
|
|
|
|
|
user20044 wrote: AppendAllText uses FileShare.None flag?
AppendAllLines uses FileShare.Read . That will allow other processes to read the file, but not write to it.
user20044 wrote: So what are shortcomings of this final version of the class you think?
As previously mentioned, if multiple processes try to write to the same file at the same time, you'll get an exception, and the log entry from the second process will be lost.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
No other shortcomings?
Also like in that thread will there be no issues with accessing the logDir variable in a thread safe way?
What about performance?
|
|
|
|
|
user20044 wrote: accessing the logDir variable in a thread safe way?
The changes I've made to the code deal with that. The field is only read once, so if someone changes it after that, you'll still be using the original value.
user20044 wrote: What about performance?
Try it and see. The only way to know is to measure the performance, which you can only do by running the code that's going to call this class.
user20044 wrote: No other shortcomings?
I'm sure lots of people would pick the code apart and find various problems with it - as they would with almost any non-trivial code. But if it works and it's good enough for your requirements, does it really matter?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I will keep this as option.
Now about performance I said since I log only errors maybe this will survive.
I'm sure lots of people would pick the code apart and find various problems with it - as they would with almost any non-trivial code. But if it works and it's good enough for your requirements, does it really matter?
I will keep this as option for this class also seemed as a possibility to use but people started panicking when looking at it saying don't create your logging class etc.
|
|
|
|
|
Please also change this class so that user can set base directory
|
|
|
|
|
Replace:
private const string LogDirectory = @"C:\Logs\";
with:
private static string _logDirectory = @"C:\Logs\";
public static string LogDirectory
{
get
{
return _logDirectory;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentNullException("value");
}
if (!value.EndsWith(@"\"))
{
value += @"\";
}
_logDirectory = value;
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
There are some good points on that StackExchange thread - particularly points 1 and 3 in Nikita Brizhak's answer, which address some incorrect behaviour in the class.
Fixing point 1 is easy - copy the _logDir field to a variable at the start of the method, and only use that variable:
string logDir = _logDir;
if (!logDir.EndsWith(@"\")) logDir += @"\";
Directory.CreateDirectory(logDir);
var todaysLogFilePath = Path.Combine(logDir, ...);
Fixing point 3 is slightly harder. You need to make sure that any entries in the buffer are saved when the application exits, regardless of the number of entries. To do that, you'll need to split the code that saves the entries from the code that tests the number of entries, as EBrown suggested.
static class GMLogger
{
private const int MaxBufferSize = 25;
private static readonly object _syncObject = new object();
private static readonly List<string> _buffer = new List<string>();
private static string _logDir = @"C:\Logs\";
public static string LogDirectory
{
get
{
return _logDir;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentNullException("value");
}
if (!value.EndsWith(@"\"))
{
value += @"\";
}
_logDir = value;
}
}
private static string EnsureLogDirectory()
{
string path = LogDirectory;
Directory.CreateDirectory(path);
return path;
}
private static string BuildLogPath(string directory, DateTime logDate)
{
string fileName = string.Format("Log{0:yyyy-MM-dd}.txt", logDate);
return Path.Combine(directory, fileName);
}
private static void SaveLog()
{
if (_buffer.Count != 0)
{
string directory = EnsureLogDirectory();
string fileName = BuildLogPath(directory, DateTime.Today);
File.AppendAllLines(fileName, _buffer);
_buffer.Clear();
}
}
public static void Log(string logMessage)
{
lock (_syncObject)
{
_buffer.Add(logMessage);
if (_buffer.Count == MaxBufferSize)
{
SaveLog();
}
}
}
public static void Save()
{
lock (_syncObject)
{
SaveLog();
}
}
}
You'd then need to make sure your Main method calls GMLogger.Save() before it returns. A finally block would probably be the best place for that:
static void Main()
{
try
{
...
}
finally
{
GMLogger.Save();
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks one way is I remove buffer altogether and directly write to file what do you think? I had buffer to increase performance, but since I log only errors, maybe performance will not be problem?
Then I will take into account your advice about _logDir with temp variable. And class should be ready to be used?
Anyway, thanks for the feedback and discussion!.
|
|
|
|
|
|
First off, I would use a dedicated thread to do the logging. But just in case you don't want that, you should not lock while in the process of saving
List<string> copy = null;
lock(_syncObject) {
_buffer.Add(logMessage);
if ( _buffer.Count > _maxBufferSize) {
copy = _buffer;
_buffer = new List<string>();
}
}
if ( copy != null)
Save(copy);
(you would need to adjust your Save() function as well.
LATER EDIT: you will probably need a second lock for saving, but the main idea is that other threads would not be blocked when the buffer gets full.
Best,
John
|
|
|
|
|
How to resize rows and columns during runtime of a dynamically generated tabellayoutpanel?
|
|
|
|
|
The same way you would for one created at design time.
What part of this is giving you a problem? Is it the mechanics of changing sizes, or finding the control, or what?
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
I am creating my own tabellayoutpanel by inheriting Custom tabellayoutpanel i am able to add columns and rows but not resizing them.
|
|
|
|
|
Have you looked at the TableLayoutPanel.ColumnStyles collection?
Each column style has a SizeType and a Width[^] which is pretty much all you can control.
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
When I am studying how to use the built-in Win Form Controls, like TableLayoutPanel (TBLLP), I find this method of study pays off:
1. drop a TBLLP on a Form in a "test" project.
2. set all the design-time properties of the TBLLP: number of rows, columns, their sizes, etc., to reflect the design you are trying achieve at run-time
3. open the 'Program.cs file for the project:
a. look at the code that creates the TBLLP in the 'Program.cs file
b. make notes for future reference on the code you'll need at run-time to set the parameters of the TBLLP's structure, and visual style
4. then, in this same project ... either on the same Form ... or in another ... write the code to create a TBLLP at run-time, and apply what you've learned from studying the design-time code in the 'Program.cs file.
5. when/if you get "stuck:" go back and see if you can use any design-time setting or Property on the TBLLP on the Form to achieve what you want, then study, again, the 'Program.cs file code.
At the same time, you will probably also want to be looking up the various facilities/features/Properites/Methods, etc., the TBLLP exposes in the documentation (on- or off-line help files from MS).
Experiment > observe > analyze > research > perturb/change < repeat until you know what you are doing.
Finally, remember the CodeProject is your friend, and there may be articles here showing you useful information/techniques for using the TBLLP; and, StackOverFlow is also your friend. Just search.
«I want to stay as close to the edge as I can without going over. Out on the edge you see all kinds of things you can't see from the center» Kurt Vonnegut.
modified 21-Oct-15 8:28am.
|
|
|
|
|
public partial class WebForm1 : System.Web.UI.Page
{
public static string GetProperty(SearchResult searchResult, string PropertyName)
{
if (searchResult.Properties.Contains(PropertyName))
{
return searchResult.Properties[PropertyName][0].ToString();
}
else
{
return string.Empty;
}
}
protected void Page_Load(object sender, EventArgs e)
{
DirectoryEntry entry = new DirectoryEntry("LDAP://DC=rss,DC=org,DC=au");
DirectorySearcher Dsearch = new DirectorySearcher(entry);
SearchResultCollection results=Dsearch.FindAll();
DataTable dt =new DataTable();
//string colName;
// foreach (SearchResult sResultSet in Dsearch.FindAll())
// {
// ResultPropertyCollection myResultPropColl;
// myResultPropColl = sResultSet.Properties;
// }
foreach (string colName in Dsearch.PropertiesToLoad)
{
dt.Columns.Add(colName,Type.GetType("System.String"));
}
foreach (SearchResult sr in results)
{
DataRow dr = dt.NewRow();
foreach (String colName in Dsearch.PropertiesToLoad)
{
if(sr.Properties.Contains(colName))
{
dr[colName] = (sr.Properties[colName][0]);
}
else
{
dr[colName] = "";
}
}
dt.Rows.Add(dr);
}
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
|
|
|
|
|
Step through the code with your debugger to find out what is going on.
|
|
|
|
|
The PropertiesToLoad collection does not have a default value. Since you haven't specified any properties to load, it will load all properties for the entries it finds, but the PropertiesToLoad collection will remain empty.
As a result, your DataTable will contain no columns, and the GridView will not display anything.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Help Please,
Am working on a small application to create and dial vpn connection, route ip address and open windows remote application so users do not go thru these steps manually.
Everything is working well until i connect to rdp after the command connect i don't see anything in that window.
axMsRdpClient92.Server = "DOMAIN";
axMsRdpClient92.UserName = "user";
axMsRdpClient92.AdvancedSettings7.ClearTextPassword = "Pass";
axMsRdpClient92.OnConnected += (_1, _2) => { axMsRdpClient92.RemoteProgram.ServerStartProgram(@"C:\Pims2\Pims2.exe", @"pims2 oam.pms c:\couvent", @"C:\Pims2", true, "", true); };
axMsRdpClient92.AdvancedSettings7.RDPPort = 3389;
axMsRdpClient92.AdvancedSettings7.RedirectDevices = true;
axMsRdpClient92.AdvancedSettings7.RedirectPorts = true;
axMsRdpClient92.AdvancedSettings7.GrabFocusOnConnect = true;
axMsRdpClient92.AdvancedSettings7.RedirectPrinters = true;
axMsRdpClient92.Connect();
|
|
|
|
|
string username = "";
string password = "";
{
System.Diagnostics.Process.Start(@"\\"folder path"\ foldername");
}
This is my code. How should I access to server. there is username and password for the server.
Could anyone help me??
|
|
|
|
|
Pick either the forums or QA - but don't post in both.
Posting exactly the same thing in multiple places justs wastes our time and duplicates work - particularly when the question is too vague to answer in the first place!
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
was thinking about my upcoming school project focused on Windows 10 universal apps and I ran into very interesting experiment : http://gregtatum.com/poems/stochasticity/1/
I want to work on something very similiar or achieve similar level of animation in universal application writen in Csharp Win2D. I have never worked with any sort of animation or 2d graphics while writing UWA.
Can somebody direct me into right way to start with this ? What are your recommendations...any particular sample codes ?
Thank you.
|
|
|
|
|
Hi everyone,
I am learning delegates at the moment. I am trying to implement a keylogger for fun (found online)! Other examples work fine, but here I am lacking experience. However it seems, the method HookFunc is never reached.
I call it in the main method with
KeyboardHook keylogger = new KeyboardHook();
Shouldnt Install() give me output in the command box in the HookFunc method?
My Code:
public enum VKeys
{
KEY_0 = 0x30,
}
public KeyboardHook()
{
Install();
}
private delegate IntPtr KeyboardHookHandler(int nCode, IntPtr wParam, IntPtr lParam);
private KeyboardHookHandler hookHandler;
public delegate void KeyboardHookCallback(VKeys key);
#region Events
public event KeyboardHookCallback KeyDown;
public event KeyboardHookCallback KeyUp;
#endregion
private IntPtr hookID = IntPtr.Zero;
public void Install()
{
hookHandler = HookFunc;
hookID = SetHook(hookHandler);
}
public void Uninstall()
{
UnhookWindowsHookEx(hookID);
}
private IntPtr SetHook(KeyboardHookHandler proc)
{
Console.WriteLine("HookID: " + hookID.ToString());
using (ProcessModule module = Process.GetCurrentProcess().MainModule)
return SetWindowsHookEx(13, proc, GetModuleHandle(module.ModuleName), 0);
}
private IntPtr HookFunc(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("HookID 2: " + hookID.ToString());
if (nCode >= 0)
{
int iwParam = wParam.ToInt32();
if ((iwParam == WM_KEYDOWN || iwParam == WM_SYSKEYDOWN))
if (KeyDown != null)
KeyDown((VKeys)Marshal.ReadInt32(lParam));
int vkCode = Marshal.ReadInt32(lParam);
if ((iwParam == WM_KEYUP || iwParam == WM_SYSKEYUP))
if (KeyUp != null)
KeyUp((VKeys)Marshal.ReadInt32(lParam));
vkCode = Marshal.ReadInt32(lParam);
}
else
{
;
}
return CallNextHookEx(hookID, nCode, wParam, lParam);
}
|
|
|
|
|
There are several articles (with usable code) here on CodeProject on implementing "Global Hooks" in .NET. Just search. George Mamaladze's article on this is a "CodeProject Classic," having been updated many times over several years: [^].
«I want to stay as close to the edge as I can without going over. Out on the edge you see all kinds of things you can't see from the center» Kurt Vonnegut.
|
|
|
|