C# static function is sending wrong arguments to function - c#

My code is passing the wrong argument to a function for some reason.
I have a static class say class A having this function AddMaster :
public static void AddMaster(string ipAddress, int port, List<RegisterMap> registers)
{
// THIS LINE PRINTS THE ACTUAL VALUES SENT FROM THE CALLER FUNCTION
System.IO.File.AppendAllText("datalog_MB.txt", ipAddress + " " + registers[0].FriendlyName + "\n");
new Thread(() =>
{
_tasks.Add(Task.Factory.StartNew(() =>
{
Monitor.Enter(_masters);
_masters.Add(new Master().Connect(ipAddress, port).SetRegisters(registers));
_masters.Last().OnEvent += MasterEvent;
Debug.WriteLine(_masters.Count + " TCP masters connected");
Monitor.Exit(_masters);
}));
}).Start();
}
I have another non-static class Master having the function SetRegisters:
public Master SetRegisters(List<RegisterMap> registerList)
{
// HERE THE FriendlyName ALWAYS PRINTS THE VALUE OF THE LAST FUNCTION CALL
System.IO.File.AppendAllText("datalog_MB_1.txt", _hostname + " " + registerList[0].FriendlyName + "\n");
_registersToRead = registerList;
return this;
}
The function AddMaster() is called in a loop.
The first code logs the following which is correct:
# datalog_MB.txt
192.168.0.12 192.168.0.12:Value 1
192.168.0.11 192.168.0.11:Value 1
However the second code block prints the following ( See the second value has changed ):
# datalog_MB_1.txt
192.168.0.12 192.168.0.11:Value 1
192.168.0.11 192.168.0.11:Value 1
Edit #1
foreach (var equipment in MSSQL.GetEquipments(true))
{
registers.Clear();
System.IO.File.AppendAllText("dataeq.txt", equipment.IPAddress + " " + equipment.Name + " " + equipment.ID + "\n");
try
{
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 1",
Register = 2001,
Type = RegisterType.HoldingRegister,
StationID = 1
});
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 2",
Register = 2002,
Type = RegisterType.HoldingRegister,
StationID = 1
});
A.AddMaster(equipment.IPAddress, 502, registers);
var json = new JavaScriptSerializer().Serialize(registers);
System.IO.File.AppendAllText("data_reg.txt", json + "\n\n");
}
catch(Exception err)
{
System.Windows.MessageBox.Show(err.Message);
}
}
Edit #2*
Fiddle: https://dotnetfiddle.net/h3yn7p
Any idea what might be going wrong?

You should not Clear the registers - recreate it:
List<RegisterMap> registers = null;
foreach(var equipment in equipments)
{
registers = new List<RegisterMap>();
....
}
Otherwise you are processing the same instance of List<RegisterMap> in parallel in multiple threads while manipulating it (i.e. thread which has the foreach(var equipment in equipments) loop will run and create all the threads and start them), which can lead to a lot of different concurrency issues.
Also some notes:
Consider using concurrent collections, for example ConcurrentBag<T> instead of Monitor + List (cause in current code it makes Thread/Task handling pointless)
Based on the provided code there is no need to create Thread - tasks should be enough. In modern .NET there is rarely a case when you need to create Threads manually, most of the time it is hugely discouraged (read more).

Related

Call Monitor using C# TAPI

