Server startup error - c#

Server start up error when trying to add a purger timer ( game feature) seems that the server is not allowed access?
PurgeTimer:
using System;
using System.Threading;
using System.Collections.Concurrent;
using Plus.HabboHotel.GameClients;
using Plus.HabboHotel.Rooms;
namespace Plus.HabboHotel.Minigames.Purge
{
/// <summary>
/// This will do a countdown before the match starts
/// </summary>
public class PurgeTimer
{
/// <summary>
/// Timer for our operation
/// </summary>
private Timer Timer;
public bool On = false;
/// <summary>
/// Constructor
/// </summary>
public PurgeTimer()
{
// Method to call when completed
TimerCallback TimerCallback = Ticked;
// Create a new instance of timer
Timer = new Timer(TimerCallback, null, 30000, Timeout.Infinite);
}
/// <summary>
/// Method is call when timer is finished
/// </summary>
/// <param name="info">The information</param>
public void Ticked(object info)
{
try
{
if (PurgeManager.Running)
{
foreach (GameClient client in PlusEnvironment.GetGame().GetClientManager()._clients.Values)
{
try
{
if (client == null)
{
continue;
}
client.SendWhisper("[Automatic Event Alert]: The hotel is currently under Purge Mode. All crime is legal.");
}
catch (Exception e)
{
}
}
Timer.Change(30000, Timeout.Infinite);
}
else
{
return;
}
}
catch { }
}
}
}
PurgeManager:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Plus.HabboHotel.Minigames.Purge;
using System.Threading.Tasks;
namespace Plus.HabboHotel.Minigames.Purge
{
public class PurgeManager
{
public static PurgeTimer MainTimer;
public static bool Running;
}
}
Error:
http://prntscr.com/9ss0qb I don't get while it's not accessible!

Firstly, please post the error directly into the question, not as a linked image.
The error Plus.HabboHotel.GameClients.GameClientManager._clients is inaccessible due to its protection level seems pretty clear. From the naming convention used I'd take a guess that the _clients collection is private.

Here is your problem.
From your GameClientManager class, you're trying to access a private field.
private ConcurrentDictionary<int, GameClient> _clients;
For more details regarding your problem, review this. What are Access Modifiers in C#?

Related

Initialize an object inside a thread and control it from main thread

