Main function looping based on file called in a different class - c#

Rookie here so please be nice!! I have had so much fun learning to program and gotten some great help along the way when google failed me. But alas, I'm stuck again.
I have a C# program that looks like this (It's MWS if anyone is familiar)
I've tried so many different ways to get this to effectively loop through a list of values in a text file. The problem I'm having is that the Main function is where I have to set the loop, but the BuildClass is where I need to cycle through the values in the text file (sentinel). I've included some stuff that probably isn't necessary just in case it is messing my code up and I don't realize it.
Here's what I've tried:
setting the loop inside the BuildClass - didn't expect it to work but it threw an exception before getting to the sentinel.
Reference the sentinel within the main function by changing the "using" or "var" in the main function sentinel to public - turned EVERYTHING red in visual studio
moving the string sentinel outside the main function so that the function and the BuildClass would recognize it - main function did not recognize it anymore.
I've tried so many other things unsuccessfully. I've gotten it to loop with the same sentinel value passed from BuildClass to the function over and over again but that's about it.
What I think I need:
A destructive version of streamReader that will remove the value from the text file when reading it. I'll put this inside the BuildClass, so that the next loop of the main function, the next value will be read and passed into the main function until the file is empty, terminating the loop.
an understanding of why changing sentinel to public destroys the code so badly. I have a decent understanding of why the other attempts wouldn't work.
namespace MainSpace
{
public class MainClass
{
int i;
public static void Main(string[] args)
{
ClientClass client = new ClientInterface(appName, appVersion, password, config);
MainClass sample = new MainClass(client);
string sentinel;
using (var streamReader = new StreamReader(#"sample.txt", true))
while((sentinel = streamReader.ReadLine()) != null)
{
try
{
//stuff
response = sample.InvokeBuild();
Console.WriteLine("Response Stuff");
string responseXml = response.ToXML();
Console.WriteLine(responseXml);
StreamWriter FileWrite = new StreamWriter("FileTest.xml", true);
FileWrite.WriteLine(responseXml);
FileWrite.Close();
}
catch (ExceptionsClass)
{
// Exception stuff
throw ex;
}
}
}
private readonly ClientInterface client;
public MainClass(ClientInterface client)
{
this.client = client;
}
public BuildClass InvokeBuild()
{
{
using (var streamReader = new StreamReader("sample.txt", true))
{
string sentinel = streamReader.ReadLine();
Thread.Sleep(6000);
i++;
Console.WriteLine("attempt " + i);
// Create a request.
RequestClass request = new RequestClass();
//Password Stuff
request.IdType = idType;
IdListType idList = new IdListType();
idList.Id.Add(sentinel);
request.IdList = idList;
return this.client.RequestClass(request);
}
}
}
}

Related

C# COM events are not fired

I am trying to fetch events from the TaiPan Realtime COM server. I am able to extract other data from there. Accessing keys is working correctly.
But when i try to fetch events, the function is not fired somehow. Hopefully this is a small mistake. For better readability i made a small test code, which is easyer to read for you. After adding those ids to the Stream the Visual Basic debugger is working and it show cpu activity for com_test.
So i gues events are there but i made mistake in eventhandling somehow.
Thanks for help.
using System;
using System.Collections.Generic;
using TaiPanRTLib;
namespace com_test
{
class Program
{
static void Main(string[] args)
{
var handle = new handle();
handle.start();
Console.ReadLine();
}
}
public class handle
{
public int counter;
// this is a list contains the internal numbers of the taipan Software
public static List<int> numbercodes = new List<int>(new int[] { 78379670, 78379685, 78379692, 78379669, 78379729, 78379672, 78379674, 78379698, 78379682, 78379681, 78379704, 78379689, 78379694, 78379673, 78379697, 78379687, 78379702, 78379690, 78379668, 78379671, 78379715, 78379666, 78379706, 78379727, 78379679, 127289939, 78379677, 78379693, 78379676, 78379678, 78379680, 78379688, 78379726, 78379686, 78379696, 78379675, 78379667, 78379703, 78379691, 78379684, 78379700, 78379699, 78379705, 78379695, 78379701, 78379664, 78379716, 78379982, 78379665, 78379707, 78379728, 78379717, 78379719, 7837971 });
void TPRTDataStream_Bezahlt(int SymbolNr, float Kurs, float Volume, DateTime Zeit)
{
Console.WriteLine("peng"); // never see this in window - so not fired?
counter += 1;
}
public void start()
{
TaiPanRealtime TPRTObject = new TaiPanRealtime(); // connects to launches Application
DataStream TPRTDataStream = (DataStream)TPRTObject.DataStream; // attach to the DataStream Object.
foreach (int db_num in numbercodes)
{
TPRTDataStream.Add(db_num, 0); // This adds the internal dbnumber to the Stream
}
TPRTDataStream.Bezahlt+=new _IDataStreamEvents_BezahltEventHandler(TPRTDataStream_Bezahlt);
while (true)
{
Console.WriteLine(counter); // counter stays 0 all the time
System.Threading.Thread.Sleep(1000);
};
}
}
}
I want to post the solution TaiPan service found out. To handle the events correctly you need to set "Embed Interop Types" to false in the reference properties of visual basic. here is a screenshot:
screenshot properties
hope this helps others.

C#: String Variable Not Passing Value to Parameter

This is probably a simple fix, however I've spent a few hours trying to get this code to work. For my homework assignment, I have to open a text file and place it's data in an ArrayList. I did just that, but then I realized that I am required to do so but creating a method called ReadFileAndStoreInArrayList. Now here is where I am having trouble.
{
class Program
{
static void Main(string[] args)
{
*//This string variable "file" is saying it has been
//assigned but never used.*
string file = #"C:\Users\Latoy\Documents\Schoolwork\IT 232\Unit 5\FamousWords.txt";
}
*//Here is where I attempted to pass the variable by value*.
public void ReadFileAndStoreInArrayList(string file)
{
ArrayList FamousWords = new ArrayList();
using (StreamReader path = new StreamReader(file))
{
string line;
while ((line = path.ReadLine()) != null)
{
FamousWords.Add(line);
}
}
foreach (string line in FamousWords)
{
Console.Write(line);
}
}
}
}
I am fairly new to this, and I have done my research and still can not find what I am doing wrong. Is it the way I called the method? Note: The code works when placed in one method, however I am required to create a method. I attempted to use just the ReadFileAndStoreInArrayList method but the compiler is making me use the main method as well.
Use static keyword for the method you want to call from your main function, or else you won't be able to call it.
public static void ReadFileAndStoreInArrayList(string file)
{
ArrayList FamousWords = new ArrayList();
using (StreamReader path = new StreamReader(file))
{
string line;
while ((line = path.ReadLine()) != null)
{
FamousWords.Add(line);
}
}
foreach (string line in FamousWords)
{
Console.Write(line);
}
}
And then you can call it just like:
ReadFileAndStoreInArrayList(file);
in your main function which should look like:
static void Main(string[] args)
{
*//This string variable "file" is saying it has been
//assigned but never used.*
string file = #"C:\Users\Latoy\Documents\Schoolwork\IT 232\Unit 5\FamousWords.txt";
ReadFileAndStoreInArrayList(file);
}
You're not actually calling your method anywhere. You're missing a call to:
ReadFileAndStoreInArrayList(file);

Retrieve a string containing html Document source using Task parallel

I really hope there's someone experienced enough both with TPL & System.Net Classes and methods
What started as a simple thought of use TPL on current sequential set of actions led me to a halt in my project.
As I am still fresh With .NET, jumping straight to deep water using TPL ...
I was trying to extract an Aspx page's source/content(html) using WebClient
Having multiple requests per day (around 20-30 pages to go through) and extract specific values out of the source code... being only one of few daily tasks the server has on its list,
Led me to try implement it by using TPL, thus gain some speed.
Although I tried using Task.Factory.StartNew() trying to iterate on few WC instances ,
on first try execution of WC the application just does not get any result from the WebClient
This is my last try on it
static void Main(string[] args)
{
EnumForEach<Act>(Execute);
Task.WaitAll();
}
public static void EnumForEach<Mode>(Action<Mode> Exec)
{
foreach (Mode mode in Enum.GetValues(typeof(Mode)))
{
Mode Curr = mode;
Task.Factory.StartNew(() => Exec(Curr) );
}
}
string ResultsDirectory = Environment.CurrentDirectory,
URL = "",
TempSourceDocExcracted ="",
ResultFile="";
enum Act
{
dolar, ValidateTimeOut
}
void Execute(Act Exc)
{
switch (Exc)
{
case Act.dolar:
URL = "http://www.AnyDomainHere.Com";
ResultFile =ResultsDirectory + "\\TempHtm.htm";
TempSourceDocExcracted = IeNgn.AgilityPacDocExtraction(URL).GetElementbyId("Dv_Main").InnerHtml;
File.WriteAllText(ResultFile, TempSourceDocExcracted);
break;
case Act.ValidateTimeOut:
URL = "http://www.AnotherDomainHere.Com";
ResultFile += "\\TempHtm.htm";
TempSourceDocExcracted = IeNgn.AgilityPacDocExtraction(URL).GetElementbyId("Dv_Main").InnerHtml;
File.WriteAllText(ResultFile, TempSourceDocExcracted);
break;
}
//usage of HtmlAgilityPack to extract Values of elements by their attributes/properties
public HtmlAgilityPack.HtmlDocument AgilityPacDocExtraction(string URL)
{
using (WC = new WebClient())
{
WC.Proxy = null;
WC.Encoding = Encoding.GetEncoding("UTF-8");
tmpExtractedPageValue = WC.DownloadString(URL);
retAglPacHtmDoc.LoadHtml(tmpExtractedPageValue);
return retAglPacHtmDoc;
}
}
What am I doing wrong? Is it possible to use a WebClient using TPL at all or should I use another tool (not being able to use IIS 7 / .net4.5)?
I see at least several issues:
naming - FlNm is not a name - VisualStudio is modern IDE with smart code completion, there's no need to save keystrokes (you may start here, there are alternatives too, main thing is too keep it consistent: C# Coding Conventions.
If you're using multithreading, you need to care about resource sharing. For example FlNm is a static string and it is assigned inside each thread, so it's value is not deterministic (also even if it was running sequentially, code would work faulty - you would adding file name in path in each iteration, so it would be like c:\TempHtm.htm\TempHtm.htm\TempHtm.htm)
You're writing to the same file from different threads (well, at least that was your intent I think) - usually that's a recipe for disaster in multithreading. Question is, if you need at all write anything to disk, or it can be downloaded as string and parsed without touching disk - there's a good example what does it mean to touch a disk.
Overall I think you should parallelize only downloading, so do not involve HtmlAgilityPack in multithreading, as I think you don't know it is thread safe. On the other hand, downloading will have good performance/thread count ratio, html parsing - not so much, may be if thread count will be equal to cores count, but not more. Even more - I would separate downloading and parsing, as it would be easier to test, understand and maintain.
Update: I don't understand your full intent, but this may help you started (it's not production code, you should add retry/error catching, etc.).
Also at the end is extended WebClient class allowing you to get more threads spinning, because by default webclient allows only two connections.
class Program
{
static void Main(string[] args)
{
var urlList = new List<string>
{
"http://google.com",
"http://yahoo.com",
"http://bing.com",
"http://ask.com"
};
var htmlDictionary = new ConcurrentDictionary<string, string>();
Parallel.ForEach(urlList, new ParallelOptions { MaxDegreeOfParallelism = 20 }, url => Download(url, htmlDictionary));
foreach (var pair in htmlDictionary)
{
Process(pair);
}
}
private static void Process(KeyValuePair<string, string> pair)
{
// do the html processing
}
private static void Download(string url, ConcurrentDictionary<string, string> htmlDictionary)
{
using (var webClient = new SmartWebClient())
{
htmlDictionary.TryAdd(url, webClient.DownloadString(url));
}
}
}
public class SmartWebClient : WebClient
{
private readonly int maxConcurentConnectionCount;
public SmartWebClient(int maxConcurentConnectionCount = 20)
{
this.maxConcurentConnectionCount = maxConcurentConnectionCount;
}
protected override WebRequest GetWebRequest(Uri address)
{
var httpWebRequest = (HttpWebRequest)base.GetWebRequest(address);
if (httpWebRequest == null)
{
return null;
}
if (maxConcurentConnectionCount != 0)
{
httpWebRequest.ServicePoint.ConnectionLimit = maxConcurentConnectionCount;
}
return httpWebRequest;
}
}

How do I return results while inside a loop in C#?

Essentially, I have a Do..While loop going through some lines from a text file. I want to process a line, return a value (worked or didn't), then move to the next line.
I have a function called ProcessTXT that accepts 2 strings. Source and Destination of new file.
Is there a way to set a ReturnedValue string = to the result and have the backgroundworker check to see if the variable changed? And if so, add this value to the list box?
private void TranslatePOD(string strSource, string strDest,)
{
TextWriter tw = new StreamWriter(strDest);
TextReader tr = new StreamReader(strSource);
do
{
//My Code doing stuff
//Need to send a result somehow now, but i have more work to do in this loop
//Then using tw.writeline() to write my results to my new file
} while (tr.ReadLine() != null);
}
EDIT: Current test code using Yield. My output is "TestingGround.Form1+d__0". Did i do something wrong?
namespace TestingGround
{
public partial class Form1 : Form
{
static IEnumerable<string> TestYield(string strSource)
{
TextReader tr = new StreamReader(strSource);
string strCurLine = System.String.Empty;
while ((strCurLine = tr.ReadLine()) != null)
{
yield return strCurLine;
}
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string MySource = System.String.Empty;
MySource = #"C:\PODTest\Export Script\Export\Shipment List.csv";
listBox1.Items.Add(TestYield(MySource));
}
}
Yield is typically used to return results iteratively, or streaming. There are plenty of examples online. There's one on SO for reading in a file.
It sounds like this is a good case for a producer/consumer queue. C# 4.0 introduced BlockingCollection, which is great for this. Create the blocking collection and ensure that both this process, and whatever needs to consume the results you are passing have access to it. This method can add items to the queue, and whatever is reading the results can use the Take method, which will block [wait] until there is at least one item to take out. The collection is specifically designed to work in multithreaded environments; all of the operations are logically atomic.

What's wrong with my application ---- Size was 0, but I expected 46806 !

I'm a C# programmer.
Now, I'm using the ICSharpCode.SharpZipLib.dll to create a zip file in my current project. But it occurs to me that when I click the button at the SECOND TIME to execute a function to create a zip file, the application will throw an exception, friendly and seriously told me that "Size was zero, but I expected 46086".
I'm so confused that I want to know why? When I click the button at the first time, I can do it successfully without any error.
My related codes are as follows:
internal void ThreadProc()
{
try
{
ZipHelper.CreateZip(backupZipFile, Constants.HomeConstant, true);
// do other things
}
}
The CreateZip() function's realization is as follows:
public static void CreateZip(string zipFileName, string sourceDirectory, bool recurse)
{
FastZip zip = new FastZip();
if (File.Exists(zipFileName))
{
File.Delete(zipFileName);
}
zip.CreateZip(zipFileName, sourceDirectory, true, "");
}
Now, I will show you the recursive calling process:
Call method "UpdateAppAsync" in "ActiveCheckManager" class
public void UpdateAppAsync(string masterConfig)
{
this.masterConf = masterConfig;
Thread actualThread = new Thread(new ThreadStart(UpdateApp));
actualThread.IsBackground = true;
actualThread.CurrentCulture = Thread.CurrentThread.CurrentCulture;
actualThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
actualThread.Start();
}
Call the UpdateApp function asynchronously, in the UpdateApp method, it will only call the UpdateDetail function simply.
private void UpdateDetail(string masterConfig, string category)
{
IUpdate worker = new HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager();
worker.UpdateApp(masterConf);
}
The worker.UpdateApp will call UpdateDetail(string, UpdateCategory) only.
private void UpdateDetail(string masterConfig, UpdateCategory cat)
{
UpdateThread updateThread = new UpdateThread(this, cat);
updateThread.MasterConfig = masterConfig;
updateThread.ThreadProc();
}
That is the calling process. When I click the update button second time, it will throw an exception, can you help me? Thank you very much.
Has the first task thread finished before you start the second time?
I would imagine that File.Delete() and some items in the SharpZipLib to not respond nicelly to multithreadingly zip the same folder simultaneously to the same file.
Promote that " UpdateThread updateThread " as a private member of the "ActiveCheckManager" class, then check if it is already running from a previous click before creating a new thread.

Categories