I need to create a program to monitor activity of phone call.And get information about the calls, like number and Name.
I'm not strong with TAPI code and C#, so hope that anybody can help me, I'm desperate.
I have this code where I try to detect the available devices and obtain information from those devices when a call comes in:
using System;
using TAPI3Lib;
using JulMar.Atapi;
namespace ConsoleApp1
{
class Program
{
private void tapi_ITTAPIEventNotification_Event(TAPI_EVENT TapiEvent, object pEvent)
{
try
{
ITCallNotificationEvent cn = pEvent as ITCallNotificationEvent;
if(cn.Call.CallState == CALL_STATE.CS_CONNECTED)
{
string calledidname = cn.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLEDIDNAME);
Console.WriteLine("Called ID Name " + calledidname);
string callednumber = cn.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLEDIDNUMBER);
Console.WriteLine("Called Number " + callednumber);
string calleridname = cn.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNAME);
Console.WriteLine("Caller ID Name " + calleridname);
string callernumber = cn.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNUMBER);
Console.WriteLine("Caller Number " + callernumber);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void Main(string[] args)
{
TapiManager mgr = new TapiManager("ConsoleApp1");
mgr.Initialize();
foreach(TapiLine line in mgr.Lines)
{
foreach (string s in line.Capabilities.AvailableDeviceClasses)
Console.WriteLine("{0} - {1}", line.Name, s);
}
}
}
}
But when I run it, just see the available devices but don't see any information about calls. I'm used to programming in java so I guess I should send to call the method that gets the call information in the main, but I do not know how to do that and in any code I've seen they do.
So, hope that you can help me to understand how TAPI works and what can I do to do my code work.
Okay, first, you want to stick to one Version of TAPI. In your using statements, youre importing a TAPI 2.x managed libaray and a TAPI 3.x managed library.
using TAPI3Lib; // this is a TAPI 3.x library
using JulMar.Atapi; // this is a TAPI 2.x library
If you're choosing to go with TAPI 3.x, you should start by creating a new class, which handles different kinds of TAPI events. To do so, it needs to implement the ITTAPIEventNotification interface:
public class CallNotification : ITTAPIEventNotification
{
public void Event(TAPI_EVENT TapiEvent, object pEvent)
{
if(pEvent == null)
throw new ArgumentNullException(nameof(pEvent));
switch (TapiEvent)
{
case TAPI_EVENT.TE_CALLNOTIFICATION:
// This event will be raised every time a new call is created on an monitored line-
// You can use CALLINFO_LONG.CIL_ORIGIN to see weather it's an inbound call, or an
// outbound call.
break;
case TAPI_EVENT.TE_CALLSTATE:
// This event will be raised every time the state of a call on one of your monitored
// Lines changes.
// If you'd want to read information about a call, you can do it here:
ITCallStateEvent callStateEvent = (ITCallStateEvent)pEvent;
ITCallInfo call = callStateEvent.Call;
string calledidname = call.get_CallInfoString(CALLINFO_STRING.CIS_CALLEDIDNAME);
Console.WriteLine("Called ID Name " + calledidname);
string callednumber = call.get_CallInfoString(CALLINFO_STRING.CIS_CALLEDIDNUMBER);
Console.WriteLine("Called Number " + callednumber);
string calleridname = call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNAME);
Console.WriteLine("Caller ID Name " + calleridname);
string callernumber = call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNUMBER);
Console.WriteLine("Caller Number " + callernumber);
break;
}
// Since you're working with COM objects, you should release any used references.
Marshal.ReleaseComObject(pEvent);
}
}
In order to use this class, you need to create a new instance of TAPI3Lib.TAPIClass and call its Initialize method. After that, you can attach your newly create CallNotification class as an event handler. You could also specify which types of events you want your handler to receive. Notice that you wont receive any event notifications at this point, because you haven't told TAPIClass which lines it should monitor:
CallNotification callevent = new CallNotification();
TAPIClass tapi = new TAPIClass();
tapi.Initialize();
tapi.EventFilter = (int)(TAPI_EVENT.TE_CALLNOTIFICATION | TAPI_EVENT.TE_CALLSTATE);
tapi.ITTAPIEventNotification_Event_Event += new ITTAPIEventNotification_EventEventHandler(callevent.Event);
In order to tell TAPIClass which lines it should monitor, you need to do two things. ask for all lines registered to you IPBX and determine, weather its a line you have the rights to monitor (this is an IPBX configuration):
public List<ITAddress> EnumerateLines(TAPIClass tapi)
{
List<ITAddress> addresses = new List<ITAddress>();
ITAddress address;
uint arg = 0;
ITAddressCapabilities addressCapabilities;
int callfeatures;
int linefeatures;
bool hasCallFeaturesDial;
bool hasLineFeaturesMakeCall;
IEnumAddress ea = tapi.EnumerateAddresses();
do
{
ea.Next(1, out address, ref arg);
if (address != null)
{
addressCapabilities = (ITAddressCapabilities)address;
callfeatures = addressCapabilities.get_AddressCapability(ADDRESS_CAPABILITY.AC_CALLFEATURES1);
linefeatures = addressCapabilities.get_AddressCapability(ADDRESS_CAPABILITY.AC_LINEFEATURES);
hasCallFeaturesDial = (callfeatures1 & (int)0x00000040) != 0; //Contains LineCallFeatures Dial; see Tapi.h for details
hasLineFeaturesMakeCall = (linefeatures & (int)0x00000008) != 0; //Contains LineFeatures MakeCall; see Tapi.h for details
// this is basically saying "Am I allowed to dial numbers and create calls on this specific line?"
if(hasCallFeaturesDial && hasLineFeaturesMakeCall)
addresses.Add(address);
}
} while (address != null);
return addresses;
}
public void RegisterLines(TAPIClass tapi, IEnumerable<ITAddress> addresses)
{
if (tapi == null)
throw new ArgumentNullException(nameof(tapi));
if (addresses == null)
throw new ArgumentNullException(nameof(addresses));
foreach (ITAddress address in addresses)
{
tapi.RegisterCallNotifications(address, true, true, TapiConstants.TAPIMEDIATYPE_AUDIO, 2);
}
}
so Your initialization would look like this:
CallNotification callevent = new CallNotification();
TAPIClass tapi = new TAPIClass();
tapi.Initialize();
IEnumerable<ITAddress> addresses = this.EnumerateLines(tapi);
this.RegisterLines(tapi, addresses);
tapi.EventFilter = (int)(TAPI_EVENT.TE_CALLNOTIFICATION | TAPI_EVENT.TE_CALLSTATE);
tapi.ITTAPIEventNotification_Event_Event += callevent.Event;
Once you run your program, and it's done executing above code, you will get notifications from incoming and outgoing calls when their call state changes.
I hope you could follow this post. If you have any questions, just ask =)
The line is TapiLine, you have to use TapiCall.