I have created an object which is used to control a piece of test equipment (oscilloscope) which communicates using the Visa library. This object (scope object) works fine, but there is one method I created to query the scope for a waveform average, which takes a while to execute (around a second or so), and blocks execution of the UI while it is acquiring the data.
To get around this problem, I initially tried creating a task object and using this task object to execute the function that is querying the scope for the data; but I found that something in the Visa driver object itself was apparently still executing on the main thread (and thus slowing down my UI).
I then did one more test and created a new thread, and had this thread call a function. Inside this function, I initialized the scope object, setup the operating parameters, and then called the long-running function. This time, my UI was as responive as normal with no slowdowns.
So now, It seems that I need to actually initialize the scope object inside a new thread in order to get it to truly run asynchronously. But now I have a new challenge. I need to access the objects properties and methods from the main thread to set things up, query status info, etc. Is there a clean way to effectively read and write to a class's properties and methods from another thread? Or are there any existing libraries available to make this simpler?
My current idea is to create a wrapper class for the scope object and then have this wrapper class initialize the scope object in a new thread. But I'm not sure of the best way to access the object's members efficiently. Or better yet, is there a better approach to this problem?
EDIT: Below is some more information and code for the test program I wrote. The UI is a just a simple form with Acquire and Connect buttons, and two labels (one for showing the measurements and the other shows a number that gets incremented as I click on the "Click" button:
Here's the code for the Scope Object I created:
using System;
using Ivi.Scope.Interop;
using Tektronix.Tkdpo2k3k4k.Interop;
using System.Diagnostics;
namespace Test_App
{
public class DPO4034
{
#region [NOTES] Installing TekVisa Drivers for DPO4034
/*
1. Download and install the TekVisa Connectivity Software from here:
https://www.tek.com/oscilloscope/tds7054-software/tekvisa-connectivity-software-v411
2. Check under Start -> All Programs -> TekVisa and see if the "Open Choice Installation Manager" shortcut works.If not, then update all shortcuts to point to the correct base folder for the TekVISA files, which is "C:\Program Files\IVI Foundation\VISA\".
3. Download the DPO4000 series IVI driver from here:
https://www.tek.com/oscilloscope/dpo4054-software/dpo2000-dpo3000-dpo4000-ivi-driver
4. After running the unzip utility, open the unzipped folder and goto x64 -> Shared Components, and run the IviCleanupUtility_2.0.0.exe utility to make sure no shared IVI components exist.
5. Run the IviSharedComponents64_2.1.1.exe file to install shared components.
6. Go up one folder and open the IVI Driver Folder and run the Tkdpo2k3k4k-x64.msi installer to install the scope IVI driver.
7. In the VS project, add references to the following COM components:
• IviDriverLib
• IviScopeLib
• Tkdpo2k3k4kLib
8. Right Click on each of the three references in the Solution Explorer and select Properties in the menu. When the properties window appears, set the "Embed Interop Types" property to False.
*/
#endregion
#region Class Variables
Tkdpo2k3k4kClass driver; // IVI Driver representing the DPO4034
IIviScope scope; // IVI Scope object representing the DPO4034
#endregion
#region Class Constructors
public DPO4034()
{
this.driver = new Tkdpo2k3k4kClass();
this.scope = (IIviScope)driver;
}
~DPO4034()
{
this.Disconnect();
}
#endregion
#region Public Properties
/// <summary>
/// Returns true if the scope is connected (initialized)
/// </summary>
public bool Connected
{
get
{
return this.driver.IIviDriver_Initialized;
}
}
#endregion
#region Public Methods
/// <summary>
/// Initializes the connection to the scope
/// <paramref name="reset"/>Resets the scope after connecting if set to true</param>
/// </summary>
/// <returns>True if the function succeeds</returns>
public bool Connect(bool reset = false)
{
try
{
if (!this.Connected)
{
this.Disconnect();
}
this.driver.Initialize("TCPIP::10.10.0.200::INSTR", true, reset, "Simulate=false, DriverSetup= Model=DPO4034");
return true;
}
catch (Exception ex)
{
PrintError(ex, "Connect");
return false;
}
}
/// <summary>
/// Closes the connection to the scope
/// </summary>
/// <returns>True if the function succeeds</returns>
public bool Disconnect()
{
try
{
if (this.Connected)
{
this.driver.Close();
}
return true;
}
catch (Exception ex)
{
PrintError(ex, "Disconnect");
return false;
}
}
/// <summary>
/// Reads the average value of the waveform on the selected channel
/// </summary>
/// <param name="channel">1-4 for channels 1 to 4</param>
/// <returns>The measured average value</returns>
public double ReadWaveformAverage(int channel)
{
if (this.Connected)
{
try
{
double value = 0;
this.scope.Measurements.Item["CH" + channel.ToString()].FetchWaveformMeasurement(IviScopeMeasurementEnum.IviScopeMeasurementVoltageAverage, ref value);
return value;
}
catch (Exception ex)
{
PrintError(ex, "ReadWaveformAverage");
return 0;
}
}
else
{
PrintError("Oscilloscope not connected", "ReadWaveformAverage");
return 0;
}
}
#endregion
#region Private Methods
/// <summary>
/// Prints an error message to the debug console
/// </summary>
/// <param name="err">Error object</param>
/// <param name="source">Source of the error</param>
private void PrintError(Exception err, string source = "") //, bool showMessageBox = false)
{
Debug.Print($"Error: {err.Message}");
Debug.Print($"Source: {source}");
}
/// <summary>
/// Prints an error message to the debug console
/// </summary>
/// <param name="err">Error object</param>
/// <param name="source">Source of the error</param>
private void PrintError(string error, string source = "")
{
Debug.Print($"Error: {error}");
Debug.Print($"Source: {source}");
}
#endregion
}
}
Here's the code for the version of the form that uses an async function and tasks to directly call the acquisition functions:
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Test_App
{
public partial class Form1 : Form
{
byte number = 0;
public Form1()
{
InitializeComponent();
}
private void cmdAcquire_Click(object sender, EventArgs e)
{
takeMeasurements();
}
async void takeMeasurements()
{
try
{
// Create new instance of the scope object and connect to it
DPO4034 Scope = new DPO4034();
Scope.Connect();
// Update status
PrintStatus(Scope.Connected ? "Connected" : "Error");
// Loop continuously and print the samples to the status label
while (Scope.Connected)
{
double inputVoltage = await Task.Run(() => Scope.ReadWaveformAverage(1));
double inputCurrent = await Task.Run(() => Scope.ReadWaveformAverage(2));
double outputVoltage = await Task.Run(() => Scope.ReadWaveformAverage(3));
PrintStatus($"CH1: {inputVoltage}\n" +
$"CH2: {inputCurrent}\n" +
$"CH3: {outputVoltage}\n");
}
}
catch (Exception)
{
PrintStatus("Error");
}
}
private void cmdIncrement(object sender, EventArgs e)
{
// This is just something for me to make the interface do to see
// how responsive it is
lblNumber.Text = number.ToString();
number++;
}
// Prints status text to the label on the form
private void PrintStatus(string text)
{
Status.Text = text;
}
}
}
and here's the code for the version of the form that uses a separate thread to run the scope object:
using System;
using System.Threading;
using System.Windows.Forms;
namespace Test_App
{
public partial class Form1 : Form
{
Thread t;
byte number = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
t = new Thread(new ThreadStart(takeMeasurements));
}
private void cmdAcquire_Click(object sender, EventArgs e)
{
t.Start();
}
// Function to create scope object and take acquisitions
void takeMeasurements()
{
try
{
// Create new instance of the scope object and connect to it
DPO4034 Scope = new DPO4034();
Scope.Connect();
// Update status
PrintStatus(Scope.Connected ? "Connected" : "Error");
// Loop continuously and print the samples to the status label
while (Scope.Connected)
{
double inputVoltage = Scope.ReadWaveformAverage(1);
double inputCurrent = Scope.ReadWaveformAverage(2);
double outputVoltage = Scope.ReadWaveformAverage(3);
PrintStatus($"CH1: {inputVoltage}\n" +
$"CH2: {inputCurrent}\n" +
$"CH3: {outputVoltage}\n");
}
}
catch (Exception)
{
PrintStatus("Error");
}
}
private void cmdIncrement(object sender, EventArgs e)
{
// This is just something for me to make the interface do to see
// how responsive it is
lblNumber.Text = number.ToString();
number++;
}
// Prints status text to the label on the form
private void PrintStatus(string text)
{
if (!this.IsDisposed)
{
this.BeginInvoke((MethodInvoker)delegate
{
Status.Text = text;
});
}
else
{
t.Abort();
}
}
}
}
I hope this gives some more insight into what I'm trying to accomplish. Thank you all for your comments and I look forward to your feedback.
EDIT2: Just to be more clear, the method I would prefer to use (if possible) is the one using tasks. In the current program, the Scope object is initialized at the top of the form on the main thread and accessed by multiple objects within the program.
For anyone interested, I finally found a solution to the problem I was having with the GUI freezing when executing the ReadWaveformData() function.
The answer was to create a new thread inside of the Scope class that would call an Initialization function to initialize the internal scope and driver objects. Then the thread would do nothing but sit and host the instances until the ReadWavveformData() function is called inside a task. Here's the modified DPO4034 class:
using System;
using Ivi.Scope.Interop;
using Tektronix.Tkdpo2k3k4k.Interop;
using System.Diagnostics;
using System.Threading;
namespace Test_App
{
public class DPO4034
{
#region [NOTES] Installing TekVisa Drivers for DPO4034
/*
1. Download and install the TekVisa Connectivity Software from here:
https://www.tek.com/oscilloscope/tds7054-software/tekvisa-connectivity-software-v411
2. Check under Start -> All Programs -> TekVisa and see if the "Open Choice Installation Manager" shortcut works.If not, then update all shortcuts to point to the correct base folder for the TekVISA files, which is "C:\Program Files\IVI Foundation\VISA\".
3. Download the DPO4000 series IVI driver from here:
https://www.tek.com/oscilloscope/dpo4054-software/dpo2000-dpo3000-dpo4000-ivi-driver
4. After running the unzip utility, open the unzipped folder and goto x64 -> Shared Components, and run the IviCleanupUtility_2.0.0.exe utility to make sure no shared IVI components exist.
5. Run the IviSharedComponents64_2.1.1.exe file to install shared components.
6. Go up one folder and open the IVI Driver Folder and run the Tkdpo2k3k4k-x64.msi installer to install the scope IVI driver.
7. In the VS project, add references to the following COM components:
• IviDriverLib
• IviScopeLib
• Tkdpo2k3k4kLib
8. Right Click on each of the three references in the Solution Explorer and select Properties in the menu. When the properties window appears, set the "Embed Interop Types" property to False.
*/
#endregion
#region Class Variables
Tkdpo2k3k4kClass driver; // IVI Driver representing the DPO4034
IIviScope scope; // IVI Scope object representing the DPO4034
Thread t; // Thread to initialize the scope objects in to ensure that they async method calls do not run on the main thread
#endregion
#region Class Constructors
public DPO4034()
{
t = new Thread(new ThreadStart(Initialize));
t.Start();
// Wait for scope object to be initialized in the thread
while (this.scope == null);
}
~DPO4034()
{
this.Disconnect();
t.Abort();
}
#endregion
#region Public Properties
/// <summary>
/// Returns true if the scope is connected (initialized)
/// </summary>
public bool Connected
{
get
{
return this.driver.IIviDriver_Initialized;
}
}
#endregion
#region Public Methods
/// <summary>
/// Initializes the connection to the scope
/// <paramref name="reset"/>Resets the scope after connecting if set to true</param>
/// </summary>
/// <returns>True if the function succeeds</returns>
public bool Connect(bool reset = false)
{
try
{
if (!this.Connected)
{
this.Disconnect();
}
this.driver.Initialize("TCPIP::10.10.0.200::INSTR", true, reset, "Simulate=false, DriverSetup= Model=DPO4034");
return true;
}
catch (Exception ex)
{
PrintError(ex, "Connect");
return false;
}
}
/// <summary>
/// Closes the connection to the scope
/// </summary>
/// <returns>True if the function succeeds</returns>
public bool Disconnect()
{
try
{
if (this.Connected)
{
this.driver.Close();
}
return true;
}
catch (Exception ex)
{
PrintError(ex, "Disconnect");
return false;
}
}
/// <summary>
/// Reads the average value of the waveform on the selected channel
/// </summary>
/// <param name="channel">1-4 for channels 1 to 4</param>
/// <returns>The measured average value</returns>
public double ReadWaveformAverage(int channel)
{
if (this.Connected)
{
try
{
double value = 0;
this.scope.Measurements.Item["CH" + channel.ToString()].FetchWaveformMeasurement(IviScopeMeasurementEnum.IviScopeMeasurementVoltageAverage, ref value);
return value;
}
catch (Exception ex)
{
PrintError(ex, "ReadWaveformAverage");
return 0;
}
}
else
{
PrintError("Oscilloscope not connected", "ReadWaveformAverage");
return 0;
}
}
#endregion
#region Private Methods
private void Initialize()
{
this.driver = new Tkdpo2k3k4kClass();
this.scope = (IIviScope)driver;
// Does nothing but allow the objects to exist on the separate thread
while (true)
{
Thread.Sleep(int.MaxValue);
}
}
/// <summary>
/// Prints an error message to the debug console
/// </summary>
/// <param name="err">Error object</param>
/// <param name="source">Source of the error</param>
private void PrintError(Exception err, string source = "") //, bool showMessageBox = false)
{
Debug.Print($"Error: {err.Message}");
Debug.Print($"Source: {source}");
}
/// <summary>
/// Prints an error message to the debug console
/// </summary>
/// <param name="err">Error object</param>
/// <param name="source">Source of the error</param>
private void PrintError(string error, string source = "")
{
Debug.Print($"Error: {error}");
Debug.Print($"Source: {source}");
}
#endregion
}
}
If this is paired up with the version of the TestApp that uses the async tasks to execute the ReadWaveformData() function, then things run smoothly and I don't need to completely rewrite the scope class to get it to work in my program. Hope this is helpful for anyone else who may run into a similar challenge.

