I have a problem writing the file: I call the app launch via the API and get its status in string.
using System;
using System.Threading.Tasks;
using UiPath.Robot.Api;
using System.Linq;
using System.IO;
namespace RobotApi
{
class Program
{
static TextWriter sw = new StreamWriter("d:\\robo\\log.txt", true, System.Text.Encoding.Default);
static async Task Main(string[] args)
{
var client = new RobotClient();
var processes = await client.GetProcesses();
var myProcess = processes.Single(process => process.Name == "MyProcess");
var job = myProcess.ToJob();
job.StatusChanged += (sender, args) => sw.WriteLine($"{((Job)sender).ProcessKey}: {args.Status}");
await client.RunJob(job);
}
}
}
I need to write the job status to a txt file for later analysis. Since the program is called asynchronously, I can't use the StreamWritter, since it simply can't be closed. File.WriteAllText just can't handle such a flow of information and doesn't have time to close the file, as a result, I get an error message that txt is being used by another process.
Please tell me, is there a way to write a large stream of information to a txt file in my case (it is necessary that the string is overwritten with each status update)?
I believe that your problem is just with the lambda expression and you don't know how to get more statements inside it except the WriteLine() call.
A solution would be to define a regular method instead of the lambda expression.
namespace RobotApi
{
class Program
{
// <-- removed the StreamWriter here
static async Task Main(string[] args)
{
var client = new RobotClient();
var processes = await client.GetProcesses();
var myProcess = processes.Single(process => process.Name == "MyProcess");
var job = myProcess.ToJob();
job.StatusChanged += OnStatusChanged; // <-- refer to the method here
await client.RunJob(job);
}
// This method is new
// Assuming StatusEventArgs
void OnStatusChanged(object sender, StatusEventArgs args)
{
// using will close the file
using (TextWriter sw = new StreamWriter("d:\\robo\\log.txt", true, System.Text.Encoding.Default))
{
sw.WriteLine($"{((Job)sender).ProcessKey}: {args.Status}");
}
}
}
}
This implementation is not thread safe, but your implementation wasn't either, so I don't care at the moment.
sw (from TextWriter) is statically global to the program object... I do not see where it is being CLOSED... you write to it on the async threading calls... but never close it... never flush it...
And of course (unless I missed something) never overwrite it with a new open call... so there is never the intended overwrite????
Related
I created the function pro:
it contains the process array
it calls another write function to make the file and write into it.
the write function writeproc:
it checks if the file at specified path is present or not.
if not it generates the file else it appends the text into the file.
when i run the code it is not doing anything.... :(
This is the main method for the console app that i have made in c#.
[STAThread]
static void Main(String[] args)
{
pro();
}
pro function:
static void pro()
{
Process[] localAll = Process.GetProcesses();
String path_pro = "C://KEYLOGS//processes.txt";
foreach(Process proc in localAll)
{
writeproc(path_pro, proc);
}
}
writeproc function:
static void writeproc(String p, Process the_process)
{
if (!File.Exists(p))
{
using (StreamWriter sw = File.CreateText(p))
{
//empty file generated.
}
}
else
{
using (StreamWriter sw = File.AppendText(p))
{
sw.WriteLine("Process: "+the_process);
}
}
}
This may be the cause of two different things.
1: The folder does not exist on your C drive so the file can't be created. (It will throw a System.IO.DirectoryNotFoundException)
Add Directory.CreateDirectory(p); to the start of your writeproc method.
2: You don't have enough rights to write to your C drive. (It will throw a System.UnauthorizedAccessException)
I suggest adding a breakpoint in your writeproc method to see what exception is being thrown.
This is using stackexchange.redis v1.1.603, .net 4.6, console application.
Here is my codes:
using System;
using System.Collections.Generic;
using StackExchange.Redis;
namespace RedisClusterTesting
{
class Program
{
static void Main(string[] args)
{
string ip = "192.168.1.20:30001,192.168.1.20:30002,192.168.1.20:30003,resolvedns=1";
var conf = ConfigurationOptions.Parse(ip);
conf.CommandMap = CommandMap.Create(new HashSet<string> {
"INFO", "CONFIG", "CLUSTER","PING", "ECHO", "CLIENT"
}, false);
using (ConnectionMultiplexer conn = ConnectionMultiplexer.Connect(conf))
{
var db = conn.GetDatabase();
Do(db);
}
Console.ReadKey();
}
private static void Do(IDatabase db)
{
/*here throws MOVED Exception:MOVED 12182 192.168.1.20:30003*/
db.StringSet("foo", "changed");
Console.WriteLine("foo now:" + db.StringGet("foo").ToString());
}
}
}
Always show the message "MOVED: 12586[192.168.1.20:30003]".
I search all the offcial document and on the Internet, can't find the right answer. It's OK while I use redis-cli.
How to fix this?Do I need process the exception in my code?If, how?
Seems like you may be running into this issue: https://github.com/StackExchange/StackExchange.Redis/issues/248. If you put a 1 second sleep between your Connect() call and your Do() call, I would guess that you will see the issue go away.
I am using the following code to log the exception, but it's not writing any logs into the file "mylistener.log". What am I missing here?
using System;
using System.Diagnostics;
namespace TraceSourceApp
{
class Program
{
private static TraceSource mySource = new TraceSource("TraceSourceApp");
static void Main(string[] args)
{
TextWriterTraceListener textListener =
new TextWriterTraceListener("myListener.log");
mySource.Listeners.Add(textListener);
int i = 10, j = 0, k;
try
{
k = i / j;
}
catch
{
mySource.TraceEvent(TraceEventType.Error, 12,
"Division by Zero");
}
mySource.Close();
}
}
}
In order for the TraceSource to write data to the file, you need to set the Switch-property of the TraceSource to a SourceSwitch instance. Change your code as follows:
static void Main(string[] args)
{
TextWriterTraceListener textListener = new TextWriterTraceListener("myListener.log");
// New code starts here
var sourceSwitch = new SourceSwitch("SourceSwitch", "Verbose");
mySource.Switch = sourceSwitch;
// New code ends here
mySource.Listeners.Add(textListener);
// ...
In addition to have the TraceWriter flush its content automatically, set Trace.AutoFlush at the beginning of you main method (the sample works without it, but it is always a good idea to make sure that the listeners are flushed in order not to loose log entries):
static void Main(string[] args)
{
Trace.AutoFlush = true;
// ...
As an alternative, you can also flush the listener explicitly by calling its Flush-method at the end:
textListener.Flush();
mySource.Close();
In real world code, I'd suggest to add a try-finally or using block to assert that Flush is called and that the source is closed.
I'm trying to read the static securities definition file from the CME, located at:
ftp://ftp.cmegroup.com/fix/Production/secdef.dat.gz
Since they seem to be standard fix messages, I thought I could use QuickFix to help me read them into C# rather than parsing the file myself. I created a test app that basically does what I want, but I'm having 2 issues:
1) I'm getting a QuickFix exception "Invalid message: Header fields out of order" when forming the message from the string. If I set the "validate" boolean to false, this message disappears and the constructor succeeds, but may be an indicator for the next issue.
2) Upon calling p.Crack, I'm getting the QuickFix exception "QuickFix.UnsupportedMessageType", but there doesn't seem to be any indication of what the message type is that is supposedly unsupported.
Anyway, maybe QuickFix wasn't intended to be used in this way, but any ideas on how to get this to work?
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using QuickFix;
namespace TestQuickFix
{
class Program : QuickFix.MessageCracker
{
static void Main(string[] args)
{
int count = 0;
string line;
Program p = new Program();
StreamReader file = new StreamReader(#"C:\secdef.dat");
while (((line = file.ReadLine()) != null && count < 10))
{
// ISSUE #1 REQUIRES false 2ND ARG WHEN CREATING THE MESSAGE
Message m = new Message(line, false);
// ISSUE #2 Exception of type 'QuickFix.UnsupportedMessageType' was thrown.
p.Crack(m, new SessionID("beginString", "senderCompID", "targetCompID"));
}
file.Close();
}
public void OnMessage(QuickFix.FIX50.SecurityDefinition secDef, SessionID sessionID)
{
Console.WriteLine(secDef.ToString());
}
}
}
The messages seems to be in FIX50sp2 format, supported by QuickFIX. (Please take a look at the tag 1128=9).
http://www.onixs.biz/fix-dictionary/5.0.SP2/tagNum_1128.html
BUT every single message seems to be not-well formatted. In the header are missed tag 8 (should be the BeginString), and also the tag 56 (TargetCompID), that are mandatory.
Therefore in order to load a single line in a message you must put the "false" parameter to avoid validation.
I suppose the second error is related to the not-well formatted messages.
After emailing the QuickFix listserv with this question, I was able to get enough information to get this to work. Although each line still seems to be malformed for some reason, if I keep validation off, I can get the parser to do exactly what I need it to with the following simplified code:
using System;
using System.IO;
using QuickFix;
using QuickFix.DataDictionary;
namespace TestQuickFix
{
class Program
{
private const int MAX_LINES = 10;
static void Main(string[] args)
{
DataDictionary dd = new QuickFix.DataDictionary.DataDictionary("fix\\FIX50SP2.xml");
StreamReader file = new StreamReader(#"C:\secdef.dat");
int count = 0; string line;
while (((line = file.ReadLine()) != null && count++ < MAX_LINES))
{
QuickFix.FIX50.SecurityDefinition secDef = new QuickFix.FIX50.SecurityDefinition();
secDef.FromString(line, false, dd, dd);
Console.WriteLine(secDef.SecurityDesc);
}
file.Close();
}
}
}
I have a library that handles reading and writing a cache file. This library is used by a Windows Service and several instances of a console application on the same machine. The console application runs when a user logs in.
I am getting occasional IO errors saying the cache file is in use by another process. I assume that collisions are occurring between the different application instances and service trying to read and write at the same time.
Is there a way to lock the file when it is in use and force all other requests to "wait in line" to access the file?
private void SaveCacheToDisk(WindowsUser user) {
string serializedCache = SerializeCache(_cache);
//encryt
serializedCache = AES.Encrypt(serializedCache);
string path = user == null ? ApplicationHelper.CacheDiskPath() :
_registry.GetCachePath(user);
string appdata = user == null ? ApplicationHelper.ClientApplicationDataFolder() :
_registry.GetApplicationDataPath(user);
if (Directory.Exists(appdata) == false) {
Directory.CreateDirectory(appdata);
}
if (File.Exists(path) == false) {
using (FileStream stream = File.Create(path)) { }
}
using (FileStream stream = File.Open(path, FileMode.Truncate)) {
using (StreamWriter writer = new StreamWriter(stream)) {
writer.Write(serializedCache);
}
}
}
private string ReadCacheFromDisk(WindowsUser user) {
//cache file path
string path = user == null ? ApplicationHelper.CacheDiskPath() :
_registry.GetCachePath(user);
using (FileStream stream = File.Open(path, FileMode.Open)) {
using (StreamReader reader = new StreamReader(stream)) {
string serializedCache = reader.ReadToEnd();
//decrypt
serializedCache = AES.Decrypt(serializedCache);
return serializedCache;
}
}
}
Sure, you could use a mutex and permit access only when holding the mutex.
You could use a cross-process EventWaitHandle. This lets you create and use a WaitHandle that's identified across processes by name. A thread is notified when it's its turn, does some work, and then indicates it's done allowing another thread to proceed.
Note that this only works if every process/thread is referring to the same named WaitHandle.
The EventWaitHandle constructors with strings in their signature create named system synchronization events.
One option you could consider is having the console applications route their file access through the service, that way there's only one process accessing the file and you can synchronise access to it there.
One way of implementing this is by remoting across an IPC channel (and here's another example from weblogs.asp.net). We used this technique in a project for the company I work for and it works well, with our specific case providing a way for a .net WebService to talk to a Windows Service running on the same machine.
Sample based on the weblogs.asp.net example
Basically what you need to do with the code below is create a Solution, add two Console Apps (one called "Server" and the other called "Client" and one Library to it. Add a reference to the Library to both console apps, paste the code below in and add a reference to System.Runtime.Remoting to both Server & Console.
Run the Server app, then run the client app. Observe the fact that the server app has a message passed to it by the client. You can extend this to any number of messages/tasks
// Server:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
namespace RemotingSample
{
public class Server
{
public Server()
{
}
public static int Main(string[] args)
{
IpcChannel chan = new IpcChannel("Server");
//register channel
ChannelServices.RegisterChannel(chan, false);
//register remote object
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemotingSample.RemoteObject),
"RemotingServer",
WellKnownObjectMode.SingleCall);
Console.WriteLine("Server Activated");
Console.ReadLine();
return 0;
}
}
}
// Client:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using RemotingSample;
namespace RemotingSample
{
public class Client
{
public Client()
{
}
public static int Main(string[] args)
{
IpcChannel chan = new IpcChannel("Client");
ChannelServices.RegisterChannel(chan);
RemoteObject remObject = (RemoteObject)Activator.GetObject(
typeof(RemotingSample.RemoteObject),
"ipc://Server/RemotingServer");
if (remObject == null)
{
Console.WriteLine("cannot locate server");
}
else
{
remObject.ReplyMessage("You there?");
}
return 0;
}
}
}
// Shared Library:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
namespace RemotingSample
{
public class RemoteObject : MarshalByRefObject
{
public RemoteObject()
{
Console.WriteLine("Remote object activated");
}
public String ReplyMessage(String msg)
{
Console.WriteLine("Client : " + msg);//print given message on console
return "Server : I'm alive !";
}
}
}
Check out the TextWriter.Synchronized method.
http://msdn.microsoft.com/en-us/library/system.io.textwriter.synchronized.aspx
This should let you do this:
TextWriter.Synchronized(writer).Write(serializedCache);