“An item with the same key has already been added” in dictionary

I am trying to add some elements to a dictionary in C# but I've been running into some problems. I am new to C# development so I hope someone could help me with this.
The code for adding the element is:
if (!connections.ContainsKey(port.getParentName()))
{
connections.Add(port.getParentName(), port.getLabel() + ";" + cable + ";" + cableTemplate + "|");
}
else
{
connections[port.getParentName()] += port.getLabel() + ";" + cable + ";" + cableTemplate + "|";
}
Although I'm checking if the key is allready contained in my ports dictionary I'm getting:
“An item with the same key has already been added”
Have to mention also that I am getting the data asynchronously so I would guess that this is a synchronization issue. I tried to handle this by locking this block of code but this does not seem to solve the problem:
System.Object lockThis = new System.Object();
lock (lockThis)
{
....
}
Also have to mention that I am not getting this error all the time. Just that occasionally when starting the application. Any idea what could be causing this? Is the way I'm making the synchronization wrong or is it something else?
Your lock is invalid. You need to have one instance to lock on. You currently create a new one everytime.
Use a ConcurrentDictionary<TKey, TValue> instead and use AddOrUpdate. This removes the need for a lock altogether:
var value = port.getLabel() + ";" + cable + ";" + cableTemplate + "|";
connections.AddOrUpdate(port.getParentName(), value, (k, v) => v + value);
Move your synchronization object in the scope of the class:
public class Test
{
private object syncRoot = new object();
private void Foo()
{
lock (this.syncRoot)
{
....
}
}
}
Make it static or not, depending on how you use your class.
ConcurrentDictionary can handle the synchronization issues for you.

C# Getter-Setter Race Conditions