C# Application using Fiorano JMS hangs on exit

I'm using Fiorano's C# support for JMS to publish messages on a topic.
Everything goes fine until the application exits. Then it doesn't actually exit.
I'm assuming that Fiorano is running a foreground thread (but that's a guess on my part.)
Here's a minimal, but complete, example that illustrates the problem:
using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using fiorano.csharp.naming;
// Note: Reference to
// Assembly: fmq-csharp-native
// Version: v2.0.50727
// Runtime Version: 10.2.0.10533
namespace NotificationClientTest
{
/// <summary>
/// Main program
/// </summary>
public static class Program
{
/// <summary>
/// Main method
/// </summary>
/// <param name="args">The arguments. If any exist we hang.</param>
public static void Main(string[] args)
{
Report("Enter Main");
TheFioranoHangOnExit(args.Any());
Report("Leave Main");
}
/// <summary>
/// Trigger the problem.
/// </summary>
/// <param name="problem"> If true, trigger the problem </param>
private static void TheFioranoHangOnExit(bool problem)
{
// Initialize queue
var contextProperties = new Hashtable
{
{ FioranoContext.SECURITY_PRINCIPAL, "user" },
{ FioranoContext.SECURITY_CREDENTIALS, "secretPassword" },
{ FioranoContext.PROVIDER_URL, "http://192.168.5.1:1956" },
{ FioranoContext.BACKUP_URLS, "http://192.168.5.2:1956" },
{ FioranoContext.INITIAL_CONTEXT_FACTORY, "fiorano.jms.runtime.naming.FioranoInitialContextFactory" },
};
var namingContext = new FioranoNamingContext(contextProperties);
var topicFactory = namingContext.lookupTCF("PRIMARYTCF");
if (problem)
{
Report("Creating a connection");
var connection = topicFactory.createTopicConnection();
connection.stop(); // I've tried swapping the order of stop and close just in case...
connection.close();
}
else
{
Report("No Connection");
}
namingContext.close();
}
/// <summary>
/// Write to console, write to debug window
/// </summary>
/// <param name="message">What to say</param>
private static void Report(string message)
{
Console.WriteLine(message);
Debug.WriteLine(message);
}
}
}
Running this application
C:\Playground\FioranoHangTest\bin\Debug>NotificationClientTest.exe
Enter Main
No Connection
Leave Main
C:\Playground\FioranoHangTest\bin\Debug>NotificationClientTest.exe oops
Enter Main
Creating a connection
Leave Main
[At this point the program hangs.
^C or Task Manager can kill it.]
This question describes a similar problem encountered in Java with GlassFish's JMS. Does Fiorano/C# have the same problem?
Otherwise, what am I missing?
I found an ugly work-around:
public static void Main(string[] args)
{
Report("Enter Main");
TheFioranoHangOnExit(args.Any());
Report("Leave Main");
// Evict Fiorano Foreground threads.
Environment.Exit(0);
}
Excuse me, I have to go wash my fingers off with lye soap after typing that one.
I'm still hoping for a better answer.

Code doesn't compile after all errors addressed for Rate Limitation Attempt

The end goal is to rate limit on the parameter which could be brute-forced to reveal sensitive information.
The first file is DisplayMessage.cs having this code:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using BLL;
using DOL;
public partial class DisplayMessage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
//Security Fix for Session Fixation
if (Session["User"] != null && Session["AuthToken"] != null
&& Request.Cookies["AuthToken"] != null)
{
if (!Session["AuthToken"].ToString().Equals(
Request.Cookies["AuthToken"].Value))
{
Response.Redirect("~/default.aspx");
}
}
else
{
Response.Redirect("~/default.aspx");
}
//if (!this.IsPostBack)
//{
BindFullMessage(Convert.ToInt32(Request.QueryString["MessageId"]));
//}
//Rate Limiting Security Vulnerability
using (RateGate rateGate = new RateGate(2, TimeSpan.FromSeconds(1)))
{
for (int i = 0; i < 1000; i++)
{
rateGate.WaitToProceed();
BindFullMessage(Convert.ToInt32(Request.QueryString["MessageId"]));
}
}
}
private void BindFullMessage(int MessageId)
{
CommonMethods commonMethod = new CommonMethods();
lblFullMessage.Text = commonMethod.GetFullMessageByMessageId(MessageId);
}
}
The file RateLim.cs is as follows:
using System;
using System.Web;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
/// <summary>
/// Summary description for RateLim
/// </summary>
public class RateGate : IDisposable
{
// Semaphore used to count and limit the number of occurrences per
// unit time.
private readonly System.Threading.SemaphoreSlim _semaphore;
// Times (in millisecond ticks) at which the semaphore should be exited.
private readonly System.Collections.Concurrent.ConcurrentQueue<int> _exitTimes;
// Timer used to trigger exiting the semaphore.
private readonly Timer _exitTimer;
// Whether this instance is disposed.
private bool _isDisposed;
/// <summary>
/// Number of occurrences allowed per unit of time.
/// </summary>
public int Occurrences { get; private set; }
/// <summary>
/// The length of the time unit, in milliseconds.
/// </summary>
public int TimeUnitMilliseconds { get; private set; }
/// <summary>
/// Initializes a <see cref="RateGate"/> with a rate of <paramref name="occurrences"/>
/// per <paramref name="timeUnit"/>.
/// </summary>
/// <param name="occurrences">Number of occurrences allowed per unit of time.</param>
/// <param name="timeUnit">Length of the time unit.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// If <paramref name="occurrences"/> or <paramref name="timeUnit"/> is negative.
/// </exception>
public RateGate(int occurrences, TimeSpan timeUnit)
{
// Check the arguments.
if (occurrences <= 0)
throw new ArgumentOutOfRangeException("occurrences", "Number of occurrences must be a positive integer");
if (timeUnit != timeUnit.Duration())
throw new ArgumentOutOfRangeException("timeUnit", "Time unit must be a positive span of time");
if (timeUnit >= TimeSpan.FromMilliseconds(UInt32.MaxValue))
throw new ArgumentOutOfRangeException("timeUnit", "Time unit must be less than 2^32 milliseconds");
Occurrences = occurrences;
TimeUnitMilliseconds = (int)timeUnit.TotalMilliseconds;
// Create the semaphore, with the number of occurrences as the maximum count.
_semaphore = new System.Threading.SemaphoreSlim(Occurrences, Occurrences);
// Create a queue to hold the semaphore exit times.
_exitTimes = new System.Collections.Concurrent.ConcurrentQueue<int>();
// Create a timer to exit the semaphore. Use the time unit as the original
// interval length because that's the earliest we will need to exit the semaphore.
_exitTimer = new Timer(ExitTimerCallback, null, TimeUnitMilliseconds, -1);
}
// Callback for the exit timer that exits the semaphore based on exit times
// in the queue and then sets the timer for the nextexit time.
private void ExitTimerCallback(object state)
{
// While there are exit times that are passed due still in the queue,
// exit the semaphore and dequeue the exit time.
int exitTime;
while (_exitTimes.TryPeek(out exitTime)
&& unchecked(exitTime - Environment.TickCount) <= 0)
{
_semaphore.Release();
_exitTimes.TryDequeue(out exitTime);
}
// Try to get the next exit time from the queue and compute
// the time until the next check should take place. If the
// queue is empty, then no exit times will occur until at least
// one time unit has passed.
int timeUntilNextCheck;
if (_exitTimes.TryPeek(out exitTime))
timeUntilNextCheck = unchecked(exitTime - Environment.TickCount);
else
timeUntilNextCheck = TimeUnitMilliseconds;
// Set the timer.
_exitTimer.Change(timeUntilNextCheck, -1);
}
/// <summary>
/// Blocks the current thread until allowed to proceed or until the
/// specified timeout elapses.
/// </summary>
/// <param name="millisecondsTimeout">Number of milliseconds to wait, or -1 to wait indefinitely.</param>
/// <returns>true if the thread is allowed to proceed, or false if timed out</returns>
public bool WaitToProceed(int millisecondsTimeout)
{
// Check the arguments.
if (millisecondsTimeout < -1)
throw new ArgumentOutOfRangeException("millisecondsTimeout");
CheckDisposed();
// Block until we can enter the semaphore or until the timeout expires.
var entered = _semaphore.Wait(millisecondsTimeout);
// If we entered the semaphore, compute the corresponding exit time
// and add it to the queue.
if (entered)
{
var timeToExit = unchecked(Environment.TickCount + TimeUnitMilliseconds);
_exitTimes.Enqueue(timeToExit);
}
return entered;
}
/// <summary>
/// Blocks the current thread until allowed to proceed or until the
/// specified timeout elapses.
/// </summary>
/// <param name="timeout"></param>
/// <returns>true if the thread is allowed to proceed, or false if timed out</returns>
public bool WaitToProceed(TimeSpan timeout)
{
return WaitToProceed((int)timeout.TotalMilliseconds);
}
/// <summary>
/// Blocks the current thread indefinitely until allowed to proceed.
/// </summary>
public void WaitToProceed()
{
WaitToProceed(Timeout.Infinite);
}
// Throws an ObjectDisposedException if this object is disposed.
private void CheckDisposed()
{
if (_isDisposed)
throw new ObjectDisposedException("RateGate is already disposed");
}
/// <summary>
/// Releases unmanaged resources held by an instance of this class.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged resources held by an instance of this class.
/// </summary>
/// <param name="isDisposing">Whether this object is being disposed.</param>
protected virtual void Dispose(bool isDisposing)
{
if (!_isDisposed)
{
if (isDisposing)
{
// The semaphore and timer both implement IDisposable and
// therefore must be disposed.
_semaphore.Dispose();
_exitTimer.Dispose();
_isDisposed = true;
}
}
}
}
The following is the error what it gives:
What am I doing wrong?
EDIT: Build Version + Settings Screenshots added for reference as asked by community
The System.Collections.Concurrent namespace is only available in .Net Framework v4.0 and above. Since it exists in mscorlib, it's not possible that you are missing that reference. The same goes for SemaphoreSlim. Possible solutions are:
If possible, upgrade your project to the newer version of .Net.
Find a library (Nuget?) that will help.
Write your own concurrent collection class.