Suppose I have two threads, thread A and thread B. What happens in C# when thread A sets an object, call it object X, to a value, and thread B comes along and tries to fetch that object while it is getting set by thread A? Would C# throw an exception, would B receive object X before A makes changes to it, or would B receive object X after A makes changes to it?
I thought it was clear, but here is the code (and even with added synchronization I am still not 100% sure that this would cause the exact case I mentioned above to occur):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication8 {
public partial class Form1 : Form {
private AutoResetEvent waitEvent = new AutoResetEvent(false);
int objectX = 0;
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
DateTime startTime = DateTime.Now;
Console.WriteLine("---------------------------- START # " + startTime + " ----------------------------------------------------------------------");
Thread A = new Thread(ThreadAWorkMethod);
Thread B = new Thread(ThreadBWorkMethod);
objectX = 0;
waitEvent = new AutoResetEvent(false);
A.Start();
B.Start();
A.Join();
B.Join();
Console.WriteLine("---------------------------- FINISHED AFTER " + (DateTime.Now - startTime).TotalMilliseconds + " ----------------------------");
}
public void ThreadAWorkMethod() {
waitEvent.WaitOne();
objectX = 5;
Console.WriteLine("Value has been changed to: " + objectX + " in thread A at " + DateTime.Now);
return;
}
public void ThreadBWorkMethod() {
waitEvent.Set();
string xInThreadB = objectX.ToString();
Console.WriteLine("Value in thread B: " + xInThreadB + " at " + DateTime.Now);
return;
}
}
}
The output of thread B to the console looks to be either 0 or 5, but even still you cannot say for certain which thread got serviced first even by checking the DateTime because both threads will have identical timestamps...and one output always makes it to the console first, so whose to say which got serviced first and if the threads actually collided on a get-set. So, in the end it seems that locking is implemented on variables in C# from a lower framework level as some people have mentioned.
Would C# throw an exception
No, it will likely not. There is nothing in the runtime that will check for this condition automatically and raise an exception.
However, the "value" being set may or may not be in a valid state at that point, so as soon as the result is used, whatever uses the value could easily raise an exception.
would B receive object X before A makes changes to it, or would B receive object X after A makes changes to it?
Either is possible. It's also possible, depending on the type of "object", that B would receive the object in an invalid state.
If you know multiple threads will be accessing a value, you should always take care to synchronize the access to your property. There are many options for synchronization, from using the (relatively) simple lock statement to other more complex synchronization options (such as ReaderWriterLock/ReaderWriterLockSlim, Mutex, Semaphore, etc).
So, something like this?
public class Test
{
public Test()
{
DateTime now = DateTime.Now;
Debug.WriteLine("Test started.");
A.Start();
B.Start();
A.Join();
B.Join();
Debug.WriteLine("Total time, in milliseconds, that you just spent in order to save StackOverflow members several minutes of their time: " + (DateTime.Now - now).TotalMilliseconds + " :)");
}
int objectX = 0;
Thread A = new Thread(ThreadAWorkMethod);
Thread B = new Thread(ThreadBWorkMethod);
public void ThreadAWorkMethod()
{
objectX = 5;
Debug.WriteLine("Value has been changed to: " + objectX.ToString() + "at " DateTime.Now.Milliseconds);
return;
}
public void ThreadBWorkMethod()
{
string xInThreadB = objectX.ToString();
Debug.WriteLine("Value in thread b: " + xInThreadB + "at " DateTime.Now.Milliseconds);
return;
}
}
I dunno, try it :)
Potentially similar question to C# Threading: a race condition example.
PS: That's why there is the lock and mutex in .NET Framework.

Query inside a thread

I have 3 comboboxes that are loaded with data from LINQ queries on page load. The problem is that queries contain so much data that it causes Internet Explorer to stop responding for a bit more than a minute.
As there are 3 queries my idea is to put them in 3 different threads, but the problem is at the end the only thing I get is the error saying: "Both DataSource and DataSourceID are defined on 'cbOrganizator'. Remove one definition."
cbOrganizator is a combobox.
Here is the code:
protected void Page_Load(object sender, EventArgs e)
{
Bind();
}
public void Osobe()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var osoba = from o in db.osobas
orderby o.osoba_prezime
select new { o.osoba_id, imePrezime = o.osoba_prezime + " " + o.osoba_ime + " | " + o.tijelo.tijelo_naziv + " | " + o.radno_mjesto.rm_naziv_m };
cbPolaznik.DataSource = osoba;
cbPolaznik.DataTextField = "imePrezime";
cbPolaznik.DataValueField = "osoba_id";
cbPolaznik.DataBind();
cbPolaznik.Items.Insert(0, " ");
cbPredavac.DataSource = osoba;
cbPredavac.DataTextField = "imePrezime";
cbPredavac.DataValueField = "osoba_id";
cbPredavac.DataBind();
cbPredavac.Items.Insert(0, " ");
cbAOM.DataSource = osoba;
cbAOM.DataTextField = "imePrezime";
cbAOM.DataValueField = "osoba_id";
cbAOM.DataBind();
cbAOM.Items.Insert(0, " ");
}
public void Tijela()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var tijelo = from t in db.tijeloes
orderby t.tijelo_naziv
select new { t.tijelo_id, sve = t.tijelo_naziv + " | " + t.mjesto.zupanija_drzava.zupanija_naziv };
cbOrganizator.DataSource = tijelo;
cbOrganizator.DataTextField = "sve";
cbOrganizator.DataValueField = "tijelo_id";
cbOrganizator.DataBind();
cbOrganizator.Items.Insert(0, " ");
}
public void Bind()
{
Thread tOsobe = new Thread(Osobe);
tOsobe.Start();
Thread tTijela = new Thread(Tijela);
tTijela.Start();
}
I don't know what's wrong so any help would be appreciated. The primary idea is to separate queries into threads so if my approach is wrong please let me know.
You're starting threads but not giving them a chance to finish before the page is loaded. I don't know how that results in your particular error, but if your page loads before the thread is completed, then you definitely won't get results.
I really don't see how you'll be able to accomplish what you're trying to do without AJAX.
if you do really want to do it with threads i would suggest performing the query on the threadpool. you can abstract your method so that it is called in delegate of the threadpool method
so i would replace bind with
ThreadPool.QueueUserWorkItem(new WaitCallback(Osobe));
ThreadPool.QueueUserWorkItem(new WaitCallback(Tijela));
change signature of Osobe, and Tijela to acccept a Object
eg.public void Osobe(object a )
you will also need to marshal the call across the thread as i am not sure if webforms will accept if the binding is happening on another thread.
All said and done is still feel the ajax method is the best way forward.

Question about effective logging in C#

I've written a simple class for debugging and I call the method Debugger.WriteLine(...) in my code like this:
Debugger.WriteLine("[Draw]", "InProgress",
"[x,y] = " + x.ToString("0.00") +
", " + y.ToString("0.00") +
"; pos = " + lastPosX.ToString() + "x" +
lastPosY.ToString() + " -> " + posX.ToString() +
"x" + posY.ToString() + "; SS = " +
squareSize.ToString() + "; MST = " +
startTime.ToString("0.000") + "; Time = " + time.ToString() +
phase.ToString(".0000") + "; progress = " +
progress.ToString("0.000") + "; step = " +
step.ToString() + "; TimeMovementEnd = " +
UI.MovementEndTime.ToString()
);
The body of the procedure Debugger.WriteLine is compiled only in Debug mode (directives #if, #endif). What makes me worry is that I often need ToString() in Debugger.WriteLine call which is costly because it creates still new strings (for changing number for example). How to solve this problem?
A few points/questions about debugging/tracing:
I don't want to wrap every Debugger.WriteLine in an IF statement or to use preprocessor directives in order to leave out debugging methods because it would inevitable lead to a not very readable code and it requires too much typing.
I don't want to use any framework for tracing/debugging. I want to try to program it myself.
Are Trace methods left out if compiling in release mode? If it is so is it possible that my methods would behave similarly?
With the static String.Format method I can do this:
output = String.Format("You are now {0} years old.", years);
Which seems nice. Is it a solution for my problem with ToString()?
Using Reflector I found out that Debug.Writeline is declared this way :
[Conditional("DEBUG")]
public static void WriteLine(string message)
That means that in Release mode all calls to this method are eliminated from code.
For example this code :
public static void Test(int a)
{
string b = Console.ReadLine();
Debug.WriteLine(a + " " + b);
Console.WriteLine(a + " " + b);
}
compiles in release mode to :
public static void Test(int a)
{
Console.WriteLine(a + " " + Console.ReadLine());
}
Use StringBuilder to create your output strings instead of concatenating each and every value.
And you can create your own custom debugger (MyDbg) class that contains a WriteLine member the contents of which you can surround with compile directives. It wouldn't entirely compile out the debug code but would turn you MyDbg.WriteLine calls into no-ops.
Here's a quick sketch of the class:
using System;
using System.Text ;
public static class MyDbg
{
public static void WriteLine(string str) // and some other params
{
#if DEBUG
StringBuilder sb = new StringBuilder();
sb.Append(str);
// etc. appending other params as you see fit
#endif
}
}
OR
[Conditional("DEBUG")]
public static class MyDbg
{
public static void WriteLine(string str) // and some other params
{
StringBuilder sb = new StringBuilder();
sb.Append(str);
// etc. appending other params as you see fit
}
}
You'd modify it to suit your own needs of course. And instead of creating a separate class, you could create a member method if #if DEBUG/#endif built-in for displaying its own state when in the debugger.
For Logging have a look at frameworks such as Log4net or the Enterprise library. They make logging configurable in many ways. Even if you want to log at all.
HTH
The pattern I use is to define a logging interface (ILogger) that gets dependency injected into all the classes
public class MyClassThatLogs
{
public MyClassThatLogs(ILogger logger)
{
try
{
logger.Write("bla bla bla");
}
catch(Exception ex)
{
logger.Write(ex); //overload of Write() that takes in an Exception
}
}
}
So when you new it up you can pass in a 'real' logger or a mock/fake one
var mc = new MyClassThatLogs(new FakeLogger());
Now you have abstracted away the need to know in the MyClassThatLogs class what's going on with logging. Basic SOLID stuff. So the 'top' (say main() method of a console) would have the IF DEBUG directive then pass in the correct implementation of the logger.
You do not need to wrap every line. Just write helper method containing Debug.WriteLine and turn it on/off by flag (usually bool).
Tracing will be in your code even in release mode. You can configure it, see http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener.aspx
string.Format calls ToString() on arguments internally, so no benefit there.

Categories