Multithreading 4-Tier Mixed Producer Consumer Pattern - Threads Not Alternating Properly

Here is the problem I am trying to model: I have an incoming call center (no outbound calls). There are 3 employee levels - Freshers, Technical Lead, Project Manager. In our call center there is only one TL, one PM and multiple Freshers. Calls that the Freshers cannot handle are escalated to the TL, and calls that the TL cannot handle are escalated to the PM.
I need to take an OO C# approach.
Here is my current attempt: I used C# ConcurrentQueue since I thought it would take care of the 'locks'. I want FIFO for call center. I made a queue for each level.
I have a producer (callers) adding calls to the first queue. Mixed prod/consumer freshers check the call (take or escalate to the next queue). Mixed prod/consumer tl, then a pure consumer project manager.
The output is not what I expect. Only the first fresher runs and the project manager does not run at all. I expect a lot more alternation as the calls are added to the queue.
My code is below. Does anyone have a better approach to this problem or is there something wrong with my code?
The CallCenter Class is where most of the action takes place.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
///
/// MIXED CONSUMER/PRODUCER TYPE
/// </summary>
class Fresher
{
// add a class variable for the number of Employee objects instantiated
private static int fresherNum = 0;
private int fresherId;
private ConcurrentQueue<Call> incommingCalls;
private ConcurrentQueue<Call> outgoingCalls;
public Fresher(ConcurrentQueue<Call> calls, ConcurrentQueue<Call> outcalls)
{
fresherId = ++fresherNum;
incommingCalls = calls;
outgoingCalls = outcalls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return fresherId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null)
{
if (call.EscalationLevel == 0)
{
TakeCalls(call);
}
else
{
TransferCalls(call);
}
}
}
}
/// <summary>
/// Transfer to the TL
/// </summary>
public void TransferCalls(Call call)
{
outgoingCalls.Enqueue(call);
Console.WriteLine(".......Fresher {0} escalated call {1}", ID, call.CallID);
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Fresher {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
/// MIXED CONSUMER/PRODUCER TYPE
/// </summary>
class TechnicalLead
{
// add a class variable for the number of Employee objects instantiated
private static int tlNum = 0;
private int tlId;
private ConcurrentQueue<Call> incommingCalls;
private ConcurrentQueue<Call> outgoingCalls;
public TechnicalLead(ConcurrentQueue<Call> calls, ConcurrentQueue<Call> outcalls)
{
tlId = ++tlNum;
incommingCalls = calls;
outgoingCalls = outcalls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return tlId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null)
{
if (call.EscalationLevel == 1)
{
TakeCalls(call);
}
else
{
TransferCalls(call);
}
}
}
}
/// <summary>
/// Transfer to the PM
/// </summary>
public void TransferCalls(Call call)
{
//Console.WriteLine(".......Technical Lead {0} escalated call {1}", ID, call.CallID);
outgoingCalls.Enqueue(call);
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Technical Lead {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CallCenterThreaded
{
class Call
{
private static int numberCalls = 0;
private int callno;
private int esclataion;
public Call()
{
callno = ++numberCalls;
esclataion = 0;
if(callno % 3 == 0)
{
esclataion = 1;
}
if(callno % 5 == 0)
{
esclataion = 2;
}
}
public int CallID { get { return callno; } }
public int EscalationLevel { get { return esclataion; } }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
///
/// </summary>
class CallCenter
{
private ConcurrentQueue<Call> fresherCalls;
private ConcurrentQueue<Call> tlCalls;
private ConcurrentQueue<Call> pmCalls;
private List<Caller> myCallers;
private List<Fresher> myFreshers;
private TechnicalLead tl;
private ProjectManager pm;
public CallCenter()
{
//initial incomming calls to the fresher queue
fresherCalls = new ConcurrentQueue<Call>();
tlCalls = new ConcurrentQueue<Call>();
pmCalls = new ConcurrentQueue<Call>();
myFreshers = new List<Fresher>();
myCallers = new List<Caller>();
generate_callers();
generate_freshers();
tl = new TechnicalLead(tlCalls, pmCalls);
pm = new ProjectManager(pmCalls);
}
/// <summary>
///
/// </summary>
private void generate_freshers()
{
for (int i = 0; i < 5; i++ )
{
myFreshers.Add(new Fresher(fresherCalls, tlCalls));
}
}
/// <summary>
///
/// </summary>
private void generate_callers()
{
for (int i = 0; i < 5; i++ )
{
myCallers.Add(new Caller(fresherCalls));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
/// <summary>
/// PURE CONSUMER
/// </summary>
class ProjectManager
{
// add a class variable for the number of Employee objects instantiated
private static int pmNum = 0;
private int pmId;
private ConcurrentQueue<Call> incommingCalls;
public ProjectManager(ConcurrentQueue<Call> calls)
{
pmId = ++pmNum;
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
public int ID
{
get { return pmId; }
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
Call call;
incommingCalls.TryDequeue(out call);
if (call != null && call.EscalationLevel == 2)
{
TakeCalls(call);
}
}
}
/// <summary>
/// Consume the calls
/// </summary>
public void TakeCalls(Call call)
{
Console.WriteLine("Project Manager {0} handled call {1}", ID, call.CallID);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace CallCenterThreaded
{
class MainClass
{
static void Main(string[] args)
{
CallCenter myCenter = new CallCenter();
Console.ReadLine();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Threading;
namespace CallCenterThreaded
{
/// <summary>
/// This is a producer. It produces calls and adds them to the queue.
/// PURE PRODUCER TYPE
/// </summary>
class Caller
{
private ConcurrentQueue<Call> incommingCalls;
public Caller(ConcurrentQueue<Call> calls)
{
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(placeCalls));
thread.Start();
}
public void placeCalls()
{
//place 10 calls
for (int callno = 0; callno < 4; callno++)
{
//Console.WriteLine("Call {0} was added to the queue", callno);
incommingCalls.Enqueue(new Call());
}
}
}
}
The problem is in the HandleCalls() methods:
public void HandleCalls()
{
while (incommingCalls.Count > 0)
{
…
}
}
What this code does is to check incomingCalls and if there are none, it immediately exits the thread. It's as if the worker came to work, looked at his queue of calls, found nothing there (because he came to work at the same time as the freshers who are supposed to redirect the calls) and so he left and went home.
What you need to do is to wait if there is no work at the moment. Probably the best way to do that is to use BlockingCollection instead of ConcurrentQueue.
Also, your design doesn't seem to that good. For example, there is lots of repeated code.

Unit testing in visual studio 2010 without a main method

Trying to unit test some simple code for a class project, however every time I try to run the test I get an error that there is no home.exe and no main static main method. However, we haven't gotten to the point where we are supposed to have either of those things yet, so how can I run the test without them?
My code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Home
{
class InventoryType
{
/// <summary>
/// Selects the inventory type and returns the selected value
/// </summary>
public class InventorySelect
{
private string inventoryTypes;
public String InventoryTypes
{
set
{
inventoryTypes = value;
}
get
{
return inventoryTypes;
}
}
/// <summary>
/// Validate that the inventory is returning some sort of value
/// </summary>
/// <returns></returns>
public bool Validate()
{
if (InventoryTypes == null) return false;
return true;
}
}
}
}
My Test Code
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Home.InventoryType.InventorySelect;
namespace HomeTest
{
[TestClass]
public class TestInventoryTypeCase
{
[TestMethod]
public void TestInventoryTypeClass()
{
InventorySelect select = new InventorySelect();
select.inventoryTypes = "Collection";
if (Validate() = true)
Console.WriteLine("Test Passed");
else
if (Validate() = false)
Console.WriteLine("Test Returned False");
else
Console.WriteLine("Test Failed To Run");
Console.ReadLine();
}
}
}
OK, a couple things here.
Make sure that your Output type for your main project (the project to be tested) is ClassLibrary
Use Assertions in your tests
I created a ClassLibrary solution called ExampleLibrary. Created a class called InventoryType and copied in your code e.g.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExampleLibrary
{
class InventoryType
{
/// <summary>
/// Selects the inventory type and returns the selected value
/// </summary>
public class InventorySelect
{
private string inventoryTypes;
public String InventoryTypes
{
set
{
inventoryTypes = value;
}
get
{
return inventoryTypes;
}
}
/// <summary>
/// Validate that the inventory is returning some sort of value
/// </summary>
/// <returns></returns>
public bool Validate()
{
if (InventoryTypes == null) return false;
return true;
}
}
}
}
I then created a Unit Test and coded it as follows:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ExampleLibrary;
namespace HomeTest
{
[TestClass]
public class TestInventoryTypeCase
{
[TestMethod]
public void TestInventoryTypeClass()
{
InventoryType.InventorySelect select = new InventoryType.InventorySelect();
select.InventoryTypes = "Collection";
Assert.IsTrue(select.Validate());
select.InventoryTypes = null;
Assert.IsFalse(select.Validate());
}
}
}
I compile and run the test as described above and it runs and returns Test Passed.
To run a test on the main menu bar at the top of your Visual Studio...
Test - Windows - Test Explorer
In the Test Explorer window, select the test you wish to run and click on the run Icon at the top of the window.

Categories